diff --git a/analyzers/archive-analyzer.html b/analyzers/archive-analyzer.html index c8e43e764..931977e6b 100644 --- a/analyzers/archive-analyzer.html +++ b/analyzers/archive-analyzer.html @@ -1,13 +1,13 @@ - + dependency-check – Archive Analyzer @@ -59,9 +59,9 @@
  • Archive Analyzer
  • -
  • | Last Published: 2016-11-05
  • +
  • | Last Published: 2017-01-22
  • - Version: 1.4.4 + Version: 1.4.5
  • @@ -186,7 +186,7 @@ - +
  • @@ -260,7 +260,7 @@
  • - +
  • @@ -248,6 +248,7 @@

    Assembly Analyzer

    OWASP dependency-check includes an analyzer that scans .NET dll and exe files and collect as much information it can about the files as it can. The information collected is internally referred to as evidence and is grouped into vendor, product, and version buckets. Other analyzers later use this evidence to identify any Common Platform Enumeration (CPE) identifiers that apply.

    +

    If dependency-check is being run on a linux system mono-runtime and mono-devel needs to be installed for this analyzer to work.

    Files Types Scanned: EXE, DLL

    @@ -258,7 +259,7 @@
  • - +
  • @@ -259,7 +259,7 @@
  • - +
  • @@ -257,7 +257,7 @@
  • - +
  • @@ -259,7 +259,7 @@
  • - +
  • @@ -259,7 +259,7 @@
  • - +
  • @@ -160,7 +160,7 @@
  • - +
  • @@ -418,7 +418,7 @@
  • - +
  • @@ -258,7 +258,7 @@
  • - +
  • @@ -267,7 +267,7 @@ WARNING: There was an issue getting Nexus status. Disabling analyzer.
  • - +
  • @@ -260,7 +260,7 @@
  • - +
  • @@ -259,7 +259,7 @@
  • - +
  • @@ -258,7 +258,7 @@
  • - +
  • @@ -259,7 +259,7 @@
  • - +
  • @@ -260,7 +260,7 @@
  • - +
  • @@ -259,7 +259,7 @@
  • - +
  • @@ -320,7 +320,7 @@ $CLI_SCRIPT --cveUrl20Base $NVD/nvdcve-2.0-%d.xml.gz \
  • - +
  • @@ -293,7 +293,7 @@ <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> - <version>1.4.4</version> + <version>1.4.5</version> <dependencies> <dependency> <groupId>org.mariadb.jdbc</groupId> @@ -331,7 +331,7 @@
  • - +
  • @@ -276,7 +276,7 @@
  • - +
  • @@ -287,7 +287,7 @@
  • - +
  • @@ -276,7 +276,7 @@
  • - +
  • @@ -160,7 +160,7 @@
  • - +
  • @@ -160,7 +160,7 @@
  • - +
  • @@ -200,7 +200,7 @@
  • Field | 
  • Constr | 
  • -
  • Method
  • +
  • Method
  • diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/HintAnalyzer.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/HintAnalyzer.html index 8e8b33a6f..06a50e3b9 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/HintAnalyzer.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/HintAnalyzer.html @@ -2,10 +2,10 @@ - + -HintAnalyzer (Dependency-Check Core 1.4.4 API) - +HintAnalyzer (Dependency-Check Core 1.4.5 API) + @@ -13,13 +13,13 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,13 +13,13 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,13 +13,13 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/exception/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/exception/package-summary.html index 6c0f2adf8..510b4f139 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/exception/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/exception/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.analyzer.exception (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.analyzer.exception (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -33,6 +33,7 @@
  • CPEAnalyzer
  • CpeSuppressionAnalyzer
  • DependencyBundlingAnalyzer
  • +
  • DependencyMergingAnalyzer
  • FalsePositiveAnalyzer
  • FileNameAnalyzer
  • HintAnalyzer
  • @@ -49,6 +50,7 @@
  • RubyBundlerAnalyzer
  • RubyGemspecAnalyzer
  • SwiftPackageManagerAnalyzer
  • +
  • VersionFilterAnalyzer
  • VulnerabilitySuppressionAnalyzer
  • Enums

    diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/package-summary.html index f82414874..b75f7ee1b 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.analyzer (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.analyzer (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/central/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/central/package-summary.html index 379ac2250..6a6d3c9c4 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/central/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/central/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.central (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.central (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/composer/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/composer/package-summary.html index 1d7e76019..ffe6e9064 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/composer/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/composer/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.composer (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.composer (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cpe/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cpe/package-summary.html index f7f36f220..19e281080 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cpe/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cpe/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.cpe (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.cpe (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cwe/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cwe/package-summary.html index 3c782172d..a5a3a56ae 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cwe/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/cwe/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.cwe (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.cwe (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/lucene/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/lucene/package-summary.html index a72b9d526..362d9082b 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/lucene/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/lucene/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.lucene (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.lucene (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nexus/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nexus/package-summary.html index 9a6a652aa..49d0ce051 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nexus/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nexus/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.nexus (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.nexus (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nuget/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nuget/package-summary.html index 9bb4fc0c5..ea8189d3e 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nuget/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nuget/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.nuget (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.nuget (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nvdcve/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nvdcve/package-summary.html index f779b7de2..c90320ea3 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nvdcve/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/nvdcve/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.nvdcve (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.nvdcve (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,14 +13,14 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/cpe/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/cpe/package-summary.html index 475220de1..65cee9dcf 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/cpe/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/cpe/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.update.cpe (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.update.cpe (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/exception/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/exception/package-summary.html index 23398f9e3..6590eccc0 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/exception/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/exception/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.update.exception (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.update.exception (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/nvd/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/nvd/package-summary.html index 669014015..d8ff09010 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/nvd/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/nvd/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.update.nvd (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.update.nvd (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/package-summary.html index 9861784bc..ce4e56c0f 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/data/update/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.data.update (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.data.update (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/dependency/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/dependency/package-summary.html index 629160de9..dae30ebb4 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/dependency/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/dependency/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.dependency (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.dependency (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/exception/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/exception/package-summary.html index bcea75902..000b6c3e8 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/exception/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/exception/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.exception (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.exception (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/package-summary.html index f7983e6bf..0bec60560 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/reporting/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/reporting/package-summary.html index 5416cd003..9bf3fa3ba 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/reporting/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/reporting/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.reporting (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.reporting (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,13 +13,13 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/utils/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/utils/package-summary.html index 18ee04ec6..d145dda47 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/utils/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/utils/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.utils (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.utils (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/hints/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/hints/package-summary.html index 7d240f63e..5619adc60 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/hints/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/hints/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.xml.hints (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.xml.hints (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/pom/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/pom/package-summary.html index e78cd1af3..1ea2c0347 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/pom/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/pom/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.xml.pom (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.xml.pom (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/suppression/package-summary.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/suppression/package-summary.html index 91ca914bb..d36b70a06 100644 --- a/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/suppression/package-summary.html +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/xml/suppression/package-summary.html @@ -2,10 +2,10 @@ - + -org.owasp.dependencycheck.xml.suppression (Dependency-Check Core 1.4.4 API) - +org.owasp.dependencycheck.xml.suppression (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ diff --git a/dependency-check-core/apidocs/overview-summary.html b/dependency-check-core/apidocs/overview-summary.html index 5a3b31dba..29ab484ae 100644 --- a/dependency-check-core/apidocs/overview-summary.html +++ b/dependency-check-core/apidocs/overview-summary.html @@ -2,10 +2,10 @@ - + -Overview (Dependency-Check Core 1.4.4 API) - +Overview (Dependency-Check Core 1.4.5 API) + @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@ - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.exception.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.exception.html index eb8905e40..97c414d7c 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.exception.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.exception.html @@ -39,6 +39,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.html index 012df8b5a..ae976e390 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.analyzer.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.analyzer39
    57%
    1777/3082
    41%
    690/1652
    4.652
    org.owasp.dependencycheck.analyzer41
    58%
    1868/3176
    43%
    767/1756
    4.6
    org.owasp.dependencycheck.analyzer.exception2
    12%
    2/16
    N/A
    1
    @@ -29,68 +29,70 @@ packageTable.sort(0); - + - + - + - + - + - - - + + + - + - + - + + + - + - + - + - + - - + + - + - + - + - + @@ -100,7 +102,9 @@ packageTable.sort(0); - + + +
    Classes in this Package Line Coverage Branch Coverage Complexity
    AbstractAnalyzer
    100%
    4/4
    N/A
    1
    AbstractAnalyzer
    88%
    22/25
    83%
    5/6
    1.4
    AbstractFileTypeAnalyzer
    84%
    33/39
    80%
    8/10
    1.429
    AbstractFileTypeAnalyzer
    90%
    20/22
    87%
    7/8
    1.571
    AbstractSuppressionAnalyzer
    68%
    51/74
    77%
    14/18
    5.333
    AnalysisPhase
    100%
    11/11
    N/A
    0
    AnalysisPhase
    100%
    12/12
    N/A
    0
    Analyzer
    N/A
    N/A
    1
    AnalyzerService
    89%
    17/19
    100%
    6/6
    3
    ArchiveAnalyzer
    34%
    91/261
    18%
    27/146
    6.5
    ArchiveAnalyzer
    34%
    87/255
    16%
    25/148
    6.824
    AssemblyAnalyzer
    32%
    48/148
    21%
    10/46
    7
    AssemblyAnalyzer
    30%
    45/148
    19%
    9/46
    7
    AutoconfAnalyzer
    94%
    64/68
    76%
    26/34
    3.222
    CMakeAnalyzer
    94%
    71/75
    80%
    8/10
    2.625
    CPEAnalyzer
    80%
    191/238
    76%
    102/134
    4.679
    CPEAnalyzer$IdentifierConfidence
    100%
    4/4
    N/A
    4.679
    CPEAnalyzer$IdentifierMatch
    36%
    14/38
    0%
    0/20
    4.679
    CPEAnalyzer
    80%
    193/240
    76%
    102/134
    4.433
    CPEAnalyzer$IdentifierConfidence
    100%
    4/4
    N/A
    4.433
    CPEAnalyzer$IdentifierMatch
    36%
    14/38
    0%
    0/20
    4.433
    CentralAnalyzer
    24%
    18/74
    9%
    3/32
    4
    CentralAnalyzer
    25%
    19/74
    9%
    3/32
    4
    CocoaPodsAnalyzer
    95%
    47/49
    75%
    9/12
    2
    ComposerLockAnalyzer
    86%
    39/45
    75%
    3/4
    2.429
    CpeSuppressionAnalyzer
    90%
    9/10
    66%
    4/6
    2.333
    CpeSuppressionAnalyzer
    90%
    10/11
    66%
    4/6
    2
    DependencyBundlingAnalyzer
    42%
    85/201
    30%
    65/210
    7.2
    DependencyBundlingAnalyzer
    42%
    72/168
    31%
    54/174
    6.5
    DependencyMergingAnalyzer
    48%
    36/75
    33%
    20/60
    4.273
    Experimental
    N/A
    N/A
    0
    FalsePositiveAnalyzer
    46%
    106/227
    25%
    58/230
    10.385
    FalsePositiveAnalyzer
    46%
    107/228
    25%
    58/230
    9.714
    FileNameAnalyzer
    90%
    18/20
    62%
    5/8
    2.333
    FileNameAnalyzer
    90%
    19/21
    62%
    5/8
    2
    FileTypeAnalyzer
    N/A
    N/A
    1
    FileTypeAnalyzer
    N/A
    N/A
    0
    HintAnalyzer
    44%
    50/113
    57%
    29/50
    9.2
    HintAnalyzer
    44%
    50/113
    57%
    29/50
    7.833
    JarAnalyzer
    65%
    351/532
    55%
    198/360
    7.677
    JarAnalyzer$ClassNameInformation
    80%
    17/21
    80%
    8/10
    7.677
    JarAnalyzer
    68%
    365/532
    55%
    199/360
    8.207
    JarAnalyzer$ClassNameInformation
    80%
    17/21
    80%
    8/10
    8.207
    NexusAnalyzer
    18%
    14/77
    3%
    1/30
    3.778
    NexusAnalyzer
    19%
    15/77
    3%
    1/30
    3.778
    NodePackageAnalyzer
    86%
    46/53
    64%
    9/14
    2.429
    NuspecAnalyzer
    25%
    9/36
    0%
    0/6
    2.667
    NvdCveAnalyzer
    53%
    26/49
    50%
    6/12
    3.125
    NvdCveAnalyzer
    54%
    27/50
    50%
    6/12
    2.889
    OpenSSLAnalyzer
    91%
    32/35
    71%
    10/14
    2.25
    PythonDistributionAnalyzer
    79%
    96/121
    55%
    32/58
    4
    PythonDistributionAnalyzer
    79%
    96/121
    53%
    31/58
    4
    PythonPackageAnalyzer
    95%
    66/69
    77%
    14/18
    2
    RubyBundleAuditAnalyzer
    14%
    32/221
    2%
    2/80
    6.231
    RubyBundleAuditAnalyzer
    16%
    38/227
    4%
    4/86
    6.462
    RubyBundlerAnalyzer
    66%
    20/30
    43%
    13/30
    4.5
    RubyBundlerAnalyzer$1
    100%
    2/2
    N/A
    4.5
    SwiftPackageManagerAnalyzer
    92%
    37/40
    50%
    8/16
    2.375
    VulnerabilitySuppressionAnalyzer
    90%
    9/10
    66%
    4/6
    2.333
    VersionFilterAnalyzer
    100%
    40/40
    95%
    65/68
    8.75
    VulnerabilitySuppressionAnalyzer
    90%
    10/11
    66%
    4/6
    2
    @@ -109,6 +113,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.central.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.central.html index c49c34a65..51a0d7f3c 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.central.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.central.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.data.central1
    87%
    55/63
    87%
    21/24
    9.5
    org.owasp.dependencycheck.data.central1
    86%
    53/61
    87%
    21/24
    9.5
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.composer.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.composer.html index c1b50c73c..a9c8906c8 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.composer.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.composer.html @@ -41,6 +41,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cpe.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cpe.html index 03b725b43..d6ab76539 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cpe.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cpe.html @@ -43,6 +43,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cwe.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cwe.html index 0c7489bc0..8b3e84a57 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cwe.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.cwe.html @@ -39,6 +39,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.lucene.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.lucene.html index 6037e0b78..11c827f03 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.lucene.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.lucene.html @@ -51,6 +51,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nexus.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nexus.html index cd3b6c6fb..5ccee3e28 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nexus.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nexus.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.data.nexus2
    22%
    22/99
    12%
    3/25
    2.278
    org.owasp.dependencycheck.data.nexus2
    22%
    22/97
    12%
    3/25
    2.278
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nuget.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nuget.html index 966fe4cfd..1a877d488 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nuget.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nuget.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.data.nuget4
    67%
    46/68
    15%
    6/40
    2.238
    org.owasp.dependencycheck.data.nuget4
    67%
    45/67
    15%
    6/40
    2.238
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nvdcve.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nvdcve.html index bc8016e8e..3b7245263 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nvdcve.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.nvdcve.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.data.nvdcve9
    41%
    315/754
    43%
    96/222
    4.258
    org.owasp.dependencycheck.data.nvdcve9
    42%
    320/754
    45%
    102/222
    4.258
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.cpe.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.cpe.html index 3d920aa29..74c8f3f25 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.cpe.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.cpe.html @@ -40,6 +40,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.exception.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.exception.html index c066a944c..d223fcd10 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.exception.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.exception.html @@ -39,6 +39,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.html index c2de5b58b..3f02f9317 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.html @@ -16,10 +16,10 @@ - + - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.data.update6
    15%
    52/346
    11%
    14/122
    5.68
    org.owasp.dependencycheck.data.update6
    15%
    52/331
    11%
    14/122
    5.833
    org.owasp.dependencycheck.data.update.cpe3
    0%
    0/66
    0%
    0/18
    1.5
    org.owasp.dependencycheck.data.update.exception2
    0%
    0/12
    N/A
    1
    org.owasp.dependencycheck.data.update.nvd8
    69%
    289/414
    71%
    135/188
    2.824
    org.owasp.dependencycheck.data.update.nvd8
    70%
    269/383
    73%
    127/172
    2.699
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.nvd.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.nvd.html index 8deb02b6e..08fc6dc96 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.nvd.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.data.update.nvd.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.data.update.nvd8
    69%
    289/414
    71%
    135/188
    2.824
    org.owasp.dependencycheck.data.update.nvd8
    70%
    269/383
    73%
    127/172
    2.699
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.dependency.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.dependency.html index ac3ee564b..5a51661f0 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.dependency.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.dependency.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.dependency14
    63%
    405/639
    54%
    156/288
    1.957
    org.owasp.dependencycheck.dependency14
    63%
    410/641
    55%
    161/292
    1.973
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.exception.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.exception.html index 7d761f756..0525a2aef 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.exception.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.exception.html @@ -45,6 +45,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.html index 4cdeac94f..2c02f499c 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.html @@ -16,29 +16,29 @@ - + - + - + - - - - + + + + - - + + - - - - + + + +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck2
    64%
    181/282
    64%
    57/88
    2.895
    org.owasp.dependencycheck2
    64%
    187/288
    65%
    59/90
    2.921
    org.owasp.dependencycheck.agent1
    0%
    0/231
    0%
    0/38
    1.375
    org.owasp.dependencycheck.analyzer39
    57%
    1777/3082
    41%
    690/1652
    4.652
    org.owasp.dependencycheck.analyzer41
    58%
    1868/3176
    43%
    767/1756
    4.6
    org.owasp.dependencycheck.analyzer.exception2
    12%
    2/16
    N/A
    1
    org.owasp.dependencycheck.data.central1
    87%
    55/63
    87%
    21/24
    9.5
    org.owasp.dependencycheck.data.central1
    86%
    53/61
    87%
    21/24
    9.5
    org.owasp.dependencycheck.data.composer3
    79%
    53/67
    45%
    19/42
    3.417
    org.owasp.dependencycheck.data.cpe4
    70%
    101/144
    43%
    26/60
    2.621
    org.owasp.dependencycheck.data.cwe2
    39%
    13/33
    25%
    2/8
    2.8
    org.owasp.dependencycheck.data.lucene8
    78%
    97/124
    53%
    35/66
    3.32
    org.owasp.dependencycheck.data.nexus2
    22%
    22/99
    12%
    3/25
    2.278
    org.owasp.dependencycheck.data.nuget4
    67%
    46/68
    15%
    6/40
    2.238
    org.owasp.dependencycheck.data.nvdcve9
    41%
    315/754
    43%
    96/222
    4.258
    org.owasp.dependencycheck.data.update6
    15%
    52/346
    11%
    14/122
    5.68
    org.owasp.dependencycheck.data.nexus2
    22%
    22/97
    12%
    3/25
    2.278
    org.owasp.dependencycheck.data.nuget4
    67%
    45/67
    15%
    6/40
    2.238
    org.owasp.dependencycheck.data.nvdcve9
    42%
    320/754
    45%
    102/222
    4.258
    org.owasp.dependencycheck.data.update6
    15%
    52/331
    11%
    14/122
    5.833
    org.owasp.dependencycheck.data.update.cpe3
    0%
    0/66
    0%
    0/18
    1.5
    org.owasp.dependencycheck.data.update.exception2
    0%
    0/12
    N/A
    1
    org.owasp.dependencycheck.data.update.nvd8
    69%
    289/414
    71%
    135/188
    2.824
    org.owasp.dependencycheck.dependency14
    63%
    405/639
    54%
    156/288
    1.957
    org.owasp.dependencycheck.data.update.nvd8
    70%
    269/383
    73%
    127/172
    2.699
    org.owasp.dependencycheck.dependency14
    63%
    410/641
    55%
    161/292
    1.973
    org.owasp.dependencycheck.exception5
    10%
    10/92
    0%
    0/10
    1.161
    org.owasp.dependencycheck.reporting4
    0%
    0/164
    0%
    0/90
    5.6
    org.owasp.dependencycheck.utils11
    64%
    243/375
    64%
    127/196
    3.855
    org.owasp.dependencycheck.xml.hints7
    72%
    129/179
    62%
    30/48
    2.229
    org.owasp.dependencycheck.xml.pom7
    60%
    133/219
    54%
    40/74
    2.388
    org.owasp.dependencycheck.xml.suppression6
    72%
    257/354
    64%
    120/186
    3.357
    org.owasp.dependencycheck.utils11
    65%
    260/398
    64%
    136/210
    4.018
    org.owasp.dependencycheck.xml.hints7
    75%
    123/162
    75%
    30/40
    2.147
    org.owasp.dependencycheck.xml.pom7
    56%
    123/217
    50%
    37/74
    2.388
    org.owasp.dependencycheck.xml.suppression6
    72%
    224/307
    65%
    115/176
    3.164
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.reporting.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.reporting.html index f49092010..f00be3161 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.reporting.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.reporting.html @@ -42,6 +42,6 @@ var classTable = new SortableTable(document.getElementById("classResults"), ["String", "Percentage", "Percentage", "FormattedNumber"]); classTable.sort(0); - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.utils.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.utils.html index 1b2016c1b..10726e4ef 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.utils.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.utils.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.utils11
    64%
    243/375
    64%
    127/196
    3.855
    org.owasp.dependencycheck.utils11
    65%
    260/398
    64%
    136/210
    4.018
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.hints.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.hints.html index f6663a44b..1c1c65eb4 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.hints.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.hints.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.xml.hints7
    72%
    129/179
    62%
    30/48
    2.229
    org.owasp.dependencycheck.xml.hints7
    75%
    123/162
    75%
    30/40
    2.147
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.pom.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.pom.html index ec79012ba..e048798b4 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.pom.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.pom.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.xml.pom7
    60%
    133/219
    54%
    40/74
    2.388
    org.owasp.dependencycheck.xml.pom7
    56%
    123/217
    50%
    37/74
    2.388
    - + diff --git a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.suppression.html b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.suppression.html index 2162e8e85..f52769c7d 100644 --- a/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.suppression.html +++ b/dependency-check-core/cobertura/frame-summary-org.owasp.dependencycheck.xml.suppression.html @@ -16,7 +16,7 @@ - +
    Package # Classes Line Coverage Branch Coverage Complexity
    org.owasp.dependencycheck.xml.suppression6
    72%
    257/354
    64%
    120/186
    3.357
    org.owasp.dependencycheck.xml.suppression6
    72%
    224/307
    65%
    115/176
    3.164
    - + diff --git a/dependency-check-core/cobertura/frame-summary.html b/dependency-check-core/cobertura/frame-summary.html index 86f01e233..8cb5df9e8 100644 --- a/dependency-check-core/cobertura/frame-summary.html +++ b/dependency-check-core/cobertura/frame-summary.html @@ -16,30 +16,30 @@ - - + + - + - + - - - - + + + + - - + + - - - - + + + +
    Package # Classes Line Coverage Branch Coverage Complexity
    All Packages150
    53%
    4180/7823
    45%
    1577/3485
    3.197
    org.owasp.dependencycheck2
    64%
    181/282
    64%
    57/88
    2.895
    All Packages152
    54%
    4232/7831
    46%
    1660/3575
    3.199
    org.owasp.dependencycheck2
    64%
    187/288
    65%
    59/90
    2.921
    org.owasp.dependencycheck.agent1
    0%
    0/231
    0%
    0/38
    1.375
    org.owasp.dependencycheck.analyzer39
    57%
    1777/3082
    41%
    690/1652
    4.652
    org.owasp.dependencycheck.analyzer41
    58%
    1868/3176
    43%
    767/1756
    4.6
    org.owasp.dependencycheck.analyzer.exception2
    12%
    2/16
    N/A
    1
    org.owasp.dependencycheck.data.central1
    87%
    55/63
    87%
    21/24
    9.5
    org.owasp.dependencycheck.data.central1
    86%
    53/61
    87%
    21/24
    9.5
    org.owasp.dependencycheck.data.composer3
    79%
    53/67
    45%
    19/42
    3.417
    org.owasp.dependencycheck.data.cpe4
    70%
    101/144
    43%
    26/60
    2.621
    org.owasp.dependencycheck.data.cwe2
    39%
    13/33
    25%
    2/8
    2.8
    org.owasp.dependencycheck.data.lucene8
    78%
    97/124
    53%
    35/66
    3.32
    org.owasp.dependencycheck.data.nexus2
    22%
    22/99
    12%
    3/25
    2.278
    org.owasp.dependencycheck.data.nuget4
    67%
    46/68
    15%
    6/40
    2.238
    org.owasp.dependencycheck.data.nvdcve9
    41%
    315/754
    43%
    96/222
    4.258
    org.owasp.dependencycheck.data.update6
    15%
    52/346
    11%
    14/122
    5.68
    org.owasp.dependencycheck.data.nexus2
    22%
    22/97
    12%
    3/25
    2.278
    org.owasp.dependencycheck.data.nuget4
    67%
    45/67
    15%
    6/40
    2.238
    org.owasp.dependencycheck.data.nvdcve9
    42%
    320/754
    45%
    102/222
    4.258
    org.owasp.dependencycheck.data.update6
    15%
    52/331
    11%
    14/122
    5.833
    org.owasp.dependencycheck.data.update.cpe3
    0%
    0/66
    0%
    0/18
    1.5
    org.owasp.dependencycheck.data.update.exception2
    0%
    0/12
    N/A
    1
    org.owasp.dependencycheck.data.update.nvd8
    69%
    289/414
    71%
    135/188
    2.824
    org.owasp.dependencycheck.dependency14
    63%
    405/639
    54%
    156/288
    1.957
    org.owasp.dependencycheck.data.update.nvd8
    70%
    269/383
    73%
    127/172
    2.699
    org.owasp.dependencycheck.dependency14
    63%
    410/641
    55%
    161/292
    1.973
    org.owasp.dependencycheck.exception5
    10%
    10/92
    0%
    0/10
    1.161
    org.owasp.dependencycheck.reporting4
    0%
    0/164
    0%
    0/90
    5.6
    org.owasp.dependencycheck.utils11
    64%
    243/375
    64%
    127/196
    3.855
    org.owasp.dependencycheck.xml.hints7
    72%
    129/179
    62%
    30/48
    2.229
    org.owasp.dependencycheck.xml.pom7
    60%
    133/219
    54%
    40/74
    2.388
    org.owasp.dependencycheck.xml.suppression6
    72%
    257/354
    64%
    120/186
    3.357
    org.owasp.dependencycheck.utils11
    65%
    260/398
    64%
    136/210
    4.018
    org.owasp.dependencycheck.xml.hints7
    75%
    123/162
    75%
    30/40
    2.147
    org.owasp.dependencycheck.xml.pom7
    56%
    123/217
    50%
    37/74
    2.388
    org.owasp.dependencycheck.xml.suppression6
    72%
    224/307
    65%
    115/176
    3.164
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.AnalysisTask.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.AnalysisTask.html index 46624b4d0..a734ed8cb 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.AnalysisTask.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.AnalysisTask.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    AnalysisTask
    66%
    18/27
    100%
    4/4
    2.667
    AnalysisTask
    70%
    21/30
    100%
    4/4
    2.667
     
    @@ -80,16 +80,16 @@  31  
     /**
     32   -
      * Task to support parallelism of dependency-check analysis.
    +
      * Task to support parallelism of dependency-check analysis. Analyses a single
     33   -
      * Analyses a single {@link Dependency} by a specific {@link Analyzer}.
    +
      * {@link Dependency} by a specific {@link Analyzer}.
     34  
      *
     35  
      * @author Stefan Neuhaus
     36  
      */
    -  37  101
     class AnalysisTask implements Callable<Void> {
    +  37  47
     class AnalysisTask implements Callable<Void> {
     38  
     
     39   @@ -134,102 +134,121 @@  59  
         private final List<Throwable> exceptions;
     60   -
     
    +
         /**
     61   -
         /**
    +
          * A reference to the global settings object.
     62   -
          * Creates a new analysis task.
    +
          */
     63   -
          *
    +
         private final Settings settings;
     64   -
          * @param analyzer a reference of the analyzer to execute
    +
     
     65   -
          * @param dependency the dependency to analyze
    +
         /**
     66   -
          * @param engine the dependency-check engine
    +
          * Creates a new analysis task.
     67   -
          * @param exceptions exceptions that occur during analysis will be added to
    +
          *
     68   -
          * this collection of exceptions
    +
          * @param analyzer a reference of the analyzer to execute
     69   -
          */
    -  70  107
         AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions) {
    -  71  107
             this.analyzer = analyzer;
    -  72  107
             this.dependency = dependency;
    -  73  107
             this.engine = engine;
    -  74  107
             this.exceptions = exceptions;
    -  75  107
         }
    +
          * @param dependency the dependency to analyze
    +  70   +
          * @param engine the dependency-check engine
    +  71   +
          * @param exceptions exceptions that occur during analysis will be added to
    +  72   +
          * this collection of exceptions
    +  73   +
          * @param settings a reference to the global settings object; this is
    +  74   +
          * necessary so that when the thread is started the dependencies have a
    +  75   +
          * correct reference to the global settings.
     76   -
     
    -  77   -
         /**
    -  78   -
          * Executes the analysis task.
    -  79   -
          *
    -  80   -
          * @return null
    -  81   -
          * @throws Exception thrown if unable to execute the analysis task
    -  82  
          */
    -  83   -
         @Override
    +  77  53
         AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions, Settings settings) {
    +  78  53
             this.analyzer = analyzer;
    +  79  53
             this.dependency = dependency;
    +  80  53
             this.engine = engine;
    +  81  53
             this.exceptions = exceptions;
    +  82  53
             this.settings = settings;
    +  83  53
         }
     84   -
         public Void call() {
    -  85  102
             Settings.initialize();
    -  86  
     
    -  87  102
             if (shouldAnalyze()) {
    -  88  39
                 LOGGER.debug("Begin Analysis of '{}' ({})", dependency.getActualFilePath(), analyzer.getName());
    -  89   -
                 try {
    -  90  39
                     analyzer.analyze(dependency, engine);
    -  91  0
                 } catch (AnalysisException ex) {
    -  92  0
                     LOGGER.warn("An error occurred while analyzing '{}' ({}).", dependency.getActualFilePath(), analyzer.getName());
    -  93  0
                     LOGGER.debug("", ex);
    -  94  0
                     exceptions.add(ex);
    -  95  0
                 } catch (Throwable ex) {
    -  96  0
                     LOGGER.warn("An unexpected error occurred during analysis of '{}' ({}): {}",
    -  97  0
                             dependency.getActualFilePath(), analyzer.getName(), ex.getMessage());
    -  98  0
                     LOGGER.debug("", ex);
    -  99  0
                     exceptions.add(ex);
    -  100  39
                 }
    -  101   -
             }
    -  102   -
     
    -  103  102
             return null;
    -  104   -
         }
    -  105   -
     
    -  106   +  85  
         /**
    -  107   -
          * Determines if the analyzer can analyze the given dependency.
    -  108   +  86   +
          * Executes the analysis task.
    +  87  
          *
    -  109   -
          * @return whether or not the analyzer can analyze the dependency
    -  110   +  88   +
          * @return null
    +  89   +
          * @throws Exception thrown if unable to execute the analysis task
    +  90  
          */
    +  91   +
         @Override
    +  92   +
         public Void call() {
    +  93   +
             try {
    +  94  49
                 Settings.setInstance(settings);
    +  95   +
     
    +  96  48
                 if (shouldAnalyze()) {
    +  97  46
                     LOGGER.debug("Begin Analysis of '{}' ({})", dependency.getActualFilePath(), analyzer.getName());
    +  98   +
                     try {
    +  99  47
                         analyzer.analyze(dependency, engine);
    +  100  0
                     } catch (AnalysisException ex) {
    +  101  0
                         LOGGER.warn("An error occurred while analyzing '{}' ({}).", dependency.getActualFilePath(), analyzer.getName());
    +  102  0
                         LOGGER.debug("", ex);
    +  103  0
                         exceptions.add(ex);
    +  104  0
                     } catch (Throwable ex) {
    +  105  0
                         LOGGER.warn("An unexpected error occurred during analysis of '{}' ({}): {}",
    +  106  0
                                 dependency.getActualFilePath(), analyzer.getName(), ex.getMessage());
    +  107  0
                         LOGGER.debug("", ex);
    +  108  0
                         exceptions.add(ex);
    +  109  46
                     }
    +  110   +
                 }
     111   -
         boolean shouldAnalyze() {
    -  112  104
             if (analyzer instanceof FileTypeAnalyzer) {
    -  113  70
                 final FileTypeAnalyzer fileTypeAnalyzer = (FileTypeAnalyzer) analyzer;
    -  114  69
                 return fileTypeAnalyzer.accept(dependency.getActualFile());
    +
             } finally {
    +  112  48
                 Settings.cleanup(false);
    +  113  50
             }
    +  114  50
             return null;
     115   -
             }
    +
         }
     116  
     
    -  117  32
             return true;
    +  117   +
         /**
     118   -
         }
    +
          * Determines if the analyzer can analyze the given dependency.
     119   +
          *
    +  120   +
          * @return whether or not the analyzer can analyze the dependency
    +  121   +
          */
    +  122   +
         boolean shouldAnalyze() {
    +  123  49
             if (analyzer instanceof FileTypeAnalyzer) {
    +  124  10
                 final FileTypeAnalyzer fileTypeAnalyzer = (FileTypeAnalyzer) analyzer;
    +  125  10
                 return fileTypeAnalyzer.accept(dependency.getActualFile());
    +  126   +
             }
    +  127   +
     
    +  128  40
             return true;
    +  129   +
         }
    +  130  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.Engine.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.Engine.html index de14e8ba1..e8d759f7e 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.Engine.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.Engine.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    Engine
    63%
    163/255
    63%
    53/84
    2.914
    Engine
    64%
    166/258
    63%
    55/86
    2.943
     
    @@ -276,8 +276,8 @@  138  0
                 return;
     139  
             }
    -  140  66
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    -  141  60
                 analyzers.put(phase, new ArrayList<Analyzer>());
    +  140  72
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    +  141  66
                 analyzers.put(phase, new ArrayList<Analyzer>());
     142  
             }
     143   @@ -285,12 +285,12 @@  144  6
             final AnalyzerService service = new AnalyzerService(serviceClassLoader);
     145  6
             final List<Analyzer> iterator = service.getAnalyzers();
     146  6
             for (Analyzer a : iterator) {
    -  147  156
                 analyzers.get(a.getAnalysisPhase()).add(a);
    -  148  156
                 if (a instanceof FileTypeAnalyzer) {
    +  147  168
                 analyzers.get(a.getAnalysisPhase()).add(a);
    +  148  168
                 if (a instanceof FileTypeAnalyzer) {
     149  108
                     this.fileTypeAnalyzers.add((FileTypeAnalyzer) a);
     150  
                 }
    -  151  156
             }
    +  151  168
             }
     152  6
         }
     153  
     
    @@ -318,1002 +318,1009 @@  165  
          * Get the dependencies identified. The returned list is a reference to the
     166   -
          * engine's synchronized list. You must synchronize on it, when you modify
    +
          * engine's synchronized list. <b>You must synchronize on the returned
     167   -
          * and iterate over it from multiple threads. E.g. this holds for analyzers
    +
          * list</b> when you modify and iterate over it from multiple threads. E.g.
     168   -
          * supporting parallel processing during their analysis phase.
    +
          * this holds for analyzers supporting parallel processing during their
     169   -
          *
    +
          * analysis phase.
     170   -
          * @return the dependencies identified
    +
          *
     171   -
          * @see Collections#synchronizedList(List)
    +
          * @return the dependencies identified
     172   -
          * @see Analyzer#supportsParallelProcessing()
    +
          * @see Collections#synchronizedList(List)
     173   -
          */
    +
          * @see Analyzer#supportsParallelProcessing()
     174   -
         public List<Dependency> getDependencies() {
    -  175  46
             return dependencies;
    -  176   -
         }
    +
          */
    +  175   +
         public synchronized List<Dependency> getDependencies() {
    +  176  52
             return dependencies;
     177   -
     
    +
         }
     178   -
         /**
    +
     
     179   -
          * Sets the dependencies.
    +
         /**
     180   -
          *
    +
          * Sets the dependencies.
     181   -
          * @param dependencies the dependencies
    +
          *
     182   -
          */
    +
          * @param dependencies the dependencies
     183   +
          */
    +  184  
         public void setDependencies(List<Dependency> dependencies) {
    -  184  0
             synchronized (this.dependencies) {
    -  185  0
                 this.dependencies.clear();
    -  186  0
                 this.dependencies.addAll(dependencies);
    -  187  0
             }
    -  188  0
         }
    -  189   -
     
    +  185  0
             synchronized (this.dependencies) {
    +  186  0
                 this.dependencies.clear();
    +  187  0
                 this.dependencies.addAll(dependencies);
    +  188  0
             }
    +  189  0
         }
     190   -
         /**
    +
     
     191   -
          * Scans an array of files or directories. If a directory is specified, it
    +
         /**
     192   -
          * will be scanned recursively. Any dependencies identified are added to the
    +
          * Scans an array of files or directories. If a directory is specified, it
     193   -
          * dependency collection.
    +
          * will be scanned recursively. Any dependencies identified are added to the
     194   -
          *
    +
          * dependency collection.
     195   -
          * @param paths an array of paths to files or directories to be analyzed
    +
          *
     196   -
          * @return the list of dependencies scanned
    -  197   -
          * @since v0.3.2.5
    -  198   -
          */
    -  199   -
         public List<Dependency> scan(String[] paths) {
    -  200  0
             return scan(paths, null);
    -  201   -
         }
    -  202   -
     
    -  203   -
         /**
    -  204   -
          * Scans an array of files or directories. If a directory is specified, it
    -  205   -
          * will be scanned recursively. Any dependencies identified are added to the
    -  206   -
          * dependency collection.
    -  207   -
          *
    -  208  
          * @param paths an array of paths to files or directories to be analyzed
    +  197   +
          * @return the list of dependencies scanned
    +  198   +
          * @since v0.3.2.5
    +  199   +
          */
    +  200   +
         public List<Dependency> scan(String[] paths) {
    +  201  0
             return scan(paths, null);
    +  202   +
         }
    +  203   +
     
    +  204   +
         /**
    +  205   +
          * Scans an array of files or directories. If a directory is specified, it
    +  206   +
          * will be scanned recursively. Any dependencies identified are added to the
    +  207   +
          * dependency collection.
    +  208   +
          *
     209   -
          * @param projectReference the name of the project or scope in which the
    +
          * @param paths an array of paths to files or directories to be analyzed
     210   -
          * dependency was identified
    +
          * @param projectReference the name of the project or scope in which the
     211   -
          * @return the list of dependencies scanned
    +
          * dependency was identified
     212   -
          * @since v1.4.4
    +
          * @return the list of dependencies scanned
     213   -
          */
    +
          * @since v1.4.4
     214   +
          */
    +  215  
         public List<Dependency> scan(String[] paths, String projectReference) {
    -  215  0
             final List<Dependency> deps = new ArrayList<Dependency>();
    -  216  0
             for (String path : paths) {
    -  217  0
                 final List<Dependency> d = scan(path, projectReference);
    -  218  0
                 if (d != null) {
    -  219  0
                     deps.addAll(d);
    -  220   -
                 }
    +  216  0
             final List<Dependency> deps = new ArrayList<Dependency>();
    +  217  0
             for (String path : paths) {
    +  218  0
                 final List<Dependency> d = scan(path, projectReference);
    +  219  0
                 if (d != null) {
    +  220  0
                     deps.addAll(d);
     221   +
                 }
    +  222  
             }
    -  222  0
             return deps;
    -  223   -
         }
    +  223  0
             return deps;
     224   -
     
    +
         }
     225   -
         /**
    +
     
     226   -
          * Scans a given file or directory. If a directory is specified, it will be
    +
         /**
     227   -
          * scanned recursively. Any dependencies identified are added to the
    +
          * Scans a given file or directory. If a directory is specified, it will be
     228   -
          * dependency collection.
    +
          * scanned recursively. Any dependencies identified are added to the
     229   -
          *
    +
          * dependency collection.
     230   -
          * @param path the path to a file or directory to be analyzed
    +
          *
     231   -
          * @return the list of dependencies scanned
    -  232   -
          */
    -  233   -
         public List<Dependency> scan(String path) {
    -  234  0
             return scan(path, null);
    -  235   -
         }
    -  236   -
     
    -  237   -
         /**
    -  238   -
          * Scans a given file or directory. If a directory is specified, it will be
    -  239   -
          * scanned recursively. Any dependencies identified are added to the
    -  240   -
          * dependency collection.
    -  241   -
          *
    -  242  
          * @param path the path to a file or directory to be analyzed
    +  232   +
          * @return the list of dependencies scanned
    +  233   +
          */
    +  234   +
         public List<Dependency> scan(String path) {
    +  235  0
             return scan(path, null);
    +  236   +
         }
    +  237   +
     
    +  238   +
         /**
    +  239   +
          * Scans a given file or directory. If a directory is specified, it will be
    +  240   +
          * scanned recursively. Any dependencies identified are added to the
    +  241   +
          * dependency collection.
    +  242   +
          *
     243   -
          * @param projectReference the name of the project or scope in which the
    +
          * @param path the path to a file or directory to be analyzed
     244   -
          * dependency was identified
    +
          * @param projectReference the name of the project or scope in which the
     245   -
          * @return the list of dependencies scanned
    +
          * dependency was identified
     246   -
          * @since v1.4.4
    +
          * @return the list of dependencies scanned
     247   -
          */
    +
          * @since v1.4.4
     248   +
          */
    +  249  
         public List<Dependency> scan(String path, String projectReference) {
    -  249  0
             final File file = new File(path);
    -  250  0
             return scan(file, projectReference);
    -  251   -
         }
    +  250  0
             final File file = new File(path);
    +  251  0
             return scan(file, projectReference);
     252   -
     
    +
         }
     253   -
         /**
    +
     
     254   -
          * Scans an array of files or directories. If a directory is specified, it
    +
         /**
     255   -
          * will be scanned recursively. Any dependencies identified are added to the
    -  256   -
          * dependency collection.
    -  257   -
          *
    -  258   -
          * @param files an array of paths to files or directories to be analyzed.
    -  259   -
          * @return the list of dependencies
    -  260   -
          * @since v0.3.2.5
    -  261   -
          */
    -  262   -
         public List<Dependency> scan(File[] files) {
    -  263  0
             return scan(files, null);
    -  264   -
         }
    -  265   -
     
    -  266   -
         /**
    -  267  
          * Scans an array of files or directories. If a directory is specified, it
    -  268   +  256  
          * will be scanned recursively. Any dependencies identified are added to the
    -  269   +  257  
          * dependency collection.
    -  270   +  258  
          *
    -  271   +  259  
          * @param files an array of paths to files or directories to be analyzed.
    -  272   -
          * @param projectReference the name of the project or scope in which the
    -  273   -
          * dependency was identified
    -  274   +  260  
          * @return the list of dependencies
    -  275   -
          * @since v1.4.4
    -  276   -
          */
    -  277   -
         public List<Dependency> scan(File[] files, String projectReference) {
    -  278  0
             final List<Dependency> deps = new ArrayList<Dependency>();
    -  279  0
             for (File file : files) {
    -  280  0
                 final List<Dependency> d = scan(file, projectReference);
    -  281  0
                 if (d != null) {
    -  282  0
                     deps.addAll(d);
    -  283   -
                 }
    -  284   -
             }
    -  285  0
             return deps;
    -  286   -
         }
    -  287   -
     
    -  288   -
         /**
    -  289   -
          * Scans a collection of files or directories. If a directory is specified,
    -  290   -
          * it will be scanned recursively. Any dependencies identified are added to
    -  291   -
          * the dependency collection.
    -  292   -
          *
    -  293   -
          * @param files a set of paths to files or directories to be analyzed
    -  294   -
          * @return the list of dependencies scanned
    -  295   +  261  
          * @since v0.3.2.5
    -  296   +  262  
          */
    -  297   -
         public List<Dependency> scan(Collection<File> files) {
    -  298  0
             return scan(files, null);
    -  299   +  263   +
         public List<Dependency> scan(File[] files) {
    +  264  0
             return scan(files, null);
    +  265  
         }
    -  300   +  266  
     
    -  301   +  267  
         /**
    -  302   +  268   +
          * Scans an array of files or directories. If a directory is specified, it
    +  269   +
          * will be scanned recursively. Any dependencies identified are added to the
    +  270   +
          * dependency collection.
    +  271   +
          *
    +  272   +
          * @param files an array of paths to files or directories to be analyzed.
    +  273   +
          * @param projectReference the name of the project or scope in which the
    +  274   +
          * dependency was identified
    +  275   +
          * @return the list of dependencies
    +  276   +
          * @since v1.4.4
    +  277   +
          */
    +  278   +
         public List<Dependency> scan(File[] files, String projectReference) {
    +  279  0
             final List<Dependency> deps = new ArrayList<Dependency>();
    +  280  0
             for (File file : files) {
    +  281  0
                 final List<Dependency> d = scan(file, projectReference);
    +  282  0
                 if (d != null) {
    +  283  0
                     deps.addAll(d);
    +  284   +
                 }
    +  285   +
             }
    +  286  0
             return deps;
    +  287   +
         }
    +  288   +
     
    +  289   +
         /**
    +  290  
          * Scans a collection of files or directories. If a directory is specified,
    -  303   +  291  
          * it will be scanned recursively. Any dependencies identified are added to
    -  304   +  292  
          * the dependency collection.
    -  305   +  293  
          *
    -  306   +  294  
          * @param files a set of paths to files or directories to be analyzed
    +  295   +
          * @return the list of dependencies scanned
    +  296   +
          * @since v0.3.2.5
    +  297   +
          */
    +  298   +
         public List<Dependency> scan(Collection<File> files) {
    +  299  0
             return scan(files, null);
    +  300   +
         }
    +  301   +
     
    +  302   +
         /**
    +  303   +
          * Scans a collection of files or directories. If a directory is specified,
    +  304   +
          * it will be scanned recursively. Any dependencies identified are added to
    +  305   +
          * the dependency collection.
    +  306   +
          *
     307   -
          * @param projectReference the name of the project or scope in which the
    +
          * @param files a set of paths to files or directories to be analyzed
     308   -
          * dependency was identified
    +
          * @param projectReference the name of the project or scope in which the
     309   -
          * @return the list of dependencies scanned
    +
          * dependency was identified
     310   -
          * @since v1.4.4
    +
          * @return the list of dependencies scanned
     311   -
          */
    +
          * @since v1.4.4
     312   +
          */
    +  313  
         public List<Dependency> scan(Collection<File> files, String projectReference) {
    -  313  0
             final List<Dependency> deps = new ArrayList<Dependency>();
    -  314  0
             for (File file : files) {
    -  315  0
                 final List<Dependency> d = scan(file, projectReference);
    -  316  0
                 if (d != null) {
    -  317  0
                     deps.addAll(d);
    -  318   +  314  0
             final List<Dependency> deps = new ArrayList<Dependency>();
    +  315  0
             for (File file : files) {
    +  316  0
                 final List<Dependency> d = scan(file, projectReference);
    +  317  0
                 if (d != null) {
    +  318  0
                     deps.addAll(d);
    +  319  
                 }
    -  319  0
             }
    -  320  0
             return deps;
    -  321   -
         }
    +  320  0
             }
    +  321  0
             return deps;
     322   -
     
    +
         }
     323   -
         /**
    +
     
     324   -
          * Scans a given file or directory. If a directory is specified, it will be
    +
         /**
     325   -
          * scanned recursively. Any dependencies identified are added to the
    -  326   -
          * dependency collection.
    -  327   -
          *
    -  328   -
          * @param file the path to a file or directory to be analyzed
    -  329   -
          * @return the list of dependencies scanned
    -  330   -
          * @since v0.3.2.4
    -  331   -
          */
    -  332   -
         public List<Dependency> scan(File file) {
    -  333  5
             return scan(file, null);
    -  334   -
         }
    -  335   -
     
    -  336   -
         /**
    -  337  
          * Scans a given file or directory. If a directory is specified, it will be
    -  338   +  326  
          * scanned recursively. Any dependencies identified are added to the
    -  339   +  327  
          * dependency collection.
    -  340   +  328  
          *
    -  341   +  329  
          * @param file the path to a file or directory to be analyzed
    -  342   -
          * @param projectReference the name of the project or scope in which the
    -  343   -
          * dependency was identified
    -  344   +  330  
          * @return the list of dependencies scanned
    +  331   +
          * @since v0.3.2.4
    +  332   +
          */
    +  333   +
         public List<Dependency> scan(File file) {
    +  334  5
             return scan(file, null);
    +  335   +
         }
    +  336   +
     
    +  337   +
         /**
    +  338   +
          * Scans a given file or directory. If a directory is specified, it will be
    +  339   +
          * scanned recursively. Any dependencies identified are added to the
    +  340   +
          * dependency collection.
    +  341   +
          *
    +  342   +
          * @param file the path to a file or directory to be analyzed
    +  343   +
          * @param projectReference the name of the project or scope in which the
    +  344   +
          * dependency was identified
     345   -
          * @since v1.4.4
    +
          * @return the list of dependencies scanned
     346   -
          */
    +
          * @since v1.4.4
     347   +
          */
    +  348  
         public List<Dependency> scan(File file, String projectReference) {
    -  348  5
             if (file.exists()) {
    -  349  5
                 if (file.isDirectory()) {
    -  350  3
                     return scanDirectory(file, projectReference);
    -  351   +  349  5
             if (file.exists()) {
    +  350  5
                 if (file.isDirectory()) {
    +  351  3
                     return scanDirectory(file, projectReference);
    +  352  
                 } else {
    -  352  2
                     final Dependency d = scanFile(file, projectReference);
    -  353  2
                     if (d != null) {
    -  354  2
                         final List<Dependency> deps = new ArrayList<Dependency>();
    -  355  2
                         deps.add(d);
    -  356  2
                         return deps;
    -  357   -
                     }
    +  353  2
                     final Dependency d = scanFile(file, projectReference);
    +  354  2
                     if (d != null) {
    +  355  2
                         final List<Dependency> deps = new ArrayList<Dependency>();
    +  356  2
                         deps.add(d);
    +  357  2
                         return deps;
     358   -
                 }
    +
                     }
     359   +
                 }
    +  360  
             }
    -  360  0
             return null;
    -  361   -
         }
    +  361  0
             return null;
     362   -
     
    +
         }
     363   -
         /**
    +
     
     364   -
          * Recursively scans files and directories. Any dependencies identified are
    +
         /**
     365   -
          * added to the dependency collection.
    -  366   -
          *
    -  367   -
          * @param dir the directory to scan
    -  368   -
          * @return the list of Dependency objects scanned
    -  369   -
          */
    -  370   -
         protected List<Dependency> scanDirectory(File dir) {
    -  371  0
             return scanDirectory(dir, null);
    -  372   -
         }
    -  373   -
     
    -  374   -
         /**
    -  375  
          * Recursively scans files and directories. Any dependencies identified are
    -  376   +  366  
          * added to the dependency collection.
    -  377   +  367  
          *
    -  378   +  368  
          * @param dir the directory to scan
    -  379   -
          * @param projectReference the name of the project or scope in which the
    -  380   -
          * dependency was identified
    -  381   +  369  
          * @return the list of Dependency objects scanned
    -  382   -
          * @since v1.4.4
    -  383   +  370  
          */
    -  384   -
         protected List<Dependency> scanDirectory(File dir, String projectReference) {
    -  385  46
             final File[] files = dir.listFiles();
    -  386  46
             final List<Dependency> deps = new ArrayList<Dependency>();
    -  387  46
             if (files != null) {
    -  388  93
                 for (File f : files) {
    -  389  47
                     if (f.isDirectory()) {
    -  390  43
                         final List<Dependency> d = scanDirectory(f, projectReference);
    -  391  43
                         if (d != null) {
    -  392  43
                             deps.addAll(d);
    -  393   -
                         }
    -  394  43
                     } else {
    -  395  4
                         final Dependency d = scanFile(f, projectReference);
    -  396  4
                         deps.add(d);
    -  397   -
                     }
    -  398   -
                 }
    -  399   -
             }
    -  400  46
             return deps;
    -  401   +  371   +
         protected List<Dependency> scanDirectory(File dir) {
    +  372  0
             return scanDirectory(dir, null);
    +  373  
         }
    -  402   +  374  
     
    -  403   +  375  
         /**
    -  404   -
          * Scans a specified file. If a dependency is identified it is added to the
    -  405   -
          * dependency collection.
    -  406   +  376   +
          * Recursively scans files and directories. Any dependencies identified are
    +  377   +
          * added to the dependency collection.
    +  378  
          *
    -  407   -
          * @param file The file to scan
    -  408   -
          * @return the scanned dependency
    -  409   -
          */
    -  410   -
         protected Dependency scanFile(File file) {
    -  411  3
             return scanFile(file, null);
    -  412   -
         }
    -  413   -
     
    -  414   -
         /**
    -  415   -
          * Scans a specified file. If a dependency is identified it is added to the
    -  416   -
          * dependency collection.
    -  417   -
          *
    -  418   -
          * @param file The file to scan
    -  419   +  379   +
          * @param dir the directory to scan
    +  380  
          * @param projectReference the name of the project or scope in which the
    -  420   +  381  
          * dependency was identified
    -  421   -
          * @return the scanned dependency
    -  422   +  382   +
          * @return the list of Dependency objects scanned
    +  383  
          * @since v1.4.4
    -  423   +  384  
          */
    -  424   -
         protected Dependency scanFile(File file, String projectReference) {
    -  425  9
             Dependency dependency = null;
    -  426  9
             if (file.isFile()) {
    -  427  9
                 if (accept(file)) {
    -  428  7
                     dependency = new Dependency(file);
    -  429  7
                     if (projectReference != null) {
    -  430  0
                         dependency.addProjectReference(projectReference);
    -  431   +  385   +
         protected List<Dependency> scanDirectory(File dir, String projectReference) {
    +  386  46
             final File[] files = dir.listFiles();
    +  387  46
             final List<Dependency> deps = new ArrayList<Dependency>();
    +  388  46
             if (files != null) {
    +  389  93
                 for (File f : files) {
    +  390  47
                     if (f.isDirectory()) {
    +  391  43
                         final List<Dependency> d = scanDirectory(f, projectReference);
    +  392  43
                         if (d != null) {
    +  393  43
                             deps.addAll(d);
    +  394   +
                         }
    +  395  43
                     } else {
    +  396  4
                         final Dependency d = scanFile(f, projectReference);
    +  397  4
                         deps.add(d);
    +  398  
                     }
    -  432  7
                     final String sha1 = dependency.getSha1sum();
    -  433  7
                     boolean found = false;
    -  434  7
                     synchronized (dependencies) {
    -  435  7
                         if (sha1 != null) {
    -  436  7
                             for (Dependency existing : dependencies) {
    -  437  4
                                 if (sha1.equals(existing.getSha1sum())) {
    -  438  1
                                     found = true;
    -  439  1
                                     if (projectReference != null) {
    -  440  0
                                         existing.addProjectReference(projectReference);
    -  441   -
                                     }
    -  442  1
                                     if (existing.getActualFilePath() != null && dependency.getActualFilePath() != null
    -  443  1
                                             && !existing.getActualFilePath().equals(dependency.getActualFilePath())) {
    -  444  0
                                         existing.addRelatedDependency(dependency);
    -  445   -
                                     } else {
    -  446  1
                                         dependency = existing;
    -  447   -
                                     }
    -  448  1
                                     break;
    -  449   -
                                 }
    -  450  3
                             }
    -  451   -
                         }
    -  452  7
                         if (!found) {
    -  453  6
                             dependencies.add(dependency);
    -  454   -
                         }
    -  455  7
                     }
    -  456  7
                 } else {
    -  457  2
                     LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
    -  458   +  399  
                 }
    -  459   +  400  
             }
    -  460  9
             return dependency;
    -  461   +  401  46
             return deps;
    +  402  
         }
    -  462   +  403  
     
    -  463   +  404  
         /**
    -  464   -
          * Runs the analyzers against all of the dependencies. Since the mutable
    -  465   -
          * dependencies list is exposed via {@link #getDependencies()}, this method
    -  466   -
          * iterates over a copy of the dependencies list. Thus, the potential for
    -  467   -
          * {@link java.util.ConcurrentModificationException}s is avoided, and
    -  468   -
          * analyzers may safely add or remove entries from the dependencies list.
    -  469   -
          * <p>
    -  470   -
          * Every effort is made to complete analysis on the dependencies. In some
    -  471   -
          * cases an exception will occur with part of the analysis being performed
    -  472   -
          * which may not affect the entire analysis. If an exception occurs it will
    -  473   -
          * be included in the thrown exception collection.
    -  474   +  405   +
          * Scans a specified file. If a dependency is identified it is added to the
    +  406   +
          * dependency collection.
    +  407  
          *
    -  475   -
          * @throws ExceptionCollection a collections of any exceptions that occurred
    -  476   -
          * during analysis
    -  477   +  408   +
          * @param file The file to scan
    +  409   +
          * @return the scanned dependency
    +  410  
          */
    +  411   +
         protected Dependency scanFile(File file) {
    +  412  3
             return scanFile(file, null);
    +  413   +
         }
    +  414   +
     
    +  415   +
         /**
    +  416   +
          * Scans a specified file. If a dependency is identified it is added to the
    +  417   +
          * dependency collection.
    +  418   +
          *
    +  419   +
          * @param file The file to scan
    +  420   +
          * @param projectReference the name of the project or scope in which the
    +  421   +
          * dependency was identified
    +  422   +
          * @return the scanned dependency
    +  423   +
          * @since v1.4.4
    +  424   +
          */
    +  425   +
         protected Dependency scanFile(File file, String projectReference) {
    +  426  9
             Dependency dependency = null;
    +  427  9
             if (file.isFile()) {
    +  428  9
                 if (accept(file)) {
    +  429  7
                     dependency = new Dependency(file);
    +  430  7
                     if (projectReference != null) {
    +  431  0
                         dependency.addProjectReference(projectReference);
    +  432   +
                     }
    +  433  7
                     final String sha1 = dependency.getSha1sum();
    +  434  7
                     boolean found = false;
    +  435  7
                     synchronized (dependencies) {
    +  436  7
                         if (sha1 != null) {
    +  437  7
                             for (Dependency existing : dependencies) {
    +  438  4
                                 if (sha1.equals(existing.getSha1sum())) {
    +  439  1
                                     found = true;
    +  440  1
                                     if (projectReference != null) {
    +  441  0
                                         existing.addProjectReference(projectReference);
    +  442   +
                                     }
    +  443  1
                                     if (existing.getActualFilePath() != null && dependency.getActualFilePath() != null
    +  444  1
                                             && !existing.getActualFilePath().equals(dependency.getActualFilePath())) {
    +  445  0
                                         existing.addRelatedDependency(dependency);
    +  446   +
                                     } else {
    +  447  1
                                         dependency = existing;
    +  448   +
                                     }
    +  449  1
                                     break;
    +  450   +
                                 }
    +  451  3
                             }
    +  452   +
                         }
    +  453  7
                         if (!found) {
    +  454  6
                             dependencies.add(dependency);
    +  455   +
                         }
    +  456  7
                     }
    +  457  7
                 } else {
    +  458  2
                     LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
    +  459   +
                 }
    +  460   +
             }
    +  461  9
             return dependency;
    +  462   +
         }
    +  463   +
     
    +  464   +
         /**
    +  465   +
          * Runs the analyzers against all of the dependencies. Since the mutable
    +  466   +
          * dependencies list is exposed via {@link #getDependencies()}, this method
    +  467   +
          * iterates over a copy of the dependencies list. Thus, the potential for
    +  468   +
          * {@link java.util.ConcurrentModificationException}s is avoided, and
    +  469   +
          * analyzers may safely add or remove entries from the dependencies list.
    +  470   +
          * <p>
    +  471   +
          * Every effort is made to complete analysis on the dependencies. In some
    +  472   +
          * cases an exception will occur with part of the analysis being performed
    +  473   +
          * which may not affect the entire analysis. If an exception occurs it will
    +  474   +
          * be included in the thrown exception collection.
    +  475   +
          *
    +  476   +
          * @throws ExceptionCollection a collections of any exceptions that occurred
    +  477   +
          * during analysis
     478   +
          */
    +  479  
         public void analyzeDependencies() throws ExceptionCollection {
    -  479  2
             final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
    -  480  2
             boolean autoUpdate = true;
    -  481   +  480  2
             final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
    +  481  2
             boolean autoUpdate = true;
    +  482  
             try {
    -  482  2
                 autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
    -  483  0
             } catch (InvalidSettingException ex) {
    -  484  0
                 LOGGER.debug("Invalid setting for auto-update; using true.");
    -  485  0
                 exceptions.add(ex);
    -  486  2
             }
    -  487  2
             if (autoUpdate) {
    -  488   +  483  2
                 autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
    +  484  0
             } catch (InvalidSettingException ex) {
    +  485  0
                 LOGGER.debug("Invalid setting for auto-update; using true.");
    +  486  0
                 exceptions.add(ex);
    +  487  2
             }
    +  488  2
             if (autoUpdate) {
    +  489  
                 try {
    -  489  0
                     doUpdates();
    -  490  0
                 } catch (UpdateException ex) {
    -  491  0
                     exceptions.add(ex);
    -  492  0
                     LOGGER.warn("Unable to update Cached Web DataSource, using local "
    -  493   +  490  0
                     doUpdates();
    +  491  0
                 } catch (UpdateException ex) {
    +  492  0
                     exceptions.add(ex);
    +  493  0
                     LOGGER.warn("Unable to update Cached Web DataSource, using local "
    +  494  
                             + "data instead. Results may not include recent vulnerabilities.");
    -  494  0
                     LOGGER.debug("Update Error", ex);
    -  495  0
                 }
    -  496   -
             }
    +  495  0
                     LOGGER.debug("Update Error", ex);
    +  496  0
                 }
     497   -
     
    +
             }
     498   -
             //need to ensure that data exists
    +
     
     499   +
             //need to ensure that data exists
    +  500  
             try {
    -  500  2
                 ensureDataExists();
    -  501  0
             } catch (NoDataException ex) {
    -  502  0
                 throwFatalExceptionCollection("Unable to continue dependency-check analysis.", ex, exceptions);
    -  503  0
             } catch (DatabaseException ex) {
    -  504  0
                 throwFatalExceptionCollection("Unable to connect to the dependency-check database.", ex, exceptions);
    -  505  2
             }
    -  506   -
     
    -  507  2
             LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
    -  508  2
             LOGGER.info("Analysis Started");
    -  509  2
             final long analysisStart = System.currentTimeMillis();
    -  510   +  501  2
                 ensureDataExists();
    +  502  0
             } catch (NoDataException ex) {
    +  503  0
                 throwFatalExceptionCollection("Unable to continue dependency-check analysis.", ex, exceptions);
    +  504  0
             } catch (DatabaseException ex) {
    +  505  0
                 throwFatalExceptionCollection("Unable to connect to the dependency-check database.", ex, exceptions);
    +  506  2
             }
    +  507  
     
    +  508  2
             LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
    +  509  2
             LOGGER.info("Analysis Started");
    +  510  2
             final long analysisStart = System.currentTimeMillis();
     511   +
     
    +  512  
             // analysis phases
    -  512  22
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    -  513  20
                 final List<Analyzer> analyzerList = analyzers.get(phase);
    -  514   +  513  24
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    +  514  22
                 final List<Analyzer> analyzerList = analyzers.get(phase);
    +  515  
     
    -  515  20
                 for (final Analyzer analyzer : analyzerList) {
    -  516  52
                     final long analyzerStart = System.currentTimeMillis();
    -  517   +  516  22
                 for (final Analyzer analyzer : analyzerList) {
    +  517  56
                     final long analyzerStart = System.currentTimeMillis();
    +  518  
                     try {
    -  518  52
                         initializeAnalyzer(analyzer);
    -  519  1
                     } catch (InitializationException ex) {
    -  520  1
                         exceptions.add(ex);
    -  521  1
                         continue;
    -  522  51
                     }
    -  523   +  519  56
                         initializeAnalyzer(analyzer);
    +  520  1
                     } catch (InitializationException ex) {
    +  521  1
                         exceptions.add(ex);
    +  522  1
                         continue;
    +  523  55
                     }
    +  524  
     
    -  524  51
                     executeAnalysisTasks(analyzer, exceptions);
    -  525   +  525  55
                     if (analyzer.isEnabled()) {
    +  526  24
                         executeAnalysisTasks(analyzer, exceptions);
    +  527  
     
    -  526  51
                     final long analyzerDurationMillis = System.currentTimeMillis() - analyzerStart;
    -  527  51
                     final long analyzerDurationSeconds = TimeUnit.MILLISECONDS.toSeconds(analyzerDurationMillis);
    -  528  51
                     LOGGER.info("Finished {} ({} seconds)", analyzer.getName(), analyzerDurationSeconds);
    -  529  51
                 }
    -  530   -
             }
    -  531  22
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    -  532  20
                 final List<Analyzer> analyzerList = analyzers.get(phase);
    +  528  24
                         final long analyzerDurationMillis = System.currentTimeMillis() - analyzerStart;
    +  529  24
                         final long analyzerDurationSeconds = TimeUnit.MILLISECONDS.toSeconds(analyzerDurationMillis);
    +  530  24
                         LOGGER.info("Finished {} ({} seconds)", analyzer.getName(), analyzerDurationSeconds);
    +  531  24
                     } else {
    +  532  31
                         LOGGER.debug("Skipping {} (not enabled)", analyzer.getName());
     533   -
     
    -  534  20
                 for (Analyzer a : analyzerList) {
    -  535  52
                     closeAnalyzer(a);
    -  536  52
                 }
    -  537   +
                     }
    +  534  55
                 }
    +  535  
             }
    +  536  24
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    +  537  22
                 final List<Analyzer> analyzerList = analyzers.get(phase);
     538  
     
    -  539  2
             LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
    -  540  2
             final long analysisDurationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - analysisStart);
    -  541  2
             LOGGER.info("Analysis Complete ({} seconds)", analysisDurationSeconds);
    -  542  2
             if (exceptions.size() > 0) {
    -  543  1
                 throw new ExceptionCollection("One or more exceptions occurred during dependency-check analysis", exceptions);
    -  544   +  539  22
                 for (Analyzer a : analyzerList) {
    +  540  56
                     closeAnalyzer(a);
    +  541  56
                 }
    +  542  
             }
    -  545  1
         }
    -  546   +  543  
     
    -  547   -
         /**
    -  548   -
          * Executes executes the analyzer using multiple threads.
    +  544  2
             LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
    +  545  2
             final long analysisDurationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - analysisStart);
    +  546  2
             LOGGER.info("Analysis Complete ({} seconds)", analysisDurationSeconds);
    +  547  2
             if (exceptions.size() > 0) {
    +  548  1
                 throw new ExceptionCollection("One or more exceptions occurred during dependency-check analysis", exceptions);
     549   -
          *
    -  550   -
          * @param exceptions a collection of exceptions that occurred during
    +
             }
    +  550  1
         }
     551   -
          * analysis
    +
     
     552   -
          * @param analyzer the analyzer to execute
    +
         /**
     553   -
          * @throws ExceptionCollection thrown if exceptions occurred during analysis
    +
          * Executes executes the analyzer using multiple threads.
     554   -
          */
    +
          *
     555   -
         void executeAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) throws ExceptionCollection {
    -  556  52
             LOGGER.debug("Starting {}", analyzer.getName());
    -  557  52
             final List<AnalysisTask> analysisTasks = getAnalysisTasks(analyzer, exceptions);
    -  558  52
             final ExecutorService executorService = getExecutorService(analyzer);
    +
          * @param exceptions a collection of exceptions that occurred during
    +  556   +
          * analysis
    +  557   +
          * @param analyzer the analyzer to execute
    +  558   +
          * @throws ExceptionCollection thrown if exceptions occurred during analysis
     559   -
     
    +
          */
     560   -
             try {
    -  561  52
                 final List<Future<Void>> results = executorService.invokeAll(analysisTasks, 10, TimeUnit.MINUTES);
    -  562   +
         void executeAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) throws ExceptionCollection {
    +  561  25
             LOGGER.debug("Starting {}", analyzer.getName());
    +  562  25
             final List<AnalysisTask> analysisTasks = getAnalysisTasks(analyzer, exceptions);
    +  563  25
             final ExecutorService executorService = getExecutorService(analyzer);
    +  564  
     
    -  563   -
                 // ensure there was no exception during execution
    -  564  52
                 for (Future<Void> result : results) {
     565   +
             try {
    +  566  25
                 final List<Future<Void>> results = executorService.invokeAll(analysisTasks, 10, TimeUnit.MINUTES);
    +  567   +
     
    +  568   +
                 // ensure there was no exception during execution
    +  569  25
                 for (Future<Void> result : results) {
    +  570  
                     try {
    -  566  103
                         result.get();
    -  567  1
                     } catch (ExecutionException e) {
    -  568  1
                         throwFatalExceptionCollection("Analysis task failed with a fatal exception.", e, exceptions);
    -  569  0
                     } catch (CancellationException e) {
    -  570  0
                         throwFatalExceptionCollection("Analysis task timed out.", e, exceptions);
    -  571  102
                     }
    -  572  102
                 }
    -  573  0
             } catch (InterruptedException e) {
    -  574  0
                 throwFatalExceptionCollection("Analysis has been interrupted.", e, exceptions);
    -  575   -
             } finally {
    -  576  52
                 executorService.shutdown();
    -  577  51
             }
    -  578  51
         }
    -  579   -
     
    +  571  49
                         result.get();
    +  572  1
                     } catch (ExecutionException e) {
    +  573  1
                         throwFatalExceptionCollection("Analysis task failed with a fatal exception.", e, exceptions);
    +  574  0
                     } catch (CancellationException e) {
    +  575  0
                         throwFatalExceptionCollection("Analysis task timed out.", e, exceptions);
    +  576  48
                     }
    +  577  48
                 }
    +  578  0
             } catch (InterruptedException e) {
    +  579  0
                 throwFatalExceptionCollection("Analysis has been interrupted.", e, exceptions);
     580   -
         /**
    -  581   -
          * Returns the analysis tasks for the dependencies.
    -  582   -
          *
    -  583   -
          * @param analyzer the analyzer to create tasks for
    -  584   -
          * @param exceptions the collection of exceptions to collect
    -  585   -
          * @return a collection of analysis tasks
    -  586   -
          */
    -  587   -
         List<AnalysisTask> getAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) {
    -  588  51
             final List<AnalysisTask> result = new ArrayList<AnalysisTask>();
    -  589  51
             synchronized (dependencies) {
    -  590  51
                 for (final Dependency dependency : dependencies) {
    -  591  102
                     final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions);
    -  592  102
                     result.add(task);
    -  593  102
                 }
    -  594  51
             }
    -  595  51
             return result;
    -  596   -
         }
    -  597   -
     
    -  598   -
         /**
    -  599   -
          * Returns the executor service for a given analyzer.
    -  600   -
          *
    -  601   -
          * @param analyzer the analyzer to obtain an executor
    -  602   -
          * @return the executor service
    -  603   -
          */
    -  604   -
         ExecutorService getExecutorService(Analyzer analyzer) {
    -  605  51
             if (analyzer.supportsParallelProcessing()) {
    -  606   -
                 // just a fair trade-off that should be reasonable for all analyzer types
    -  607  47
                 final int maximumNumberOfThreads = 4 * Runtime.getRuntime().availableProcessors();
    -  608   -
     
    -  609  47
                 LOGGER.debug("Parallel processing with up to {} threads: {}.", maximumNumberOfThreads, analyzer.getName());
    -  610  47
                 return Executors.newFixedThreadPool(maximumNumberOfThreads);
    -  611   -
             } else {
    -  612  4
                 LOGGER.debug("Parallel processing is not supported: {}.", analyzer.getName());
    -  613  4
                 return Executors.newSingleThreadExecutor();
    -  614   -
             }
    -  615   -
         }
    -  616   -
     
    -  617   -
         /**
    -  618   -
          * Initializes the given analyzer.
    -  619   -
          *
    -  620   -
          * @param analyzer the analyzer to initialize
    -  621   -
          * @return the initialized analyzer
    -  622   -
          * @throws InitializationException thrown when there is a problem
    -  623   -
          * initializing the analyzer
    -  624   -
          */
    -  625   -
         protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
    -  626   -
             try {
    -  627  52
                 LOGGER.debug("Initializing {}", analyzer.getName());
    -  628  52
                 analyzer.initialize();
    -  629  1
             } catch (InitializationException ex) {
    -  630  1
                 LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
    -  631  1
                 LOGGER.debug("", ex);
    -  632   -
                 try {
    -  633  1
                     analyzer.close();
    -  634  0
                 } catch (Throwable ex1) {
    -  635  0
                     LOGGER.trace("", ex1);
    -  636  1
                 }
    -  637  1
                 throw ex;
    -  638  0
             } catch (Throwable ex) {
    -  639  0
                 LOGGER.error("Unexpected exception occurred initializing {}.", analyzer.getName());
    -  640  0
                 LOGGER.debug("", ex);
    -  641   -
                 try {
    -  642  0
                     analyzer.close();
    -  643  0
                 } catch (Throwable ex1) {
    -  644  0
                     LOGGER.trace("", ex1);
    -  645  0
                 }
    -  646  0
                 throw new InitializationException("Unexpected Exception", ex);
    -  647  51
             }
    -  648  51
             return analyzer;
    -  649   -
         }
    -  650   -
     
    -  651   -
         /**
    -  652   -
          * Closes the given analyzer.
    -  653   -
          *
    -  654   -
          * @param analyzer the analyzer to close
    -  655   -
          */
    -  656   -
         protected void closeAnalyzer(Analyzer analyzer) {
    -  657  52
             LOGGER.debug("Closing Analyzer '{}'", analyzer.getName());
    -  658   -
             try {
    -  659  52
                 analyzer.close();
    -  660  0
             } catch (Throwable ex) {
    -  661  0
                 LOGGER.trace("", ex);
    -  662  52
             }
    -  663  52
         }
    -  664   -
     
    -  665   -
         /**
    -  666   -
          * Cycles through the cached web data sources and calls update on all of
    -  667   -
          * them.
    -  668   -
          *
    -  669   -
          * @throws UpdateException thrown if the operation fails
    -  670   -
          */
    -  671   -
         public void doUpdates() throws UpdateException {
    -  672  0
             LOGGER.info("Checking for updates");
    -  673  0
             final long updateStart = System.currentTimeMillis();
    -  674  0
             final UpdateService service = new UpdateService(serviceClassLoader);
    -  675  0
             final Iterator<CachedWebDataSource> iterator = service.getDataSources();
    -  676  0
             while (iterator.hasNext()) {
    -  677  0
                 final CachedWebDataSource source = iterator.next();
    -  678  0
                 source.update();
    -  679  0
             }
    -  680  0
             LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart);
    -  681  0
         }
    -  682   -
     
    -  683   -
         /**
    -  684   -
          * Returns a full list of all of the analyzers. This is useful for reporting
    -  685   -
          * which analyzers where used.
    -  686   -
          *
    -  687   -
          * @return a list of Analyzers
    -  688   -
          */
    -  689   -
         public List<Analyzer> getAnalyzers() {
    -  690  0
             final List<Analyzer> ret = new ArrayList<Analyzer>();
    -  691  0
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    -  692  0
                 final List<Analyzer> analyzerList = analyzers.get(phase);
    -  693  0
                 ret.addAll(analyzerList);
    -  694   -
             }
    -  695  0
             return ret;
    -  696   -
         }
    -  697   -
     
    -  698   -
         /**
    -  699   -
          * Checks all analyzers to see if an extension is supported.
    -  700   -
          *
    -  701   -
          * @param file a file extension
    -  702   -
          * @return true or false depending on whether or not the file extension is
    -  703   -
          * supported
    -  704   -
          */
    -  705   -
         @Override
    -  706   -
         public boolean accept(File file) {
    -  707  858
             if (file == null) {
    -  708  0
                 return false;
    -  709   -
             }
    -  710  858
             boolean scan = false;
    -  711  858
             for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
    -  712   -
                 /* note, we can't break early on this loop as the analyzers need to know if
    -  713   -
                  they have files to work on prior to initialization */
    -  714  15447
                 scan |= a.accept(file);
    -  715  15447
             }
    -  716  858
             return scan;
    -  717   -
         }
    -  718   -
     
    -  719   -
         /**
    -  720   -
          * Returns the set of file type analyzers.
    -  721   -
          *
    -  722   -
          * @return the set of file type analyzers
    -  723   -
          */
    -  724   -
         public Set<FileTypeAnalyzer> getFileTypeAnalyzers() {
    -  725  0
             return this.fileTypeAnalyzers;
    -  726   -
         }
    -  727   -
     
    -  728   -
         /**
    -  729   -
          * Adds a file type analyzer. This has been added solely to assist in unit
    -  730   -
          * testing the Engine.
    -  731   -
          *
    -  732   -
          * @param fta the file type analyzer to add
    -  733   -
          */
    -  734   -
         protected void addFileTypeAnalyzer(FileTypeAnalyzer fta) {
    -  735  1
             this.fileTypeAnalyzers.add(fta);
    -  736  1
         }
    -  737   -
     
    -  738   -
         /**
    -  739   -
          * Checks the CPE Index to ensure documents exists. If none exist a
    -  740   -
          * NoDataException is thrown.
    -  741   -
          *
    -  742   -
          * @throws NoDataException thrown if no data exists in the CPE Index
    -  743   -
          * @throws DatabaseException thrown if there is an exception opening the
    -  744   -
          * database
    -  745   -
          */
    -  746   -
         private void ensureDataExists() throws NoDataException, DatabaseException {
    -  747  2
             final CveDB cve = new CveDB();
    -  748   -
             try {
    -  749  2
                 cve.open();
    -  750  2
                 if (!cve.dataExists()) {
    -  751  0
                     throw new NoDataException("No documents exist");
    -  752   -
                 }
    -  753  0
             } catch (DatabaseException ex) {
    -  754  0
                 throw new NoDataException(ex.getMessage(), ex);
    -  755  
             } finally {
    -  756  2
                 cve.close();
    -  757  2
             }
    -  758  2
         }
    -  759   +  581  25
                 executorService.shutdown();
    +  582  24
             }
    +  583  24
         }
    +  584  
     
    -  760   +  585  
         /**
    -  761   -
          * Constructs and throws a fatal exception collection.
    -  762   +  586   +
          * Returns the analysis tasks for the dependencies.
    +  587  
          *
    -  763   -
          * @param message the exception message
    -  764   -
          * @param throwable the cause
    -  765   -
          * @param exceptions a collection of exception to include
    -  766   -
          * @throws ExceptionCollection a collection of exceptions that occurred
    -  767   -
          * during analysis
    -  768   +  588   +
          * @param analyzer the analyzer to create tasks for
    +  589   +
          * @param exceptions the collection of exceptions to collect
    +  590   +
          * @return a collection of analysis tasks
    +  591  
          */
    -  769   -
         private void throwFatalExceptionCollection(String message, Throwable throwable, List<Throwable> exceptions) throws ExceptionCollection {
    -  770  1
             LOGGER.error("{}\n\n{}", throwable.getMessage(), message);
    -  771  1
             LOGGER.debug("", throwable);
    -  772  1
             exceptions.add(throwable);
    -  773  1
             throw new ExceptionCollection(message, exceptions, true);
    -  774   +  592   +
         List<AnalysisTask> getAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) {
    +  593  24
             final List<AnalysisTask> result = new ArrayList<AnalysisTask>();
    +  594  24
             synchronized (dependencies) {
    +  595  24
                 for (final Dependency dependency : dependencies) {
    +  596  48
                     final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions, Settings.getInstance());
    +  597  48
                     result.add(task);
    +  598  48
                 }
    +  599  24
             }
    +  600  24
             return result;
    +  601  
         }
    -  775   +  602   +
     
    +  603   +
         /**
    +  604   +
          * Returns the executor service for a given analyzer.
    +  605   +
          *
    +  606   +
          * @param analyzer the analyzer to obtain an executor
    +  607   +
          * @return the executor service
    +  608   +
          */
    +  609   +
         ExecutorService getExecutorService(Analyzer analyzer) {
    +  610  24
             if (analyzer.supportsParallelProcessing()) {
    +  611   +
                 // just a fair trade-off that should be reasonable for all analyzer types
    +  612  17
                 final int maximumNumberOfThreads = 4 * Runtime.getRuntime().availableProcessors();
    +  613   +
     
    +  614  17
                 LOGGER.debug("Parallel processing with up to {} threads: {}.", maximumNumberOfThreads, analyzer.getName());
    +  615  17
                 return Executors.newFixedThreadPool(maximumNumberOfThreads);
    +  616   +
             } else {
    +  617  7
                 LOGGER.debug("Parallel processing is not supported: {}.", analyzer.getName());
    +  618  7
                 return Executors.newSingleThreadExecutor();
    +  619   +
             }
    +  620   +
         }
    +  621   +
     
    +  622   +
         /**
    +  623   +
          * Initializes the given analyzer.
    +  624   +
          *
    +  625   +
          * @param analyzer the analyzer to initialize
    +  626   +
          * @return the initialized analyzer
    +  627   +
          * @throws InitializationException thrown when there is a problem
    +  628   +
          * initializing the analyzer
    +  629   +
          */
    +  630   +
         protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
    +  631   +
             try {
    +  632  56
                 LOGGER.debug("Initializing {}", analyzer.getName());
    +  633  56
                 analyzer.initialize();
    +  634  1
             } catch (InitializationException ex) {
    +  635  1
                 LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
    +  636  1
                 LOGGER.debug("", ex);
    +  637   +
                 try {
    +  638  1
                     analyzer.close();
    +  639  0
                 } catch (Throwable ex1) {
    +  640  0
                     LOGGER.trace("", ex1);
    +  641  1
                 }
    +  642  1
                 throw ex;
    +  643  0
             } catch (Throwable ex) {
    +  644  0
                 LOGGER.error("Unexpected exception occurred initializing {}.", analyzer.getName());
    +  645  0
                 LOGGER.debug("", ex);
    +  646   +
                 try {
    +  647  0
                     analyzer.close();
    +  648  0
                 } catch (Throwable ex1) {
    +  649  0
                     LOGGER.trace("", ex1);
    +  650  0
                 }
    +  651  0
                 throw new InitializationException("Unexpected Exception", ex);
    +  652  55
             }
    +  653  55
             return analyzer;
    +  654   +
         }
    +  655   +
     
    +  656   +
         /**
    +  657   +
          * Closes the given analyzer.
    +  658   +
          *
    +  659   +
          * @param analyzer the analyzer to close
    +  660   +
          */
    +  661   +
         protected void closeAnalyzer(Analyzer analyzer) {
    +  662  56
             LOGGER.debug("Closing Analyzer '{}'", analyzer.getName());
    +  663   +
             try {
    +  664  56
                 analyzer.close();
    +  665  0
             } catch (Throwable ex) {
    +  666  0
                 LOGGER.trace("", ex);
    +  667  56
             }
    +  668  56
         }
    +  669   +
     
    +  670   +
         /**
    +  671   +
          * Cycles through the cached web data sources and calls update on all of
    +  672   +
          * them.
    +  673   +
          *
    +  674   +
          * @throws UpdateException thrown if the operation fails
    +  675   +
          */
    +  676   +
         public void doUpdates() throws UpdateException {
    +  677  0
             LOGGER.info("Checking for updates");
    +  678  0
             final long updateStart = System.currentTimeMillis();
    +  679  0
             final UpdateService service = new UpdateService(serviceClassLoader);
    +  680  0
             final Iterator<CachedWebDataSource> iterator = service.getDataSources();
    +  681  0
             while (iterator.hasNext()) {
    +  682  0
                 final CachedWebDataSource source = iterator.next();
    +  683  0
                 source.update();
    +  684  0
             }
    +  685  0
             LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart);
    +  686  0
         }
    +  687   +
     
    +  688   +
         /**
    +  689   +
          * Returns a full list of all of the analyzers. This is useful for reporting
    +  690   +
          * which analyzers where used.
    +  691   +
          *
    +  692   +
          * @return a list of Analyzers
    +  693   +
          */
    +  694   +
         public List<Analyzer> getAnalyzers() {
    +  695  0
             final List<Analyzer> ret = new ArrayList<Analyzer>();
    +  696  0
             for (AnalysisPhase phase : AnalysisPhase.values()) {
    +  697  0
                 final List<Analyzer> analyzerList = analyzers.get(phase);
    +  698  0
                 ret.addAll(analyzerList);
    +  699   +
             }
    +  700  0
             return ret;
    +  701   +
         }
    +  702   +
     
    +  703   +
         /**
    +  704   +
          * Checks all analyzers to see if an extension is supported.
    +  705   +
          *
    +  706   +
          * @param file a file extension
    +  707   +
          * @return true or false depending on whether or not the file extension is
    +  708   +
          * supported
    +  709   +
          */
    +  710   +
         @Override
    +  711   +
         public boolean accept(File file) {
    +  712  858
             if (file == null) {
    +  713  0
                 return false;
    +  714   +
             }
    +  715  858
             boolean scan = false;
    +  716  858
             for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
    +  717   +
                 /* note, we can't break early on this loop as the analyzers need to know if
    +  718   +
                  they have files to work on prior to initialization */
    +  719  15447
                 scan |= a.accept(file);
    +  720  15447
             }
    +  721  858
             return scan;
    +  722   +
         }
    +  723   +
     
    +  724   +
         /**
    +  725   +
          * Returns the set of file type analyzers.
    +  726   +
          *
    +  727   +
          * @return the set of file type analyzers
    +  728   +
          */
    +  729   +
         public Set<FileTypeAnalyzer> getFileTypeAnalyzers() {
    +  730  0
             return this.fileTypeAnalyzers;
    +  731   +
         }
    +  732   +
     
    +  733   +
         /**
    +  734   +
          * Adds a file type analyzer. This has been added solely to assist in unit
    +  735   +
          * testing the Engine.
    +  736   +
          *
    +  737   +
          * @param fta the file type analyzer to add
    +  738   +
          */
    +  739   +
         protected void addFileTypeAnalyzer(FileTypeAnalyzer fta) {
    +  740  1
             this.fileTypeAnalyzers.add(fta);
    +  741  1
         }
    +  742   +
     
    +  743   +
         /**
    +  744   +
          * Checks the CPE Index to ensure documents exists. If none exist a
    +  745   +
          * NoDataException is thrown.
    +  746   +
          *
    +  747   +
          * @throws NoDataException thrown if no data exists in the CPE Index
    +  748   +
          * @throws DatabaseException thrown if there is an exception opening the
    +  749   +
          * database
    +  750   +
          */
    +  751   +
         private void ensureDataExists() throws NoDataException, DatabaseException {
    +  752  2
             final CveDB cve = new CveDB();
    +  753   +
             try {
    +  754  2
                 cve.open();
    +  755  2
                 if (!cve.dataExists()) {
    +  756  0
                     throw new NoDataException("No documents exist");
    +  757   +
                 }
    +  758  0
             } catch (DatabaseException ex) {
    +  759  0
                 throw new NoDataException(ex.getMessage(), ex);
    +  760   +
             } finally {
    +  761  2
                 cve.close();
    +  762  2
             }
    +  763  2
         }
    +  764   +
     
    +  765   +
         /**
    +  766   +
          * Constructs and throws a fatal exception collection.
    +  767   +
          *
    +  768   +
          * @param message the exception message
    +  769   +
          * @param throwable the cause
    +  770   +
          * @param exceptions a collection of exception to include
    +  771   +
          * @throws ExceptionCollection a collection of exceptions that occurred
    +  772   +
          * during analysis
    +  773   +
          */
    +  774   +
         private void throwFatalExceptionCollection(String message, Throwable throwable, List<Throwable> exceptions) throws ExceptionCollection {
    +  775  1
             LOGGER.error("{}\n\n{}", throwable.getMessage(), message);
    +  776  1
             LOGGER.debug("", throwable);
    +  777  1
             exceptions.add(throwable);
    +  778  1
             throw new ExceptionCollection(message, exceptions, true);
    +  779   +
         }
    +  780  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.agent.DependencyCheckScanAgent.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.agent.DependencyCheckScanAgent.html index f8725f5f2..f7e1d1217 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.agent.DependencyCheckScanAgent.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.agent.DependencyCheckScanAgent.html @@ -1884,6 +1884,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractAnalyzer.html index 93eb5e48b..dfa063570 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    AbstractAnalyzer
    100%
    4/4
    N/A
    1
    AbstractAnalyzer
    88%
    22/25
    83%
    5/6
    1.4
     
    @@ -56,79 +56,266 @@  19  
     
     20   -
     import org.owasp.dependencycheck.exception.InitializationException;
    +
     import org.owasp.dependencycheck.Engine;
     21   -
     
    +
     import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
     22   -
     /**
    +
     import org.owasp.dependencycheck.dependency.Dependency;
     23   -
      * Base class for analyzers to avoid code duplication of initialize and close
    +
     import org.owasp.dependencycheck.exception.InitializationException;
     24   -
      * as most analyzers do not need these methods.
    +
     import org.owasp.dependencycheck.utils.InvalidSettingException;
     25   -
      *
    +
     import org.owasp.dependencycheck.utils.Settings;
     26   -
      * @author Jeremy Long
    +
     import org.slf4j.Logger;
     27   -
      */
    -  28  302
     public abstract class AbstractAnalyzer implements Analyzer {
    +
     import org.slf4j.LoggerFactory;
    +  28   +
     
     29   -
     
    +
     /**
     30   -
         /**
    +
      * Base class for analyzers to avoid code duplication of initialize and close as
     31   -
          * The initialize method does nothing for this Analyzer.
    +
      * most analyzers do not need these methods.
     32   -
          *
    +
      *
     33   -
          * @throws InitializationException thrown if there is an exception
    +
      * @author Jeremy Long
     34   -
          */
    -  35   -
         @Override
    +
      */
    +  35  325
     public abstract class AbstractAnalyzer implements Analyzer {
     36   -
         public void initialize() throws InitializationException {
    +
     
     37   -
             //do nothing
    -  38  16
         }
    +
         /**
    +  38   +
          * The logger.
     39   -
     
    -  40   -
         /**
    +
          */
    +  40  1
         private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAnalyzer.class);
     41   -
          * The close method does nothing for this Analyzer.
    -  42   -
          *
    -  43   -
          * @throws Exception thrown if there is an exception
    -  44   -
          */
    -  45   -
         @Override
    -  46   -
         public void close() throws Exception {
    -  47   -
             //do nothing
    -  48  99
         }
    -  49   -
     
    -  50  
         /**
    -  51   -
          * The default is to support parallel processing.
    -  52   +  42   +
          * A flag indicating whether or not the analyzer is enabled.
    +  43  
          */
    -  53   +  44  325
         private volatile boolean enabled = true;
    +  45   +
     
    +  46   +
         /**
    +  47   +
          * Get the value of enabled.
    +  48   +
          *
    +  49   +
          * @return the value of enabled
    +  50   +
          */
    +  51  
         @Override
    +  52   +
         public boolean isEnabled() {
    +  53  14137
             return enabled;
     54   -
         public boolean supportsParallelProcessing() {
    -  55  47
             return true;
    -  56  
         }
    +  55   +
     
    +  56   +
         /**
     57   +
          * Set the value of enabled.
    +  58   +
          *
    +  59   +
          * @param enabled new value of enabled
    +  60   +
          */
    +  61   +
         public void setEnabled(boolean enabled) {
    +  62  167
             this.enabled = enabled;
    +  63  167
         }
    +  64   +
     
    +  65   +
         /**
    +  66   +
          * <p>
    +  67   +
          * Returns the setting key to determine if the analyzer is enabled.</p>
    +  68   +
          *
    +  69   +
          * @return the key for the analyzer's enabled property
    +  70   +
          */
    +  71   +
         protected abstract String getAnalyzerEnabledSettingKey();
    +  72   +
     
    +  73   +
         /**
    +  74   +
          * Analyzes a given dependency. If the dependency is an archive, such as a
    +  75   +
          * WAR or EAR, the contents are extracted, scanned, and added to the list of
    +  76   +
          * dependencies within the engine.
    +  77   +
          *
    +  78   +
          * @param dependency the dependency to analyze
    +  79   +
          * @param engine the engine scanning
    +  80   +
          * @throws AnalysisException thrown if there is an analysis exception
    +  81   +
          */
    +  82   +
         protected abstract void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException;
    +  83   +
     
    +  84   +
         /**
    +  85   +
          * Initializes a given Analyzer. This will be skipped if the analyzer is disabled.
    +  86   +
          *
    +  87   +
          * @throws InitializationException thrown if there is an exception
    +  88   +
          */
    +  89   +
         protected void initializeAnalyzer() throws InitializationException {
    +  90  11
         }
    +  91   +
     
    +  92   +
         /**
    +  93   +
          * Closes a given Analyzer. This will be skipped if the analyzer is disabled.
    +  94   +
          *
    +  95   +
          * @throws Exception thrown if there is an exception
    +  96   +
          */
    +  97   +
         protected void closeAnalyzer() throws Exception {
    +  98  64
         }
    +  99   +
     
    +  100   +
     
    +  101   +
         /**
    +  102   +
          * Analyzes a given dependency. If the dependency is an archive, such as a
    +  103   +
          * WAR or EAR, the contents are extracted, scanned, and added to the list of
    +  104   +
          * dependencies within the engine.
    +  105   +
          *
    +  106   +
          * @param dependency the dependency to analyze
    +  107   +
          * @param engine the engine scanning
    +  108   +
          * @throws AnalysisException thrown if there is an analysis exception
    +  109   +
          */
    +  110   +
         @Override
    +  111   +
         public final void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    +  112  76
             if (this.isEnabled()) {
    +  113  76
                 analyzeDependency(dependency, engine);
    +  114   +
             }
    +  115  76
         }
    +  116   +
     
    +  117   +
         /**
    +  118   +
          * The initialize method does nothing for this Analyzer.
    +  119   +
          *
    +  120   +
          * @throws InitializationException thrown if there is an exception
    +  121   +
          */
    +  122   +
         @Override
    +  123   +
         public final void initialize() throws InitializationException {
    +  124  126
             final String key = getAnalyzerEnabledSettingKey();
    +  125   +
             try {
    +  126  126
                 this.setEnabled(Settings.getBoolean(key, true));
    +  127  0
             } catch (InvalidSettingException ex) {
    +  128  0
                 LOGGER.warn("Invalid setting for property '{}'", key);
    +  129  0
                 LOGGER.debug("", ex);
    +  130  126
             }
    +  131   +
     
    +  132  126
             if (isEnabled()) {
    +  133  122
                 initializeAnalyzer();
    +  134   +
             } else {
    +  135  4
                 LOGGER.debug("{} has been disabled", getName());
    +  136   +
             }
    +  137  119
         }
    +  138   +
     
    +  139   +
         /**
    +  140   +
          * The close method does nothing for this Analyzer.
    +  141   +
          *
    +  142   +
          * @throws Exception thrown if there is an exception
    +  143   +
          */
    +  144   +
         @Override
    +  145   +
         public final void close() throws Exception {
    +  146  121
             if (isEnabled()) {
    +  147  83
                 closeAnalyzer();
    +  148   +
             }
    +  149  121
         }
    +  150   +
     
    +  151   +
     
    +  152   +
         /**
    +  153   +
          * The default is to support parallel processing.
    +  154   +
          *
    +  155   +
          * @return true
    +  156   +
          */
    +  157   +
         @Override
    +  158   +
         public boolean supportsParallelProcessing() {
    +  159  17
             return true;
    +  160   +
         }
    +  161  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer.html index 6adc7c0ad..923fd2ec5 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    AbstractFileTypeAnalyzer
    84%
    33/39
    80%
    8/10
    1.429
    AbstractFileTypeAnalyzer
    90%
    20/22
    87%
    7/8
    1.571
     
    @@ -56,394 +56,243 @@  19  
     
     20   -
     import org.owasp.dependencycheck.Engine;
    -  21   -
     import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
    -  22   -
     import org.owasp.dependencycheck.dependency.Dependency;
    -  23   -
     import org.owasp.dependencycheck.utils.InvalidSettingException;
    -  24   -
     import org.owasp.dependencycheck.utils.Settings;
    -  25  
     import org.slf4j.Logger;
    -  26   +  21  
     import org.slf4j.LoggerFactory;
    -  27   +  22  
     
    -  28   +  23  
     import java.io.File;
    -  29   +  24  
     import java.io.FileFilter;
    -  30   +  25  
     import java.util.Collections;
    -  31   +  26  
     import java.util.HashSet;
    -  32   +  27  
     import java.util.Set;
    -  33   +  28  
     import org.owasp.dependencycheck.exception.InitializationException;
    -  34   +  29  
     
    -  35   +  30  
     /**
    -  36   +  31  
      * The base FileTypeAnalyzer that all analyzers that have specific file types
    -  37   +  32  
      * they analyze should extend.
    -  38   +  33  
      *
    -  39   +  34  
      * @author Jeremy Long
    -  40   +  35  
      */
    -  41   -
     public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
    -  42   +  36  217
     public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
    +  37  
     
    -  43   -
         //<editor-fold defaultstate="collapsed" desc="Constructor">
    -  44   +  38   +
         //<editor-fold defaultstate="collapsed" desc="Field definitions, getters, and setters ">
    +  39  
         /**
    -  45   -
          * Base constructor that all children must call. This checks the
    -  46   -
          * configuration to determine if the analyzer is enabled.
    -  47   -
          */
    -  48  217
         public AbstractFileTypeAnalyzer() {
    -  49  217
             reset();
    -  50  217
         }
    -  51   -
     //</editor-fold>
    -  52   -
     
    -  53   -
         //<editor-fold defaultstate="collapsed" desc="Field definitions">
    -  54   -
         /**
    -  55   +  40  
          * The logger.
    -  56   +  41  
          */
    -  57  1
         private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileTypeAnalyzer.class);
    +  42  1
         private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileTypeAnalyzer.class);
    +  43   +
         /**
    +  44   +
          * Whether the file type analyzer detected any files it needs to analyze.
    +  45   +
          */
    +  46  217
         private boolean filesMatched = false;
    +  47   +
     
    +  48   +
         /**
    +  49   +
          * Get the value of filesMatched. A flag indicating whether the scan
    +  50   +
          * included any file types this analyzer supports.
    +  51   +
          *
    +  52   +
          * @return the value of filesMatched
    +  53   +
          */
    +  54   +
         protected boolean isFilesMatched() {
    +  55  0
             return filesMatched;
    +  56   +
         }
    +  57   +
     
     58  
         /**
     59   -
          * Whether the file type analyzer detected any files it needs to analyze.
    -  60   -
          */
    -  61  217
         private boolean filesMatched = false;
    -  62   -
     
    -  63   -
         /**
    -  64   -
          * Get the value of filesMatched. A flag indicating whether the scan
    -  65   -
          * included any file types this analyzer supports.
    -  66   -
          *
    -  67   -
          * @return the value of filesMatched
    -  68   -
          */
    -  69   -
         protected boolean isFilesMatched() {
    -  70  0
             return filesMatched;
    -  71   -
         }
    -  72   -
     
    -  73   -
         /**
    -  74  
          * Set the value of filesMatched. A flag indicating whether the scan
    -  75   +  60  
          * included any file types this analyzer supports.
    -  76   +  61  
          *
    -  77   +  62  
          * @param filesMatched new value of filesMatched
    -  78   +  63  
          */
    -  79   +  64  
         protected void setFilesMatched(boolean filesMatched) {
    -  80  60
             this.filesMatched = filesMatched;
    -  81  60
         }
    -  82   +  65  60
             this.filesMatched = filesMatched;
    +  66  60
         }
    +  67  
     
    -  83   -
         /**
    -  84   -
          * A flag indicating whether or not the analyzer is enabled.
    -  85   -
          */
    -  86  217
         private volatile boolean enabled = true;
    -  87   -
     
    -  88   -
         /**
    -  89   -
          * Get the value of enabled.
    -  90   -
          *
    -  91   -
          * @return the value of enabled
    -  92   -
          */
    -  93   -
         public boolean isEnabled() {
    -  94  3
             return enabled;
    -  95   -
         }
    -  96   -
     
    -  97   -
         /**
    -  98   -
          * Set the value of enabled.
    -  99   -
          *
    -  100   -
          * @param enabled new value of enabled
    -  101   -
          */
    -  102   -
         public void setEnabled(boolean enabled) {
    -  103  10
             this.enabled = enabled;
    -  104  10
         }
    -  105   -
     //</editor-fold>
    -  106   -
     
    -  107   -
         //<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
    -  108   -
         /**
    -  109   -
          * <p>
    -  110   -
          * Returns the {@link java.io.FileFilter} used to determine which files are
    -  111   -
          * to be analyzed. An example would be an analyzer that inspected Java jar
    -  112   -
          * files. Implementors may use
    -  113   -
          * {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.</p>
    -  114   -
          * <p>
    -  115   -
          * If the analyzer returns null it will not cause additional files to be
    -  116   -
          * analyzed, but will be executed against every file loaded.</p>
    -  117   -
          *
    -  118   -
          * @return the file filter used to determine which files are to be analyzed
    -  119   -
          */
    -  120   -
         protected abstract FileFilter getFileFilter();
    -  121   -
     
    -  122   -
         /**
    -  123   -
          * Initializes the file type analyzer.
    -  124   -
          *
    -  125   -
          * @throws InitializationException thrown if there is an exception during
    -  126   -
          * initialization
    -  127   -
          */
    -  128   -
         protected abstract void initializeFileTypeAnalyzer() throws InitializationException;
    -  129   -
     
    -  130   -
         /**
    -  131   -
          * Analyzes a given dependency. If the dependency is an archive, such as a
    -  132   -
          * WAR or EAR, the contents are extracted, scanned, and added to the list of
    -  133   -
          * dependencies within the engine.
    -  134   -
          *
    -  135   -
          * @param dependency the dependency to analyze
    -  136   -
          * @param engine the engine scanning
    -  137   -
          * @throws AnalysisException thrown if there is an analysis exception
    -  138   -
          */
    -  139   -
         protected abstract void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException;
    -  140   -
     
    -  141   -
         /**
    -  142   -
          * <p>
    -  143   -
          * Returns the setting key to determine if the analyzer is enabled.</p>
    -  144   -
          *
    -  145   -
          * @return the key for the analyzer's enabled property
    -  146   -
          */
    -  147   -
         protected abstract String getAnalyzerEnabledSettingKey();
    -  148   -
     
    -  149   -
     //</editor-fold>
    -  150   -
         //<editor-fold defaultstate="collapsed" desc="Final implementations for the Analyzer interface">
    -  151   -
         /**
    -  152   -
          * Initializes the analyzer.
    -  153   -
          *
    -  154   -
          * @throws InitializationException thrown if there is an exception during
    -  155   -
          * initialization
    -  156   -
          */
    -  157   -
         @Override
    -  158   -
         public final void initialize() throws InitializationException {
    -  159  102
             if (filesMatched) {
    -  160  67
                 initializeFileTypeAnalyzer();
    -  161   -
             } else {
    -  162  35
                 enabled = false;
    -  163   -
             }
    -  164  96
         }
    -  165   -
     
    -  166   -
         /**
    -  167   -
          * Resets the enabled flag on the analyzer.
    -  168   -
          */
    -  169   -
         @Override
    -  170   -
         public final void reset() {
    -  171  217
             final String key = getAnalyzerEnabledSettingKey();
    -  172   -
             try {
    -  173  217
                 enabled = Settings.getBoolean(key, true);
    -  174  0
             } catch (InvalidSettingException ex) {
    -  175  0
                 LOGGER.warn("Invalid setting for property '{}'", key);
    -  176  0
                 LOGGER.debug("", ex);
    -  177  0
                 LOGGER.warn("{} has been disabled", getName());
    -  178  217
             }
    -  179  217
         }
    -  180   -
     
    -  181   -
         /**
    -  182   -
          * Analyzes a given dependency. If the dependency is an archive, such as a
    -  183   -
          * WAR or EAR, the contents are extracted, scanned, and added to the list of
    -  184   -
          * dependencies within the engine.
    -  185   -
          *
    -  186   -
          * @param dependency the dependency to analyze
    -  187   -
          * @param engine the engine scanning
    -  188   -
          * @throws AnalysisException thrown if there is an analysis exception
    -  189   -
          */
    -  190   -
         @Override
    -  191   -
         public final void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    -  192  31
             if (enabled) {
    -  193  31
                 analyzeFileType(dependency, engine);
    -  194   -
             }
    -  195  31
         }
    -  196   -
     
    -  197   -
         @Override
    -  198   -
         public boolean accept(File pathname) {
    -  199  15543
             final FileFilter filter = getFileFilter();
    -  200  15543
             boolean accepted = false;
    -  201  15544
             if (null == filter) {
    -  202  0
                 LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName());
    -  203  15544
             } else if (enabled) {
    -  204  13771
                 accepted = filter.accept(pathname);
    -  205  13771
                 if (accepted) {
    -  206  53
                     filesMatched = true;
    -  207   -
                 }
    -  208   -
             }
    -  209  15545
             return accepted;
    -  210   -
         }
    -  211   -
     
    -  212   +  68  
         //</editor-fold>
    -  213   -
         //<editor-fold defaultstate="collapsed" desc="Static utility methods">
    -  214   +  69   +
         //<editor-fold defaultstate="collapsed" desc="Final implementations for the Analyzer interface">
    +  70  
         /**
    -  215   -
          * <p>
    -  216   -
          * Utility method to help in the creation of the extensions set. This
    -  217   -
          * constructs a new Set that can be used in a final static declaration.</p>
    -  218   -
          * <p>
    -  219   -
          * This implementation was copied from
    -  220   -
          * http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
    -  221   +  71   +
          * Initializes the analyzer.
    +  72  
          *
    -  222   -
          * @param strings a list of strings to add to the set.
    -  223   -
          * @return a Set of strings.
    -  224   +  73   +
          * @throws InitializationException thrown if there is an exception during
    +  74   +
          * initialization
    +  75  
          */
    -  225   -
         protected static Set<String> newHashSet(String... strings) {
    -  226  5
             final Set<String> set = new HashSet<String>(strings.length);
    -  227  5
             Collections.addAll(set, strings);
    -  228  5
             return set;
    -  229   -
         }
    -  230   +  76   +
         @Override
    +  77   +
         protected final void initializeAnalyzer() throws InitializationException {
    +  78  98
             if (filesMatched) {
    +  79  67
                 initializeFileTypeAnalyzer();
    +  80   +
             } else {
    +  81  31
                 this.setEnabled(false);
    +  82   +
             }
    +  83  92
         }
    +  84  
     
    -  231   -
     //</editor-fold>
    -  232   +  85   +
         //</editor-fold>
    +  86   +
         //<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
    +  87   +
         /**
    +  88   +
          * <p>
    +  89   +
          * Returns the {@link java.io.FileFilter} used to determine which files are
    +  90   +
          * to be analyzed. An example would be an analyzer that inspected Java jar
    +  91   +
          * files. Implementors may use
    +  92   +
          * {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.</p>
    +  93   +
          * <p>
    +  94   +
          * If the analyzer returns null it will not cause additional files to be
    +  95   +
          * analyzed, but will be executed against every file loaded.</p>
    +  96   +
          *
    +  97   +
          * @return the file filter used to determine which files are to be analyzed
    +  98   +
          */
    +  99   +
         protected abstract FileFilter getFileFilter();
    +  100   +
     
    +  101   +
         /**
    +  102   +
          * Initializes the file type analyzer.
    +  103   +
          *
    +  104   +
          * @throws InitializationException thrown if there is an exception during
    +  105   +
          * initialization
    +  106   +
          */
    +  107   +
         protected abstract void initializeFileTypeAnalyzer() throws InitializationException;
    +  108   +
     
    +  109   +
         //</editor-fold>
    +  110   +
         /**
    +  111   +
          * Determines if the file can be analyzed by the analyzer.
    +  112   +
          *
    +  113   +
          * @param pathname the path to the file
    +  114   +
          * @return true if the file can be analyzed by the given analyzer; otherwise
    +  115   +
          * false
    +  116   +
          */
    +  117   +
         @Override
    +  118   +
         public boolean accept(File pathname) {
    +  119  15484
             final FileFilter filter = getFileFilter();
    +  120  15484
             boolean accepted = false;
    +  121  15484
             if (null == filter) {
    +  122  0
                 LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName());
    +  123  15484
             } else if (this.isEnabled()) {
    +  124  13771
                 accepted = filter.accept(pathname);
    +  125  13771
                 if (accepted) {
    +  126  53
                     filesMatched = true;
    +  127   +
                 }
    +  128   +
             }
    +  129  15484
             return accepted;
    +  130   +
         }
    +  131   +
     
    +  132   +
         /**
    +  133   +
          * <p>
    +  134   +
          * Utility method to help in the creation of the extensions set. This
    +  135   +
          * constructs a new Set that can be used in a final static declaration.</p>
    +  136   +
          * <p>
    +  137   +
          * This implementation was copied from
    +  138   +
          * http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
    +  139   +
          *
    +  140   +
          * @param strings a list of strings to add to the set.
    +  141   +
          * @return a Set of strings.
    +  142   +
          */
    +  143   +
         protected static Set<String> newHashSet(String... strings) {
    +  144  5
             final Set<String> set = new HashSet<String>(strings.length);
    +  145  5
             Collections.addAll(set, strings);
    +  146  5
             return set;
    +  147   +
         }
    +  148  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractSuppressionAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractSuppressionAnalyzer.html index 7d7cf96f1..12dec7ce7 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractSuppressionAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AbstractSuppressionAnalyzer.html @@ -153,77 +153,77 @@  69  
         @Override
     70   -
         public void initialize() throws InitializationException {
    -  71  7
             super.initialize();
    -  72   +
         public void initializeAnalyzer() throws InitializationException {
    +  71  
             try {
    -  73  7
                 loadSuppressionData();
    -  74  1
             } catch (SuppressionParseException ex) {
    -  75  1
                 throw new InitializationException("Error initializing the suppression analyzer", ex);
    -  76  6
             }
    -  77  6
         }
    +  72  7
                 loadSuppressionData();
    +  73  1
             } catch (SuppressionParseException ex) {
    +  74  1
                 throw new InitializationException("Error initializing the suppression analyzer", ex);
    +  75  6
             }
    +  76  6
         }
    +  77   +
     
     78   -
     
    +
         /**
     79   -
         /**
    -  80  
          * The list of suppression rules
    +  80   +
          */
     81   -
          */
    -  82  
         private List<SuppressionRule> rules;
    +  82   +
     
     83   -
     
    +
         /**
     84   -
         /**
    -  85  
          * Get the value of rules.
    +  85   +
          *
     86   -
          *
    -  87  
          * @return the value of rules
    +  87   +
          */
     88   -
          */
    -  89  
         public List<SuppressionRule> getRules() {
    -  90  26
             return rules;
    -  91   +  89  26
             return rules;
    +  90  
         }
    +  91   +
     
     92   -
     
    +
         /**
     93   -
         /**
    -  94  
          * Set the value of rules.
    +  94   +
          *
     95   -
          *
    -  96  
          * @param rules new value of rules
    +  96   +
          */
     97   -
          */
    -  98  
         public void setRules(List<SuppressionRule> rules) {
    -  99  0
             this.rules = rules;
    -  100  0
         }
    -  101   +  98  0
             this.rules = rules;
    +  99  0
         }
    +  100  
     
    -  102   +  101  
         /**
    -  103   +  102  
          * Loads the suppression rules file.
    -  104   +  103  
          *
    -  105   +  104  
          * @throws SuppressionParseException thrown if the XML cannot be parsed.
    -  106   +  105  
          */
    -  107   +  106  
         private void loadSuppressionData() throws SuppressionParseException {
    -  108  7
             final SuppressionParser parser = new SuppressionParser();
    -  109  7
             File file = null;
    -  110   +  107  7
             final SuppressionParser parser = new SuppressionParser();
    +  108  7
             File file = null;
    +  109  
             try {
    -  111  7
                 rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
    +  110  7
                 final InputStream in = this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml");
    +  111  7
                 rules = parser.parseSuppressionRules(in);
     112  0
             } catch (SAXException ex) {
     113  0
                 throw new SuppressionParseException("Unable to parse the base suppression data file", ex);
     114  7
             }
    @@ -345,6 +345,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalysisPhase.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalysisPhase.html index eb4e63c37..09b92b3d2 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalysisPhase.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalysisPhase.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    AnalysisPhase
    100%
    11/11
    N/A
    0
    AnalysisPhase
    100%
    12/12
    N/A
    0
     
    @@ -65,7 +65,7 @@
      * @author Jeremy Long
     24  
      */
    -  25  22
     public enum AnalysisPhase {
    +  25  23
     public enum AnalysisPhase {
     26  
     
     27   @@ -92,56 +92,63 @@  39  
         /**
     40   -
          * Pre identifier analysis phase.
    +
          * Post information collection phase.
     41  
          */
    -  42  1
         PRE_IDENTIFIER_ANALYSIS,
    +  42  1
         POST_INFORMATION_COLLECTION,
     43  
         /**
     44   -
          * Identifier analysis phase.
    +
          * Pre identifier analysis phase.
     45  
          */
    -  46  1
         IDENTIFIER_ANALYSIS,
    +  46  1
         PRE_IDENTIFIER_ANALYSIS,
     47  
         /**
     48   -
          * Post identifier analysis phase.
    +
          * Identifier analysis phase.
     49  
          */
    -  50  1
         POST_IDENTIFIER_ANALYSIS,
    +  50  1
         IDENTIFIER_ANALYSIS,
     51  
         /**
     52   -
          * Pre finding analysis phase.
    +
          * Post identifier analysis phase.
     53  
          */
    -  54  1
         PRE_FINDING_ANALYSIS,
    +  54  1
         POST_IDENTIFIER_ANALYSIS,
     55  
         /**
     56   -
          * Finding analysis phase.
    +
          * Pre finding analysis phase.
     57  
          */
    -  58  1
         FINDING_ANALYSIS,
    +  58  1
         PRE_FINDING_ANALYSIS,
     59  
         /**
     60   -
          * Post analysis phase.
    +
          * Finding analysis phase.
     61  
          */
    -  62  1
         POST_FINDING_ANALYSIS,
    +  62  1
         FINDING_ANALYSIS,
     63  
         /**
     64   -
          * The final analysis phase.
    +
          * Post analysis phase.
     65  
          */
    -  66  1
         FINAL
    +  66  1
         POST_FINDING_ANALYSIS,
     67   +
         /**
    +  68   +
          * The final analysis phase.
    +  69   +
          */
    +  70  1
         FINAL
    +  71  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Analyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Analyzer.html index 90f9cb571..c1a592f78 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Analyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Analyzer.html @@ -188,9 +188,21 @@  85  
         boolean supportsParallelProcessing();
     86   +
         /**
    +  87   +
          * Get the value of enabled.
    +  88   +
          *
    +  89   +
          * @return the value of enabled
    +  90   +
          */
    +  91   +
         boolean isEnabled();
    +  92  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalyzerService.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalyzerService.html index 7c3f939a1..15a48190c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalyzerService.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AnalyzerService.html @@ -140,15 +140,15 @@  65  0
             } catch (InvalidSettingException ex) {
     66  0
                 LOGGER.error("invalide experimental setting", ex);
     67  9
             }
    -  68  243
             while (iterator.hasNext()) {
    -  69  234
                 final Analyzer a = iterator.next();
    -  70  234
                 if (!experimentalEnabled && a.getClass().isAnnotationPresent(Experimental.class)) {
    +  68  261
             while (iterator.hasNext()) {
    +  69  252
                 final Analyzer a = iterator.next();
    +  70  252
                 if (!experimentalEnabled && a.getClass().isAnnotationPresent(Experimental.class)) {
     71  11
                     continue;
     72  
                 }
    -  73  223
                 LOGGER.debug("Loaded Analyzer {}", a.getName());
    -  74  223
                 analyzers.add(a);
    -  75  223
             }
    +  73  241
                 LOGGER.debug("Loaded Analyzer {}", a.getName());
    +  74  241
                 analyzers.add(a);
    +  75  241
             }
     76  9
             return analyzers;
     77  
         }
    @@ -156,6 +156,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ArchiveAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ArchiveAnalyzer.html index fa18f2829..a9c7acc08 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ArchiveAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ArchiveAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    ArchiveAnalyzer
    34%
    91/261
    18%
    27/146
    6.5
    ArchiveAnalyzer
    34%
    87/255
    16%
    25/148
    6.824
     
    @@ -58,972 +58,944 @@  20  
     import java.io.BufferedInputStream;
     21   -
     import java.io.Closeable;
    -  22  
     import java.io.File;
    -  23   +  22  
     import java.io.FileFilter;
    -  24   +  23  
     import java.io.FileInputStream;
    -  25   +  24  
     import java.io.FileNotFoundException;
    -  26   +  25  
     import java.io.FileOutputStream;
    -  27   +  26  
     import java.io.IOException;
    -  28   +  27  
     import java.util.Collections;
    -  29   +  28  
     import java.util.Enumeration;
    -  30   +  29  
     import java.util.List;
    -  31   +  30  
     import java.util.Set;
    +  31   +
     
     32   -
     
    -  33  
     import org.apache.commons.compress.archivers.ArchiveEntry;
    -  34   +  33  
     import org.apache.commons.compress.archivers.ArchiveInputStream;
    -  35   +  34  
     import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
    -  36   +  35  
     import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
    -  37   +  36  
     import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
    -  38   +  37  
     import org.apache.commons.compress.archivers.zip.ZipFile;
    -  39   +  38  
     import org.apache.commons.compress.compressors.CompressorInputStream;
    -  40   +  39  
     import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
    -  41   +  40  
     import org.apache.commons.compress.compressors.bzip2.BZip2Utils;
    -  42   +  41  
     import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
    -  43   +  42  
     import org.apache.commons.compress.compressors.gzip.GzipUtils;
    -  44   +  43  
     import org.apache.commons.compress.utils.IOUtils;
    +  44   +
     
     45   -
     
    -  46  
     import org.owasp.dependencycheck.Engine;
    -  47   +  46  
     import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
    -  48   +  47  
     import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException;
    -  49   +  48  
     import org.owasp.dependencycheck.dependency.Dependency;
    -  50   +  49  
     import org.owasp.dependencycheck.exception.InitializationException;
    -  51   +  50  
     import org.owasp.dependencycheck.utils.FileFilterBuilder;
    -  52   +  51  
     import org.owasp.dependencycheck.utils.FileUtils;
    -  53   +  52  
     import org.owasp.dependencycheck.utils.Settings;
    +  53   +
     
     54   -
     
    -  55  
     import org.slf4j.Logger;
    -  56   +  55  
     import org.slf4j.LoggerFactory;
    +  56   +
     
     57   -
     
    -  58  
     /**
    -  59   +  58  
      * <p>
    -  60   +  59  
      * An analyzer that extracts files from archives and ensures any supported files
    -  61   +  60  
      * contained within the archive are added to the dependency list.</p>
    -  62   +  61  
      *
    -  63   +  62  
      * @author Jeremy Long
    -  64   +  63  
      */
    -  65  8
     public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
    +  64  8
     public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
    +  65   +
     
     66   -
     
    +
         /**
     67   -
         /**
    -  68  
          * The logger.
    -  69   +  68  
          */
    -  70  1
         private static final Logger LOGGER = LoggerFactory.getLogger(ArchiveAnalyzer.class);
    +  69  1
         private static final Logger LOGGER = LoggerFactory.getLogger(ArchiveAnalyzer.class);
    +  70   +
         /**
     71   -
         /**
    -  72  
          * The count of directories created during analysis. This is used for
    -  73   +  72  
          * creating temporary directories.
    -  74   +  73  
          */
    -  75  1
         private static int dirCount = 0;
    +  74  1
         private static int dirCount = 0;
    +  75   +
         /**
     76   -
         /**
    -  77  
          * The parent directory for the individual directories per archive.
    -  78   +  77  
          */
    -  79  8
         private File tempFileLocation = null;
    +  78  8
         private File tempFileLocation = null;
    +  79   +
         /**
     80   -
         /**
    -  81  
          * The max scan depth that the analyzer will recursively extract nested
    -  82   +  81  
          * archives.
    -  83   +  82  
          */
    -  84  1
         private static final int MAX_SCAN_DEPTH = Settings.getInt("archive.scan.depth", 3);
    +  83  1
         private static final int MAX_SCAN_DEPTH = Settings.getInt("archive.scan.depth", 3);
    +  84   +
         /**
     85   -
         /**
    -  86  
          * Tracks the current scan/extraction depth for nested archives.
    -  87   +  86  
          */
    -  88  8
         private int scanDepth = 0;
    +  87  8
         private int scanDepth = 0;
    +  88   +
     
     89   -
     
    -  90  
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
    +  90   +
         /**
     91   -
         /**
    -  92  
          * The name of the analyzer.
    +  92   +
          */
     93   -
          */
    -  94  
         private static final String ANALYZER_NAME = "Archive Analyzer";
    +  94   +
         /**
     95   -
         /**
    -  96  
          * The phase that this analyzer is intended to run in.
    -  97   +  96  
          */
    -  98  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INITIAL;
    +  97  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INITIAL;
    +  98   +
         /**
     99   -
         /**
    -  100  
          * The set of things we can handle with Zip methods
    -  101   +  100  
          */
    -  102  1
         private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
    +  101  1
         private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
    +  102   +
         /**
     103   -
         /**
    -  104  
          * The set of file extensions supported by this analyzer. Note for
    -  105   +  104  
          * developers, any additions to this list will need to be explicitly handled
    -  106   +  105  
          * in {@link #extractFiles(File, File, Engine)}.
    -  107   +  106  
          */
    -  108  1
         private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz", "bz2", "tbz2");
    +  107  1
         private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz", "bz2", "tbz2");
    +  108   +
     
     109   -
     
    +
         /**
     110   -
         /**
    -  111  
          * Detects files with extensions to remove from the engine's collection of
    -  112   +  111  
          * dependencies.
    -  113   +  112  
          */
    -  114  1
         private static final FileFilter REMOVE_FROM_ANALYSIS = FileFilterBuilder.newInstance().addExtensions("zip", "tar", "gz", "tgz", "bz2", "tbz2")
    -  115  1
                 .build();
    +  113  1
         private static final FileFilter REMOVE_FROM_ANALYSIS = FileFilterBuilder.newInstance().addExtensions("zip", "tar", "gz", "tgz", "bz2", "tbz2")
    +  114  1
                 .build();
    +  115   +
     
     116   -
     
    -  117  
         static {
    -  118  1
             final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
    -  119  1
             if (additionalZipExt != null) {
    -  120  0
                 final String[] ext = additionalZipExt.split("\\s*,\\s*");
    -  121  0
                 Collections.addAll(ZIPPABLES, ext);
    -  122   +  117  1
             final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
    +  118  1
             if (additionalZipExt != null) {
    +  119  0
                 final String[] ext = additionalZipExt.split("\\s*,\\s*");
    +  120  0
                 Collections.addAll(ZIPPABLES, ext);
    +  121  
             }
    -  123  1
             EXTENSIONS.addAll(ZIPPABLES);
    +  122  1
             EXTENSIONS.addAll(ZIPPABLES);
    +  123   +
         }
     124   -
         }
    +
     
     125   -
     
    +
         /**
     126   -
         /**
    -  127  
          * The file filter used to filter supported files.
    -  128   +  127  
          */
    -  129  1
         private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
    +  128  1
         private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
    +  129   +
     
     130   -
     
    +
         @Override
     131   -
         @Override
    -  132  
         protected FileFilter getFileFilter() {
    -  133  862
             return FILTER;
    +  132  860
             return FILTER;
    +  133   +
         }
     134   -
         }
    +
     
     135   -
     
    +
         /**
     136   -
         /**
    -  137  
          * Detects files with .zip extension.
    -  138   +  137  
          */
    -  139  1
         private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
    +  138  1
         private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
    +  139   +
     
     140   -
     
    +
         /**
     141   -
         /**
    -  142  
          * Returns the name of the analyzer.
    +  142   +
          *
     143   -
          *
    -  144  
          * @return the name of the analyzer.
    +  144   +
          */
     145   -
          */
    +
         @Override
     146   -
         @Override
    -  147  
         public String getName() {
    -  148  24
             return ANALYZER_NAME;
    +  147  22
             return ANALYZER_NAME;
    +  148   +
         }
     149   -
         }
    +
     
     150   -
     
    +
         /**
     151   -
         /**
    -  152  
          * Returns the phase that the analyzer is intended to run in.
    +  152   +
          *
     153   -
          *
    -  154  
          * @return the phase that the analyzer is intended to run in.
    +  154   +
          */
     155   -
          */
    +
         @Override
     156   -
         @Override
    -  157  
         public AnalysisPhase getAnalysisPhase() {
    -  158  6
             return ANALYSIS_PHASE;
    +  157  6
             return ANALYSIS_PHASE;
    +  158   +
         }
     159   -
         }
    -  160  
         //</editor-fold>
    +  160   +
     
     161   -
     
    +
         /**
     162   -
         /**
    -  163  
          * Returns the key used in the properties file to reference the analyzer's
    -  164   +  163  
          * enabled property.
    +  164   +
          *
     165   -
          *
    -  166  
          * @return the analyzer's enabled property setting key
    +  166   +
          */
     167   -
          */
    +
         @Override
     168   -
         @Override
    -  169  
         protected String getAnalyzerEnabledSettingKey() {
    -  170  8
             return Settings.KEYS.ANALYZER_ARCHIVE_ENABLED;
    +  169  2
             return Settings.KEYS.ANALYZER_ARCHIVE_ENABLED;
    +  170   +
         }
     171   -
         }
    +
     
     172   -
     
    +
         /**
     173   -
         /**
    -  174  
          * The initialize method does nothing for this Analyzer.
    +  174   +
          *
     175   -
          *
    -  176  
          * @throws InitializationException is thrown if there is an exception
    -  177   +  176  
          * deleting or creating temporary files
    +  177   +
          */
     178   -
          */
    +
         @Override
     179   -
         @Override
    -  180  
         public void initializeFileTypeAnalyzer() throws InitializationException {
    -  181   +  180  
             try {
    -  182  1
                 final File baseDir = Settings.getTempDirectory();
    -  183  1
                 tempFileLocation = File.createTempFile("check", "tmp", baseDir);
    -  184  1
                 if (!tempFileLocation.delete()) {
    -  185  0
                     setEnabled(false);
    -  186  0
                     final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
    -  187  0
                     throw new InitializationException(msg);
    -  188   +  181  1
                 final File baseDir = Settings.getTempDirectory();
    +  182  1
                 tempFileLocation = File.createTempFile("check", "tmp", baseDir);
    +  183  1
                 if (!tempFileLocation.delete()) {
    +  184  0
                     setEnabled(false);
    +  185  0
                     final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
    +  186  0
                     throw new InitializationException(msg);
    +  187  
                 }
    -  189  1
                 if (!tempFileLocation.mkdirs()) {
    -  190  0
                     setEnabled(false);
    -  191  0
                     final String msg = String.format("Unable to create directory '%s'.", tempFileLocation.getAbsolutePath());
    -  192  0
                     throw new InitializationException(msg);
    -  193   +  188  1
                 if (!tempFileLocation.mkdirs()) {
    +  189  0
                     setEnabled(false);
    +  190  0
                     final String msg = String.format("Unable to create directory '%s'.", tempFileLocation.getAbsolutePath());
    +  191  0
                     throw new InitializationException(msg);
    +  192  
                 }
    -  194  0
             } catch (IOException ex) {
    -  195  0
                 setEnabled(false);
    -  196  0
                 throw new InitializationException("Unable to create a temporary file", ex);
    -  197  1
             }
    -  198  1
         }
    +  193  0
             } catch (IOException ex) {
    +  194  0
                 setEnabled(false);
    +  195  0
                 throw new InitializationException("Unable to create a temporary file", ex);
    +  196  1
             }
    +  197  1
         }
    +  198   +
     
     199   -
     
    +
         /**
     200   -
         /**
    -  201  
          * The close method deletes any temporary files and directories created
    -  202   +  201  
          * during analysis.
    +  202   +
          *
     203   -
          *
    -  204  
          * @throws Exception thrown if there is an exception deleting temporary
    -  205   +  204  
          * files
    +  205   +
          */
     206   -
          */
    +
         @Override
     207   -
         @Override
    -  208   -
         public void close() throws Exception {
    -  209  2
             if (tempFileLocation != null && tempFileLocation.exists()) {
    -  210  1
                 LOGGER.debug("Attempting to delete temporary files");
    -  211  1
                 final boolean success = FileUtils.delete(tempFileLocation);
    -  212  1
                 if (!success && tempFileLocation.exists()) {
    -  213  0
                     final String[] l = tempFileLocation.list();
    -  214  0
                     if (l != null && l.length > 0) {
    -  215  0
                         LOGGER.warn("Failed to delete some temporary files, see the log for more details");
    +
         public void closeAnalyzer() throws Exception {
    +  208  1
             if (tempFileLocation != null && tempFileLocation.exists()) {
    +  209  1
                 LOGGER.debug("Attempting to delete temporary files");
    +  210  1
                 final boolean success = FileUtils.delete(tempFileLocation);
    +  211  1
                 if (!success && tempFileLocation.exists()) {
    +  212  0
                     final String[] l = tempFileLocation.list();
    +  213  0
                     if (l != null && l.length > 0) {
    +  214  0
                         LOGGER.warn("Failed to delete some temporary files, see the log for more details");
    +  215   +
                     }
     216   -
                     }
    +
                 }
     217   -
                 }
    -  218  
             }
    -  219  2
         }
    +  218  1
         }
    +  219   +
     
     220   -
     
    +
         /**
     221   -
         /**
    -  222  
          * Does not support parallel processing as it both modifies and iterates
    -  223   +  222  
          * over the engine's list of dependencies.
    +  223   +
          *
     224   -
          *
    +
          * @see #analyzeDependency(Dependency, Engine)
     225   -
          * @see #analyzeFileType(Dependency, Engine)
    -  226  
          * @see #findMoreDependencies(Engine, File)
    +  226   +
          */
     227   -
          */
    +
         @Override
     228   -
         @Override
    -  229  
         public boolean supportsParallelProcessing() {
    -  230  2
             return false;
    +  229  1
             return false;
    +  230   +
         }
     231   -
         }
    +
     
     232   -
     
    +
         /**
     233   -
         /**
    -  234  
          * Analyzes a given dependency. If the dependency is an archive, such as a
    -  235   +  234  
          * WAR or EAR, the contents are extracted, scanned, and added to the list of
    -  236   +  235  
          * dependencies within the engine.
    +  236   +
          *
     237   -
          *
    -  238  
          * @param dependency the dependency to analyze
    -  239   +  238  
          * @param engine the engine scanning
    -  240   +  239  
          * @throws AnalysisException thrown if there is an analysis exception
    +  240   +
          */
     241   -
          */
    -  242  
         @Override
    -  243   -
         public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
    -  244  2
             final File f = new File(dependency.getActualFilePath());
    -  245  2
             final File tmpDir = getNextTempDirectory();
    -  246  2
             extractFiles(f, tmpDir, engine);
    +  242   +
         public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  243  2
             final File f = new File(dependency.getActualFilePath());
    +  244  2
             final File tmpDir = getNextTempDirectory();
    +  245  2
             extractFiles(f, tmpDir, engine);
    +  246   +
     
     247   -
     
    -  248  
             //make a copy
    -  249  2
             final List<Dependency> dependencySet = findMoreDependencies(engine, tmpDir);
    -  250   +  248  2
             final List<Dependency> dependencySet = findMoreDependencies(engine, tmpDir);
    +  249  
     
    -  251  2
             if (!dependencySet.isEmpty()) {
    -  252  0
                 for (Dependency d : dependencySet) {
    -  253  0
                     if (d.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
    -  254   +  250  2
             if (dependencySet != null && !dependencySet.isEmpty()) {
    +  251  0
                 for (Dependency d : dependencySet) {
    +  252  0
                     if (d.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
    +  253  
                         //fix the dependency's display name and path
    -  255  0
                         final String displayPath = String.format("%s%s",
    -  256  0
                                 dependency.getFilePath(),
    -  257  0
                                 d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
    -  258  0
                         final String displayName = String.format("%s: %s",
    -  259  0
                                 dependency.getFileName(),
    -  260  0
                                 d.getFileName());
    -  261  0
                         d.setFilePath(displayPath);
    -  262  0
                         d.setFileName(displayName);
    -  263  0
                         d.setProjectReferences(dependency.getProjectReferences());
    +  254  0
                         final String displayPath = String.format("%s%s",
    +  255  0
                                 dependency.getFilePath(),
    +  256  0
                                 d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
    +  257  0
                         final String displayName = String.format("%s: %s",
    +  258  0
                                 dependency.getFileName(),
    +  259  0
                                 d.getFileName());
    +  260  0
                         d.setFilePath(displayPath);
    +  261  0
                         d.setFileName(displayName);
    +  262  0
                         d.setProjectReferences(dependency.getProjectReferences());
    +  263   +
     
     264   -
     
    -  265  
                         //TODO - can we get more evidence from the parent? EAR contains module name, etc.
    -  266   +  265  
                         //analyze the dependency (i.e. extract files) if it is a supported type.
    -  267  0
                         if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
    -  268  0
                             scanDepth += 1;
    -  269  0
                             analyze(d, engine);
    -  270  0
                             scanDepth -= 1;
    -  271   +  266  0
                         if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
    +  267  0
                             scanDepth += 1;
    +  268  0
                             analyze(d, engine);
    +  269  0
                             scanDepth -= 1;
    +  270  
                         }
    -  272  0
                     } else {
    -  273  0
                         for (Dependency sub : dependencySet) {
    -  274  0
                             if (sub.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
    -  275  0
                                 final String displayPath = String.format("%s%s",
    -  276  0
                                         dependency.getFilePath(),
    -  277  0
                                         sub.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
    -  278  0
                                 final String displayName = String.format("%s: %s",
    -  279  0
                                         dependency.getFileName(),
    -  280  0
                                         sub.getFileName());
    -  281  0
                                 sub.setFilePath(displayPath);
    -  282  0
                                 sub.setFileName(displayName);
    -  283   +  271  0
                     } else {
    +  272  0
                         for (Dependency sub : dependencySet) {
    +  273  0
                             if (sub.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
    +  274  0
                                 final String displayPath = String.format("%s%s",
    +  275  0
                                         dependency.getFilePath(),
    +  276  0
                                         sub.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
    +  277  0
                                 final String displayName = String.format("%s: %s",
    +  278  0
                                         dependency.getFileName(),
    +  279  0
                                         sub.getFileName());
    +  280  0
                                 sub.setFilePath(displayPath);
    +  281  0
                                 sub.setFileName(displayName);
    +  282  
                             }
    -  284  0
                         }
    -  285   +  283  0
                         }
    +  284  
                     }
    -  286  0
                 }
    -  287   +  285  0
                 }
    +  286  
             }
    -  288  2
             if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
    -  289  0
                 addDisguisedJarsToDependencies(dependency, engine);
    -  290  0
                 engine.getDependencies().remove(dependency);
    -  291   +  287  2
             if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
    +  288  0
                 addDisguisedJarsToDependencies(dependency, engine);
    +  289  0
                 engine.getDependencies().remove(dependency);
    +  290  
             }
    -  292  2
             Collections.sort(engine.getDependencies());
    -  293  2
         }
    +  291  2
             Collections.sort(engine.getDependencies());
    +  292  2
         }
    +  293   +
     
     294   -
     
    +
         /**
     295   -
         /**
    -  296  
          * If a zip file was identified as a possible JAR, this method will add the
    -  297   +  296  
          * zip to the list of dependencies.
    +  297   +
          *
     298   -
          *
    -  299  
          * @param dependency the zip file
    -  300   +  299  
          * @param engine the engine
    -  301   +  300  
          * @throws AnalysisException thrown if there is an issue
    +  301   +
          */
     302   -
          */
    -  303  
         private void addDisguisedJarsToDependencies(Dependency dependency, Engine engine) throws AnalysisException {
    -  304  0
             if (ZIP_FILTER.accept(dependency.getActualFile()) && isZipFileActuallyJarFile(dependency)) {
    -  305  0
                 final File tdir = getNextTempDirectory();
    -  306  0
                 final String fileName = dependency.getFileName();
    -  307   +  303  0
             if (ZIP_FILTER.accept(dependency.getActualFile()) && isZipFileActuallyJarFile(dependency)) {
    +  304  0
                 final File tdir = getNextTempDirectory();
    +  305  0
                 final String fileName = dependency.getFileName();
    +  306  
     
    -  308  0
                 LOGGER.info("The zip file '{}' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName);
    -  309  0
                 final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
    -  310   +  307  0
                 LOGGER.info("The zip file '{}' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName);
    +  308  0
                 final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
    +  309  
                 //store the archives sha1 and change it so that the engine doesn't think the zip and jar file are the same
    -  311   +  310  
                 // and add it is a related dependency.
    -  312  0
                 final String archiveSha1 = dependency.getSha1sum();
    -  313   +  311  0
                 final String archiveSha1 = dependency.getSha1sum();
    +  312  
                 try {
    -  314  0
                     dependency.setSha1sum("");
    -  315  0
                     org.apache.commons.io.FileUtils.copyFile(dependency.getActualFile(), tmpLoc);
    -  316  0
                     final List<Dependency> dependencySet = findMoreDependencies(engine, tmpLoc);
    -  317  0
                     if (!dependencySet.isEmpty()) {
    -  318  0
                         for (Dependency d : dependencySet) {
    -  319   +  313  0
                     dependency.setSha1sum("");
    +  314  0
                     org.apache.commons.io.FileUtils.copyFile(dependency.getActualFile(), tmpLoc);
    +  315  0
                     final List<Dependency> dependencySet = findMoreDependencies(engine, tmpLoc);
    +  316  0
                     if (dependencySet != null && !dependencySet.isEmpty()) {
    +  317  0
                         for (Dependency d : dependencySet) {
    +  318  
                             //fix the dependency's display name and path
    -  320  0
                             if (d.getActualFile().equals(tmpLoc)) {
    -  321  0
                                 d.setFilePath(dependency.getFilePath());
    -  322  0
                                 d.setDisplayFileName(dependency.getFileName());
    -  323   +  319  0
                             if (d.getActualFile().equals(tmpLoc)) {
    +  320  0
                                 d.setFilePath(dependency.getFilePath());
    +  321  0
                                 d.setDisplayFileName(dependency.getFileName());
    +  322  
                             } else {
    -  324  0
                                 for (Dependency sub : d.getRelatedDependencies()) {
    -  325  0
                                     if (sub.getActualFile().equals(tmpLoc)) {
    -  326  0
                                         sub.setFilePath(dependency.getFilePath());
    -  327  0
                                         sub.setDisplayFileName(dependency.getFileName());
    -  328   +  323  0
                                 for (Dependency sub : d.getRelatedDependencies()) {
    +  324  0
                                     if (sub.getActualFile().equals(tmpLoc)) {
    +  325  0
                                         sub.setFilePath(dependency.getFilePath());
    +  326  0
                                         sub.setDisplayFileName(dependency.getFileName());
    +  327  
                                     }
    -  329  0
                                 }
    -  330   +  328  0
                                 }
    +  329  
                             }
    -  331  0
                         }
    -  332   +  330  0
                         }
    +  331  
                     }
    -  333  0
                 } catch (IOException ex) {
    -  334  0
                     LOGGER.debug("Unable to perform deep copy on '{}'", dependency.getActualFile().getPath(), ex);
    -  335   +  332  0
                 } catch (IOException ex) {
    +  333  0
                     LOGGER.debug("Unable to perform deep copy on '{}'", dependency.getActualFile().getPath(), ex);
    +  334  
                 } finally {
    -  336  0
                     dependency.setSha1sum(archiveSha1);
    -  337  0
                 }
    -  338   +  335  0
                     dependency.setSha1sum(archiveSha1);
    +  336  0
                 }
    +  337  
             }
    -  339  0
         }
    +  338  0
         }
    +  339   +
     
     340   -
     
    +
         /**
     341   -
         /**
    -  342  
          * Scan the given file/folder, and return any new dependencies found.
    +  342   +
          *
     343   -
          *
    -  344  
          * @param engine used to scan
    -  345   +  344  
          * @param file target of scanning
    -  346   +  345  
          * @return any dependencies that weren't known to the engine before
    +  346   +
          */
     347   -
          */
    -  348  
         private static List<Dependency> findMoreDependencies(Engine engine, File file) {
    -  349  2
             final List<Dependency> added = engine.scan(file);
    -  350  2
             return added;
    +  348  2
             final List<Dependency> added = engine.scan(file);
    +  349  2
             return added;
    +  350   +
         }
     351   -
         }
    +
     
     352   -
     
    +
         /**
     353   -
         /**
    -  354  
          * Retrieves the next temporary directory to extract an archive too.
    +  354   +
          *
     355   -
          *
    -  356  
          * @return a directory
    -  357   +  356  
          * @throws AnalysisException thrown if unable to create temporary directory
    +  357   +
          */
     358   -
          */
    -  359  
         private File getNextTempDirectory() throws AnalysisException {
    -  360  2
             dirCount += 1;
    -  361  2
             final File directory = new File(tempFileLocation, String.valueOf(dirCount));
    -  362   +  359  2
             dirCount += 1;
    +  360  2
             final File directory = new File(tempFileLocation, String.valueOf(dirCount));
    +  361  
             //getting an exception for some directories not being able to be created; might be because the directory already exists?
    -  363  2
             if (directory.exists()) {
    -  364  0
                 return getNextTempDirectory();
    -  365   +  362  2
             if (directory.exists()) {
    +  363  0
                 return getNextTempDirectory();
    +  364  
             }
    -  366  2
             if (!directory.mkdirs()) {
    -  367  0
                 final String msg = String.format("Unable to create temp directory '%s'.", directory.getAbsolutePath());
    -  368  0
                 throw new AnalysisException(msg);
    -  369   +  365  2
             if (!directory.mkdirs()) {
    +  366  0
                 final String msg = String.format("Unable to create temp directory '%s'.", directory.getAbsolutePath());
    +  367  0
                 throw new AnalysisException(msg);
    +  368  
             }
    -  370  2
             return directory;
    +  369  2
             return directory;
    +  370   +
         }
     371   -
         }
    +
     
     372   -
     
    +
         /**
     373   -
         /**
    -  374  
          * Extracts the contents of an archive into the specified directory.
    +  374   +
          *
     375   -
          *
    -  376  
          * @param archive an archive file such as a WAR or EAR
    -  377   +  376  
          * @param destination a directory to extract the contents to
    -  378   +  377  
          * @param engine the scanning engine
    -  379   +  378  
          * @throws AnalysisException thrown if the archive is not found
    +  379   +
          */
     380   -
          */
    -  381  
         private void extractFiles(File archive, File destination, Engine engine) throws AnalysisException {
    -  382  2
             if (archive != null && destination != null) {
    -  383  2
                 String archiveExt = FileUtils.getFileExtension(archive.getName());
    -  384  2
                 if (archiveExt == null) {
    -  385  0
                     return;
    -  386   +  381  2
             if (archive != null && destination != null) {
    +  382  2
                 String archiveExt = FileUtils.getFileExtension(archive.getName());
    +  383  2
                 if (archiveExt == null) {
    +  384  0
                     return;
    +  385  
                 }
    -  387  2
                 archiveExt = archiveExt.toLowerCase();
    +  386  2
                 archiveExt = archiveExt.toLowerCase();
    +  387   +
     
     388   -
     
    -  389  
                 final FileInputStream fis;
    -  390   +  389  
                 try {
    -  391  2
                     fis = new FileInputStream(archive);
    -  392  0
                 } catch (FileNotFoundException ex) {
    -  393  0
                     LOGGER.debug("", ex);
    -  394  0
                     throw new AnalysisException("Archive file was not found.", ex);
    -  395  2
                 }
    -  396  2
                 BufferedInputStream in = null;
    -  397  2
                 ZipArchiveInputStream zin = null;
    -  398  2
                 TarArchiveInputStream tin = null;
    -  399  2
                 GzipCompressorInputStream gin = null;
    -  400  2
                 BZip2CompressorInputStream bzin = null;
    -  401   +  390  2
                     fis = new FileInputStream(archive);
    +  391  0
                 } catch (FileNotFoundException ex) {
    +  392  0
                     LOGGER.debug("", ex);
    +  393  0
                     throw new AnalysisException("Archive file was not found.", ex);
    +  394  2
                 }
    +  395  2
                 BufferedInputStream in = null;
    +  396  2
                 ZipArchiveInputStream zin = null;
    +  397  2
                 TarArchiveInputStream tin = null;
    +  398  2
                 GzipCompressorInputStream gin = null;
    +  399  2
                 BZip2CompressorInputStream bzin = null;
    +  400  
                 try {
    -  402  2
                     if (ZIPPABLES.contains(archiveExt)) {
    -  403  2
                         in = new BufferedInputStream(fis);
    -  404  2
                         ensureReadableJar(archiveExt, in);
    -  405  2
                         zin = new ZipArchiveInputStream(in);
    -  406  2
                         extractArchive(zin, destination, engine);
    -  407  0
                     } else if ("tar".equals(archiveExt)) {
    -  408  0
                         in = new BufferedInputStream(fis);
    -  409  0
                         tin = new TarArchiveInputStream(in);
    -  410  0
                         extractArchive(tin, destination, engine);
    -  411  0
                     } else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
    -  412  0
                         final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
    -  413  0
                         final File f = new File(destination, uncompressedName);
    -  414  0
                         if (engine.accept(f)) {
    -  415  0
                             in = new BufferedInputStream(fis);
    -  416  0
                             gin = new GzipCompressorInputStream(in);
    -  417  0
                             decompressFile(gin, f);
    -  418   +  401  2
                     if (ZIPPABLES.contains(archiveExt)) {
    +  402  2
                         in = new BufferedInputStream(fis);
    +  403  2
                         ensureReadableJar(archiveExt, in);
    +  404  2
                         zin = new ZipArchiveInputStream(in);
    +  405  2
                         extractArchive(zin, destination, engine);
    +  406  0
                     } else if ("tar".equals(archiveExt)) {
    +  407  0
                         in = new BufferedInputStream(fis);
    +  408  0
                         tin = new TarArchiveInputStream(in);
    +  409  0
                         extractArchive(tin, destination, engine);
    +  410  0
                     } else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
    +  411  0
                         final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
    +  412  0
                         final File f = new File(destination, uncompressedName);
    +  413  0
                         if (engine.accept(f)) {
    +  414  0
                             in = new BufferedInputStream(fis);
    +  415  0
                             gin = new GzipCompressorInputStream(in);
    +  416  0
                             decompressFile(gin, f);
    +  417   +
                         }
    +  418  0
                     } else if ("bz2".equals(archiveExt) || "tbz2".equals(archiveExt)) {
    +  419  0
                         final String uncompressedName = BZip2Utils.getUncompressedFilename(archive.getName());
    +  420  0
                         final File f = new File(destination, uncompressedName);
    +  421  0
                         if (engine.accept(f)) {
    +  422  0
                             in = new BufferedInputStream(fis);
    +  423  0
                             bzin = new BZip2CompressorInputStream(in);
    +  424  0
                             decompressFile(bzin, f);
    +  425  
                         }
    -  419  0
                     } else if ("bz2".equals(archiveExt) || "tbz2".equals(archiveExt)) {
    -  420  0
                         final String uncompressedName = BZip2Utils.getUncompressedFilename(archive.getName());
    -  421  0
                         final File f = new File(destination, uncompressedName);
    -  422  0
                         if (engine.accept(f)) {
    -  423  0
                             in = new BufferedInputStream(fis);
    -  424  0
                             bzin = new BZip2CompressorInputStream(in);
    -  425  0
                             decompressFile(bzin, f);
     426   -
                         }
    -  427  
                     }
    -  428  0
                 } catch (ArchiveExtractionException ex) {
    -  429  0
                     LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
    -  430  0
                     LOGGER.debug("", ex);
    -  431  0
                 } catch (IOException ex) {
    -  432  0
                     LOGGER.warn("Exception reading archive '{}'.", archive.getName());
    -  433  0
                     LOGGER.debug("", ex);
    -  434   +  427  0
                 } catch (ArchiveExtractionException ex) {
    +  428  0
                     LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
    +  429  0
                     LOGGER.debug("", ex);
    +  430  0
                 } catch (IOException ex) {
    +  431  0
                     LOGGER.warn("Exception reading archive '{}'.", archive.getName());
    +  432  0
                     LOGGER.debug("", ex);
    +  433  
                 } finally {
    -  435   +  434  
                     //overly verbose and not needed... but keeping it anyway due to
    -  436   +  435  
                     //having issue with file handles being left open
    -  437  2
                     close(fis);
    -  438  2
                     close(in);
    -  439  2
                     close(zin);
    -  440  2
                     close(tin);
    -  441  2
                     close(gin);
    -  442  2
                     close(bzin);
    -  443  2
                 }
    -  444   +  436  2
                     FileUtils.close(fis);
    +  437  2
                     FileUtils.close(in);
    +  438  2
                     FileUtils.close(zin);
    +  439  2
                     FileUtils.close(tin);
    +  440  2
                     FileUtils.close(gin);
    +  441  2
                     FileUtils.close(bzin);
    +  442  2
                 }
    +  443  
             }
    -  445  2
         }
    +  444  2
         }
    +  445   +
     
     446   -
     
    +
         /**
     447   -
         /**
    -  448  
          * Checks if the file being scanned is a JAR that begins with '#!/bin' which
    -  449   +  448  
          * indicates it is a fully executable jar. If a fully executable JAR is
    -  450   +  449  
          * identified the input stream will be advanced to the start of the actual
    -  451   +  450  
          * JAR file ( skipping the script).
    +  451   +
          *
     452   -
          *
    -  453  
          * @see
    -  454   +  453  
          * <a href="http://docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/htmlsingle/#deployment-install">Installing
    -  455   +  454  
          * Spring Boot Applications</a>
    -  456   +  455  
          * @param archiveExt the file extension
    -  457   +  456  
          * @param in the input stream
    -  458   +  457  
          * @throws IOException thrown if there is an error reading the stream
    +  458   +
          */
     459   -
          */
    -  460  
         private void ensureReadableJar(final String archiveExt, BufferedInputStream in) throws IOException {
    -  461  2
             if ("jar".equals(archiveExt) && in.markSupported()) {
    -  462  2
                 in.mark(7);
    -  463  2
                 final byte[] b = new byte[7];
    -  464  2
                 final int read = in.read(b);
    -  465  2
                 if (read == 7
    -  466   +  460  2
             if ("jar".equals(archiveExt) && in.markSupported()) {
    +  461  2
                 in.mark(7);
    +  462  2
                 final byte[] b = new byte[7];
    +  463  2
                 final int read = in.read(b);
    +  464  2
                 if (read == 7
    +  465  
                         && b[0] == '#'
    -  467   +  466  
                         && b[1] == '!'
    -  468   +  467  
                         && b[2] == '/'
    -  469   +  468  
                         && b[3] == 'b'
    -  470   +  469  
                         && b[4] == 'i'
    -  471   +  470  
                         && b[5] == 'n'
    -  472   +  471  
                         && b[6] == '/') {
    -  473  0
                     boolean stillLooking = true;
    -  474   +  472  0
                     boolean stillLooking = true;
    +  473  
                     int chr, nxtChr;
    -  475  0
                     while (stillLooking && (chr = in.read()) != -1) {
    -  476  0
                         if (chr == '\n' || chr == '\r') {
    -  477  0
                             in.mark(4);
    -  478  0
                             if ((chr = in.read()) != -1) {
    -  479  0
                                 if (chr == 'P' && (chr = in.read()) != -1) {
    -  480  0
                                     if (chr == 'K' && (chr = in.read()) != -1) {
    -  481  0
                                         if ((chr == 3 || chr == 5 || chr == 7) && (nxtChr = in.read()) != -1) {
    -  482  0
                                             if (nxtChr == chr + 1) {
    -  483  0
                                                 stillLooking = false;
    -  484  0
                                                 in.reset();
    -  485   +  474  0
                     while (stillLooking && (chr = in.read()) != -1) {
    +  475  0
                         if (chr == '\n' || chr == '\r') {
    +  476  0
                             in.mark(4);
    +  477  0
                             if ((chr = in.read()) != -1) {
    +  478  0
                                 if (chr == 'P' && (chr = in.read()) != -1) {
    +  479  0
                                     if (chr == 'K' && (chr = in.read()) != -1) {
    +  480  0
                                         if ((chr == 3 || chr == 5 || chr == 7) && (nxtChr = in.read()) != -1) {
    +  481  0
                                             if (nxtChr == chr + 1) {
    +  482  0
                                                 stillLooking = false;
    +  483  0
                                                 in.reset();
    +  484  
                                             }
    -  486   +  485  
                                         }
    -  487   +  486  
                                     }
    -  488   +  487  
                                 }
    +  488   +
                             }
     489   -
                             }
    +
                         }
     490   -
                         }
    -  491  
                     }
    -  492  0
                 } else {
    -  493  2
                     in.reset();
    +  491  0
                 } else {
    +  492  2
                     in.reset();
    +  493   +
                 }
     494   -
                 }
    -  495  
             }
    -  496  2
         }
    +  495  2
         }
    +  496   +
     
     497   -
     
    +
         /**
     498   -
         /**
    -  499  
          * Extracts files from an archive.
    +  499   +
          *
     500   -
          *
    -  501  
          * @param input the archive to extract files from
    -  502   +  501  
          * @param destination the location to write the files too
    -  503   +  502  
          * @param engine the dependency-check engine
    +  503   +
          * @throws ArchiveExtractionException thrown if there is an exception
     504   -
          * @throws ArchiveExtractionException thrown if there is an exception
    -  505  
          * extracting files from the archive
    +  505   +
          */
     506   -
          */
    -  507  
         private void extractArchive(ArchiveInputStream input, File destination, Engine engine) throws ArchiveExtractionException {
    -  508   +  507  
             ArchiveEntry entry;
    -  509   +  508  
             try {
    -  510  887
                 while ((entry = input.getNextEntry()) != null) {
    -  511  885
                     final File file = new File(destination, entry.getName());
    -  512  885
                     if (entry.isDirectory()) {
    -  513  36
                         if (!file.exists() && !file.mkdirs()) {
    -  514  0
                             final String msg = String.format("Unable to create directory '%s'.", file.getAbsolutePath());
    -  515  0
                             throw new AnalysisException(msg);
    -  516   +  509  887
                 while ((entry = input.getNextEntry()) != null) {
    +  510  885
                     final File file = new File(destination, entry.getName());
    +  511  885
                     if (entry.isDirectory()) {
    +  512  36
                         if (!file.exists() && !file.mkdirs()) {
    +  513  0
                             final String msg = String.format("Unable to create directory '%s'.", file.getAbsolutePath());
    +  514  0
                             throw new AnalysisException(msg);
    +  515  
                         }
    -  517  849
                     } else if (engine.accept(file)) {
    -  518  0
                         extractAcceptedFile(input, file);
    -  519   +  516  849
                     } else if (engine.accept(file)) {
    +  517  0
                         extractAcceptedFile(input, file);
    +  518  
                     }
    -  520  885
                 }
    -  521  0
             } catch (Throwable ex) {
    -  522  0
                 throw new ArchiveExtractionException(ex);
    -  523   +  519  885
                 }
    +  520  0
             } catch (Throwable ex) {
    +  521  0
                 throw new ArchiveExtractionException(ex);
    +  522  
             } finally {
    -  524  2
                 close(input);
    -  525  2
             }
    -  526  2
         }
    +  523  2
                 FileUtils.close(input);
    +  524  2
             }
    +  525  2
         }
    +  526   +
     
     527   -
     
    +
         /**
     528   -
         /**
    -  529  
          * Extracts a file from an archive.
    +  529   +
          *
     530   -
          *
    -  531  
          * @param input the archives input stream
    -  532   +  531  
          * @param file the file to extract
    -  533   +  532  
          * @throws AnalysisException thrown if there is an error
    +  533   +
          */
     534   -
          */
    -  535  
         private static void extractAcceptedFile(ArchiveInputStream input, File file) throws AnalysisException {
    -  536  0
             LOGGER.debug("Extracting '{}'", file.getPath());
    -  537  0
             FileOutputStream fos = null;
    -  538   +  535  0
             LOGGER.debug("Extracting '{}'", file.getPath());
    +  536  0
             FileOutputStream fos = null;
    +  537  
             try {
    -  539  0
                 final File parent = file.getParentFile();
    -  540  0
                 if (!parent.isDirectory() && !parent.mkdirs()) {
    -  541  0
                     final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
    -  542  0
                     throw new AnalysisException(msg);
    -  543   +  538  0
                 final File parent = file.getParentFile();
    +  539  0
                 if (!parent.isDirectory() && !parent.mkdirs()) {
    +  540  0
                     final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
    +  541  0
                     throw new AnalysisException(msg);
    +  542  
                 }
    -  544  0
                 fos = new FileOutputStream(file);
    -  545  0
                 IOUtils.copy(input, fos);
    -  546  0
             } catch (FileNotFoundException ex) {
    -  547  0
                 LOGGER.debug("", ex);
    -  548  0
                 final String msg = String.format("Unable to find file '%s'.", file.getName());
    -  549  0
                 throw new AnalysisException(msg, ex);
    -  550  0
             } catch (IOException ex) {
    -  551  0
                 LOGGER.debug("", ex);
    -  552  0
                 final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
    -  553  0
                 throw new AnalysisException(msg, ex);
    -  554   +  543  0
                 fos = new FileOutputStream(file);
    +  544  0
                 IOUtils.copy(input, fos);
    +  545  0
             } catch (FileNotFoundException ex) {
    +  546  0
                 LOGGER.debug("", ex);
    +  547  0
                 final String msg = String.format("Unable to find file '%s'.", file.getName());
    +  548  0
                 throw new AnalysisException(msg, ex);
    +  549  0
             } catch (IOException ex) {
    +  550  0
                 LOGGER.debug("", ex);
    +  551  0
                 final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
    +  552  0
                 throw new AnalysisException(msg, ex);
    +  553  
             } finally {
    -  555  0
                 close(fos);
    -  556  0
             }
    -  557  0
         }
    +  554  0
                 FileUtils.close(fos);
    +  555  0
             }
    +  556  0
         }
    +  557   +
     
     558   -
     
    +
         /**
     559   -
         /**
    -  560  
          * Decompresses a file.
    +  560   +
          *
     561   -
          *
    -  562  
          * @param inputStream the compressed file
    -  563   +  562  
          * @param outputFile the location to write the decompressed file
    -  564   +  563  
          * @throws ArchiveExtractionException thrown if there is an exception
    -  565   +  564  
          * decompressing the file
    +  565   +
          */
     566   -
          */
    -  567  
         private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
    -  568  0
             LOGGER.debug("Decompressing '{}'", outputFile.getPath());
    -  569  0
             FileOutputStream out = null;
    -  570   +  567  0
             LOGGER.debug("Decompressing '{}'", outputFile.getPath());
    +  568  0
             FileOutputStream out = null;
    +  569  
             try {
    -  571  0
                 out = new FileOutputStream(outputFile);
    -  572  0
                 IOUtils.copy(inputStream, out);
    -  573  0
             } catch (FileNotFoundException ex) {
    -  574  0
                 LOGGER.debug("", ex);
    -  575  0
                 throw new ArchiveExtractionException(ex);
    -  576  0
             } catch (IOException ex) {
    -  577  0
                 LOGGER.debug("", ex);
    -  578  0
                 throw new ArchiveExtractionException(ex);
    -  579   +  570  0
                 out = new FileOutputStream(outputFile);
    +  571  0
                 IOUtils.copy(inputStream, out);
    +  572  0
             } catch (FileNotFoundException ex) {
    +  573  0
                 LOGGER.debug("", ex);
    +  574  0
                 throw new ArchiveExtractionException(ex);
    +  575  0
             } catch (IOException ex) {
    +  576  0
                 LOGGER.debug("", ex);
    +  577  0
                 throw new ArchiveExtractionException(ex);
    +  578  
             } finally {
    -  580  0
                 close(out);
    -  581  0
             }
    -  582  0
         }
    +  579  0
                 FileUtils.close(out);
    +  580  0
             }
    +  581  0
         }
    +  582   +
     
     583   -
     
    +
         /**
     584   -
         /**
    -  585   -
          * Close the given {@link Closeable} instance, ignoring nulls, and logging
    -  586   -
          * any thrown {@link IOException}.
    -  587   -
          *
    -  588   -
          * @param closeable to be closed
    -  589   -
          */
    -  590   -
         private static void close(Closeable closeable) {
    -  591  14
             if (null != closeable) {
    -  592   -
                 try {
    -  593  8
                     closeable.close();
    -  594  0
                 } catch (IOException ex) {
    -  595  0
                     LOGGER.trace("", ex);
    -  596  8
                 }
    -  597   -
             }
    -  598  14
         }
    -  599   -
     
    -  600   -
         /**
    -  601  
          * Attempts to determine if a zip file is actually a JAR file.
    -  602   +  585  
          *
    -  603   +  586  
          * @param dependency the dependency to check
    -  604   +  587  
          * @return true if the dependency appears to be a JAR file; otherwise false
    -  605   +  588  
          */
    -  606   +  589  
         private boolean isZipFileActuallyJarFile(Dependency dependency) {
    -  607  0
             boolean isJar = false;
    -  608  0
             ZipFile zip = null;
    -  609   +  590  0
             boolean isJar = false;
    +  591  0
             ZipFile zip = null;
    +  592  
             try {
    -  610  0
                 zip = new ZipFile(dependency.getActualFilePath());
    -  611  0
                 if (zip.getEntry("META-INF/MANIFEST.MF") != null
    -  612  0
                         || zip.getEntry("META-INF/maven") != null) {
    -  613  0
                     final Enumeration<ZipArchiveEntry> entries = zip.getEntries();
    -  614  0
                     while (entries.hasMoreElements()) {
    -  615  0
                         final ZipArchiveEntry entry = entries.nextElement();
    -  616  0
                         if (!entry.isDirectory()) {
    -  617  0
                             final String name = entry.getName().toLowerCase();
    -  618  0
                             if (name.endsWith(".class")) {
    -  619  0
                                 isJar = true;
    -  620  0
                                 break;
    -  621   +  593  0
                 zip = new ZipFile(dependency.getActualFilePath());
    +  594  0
                 if (zip.getEntry("META-INF/MANIFEST.MF") != null
    +  595  0
                         || zip.getEntry("META-INF/maven") != null) {
    +  596  0
                     final Enumeration<ZipArchiveEntry> entries = zip.getEntries();
    +  597  0
                     while (entries.hasMoreElements()) {
    +  598  0
                         final ZipArchiveEntry entry = entries.nextElement();
    +  599  0
                         if (!entry.isDirectory()) {
    +  600  0
                             final String name = entry.getName().toLowerCase();
    +  601  0
                             if (name.endsWith(".class")) {
    +  602  0
                                 isJar = true;
    +  603  0
                                 break;
    +  604  
                             }
    -  622   +  605  
                         }
    -  623  0
                     }
    -  624   +  606  0
                     }
    +  607  
                 }
    -  625  0
             } catch (IOException ex) {
    -  626  0
                 LOGGER.debug("Unable to unzip zip file '{}'", dependency.getFilePath(), ex);
    -  627   +  608  0
             } catch (IOException ex) {
    +  609  0
                 LOGGER.debug("Unable to unzip zip file '{}'", dependency.getFilePath(), ex);
    +  610  
             } finally {
    -  628  0
                 ZipFile.closeQuietly(zip);
    -  629  0
             }
    -  630   +  611  0
                 ZipFile.closeQuietly(zip);
    +  612  0
             }
    +  613  
     
    -  631  0
             return isJar;
    -  632   +  614  0
             return isJar;
    +  615  
         }
    -  633   +  616  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AssemblyAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AssemblyAnalyzer.html index 6985e708f..c113127a4 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AssemblyAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AssemblyAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    AssemblyAnalyzer
    32%
    48/148
    21%
    10/46
    7
    AssemblyAnalyzer
    30%
    45/148
    19%
    9/46
    7
     
    @@ -96,23 +96,23 @@  39  
     import javax.xml.parsers.DocumentBuilder;
     40   -
     import javax.xml.parsers.DocumentBuilderFactory;
    -  41  
     import javax.xml.xpath.XPath;
    -  42   +  41  
     import javax.xml.xpath.XPathExpressionException;
    -  43   +  42  
     import javax.xml.xpath.XPathFactory;
    -  44   +  43  
     import java.util.ArrayList;
    -  45   +  44  
     import java.util.List;
    -  46   +  45  
     import javax.xml.parsers.ParserConfigurationException;
    -  47   +  46  
     import org.owasp.dependencycheck.exception.InitializationException;
    -  48   +  47  
     import org.apache.commons.lang3.SystemUtils;
    +  48   +
     import org.owasp.dependencycheck.utils.XmlUtils;
     49  
     
     50   @@ -220,7 +220,7 @@  108  
         @Override
     109   -
         public void analyzeFileType(Dependency dependency, Engine engine)
    +
         public void analyzeDependency(Dependency dependency, Engine engine)
     110  
                 throws AnalysisException {
     111  0
             if (grokAssemblyExe == null) {
    @@ -242,9 +242,9 @@  124  
             try {
     125  0
                 final Process proc = pb.start();
    -  126   +  126  0
                 final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder();
    +  127  
     
    -  127  0
                 final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
     128  0
                 doc = builder.parse(proc.getInputStream());
     129  
     
    @@ -318,293 +318,297 @@  178  0
             } catch (IOException ioe) {
     179  0
                 throw new AnalysisException(ioe);
     180  0
             } catch (SAXException saxe) {
    -  181  0
                 throw new AnalysisException("Couldn't parse GrokAssembly result", saxe);
    -  182  0
             } catch (XPathExpressionException xpe) {
    +  181  0
                 LOGGER.error("----------------------------------------------------");
    +  182  0
                 LOGGER.error("Failed to read the Assembly Analyzer results. "
     183   -
                 // This shouldn't happen
    -  184  0
                 throw new AnalysisException(xpe);
    -  185  0
             }
    -  186  0
         }
    +
                         + "On some systems mono-runtime and mono-devel need to be installed.");
    +  184  0
                 LOGGER.error("----------------------------------------------------");
    +  185  0
                 throw new AnalysisException("Couldn't parse Assembly Analzyzer results (GrokAssembly)", saxe);
    +  186  0
             } catch (XPathExpressionException xpe) {
     187   -
     
    -  188   -
         /**
    -  189   -
          * Initialize the analyzer. In this case, extract GrokAssembly.exe to a
    -  190   -
          * temporary location.
    +
                 // This shouldn't happen
    +  188  0
                 throw new AnalysisException(xpe);
    +  189  0
             }
    +  190  0
         }
     191   -
          *
    +
     
     192   -
          * @throws InitializationException thrown if anything goes wrong
    +
         /**
     193   -
          */
    +
          * Initialize the analyzer. In this case, extract GrokAssembly.exe to a
     194   -
         @Override
    +
          * temporary location.
     195   -
         public void initializeFileTypeAnalyzer() throws InitializationException {
    +
          *
     196   -
             final File tempFile;
    +
          * @throws InitializationException thrown if anything goes wrong
     197   +
          */
    +  198   +
         @Override
    +  199   +
         public void initializeFileTypeAnalyzer() throws InitializationException {
    +  200   +
             final File tempFile;
    +  201  
             try {
    -  198  5
                 tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
    -  199  0
             } catch (IOException ex) {
    -  200  0
                 setEnabled(false);
    -  201  0
                 throw new InitializationException("Unable to create temporary file for the assembly analyzerr", ex);
    -  202  5
             }
    -  203  5
             FileOutputStream fos = null;
    -  204  5
             InputStream is = null;
    -  205   -
             try {
    -  206  5
                 fos = new FileOutputStream(tempFile);
    -  207  5
                 is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
    -  208  5
                 IOUtils.copy(is, fos);
    +  202  5
                 tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
    +  203  0
             } catch (IOException ex) {
    +  204  0
                 setEnabled(false);
    +  205  0
                 throw new InitializationException("Unable to create temporary file for the assembly analyzerr", ex);
    +  206  5
             }
    +  207  5
             FileOutputStream fos = null;
    +  208  5
             InputStream is = null;
     209   +
             try {
    +  210  5
                 fos = new FileOutputStream(tempFile);
    +  211  5
                 is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
    +  212  5
                 IOUtils.copy(is, fos);
    +  213  
     
    -  210  5
                 grokAssemblyExe = tempFile;
    -  211  5
                 LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
    -  212  0
             } catch (IOException ioe) {
    -  213  0
                 this.setEnabled(false);
    -  214  0
                 LOGGER.warn("Could not extract GrokAssembly.exe: {}", ioe.getMessage());
    -  215  0
                 throw new InitializationException("Could not extract GrokAssembly.exe", ioe);
    -  216   +  214  5
                 grokAssemblyExe = tempFile;
    +  215  5
                 LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
    +  216  0
             } catch (IOException ioe) {
    +  217  0
                 this.setEnabled(false);
    +  218  0
                 LOGGER.warn("Could not extract GrokAssembly.exe: {}", ioe.getMessage());
    +  219  0
                 throw new InitializationException("Could not extract GrokAssembly.exe", ioe);
    +  220  
             } finally {
    -  217  5
                 if (fos != null) {
    -  218   +  221  5
                 if (fos != null) {
    +  222  
                     try {
    -  219  5
                         fos.close();
    -  220  0
                     } catch (Throwable e) {
    -  221  0
                         LOGGER.debug("Error closing output stream");
    -  222  5
                     }
    -  223   +  223  5
                         fos.close();
    +  224  0
                     } catch (Throwable e) {
    +  225  0
                         LOGGER.debug("Error closing output stream");
    +  226  5
                     }
    +  227  
                 }
    -  224  5
                 if (is != null) {
    -  225   +  228  5
                 if (is != null) {
    +  229  
                     try {
    -  226  5
                         is.close();
    -  227  0
                     } catch (Throwable e) {
    -  228  0
                         LOGGER.debug("Error closing input stream");
    -  229  5
                     }
    -  230   +  230  5
                         is.close();
    +  231  0
                     } catch (Throwable e) {
    +  232  0
                         LOGGER.debug("Error closing input stream");
    +  233  5
                     }
    +  234  
                 }
    -  231   -
             }
    -  232   -
     
    -  233   -
             // Now, need to see if GrokAssembly actually runs from this location.
    -  234  5
             final List<String> args = buildArgumentList();
     235   -
             //TODO this creates an "unreported" error - if someone doesn't look
    -  236   -
             // at the command output this could easily be missed (especially in an
    -  237   -
             // Ant or Maven build.
    -  238   -
             //
    -  239   -
             // We need to create a non-fatal warning error type that will
    -  240   -
             // get added to the report.
    -  241   -
             //TOOD this idea needs to get replicated to the bundle audit analyzer.
    -  242  5
             if (args == null) {
    -  243  0
                 setEnabled(false);
    -  244  0
                 LOGGER.error("----------------------------------------------------");
    -  245  0
                 LOGGER.error(".NET Assembly Analyzer could not be initialized and at least one "
    -  246   -
                         + "'exe' or 'dll' was scanned. The 'mono' executable could not be found on "
    -  247   -
                         + "the path; either disable the Assembly Analyzer or configure the path mono.");
    -  248  0
                 LOGGER.error("----------------------------------------------------");
    -  249  0
                 return;
    -  250  
             }
    +  236   +
     
    +  237   +
             // Now, need to see if GrokAssembly actually runs from this location.
    +  238  5
             final List<String> args = buildArgumentList();
    +  239   +
             //TODO this creates an "unreported" error - if someone doesn't look
    +  240   +
             // at the command output this could easily be missed (especially in an
    +  241   +
             // Ant or Maven build.
    +  242   +
             //
    +  243   +
             // We need to create a non-fatal warning error type that will
    +  244   +
             // get added to the report.
    +  245   +
             //TOOD this idea needs to get replicated to the bundle audit analyzer.
    +  246  5
             if (args == null) {
    +  247  0
                 setEnabled(false);
    +  248  0
                 LOGGER.error("----------------------------------------------------");
    +  249  0
                 LOGGER.error(".NET Assembly Analyzer could not be initialized and at least one "
    +  250   +
                         + "'exe' or 'dll' was scanned. The 'mono' executable could not be found on "
     251   -
             try {
    -  252  5
                 final ProcessBuilder pb = new ProcessBuilder(args);
    -  253  5
                 final Process p = pb.start();
    -  254   -
                 // Try evacuating the error stream
    -  255  5
                 IOUtils.copy(p.getErrorStream(), NullOutputStream.NULL_OUTPUT_STREAM);
    +
                         + "the path; either disable the Assembly Analyzer or configure the path mono. "
    +  252   +
                         + "On some systems mono-runtime and mono-devel need to be installed.");
    +  253  0
                 LOGGER.error("----------------------------------------------------");
    +  254  0
                 return;
    +  255   +
             }
     256   +
             try {
    +  257  5
                 final ProcessBuilder pb = new ProcessBuilder(args);
    +  258  5
                 final Process p = pb.start();
    +  259   +
                 // Try evacuating the error stream
    +  260  5
                 IOUtils.copy(p.getErrorStream(), NullOutputStream.NULL_OUTPUT_STREAM);
    +  261  
     
    -  257  5
                 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    -  258  5
                 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  259  5
                 final DocumentBuilder builder = factory.newDocumentBuilder();
    -  260  5
                 final Document doc = builder.parse(p.getInputStream());
    -  261  5
                 final XPath xpath = XPathFactory.newInstance().newXPath();
    -  262  5
                 final String error = xpath.evaluate("/assembly/error", doc);
    -  263  5
                 if (p.waitFor() != 1 || error == null || error.isEmpty()) {
    -  264  0
                     LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
    -  265  0
                     LOGGER.debug("GrokAssembly.exe is not working properly");
    -  266  0
                     grokAssemblyExe = null;
    -  267  0
                     setEnabled(false);
    -  268  0
                     throw new InitializationException("Could not execute .NET AssemblyAnalyzer");
    -  269   +  262  5
                 final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder();
    +  263  5
                 final Document doc = builder.parse(p.getInputStream());
    +  264  5
                 final XPath xpath = XPathFactory.newInstance().newXPath();
    +  265  5
                 final String error = xpath.evaluate("/assembly/error", doc);
    +  266  5
                 if (p.waitFor() != 1 || error == null || error.isEmpty()) {
    +  267  0
                     LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
    +  268  0
                     LOGGER.debug("GrokAssembly.exe is not working properly");
    +  269  0
                     grokAssemblyExe = null;
    +  270  0
                     setEnabled(false);
    +  271  0
                     throw new InitializationException("Could not execute .NET AssemblyAnalyzer");
    +  272  
                 }
    -  270  0
             } catch (InitializationException e) {
    -  271  0
                 setEnabled(false);
    -  272  0
                 throw e;
    -  273  0
             } catch (Throwable e) {
    -  274  0
                 LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n"
    -  275   +  273  0
             } catch (InitializationException e) {
    +  274  0
                 setEnabled(false);
    +  275  0
                 throw e;
    +  276  0
             } catch (Throwable e) {
    +  277  0
                 LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n"
    +  278  
                         + "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.");
    -  276  0
                 LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage());
    -  277  0
                 setEnabled(false);
    -  278  0
                 throw new InitializationException("An error occurred with the .NET AssemblyAnalyzer", e);
    -  279  5
             }
    -  280  5
         }
    -  281   -
     
    -  282   -
         /**
    -  283   -
          * Removes resources used from the local file system.
    +  279  0
                 LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage());
    +  280  0
                 setEnabled(false);
    +  281  0
                 throw new InitializationException("An error occurred with the .NET AssemblyAnalyzer", e);
    +  282  5
             }
    +  283  5
         }
     284   -
          *
    +
     
     285   -
          * @throws Exception thrown if there is a problem closing the analyzer
    +
         /**
     286   -
          */
    +
          * Removes resources used from the local file system.
     287   -
         @Override
    +
          *
     288   -
         public void close() throws Exception {
    -  289  7
             super.close();
    +
          * @throws Exception thrown if there is a problem closing the analyzer
    +  289   +
          */
     290   +
         @Override
    +  291   +
         public void closeAnalyzer() throws Exception {
    +  292  
             try {
    -  291  7
                 if (grokAssemblyExe != null && !grokAssemblyExe.delete()) {
    -  292  0
                     LOGGER.debug("Unable to delete temporary GrokAssembly.exe; attempting delete on exit");
    -  293  0
                     grokAssemblyExe.deleteOnExit();
    -  294   +  293  5
                 if (grokAssemblyExe != null && !grokAssemblyExe.delete()) {
    +  294  0
                     LOGGER.debug("Unable to delete temporary GrokAssembly.exe; attempting delete on exit");
    +  295  0
                     grokAssemblyExe.deleteOnExit();
    +  296  
                 }
    -  295  0
             } catch (SecurityException se) {
    -  296  0
                 LOGGER.debug("Can't delete temporary GrokAssembly.exe");
    -  297  0
                 grokAssemblyExe.deleteOnExit();
    -  298  7
             }
    -  299  7
         }
    -  300   -
     
    -  301   -
         /**
    +  297  0
             } catch (SecurityException se) {
    +  298  0
                 LOGGER.debug("Can't delete temporary GrokAssembly.exe");
    +  299  0
                 grokAssemblyExe.deleteOnExit();
    +  300  5
             }
    +  301  5
         }
     302   -
          * The File Filter used to filter supported extensions.
    +
     
     303   +
         /**
    +  304   +
          * The File Filter used to filter supported extensions.
    +  305  
          */
    -  304  2
         private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
    -  305  1
                 SUPPORTED_EXTENSIONS).build();
    -  306   -
     
    -  307   -
         @Override
    +  306  2
         private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
    +  307  1
                 SUPPORTED_EXTENSIONS).build();
     308   -
         protected FileFilter getFileFilter() {
    -  309  867
             return FILTER;
    +
     
    +  309   +
         @Override
     310   -
         }
    -  311   -
     
    +
         protected FileFilter getFileFilter() {
    +  311  863
             return FILTER;
     312   -
         /**
    +
         }
     313   -
          * Gets this analyzer's name.
    +
     
     314   -
          *
    +
         /**
     315   -
          * @return the analyzer name
    +
          * Gets this analyzer's name.
     316   -
          */
    +
          *
     317   -
         @Override
    +
          * @return the analyzer name
     318   -
         public String getName() {
    -  319  22
             return ANALYZER_NAME;
    +
          */
    +  319   +
         @Override
     320   -
         }
    -  321   -
     
    +
         public String getName() {
    +  321  18
             return ANALYZER_NAME;
     322   -
         /**
    +
         }
     323   -
          * Returns the phase this analyzer runs under.
    +
     
     324   -
          *
    +
         /**
     325   -
          * @return the phase this runs under
    +
          * Returns the phase this analyzer runs under.
     326   -
          */
    +
          *
     327   -
         @Override
    +
          * @return the phase this runs under
     328   -
         public AnalysisPhase getAnalysisPhase() {
    -  329  6
             return ANALYSIS_PHASE;
    -  330   -
         }
    -  331   -
     
    -  332   -
         /**
    -  333   -
          * Returns the key used in the properties file to reference the analyzer's
    -  334   -
          * enabled property.
    -  335   -
          *
    -  336   -
          * @return the analyzer's enabled property setting key
    -  337  
          */
    -  338   +  329  
         @Override
    -  339   -
         protected String getAnalyzerEnabledSettingKey() {
    -  340  13
             return Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED;
    -  341   +  330   +
         public AnalysisPhase getAnalysisPhase() {
    +  331  6
             return ANALYSIS_PHASE;
    +  332  
         }
    -  342   +  333  
     
    -  343   +  334  
         /**
    -  344   -
          * Tests to see if a file is in the system path. <b>Note</b> - the current
    -  345   -
          * implementation only works on non-windows platforms. For purposes of the
    -  346   -
          * AssemblyAnalyzer this is okay as this is only needed on Mac/*nix.
    -  347   +  335   +
          * Returns the key used in the properties file to reference the analyzer's
    +  336   +
          * enabled property.
    +  337  
          *
    -  348   -
          * @param file the executable to look for
    -  349   -
          * @return <code>true</code> if the file exists; otherwise
    -  350   -
          * <code>false</code>
    -  351   +  338   +
          * @return the analyzer's enabled property setting key
    +  339  
          */
    -  352   -
         private boolean isInPath(String file) {
    -  353  0
             final ProcessBuilder pb = new ProcessBuilder("which", file);
    -  354   -
             try {
    -  355  0
                 final Process proc = pb.start();
    -  356  0
                 final int retCode = proc.waitFor();
    -  357  0
                 if (retCode == 0) {
    -  358  0
                     return true;
    -  359   -
                 }
    -  360  0
             } catch (IOException ex) {
    -  361  0
                 LOGGER.debug("Path seach failed for " + file);
    -  362  0
             } catch (InterruptedException ex) {
    -  363  0
                 LOGGER.debug("Path seach failed for " + file);
    -  364  0
             }
    -  365  0
             return false;
    -  366   +  340   +
         @Override
    +  341   +
         protected String getAnalyzerEnabledSettingKey() {
    +  342  7
             return Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED;
    +  343  
         }
    -  367   +  344   +
     
    +  345   +
         /**
    +  346   +
          * Tests to see if a file is in the system path. <b>Note</b> - the current
    +  347   +
          * implementation only works on non-windows platforms. For purposes of the
    +  348   +
          * AssemblyAnalyzer this is okay as this is only needed on Mac/*nix.
    +  349   +
          *
    +  350   +
          * @param file the executable to look for
    +  351   +
          * @return <code>true</code> if the file exists; otherwise
    +  352   +
          * <code>false</code>
    +  353   +
          */
    +  354   +
         private boolean isInPath(String file) {
    +  355  0
             final ProcessBuilder pb = new ProcessBuilder("which", file);
    +  356   +
             try {
    +  357  0
                 final Process proc = pb.start();
    +  358  0
                 final int retCode = proc.waitFor();
    +  359  0
                 if (retCode == 0) {
    +  360  0
                     return true;
    +  361   +
                 }
    +  362  0
             } catch (IOException ex) {
    +  363  0
                 LOGGER.debug("Path seach failed for " + file);
    +  364  0
             } catch (InterruptedException ex) {
    +  365  0
                 LOGGER.debug("Path seach failed for " + file);
    +  366  0
             }
    +  367  0
             return false;
    +  368   +
         }
    +  369  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AutoconfAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AutoconfAnalyzer.html index 330847119..a5b53a896 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AutoconfAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.AutoconfAnalyzer.html @@ -250,7 +250,7 @@
         @Override
     121  
         protected FileFilter getFileFilter() {
    -  122  865
             return FILTER;
    +  122  861
             return FILTER;
     123  
         }
     124   @@ -269,7 +269,7 @@
         @Override
     131  
         public String getName() {
    -  132  21
             return ANALYZER_NAME;
    +  132  17
             return ANALYZER_NAME;
     133  
         }
     134   @@ -309,7 +309,7 @@
         @Override
     152  
         protected String getAnalyzerEnabledSettingKey() {
    -  153  14
             return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
    +  153  8
             return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
     154  
         }
     155   @@ -317,7 +317,7 @@  156  
         @Override
     157   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     158  
                 throws AnalysisException {
     159  4
             final File actualFile = dependency.getActualFile();
    @@ -507,6 +507,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CMakeAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CMakeAnalyzer.html index d76b99c63..958fbb10e 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CMakeAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CMakeAnalyzer.html @@ -212,7 +212,7 @@
         @Override
     101  
         public String getName() {
    -  102  21
             return "CMake Analyzer";
    +  102  17
             return "CMake Analyzer";
     103  
         }
     104   @@ -250,7 +250,7 @@
         @Override
     121  
         protected FileFilter getFileFilter() {
    -  122  864
             return FILTER;
    +  122  860
             return FILTER;
     123  
         }
     124   @@ -300,7 +300,7 @@  149  
         @Override
     150   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     151  
                 throws AnalysisException {
     152  3
             final File file = dependency.getActualFile();
    @@ -423,7 +423,7 @@
         @Override
     238  
         protected String getAnalyzerEnabledSettingKey() {
    -  239  15
             return Settings.KEYS.ANALYZER_CMAKE_ENABLED;
    +  239  9
             return Settings.KEYS.ANALYZER_CMAKE_ENABLED;
     240  
         }
     241   @@ -454,6 +454,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CPEAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CPEAnalyzer.html index a7966a866..268f6a37c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CPEAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CPEAnalyzer.html @@ -12,9 +12,9 @@
     
    - - - + + +
    Classes in this File Line Coverage Branch Coverage Complexity
    CPEAnalyzer
    80%
    191/238
    76%
    102/134
    4.679
    CPEAnalyzer$IdentifierConfidence
    100%
    4/4
    N/A
    4.679
    CPEAnalyzer$IdentifierMatch
    36%
    14/38
    0%
    0/20
    4.679
    CPEAnalyzer
    80%
    193/240
    76%
    102/134
    4.433
    CPEAnalyzer$IdentifierConfidence
    100%
    4/4
    N/A
    4.433
    CPEAnalyzer$IdentifierMatch
    36%
    14/38
    0%
    0/20
    4.433
     
    @@ -124,1269 +124,1285 @@  52  
     import org.owasp.dependencycheck.utils.DependencyVersionUtil;
     53   -
     import org.slf4j.Logger;
    +
     import org.owasp.dependencycheck.utils.Settings;
     54   -
     import org.slf4j.LoggerFactory;
    +
     import org.slf4j.Logger;
     55   -
     
    +
     import org.slf4j.LoggerFactory;
     56   -
     /**
    +
     
     57   -
      * CPEAnalyzer is a utility class that takes a project dependency and attempts
    +
     /**
     58   -
      * to discern if there is an associated CPE. It uses the evidence contained
    +
      * CPEAnalyzer is a utility class that takes a project dependency and attempts
     59   -
      * within the dependency to search the Lucene index.
    +
      * to discern if there is an associated CPE. It uses the evidence contained
     60   -
      *
    +
      * within the dependency to search the Lucene index.
     61   -
      * @author Jeremy Long
    +
      *
     62   +
      * @author Jeremy Long
    +  63  
      */
    -  63  8
     public class CPEAnalyzer extends AbstractAnalyzer {
    -  64   -
     
    +  64  8
     public class CPEAnalyzer extends AbstractAnalyzer {
     65   -
         /**
    +
     
     66   -
          * The Logger.
    +
         /**
     67   +
          * The Logger.
    +  68  
          */
    -  68  1
         private static final Logger LOGGER = LoggerFactory.getLogger(CPEAnalyzer.class);
    -  69   -
         /**
    +  69  1
         private static final Logger LOGGER = LoggerFactory.getLogger(CPEAnalyzer.class);
     70   -
          * The maximum number of query results to return.
    +
         /**
     71   -
          */
    +
          * The maximum number of query results to return.
     72   -
         static final int MAX_QUERY_RESULTS = 25;
    +
          */
     73   -
         /**
    +
         static final int MAX_QUERY_RESULTS = 25;
     74   -
          * The weighting boost to give terms when constructing the Lucene query.
    +
         /**
     75   -
          */
    +
          * The weighting boost to give terms when constructing the Lucene query.
     76   -
         static final String WEIGHTING_BOOST = "^5";
    +
          */
     77   -
         /**
    +
         static final String WEIGHTING_BOOST = "^5";
     78   -
          * A string representation of a regular expression defining characters
    +
         /**
     79   -
          * utilized within the CPE Names.
    +
          * A string representation of a regular expression defining characters
     80   -
          */
    +
          * utilized within the CPE Names.
     81   -
         static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 ._-]";
    +
          */
     82   -
         /**
    +
         static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 ._-]";
     83   -
          * A string representation of a regular expression used to remove all but
    +
         /**
     84   -
          * alpha characters.
    +
          * A string representation of a regular expression used to remove all but
     85   -
          */
    +
          * alpha characters.
     86   -
         static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
    +
          */
     87   -
         /**
    +
         static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
     88   -
          * The additional size to add to a new StringBuilder to account for extra
    +
         /**
     89   -
          * data that will be written into the string.
    +
          * The additional size to add to a new StringBuilder to account for extra
     90   -
          */
    +
          * data that will be written into the string.
     91   -
         static final int STRING_BUILDER_BUFFER = 20;
    +
          */
     92   -
         /**
    +
         static final int STRING_BUILDER_BUFFER = 20;
     93   -
          * The CPE in memory index.
    +
         /**
     94   -
          */
    +
          * The CPE in memory index.
     95   -
         private CpeMemoryIndex cpe;
    +
          */
     96   -
         /**
    +
         private CpeMemoryIndex cpe;
     97   -
          * The CVE Database.
    +
         /**
     98   -
          */
    +
          * The CVE Database.
     99   -
         private CveDB cve;
    +
          */
     100   -
     
    +
         private CveDB cve;
     101   -
         /**
    +
     
     102   -
          * The URL to perform a search of the NVD CVE data at NIST.
    +
         /**
     103   -
          */
    +
          * The URL to perform a search of the NVD CVE data at NIST.
     104   -
         public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
    +
          */
     105   -
     
    +
         public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
     106   -
         /**
    +
     
     107   -
          * Returns the name of this analyzer.
    -  108   -
          *
    -  109   -
          * @return the name of this analyzer.
    -  110   -
          */
    -  111   -
         @Override
    -  112   -
         public String getName() {
    -  113  26
             return "CPE Analyzer";
    -  114   -
         }
    -  115   -
     
    -  116  
         /**
    -  117   -
          * Returns the analysis phase that this analyzer should run in.
    -  118   +  108   +
          * Returns the name of this analyzer.
    +  109  
          *
    -  119   -
          * @return the analysis phase that this analyzer should run in.
    -  120   +  110   +
          * @return the name of this analyzer.
    +  111  
          */
    -  121   +  112  
         @Override
    -  122   -
         public AnalysisPhase getAnalysisPhase() {
    -  123  6
             return AnalysisPhase.IDENTIFIER_ANALYSIS;
    -  124   +  113   +
         public String getName() {
    +  114  26
             return "CPE Analyzer";
    +  115  
         }
    -  125   +  116  
     
    +  117   +
         /**
    +  118   +
          * Returns the analysis phase that this analyzer should run in.
    +  119   +
          *
    +  120   +
          * @return the analysis phase that this analyzer should run in.
    +  121   +
          */
    +  122   +
         @Override
    +  123   +
         public AnalysisPhase getAnalysisPhase() {
    +  124  6
             return AnalysisPhase.IDENTIFIER_ANALYSIS;
    +  125   +
         }
     126  
         /**
     127   -
          * Creates the CPE Lucene Index.
    +
          * The default is to support parallel processing.
     128   -
          *
    +
          * @return false
     129   -
          * @throws InitializationException is thrown if there is an issue opening
    +
          */
     130   -
          * the index.
    +
         @Override
     131   -
          */
    -  132   -
         @Override
    +
         public boolean supportsParallelProcessing() {
    +  132  2
             return false;
     133   -
         public void initialize() throws InitializationException {
    +
         }
     134   -
             try {
    -  135  2
                 this.open();
    -  136  0
             } catch (IOException ex) {
    -  137  0
                 LOGGER.debug("Exception initializing the Lucene Index", ex);
    -  138  0
                 throw new InitializationException("An exception occurred initializing the Lucene Index", ex);
    -  139  0
             } catch (DatabaseException ex) {
    -  140  0
                 LOGGER.debug("Exception accessing the database", ex);
    -  141  0
                 throw new InitializationException("An exception occurred accessing the database", ex);
    -  142  2
             }
    -  143  2
         }
    -  144   -
     
    -  145  
         /**
    -  146   -
          * Opens the data source.
    -  147   +  135   +
          * Creates the CPE Lucene Index.
    +  136  
          *
    -  148   -
          * @throws IOException when the Lucene directory to be queried does not
    -  149   -
          * exist or is corrupt.
    -  150   -
          * @throws DatabaseException when the database throws an exception. This
    -  151   -
          * usually occurs when the database is in use by another process.
    -  152   +  137   +
          * @throws InitializationException is thrown if there is an issue opening
    +  138   +
          * the index.
    +  139  
          */
    -  153   -
         public void open() throws IOException, DatabaseException {
    -  154  2
             if (!isOpen()) {
    -  155  2
                 cve = new CveDB();
    -  156  2
                 cve.open();
    -  157  2
                 cpe = CpeMemoryIndex.getInstance();
    -  158   -
                 try {
    -  159  2
                     final long creationStart = System.currentTimeMillis();
    -  160  2
                     cpe.open(cve);
    -  161  2
                     final long creationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - creationStart);
    -  162  2
                     LOGGER.info("Created CPE Index ({} seconds)", creationSeconds);
    -  163  0
                 } catch (IndexException ex) {
    -  164  0
                     LOGGER.debug("IndexException", ex);
    -  165  0
                     throw new DatabaseException(ex);
    -  166  2
                 }
    -  167   -
             }
    -  168  2
         }
    -  169   -
     
    -  170   -
         /**
    -  171   -
          * Closes the data sources.
    -  172   -
          */
    -  173   +  140  
         @Override
    -  174   -
         public void close() {
    -  175  2
             if (cpe != null) {
    -  176  2
                 cpe.close();
    -  177  2
                 cpe = null;
    -  178   -
             }
    -  179  2
             if (cve != null) {
    -  180  2
                 cve.close();
    -  181  2
                 cve = null;
    -  182   -
             }
    -  183  2
         }
    -  184   -
     
    -  185   -
         public boolean isOpen() {
    -  186  2
             return cpe != null && cpe.isOpen();
    -  187   -
         }
    -  188   -
     
    -  189   -
         /**
    -  190   -
          * Searches the data store of CPE entries, trying to identify the CPE for
    -  191   -
          * the given dependency based on the evidence contained within. The
    -  192   -
          * dependency passed in is updated with any identified CPE values.
    -  193   -
          *
    -  194   -
          * @param dependency the dependency to search for CPE entries on.
    -  195   -
          * @throws CorruptIndexException is thrown when the Lucene index is corrupt.
    -  196   -
          * @throws IOException is thrown when an IOException occurs.
    -  197   -
          * @throws ParseException is thrown when the Lucene query cannot be parsed.
    -  198   -
          */
    -  199   -
         protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
    -  200   -
             //TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
    -  201  4
             String vendors = "";
    -  202  4
             String products = "";
    -  203  17
             for (Confidence confidence : Confidence.values()) {
    -  204  14
                 if (dependency.getVendorEvidence().contains(confidence)) {
    -  205  9
                     vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
    -  206  9
                     LOGGER.debug("vendor search: {}", vendors);
    -  207   -
                 }
    -  208  14
                 if (dependency.getProductEvidence().contains(confidence)) {
    -  209  8
                     products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
    -  210  8
                     LOGGER.debug("product search: {}", products);
    -  211   -
                 }
    -  212  14
                 if (!vendors.isEmpty() && !products.isEmpty()) {
    -  213  22
                     final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getVendorEvidence().getWeighting(),
    -  214  11
                             dependency.getProductEvidence().getWeighting());
    -  215  11
                     if (entries == null) {
    -  216  0
                         continue;
    -  217   -
                     }
    -  218  11
                     boolean identifierAdded = false;
    -  219  11
                     for (IndexEntry e : entries) {
    -  220  20
                         LOGGER.debug("Verifying entry: {}", e);
    -  221  20
                         if (verifyEntry(e, dependency)) {
    -  222  4
                             final String vendor = e.getVendor();
    -  223  4
                             final String product = e.getProduct();
    -  224  4
                             LOGGER.debug("identified vendor/product: {}/{}", vendor, product);
    -  225  4
                             identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
    -  226   -
                         }
    -  227  20
                     }
    -  228  11
                     if (identifierAdded) {
    -  229  1
                         break;
    -  230   -
                     }
    -  231   -
                 }
    -  232   -
             }
    -  233  4
         }
    -  234   -
     
    -  235   -
         /**
    -  236   -
          * Returns the text created by concatenating the text and the values from
    -  237   -
          * the EvidenceCollection (filtered for a specific confidence). This
    -  238   -
          * attempts to prevent duplicate terms from being added.<br/<br/> Note, if
    -  239   -
          * the evidence is longer then 200 characters it will be truncated.
    -  240   -
          *
    -  241   -
          * @param text the base text.
    -  242   -
          * @param ec an EvidenceCollection
    -  243   -
          * @param confidenceFilter a Confidence level to filter the evidence by.
    -  244   -
          * @return the new evidence text
    -  245   -
          */
    -  246   -
         private String addEvidenceWithoutDuplicateTerms(final String text, final EvidenceCollection ec, Confidence confidenceFilter) {
    -  247  17
             final String txt = (text == null) ? "" : text;
    -  248  17
             final StringBuilder sb = new StringBuilder(txt.length() + (20 * ec.size()));
    -  249  17
             sb.append(' ').append(txt).append(' ');
    -  250  17
             for (Evidence e : ec.iterator(confidenceFilter)) {
    -  251  36
                 String value = e.getValue();
    -  252   -
     
    -  253   -
                 //hack to get around the fact that lucene does a really good job of recognizing domains and not
    -  254   -
                 // splitting them. TODO - put together a better lucene analyzer specific to the domain.
    -  255  36
                 if (value.startsWith("http://")) {
    -  256  2
                     value = value.substring(7).replaceAll("\\.", " ");
    -  257   -
                 }
    -  258  36
                 if (value.startsWith("https://")) {
    -  259  1
                     value = value.substring(8).replaceAll("\\.", " ");
    -  260   -
                 }
    -  261  36
                 if (sb.indexOf(" " + value + " ") < 0) {
    -  262  34
                     sb.append(value).append(' ');
    -  263   -
                 }
    -  264  36
             }
    -  265  17
             return sb.toString().trim();
    -  266   -
         }
    -  267   -
     
    -  268   -
         /**
    -  269   -
          * <p>
    -  270   -
          * Searches the Lucene CPE index to identify possible CPE entries associated
    -  271   -
          * with the supplied vendor, product, and version.</p>
    -  272   -
          *
    -  273   -
          * <p>
    -  274   -
          * If either the vendorWeightings or productWeightings lists have been
    -  275   -
          * populated this data is used to add weighting factors to the search.</p>
    -  276   -
          *
    -  277   -
          * @param vendor the text used to search the vendor field
    -  278   -
          * @param product the text used to search the product field
    -  279   -
          * @param vendorWeightings a list of strings to use to add weighting factors
    -  280   -
          * to the vendor field
    -  281   -
          * @param productWeightings Adds a list of strings that will be used to add
    -  282   -
          * weighting factors to the product search
    -  283   -
          * @return a list of possible CPE values
    -  284   -
          */
    -  285   -
         protected List<IndexEntry> searchCPE(String vendor, String product,
    -  286   -
                 Set<String> vendorWeightings, Set<String> productWeightings) {
    -  287   -
     
    -  288  11
             final List<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
    -  289   -
     
    -  290  11
             final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
    -  291  11
             if (searchString == null) {
    -  292  0
                 return ret;
    -  293   -
             }
    -  294   +  141   +
         public void initializeAnalyzer() throws InitializationException {
    +  142  
             try {
    -  295  11
                 final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
    -  296  75
                 for (ScoreDoc d : docs.scoreDocs) {
    -  297  64
                     if (d.score >= 0.08) {
    -  298  20
                         final Document doc = cpe.getDocument(d.doc);
    -  299  20
                         final IndexEntry entry = new IndexEntry();
    -  300  20
                         entry.setVendor(doc.get(Fields.VENDOR));
    -  301  20
                         entry.setProduct(doc.get(Fields.PRODUCT));
    -  302  20
                         entry.setSearchScore(d.score);
    -  303  20
                         if (!ret.contains(entry)) {
    -  304  20
                             ret.add(entry);
    -  305   -
                         }
    -  306   -
                     }
    -  307   +  143  2
                 this.open();
    +  144  0
             } catch (IOException ex) {
    +  145  0
                 LOGGER.debug("Exception initializing the Lucene Index", ex);
    +  146  0
                 throw new InitializationException("An exception occurred initializing the Lucene Index", ex);
    +  147  0
             } catch (DatabaseException ex) {
    +  148  0
                 LOGGER.debug("Exception accessing the database", ex);
    +  149  0
                 throw new InitializationException("An exception occurred accessing the database", ex);
    +  150  2
             }
    +  151  2
         }
    +  152   +
     
    +  153   +
         /**
    +  154   +
          * Opens the data source.
    +  155   +
          *
    +  156   +
          * @throws IOException when the Lucene directory to be queried does not
    +  157   +
          * exist or is corrupt.
    +  158   +
          * @throws DatabaseException when the database throws an exception. This
    +  159   +
          * usually occurs when the database is in use by another process.
    +  160   +
          */
    +  161   +
         public void open() throws IOException, DatabaseException {
    +  162  2
             if (!isOpen()) {
    +  163  2
                 cve = new CveDB();
    +  164  2
                 cve.open();
    +  165  2
                 cpe = CpeMemoryIndex.getInstance();
    +  166   +
                 try {
    +  167  2
                     final long creationStart = System.currentTimeMillis();
    +  168  2
                     cpe.open(cve);
    +  169  2
                     final long creationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - creationStart);
    +  170  2
                     LOGGER.info("Created CPE Index ({} seconds)", creationSeconds);
    +  171  0
                 } catch (IndexException ex) {
    +  172  0
                     LOGGER.debug("IndexException", ex);
    +  173  0
                     throw new DatabaseException(ex);
    +  174  2
                 }
    +  175   +
             }
    +  176  2
         }
    +  177   +
     
    +  178   +
         /**
    +  179   +
          * Closes the data sources.
    +  180   +
          */
    +  181   +
         @Override
    +  182   +
         public void closeAnalyzer() {
    +  183  2
             if (cpe != null) {
    +  184  2
                 cpe.close();
    +  185  2
                 cpe = null;
    +  186   +
             }
    +  187  2
             if (cve != null) {
    +  188  2
                 cve.close();
    +  189  2
                 cve = null;
    +  190   +
             }
    +  191  2
         }
    +  192   +
     
    +  193   +
         public boolean isOpen() {
    +  194  2
             return cpe != null && cpe.isOpen();
    +  195   +
         }
    +  196   +
     
    +  197   +
         /**
    +  198   +
          * Searches the data store of CPE entries, trying to identify the CPE for
    +  199   +
          * the given dependency based on the evidence contained within. The
    +  200   +
          * dependency passed in is updated with any identified CPE values.
    +  201   +
          *
    +  202   +
          * @param dependency the dependency to search for CPE entries on.
    +  203   +
          * @throws CorruptIndexException is thrown when the Lucene index is corrupt.
    +  204   +
          * @throws IOException is thrown when an IOException occurs.
    +  205   +
          * @throws ParseException is thrown when the Lucene query cannot be parsed.
    +  206   +
          */
    +  207   +
         protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
    +  208   +
             //TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
    +  209  4
             String vendors = "";
    +  210  4
             String products = "";
    +  211  17
             for (Confidence confidence : Confidence.values()) {
    +  212  14
                 if (dependency.getVendorEvidence().contains(confidence)) {
    +  213  9
                     vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
    +  214  9
                     LOGGER.debug("vendor search: {}", vendors);
    +  215  
                 }
    -  308  11
                 return ret;
    -  309  0
             } catch (ParseException ex) {
    -  310  0
                 LOGGER.warn("An error occurred querying the CPE data. See the log for more details.");
    -  311  0
                 LOGGER.info("Unable to parse: {}", searchString, ex);
    -  312  0
             } catch (IOException ex) {
    -  313  0
                 LOGGER.warn("An error occurred reading CPE data. See the log for more details.");
    -  314  0
                 LOGGER.info("IO Error with search string: {}", searchString, ex);
    -  315  0
             }
    -  316  0
             return null;
    -  317   -
         }
    -  318   -
     
    -  319   -
         /**
    -  320   -
          * <p>
    -  321   -
          * Builds a Lucene search string by properly escaping data and constructing
    -  322   -
          * a valid search query.</p>
    -  323   -
          *
    -  324   -
          * <p>
    -  325   -
          * If either the possibleVendor or possibleProducts lists have been
    -  326   -
          * populated this data is used to add weighting factors to the search string
    -  327   -
          * generated.</p>
    -  328   -
          *
    -  329   -
          * @param vendor text to search the vendor field
    -  330   -
          * @param product text to search the product field
    -  331   -
          * @param vendorWeighting a list of strings to apply to the vendor to boost
    -  332   -
          * the terms weight
    -  333   -
          * @param productWeightings a list of strings to apply to the product to
    -  334   -
          * boost the terms weight
    -  335   -
          * @return the Lucene query
    -  336   -
          */
    -  337   -
         protected String buildSearch(String vendor, String product,
    -  338   -
                 Set<String> vendorWeighting, Set<String> productWeightings) {
    -  339  11
             final String v = vendor; //.replaceAll("[^\\w\\d]", " ");
    -  340  11
             final String p = product; //.replaceAll("[^\\w\\d]", " ");
    -  341  11
             final StringBuilder sb = new StringBuilder(v.length() + p.length()
    -  342  11
                     + Fields.PRODUCT.length() + Fields.VENDOR.length() + STRING_BUILDER_BUFFER);
    -  343   -
     
    -  344  11
             if (!appendWeightedSearch(sb, Fields.PRODUCT, p, productWeightings)) {
    -  345  0
                 return null;
    -  346   -
             }
    -  347  11
             sb.append(" AND ");
    -  348  11
             if (!appendWeightedSearch(sb, Fields.VENDOR, v, vendorWeighting)) {
    -  349  0
                 return null;
    -  350   -
             }
    -  351  11
             return sb.toString();
    -  352   -
         }
    -  353   -
     
    -  354   -
         /**
    -  355   -
          * This method constructs a Lucene query for a given field. The searchText
    -  356   -
          * is split into separate words and if the word is within the list of
    -  357   -
          * weighted words then an additional weighting is applied to the term as it
    -  358   -
          * is appended into the query.
    -  359   -
          *
    -  360   -
          * @param sb a StringBuilder that the query text will be appended to.
    -  361   -
          * @param field the field within the Lucene index that the query is
    -  362   -
          * searching.
    -  363   -
          * @param searchText text used to construct the query.
    -  364   -
          * @param weightedText a list of terms that will be considered higher
    -  365   -
          * importance when searching.
    -  366   -
          * @return if the append was successful.
    -  367   -
          */
    -  368   -
         private boolean appendWeightedSearch(StringBuilder sb, String field, String searchText, Set<String> weightedText) {
    -  369  22
             sb.append(' ').append(field).append(":( ");
    -  370   -
     
    -  371  22
             final String cleanText = cleanseText(searchText);
    -  372   -
     
    -  373  22
             if (cleanText.isEmpty()) {
    -  374  0
                 return false;
    -  375   -
             }
    -  376   -
     
    -  377  22
             if (weightedText == null || weightedText.isEmpty()) {
    -  378  14
                 LuceneUtils.appendEscapedLuceneQuery(sb, cleanText);
    -  379   -
             } else {
    -  380  8
                 final StringTokenizer tokens = new StringTokenizer(cleanText);
    -  381  103
                 while (tokens.hasMoreElements()) {
    -  382  95
                     final String word = tokens.nextToken();
    -  383  95
                     StringBuilder temp = null;
    -  384  95
                     for (String weighted : weightedText) {
    -  385  225
                         final String weightedStr = cleanseText(weighted);
    -  386  225
                         if (equalsIgnoreCaseAndNonAlpha(word, weightedStr)) {
    -  387  7
                             temp = new StringBuilder(word.length() + 2);
    -  388  7
                             LuceneUtils.appendEscapedLuceneQuery(temp, word);
    -  389  7
                             temp.append(WEIGHTING_BOOST);
    -  390  7
                             if (!word.equalsIgnoreCase(weightedStr)) {
    -  391  0
                                 temp.append(' ');
    -  392  0
                                 LuceneUtils.appendEscapedLuceneQuery(temp, weightedStr);
    -  393  0
                                 temp.append(WEIGHTING_BOOST);
    -  394   -
                             }
    -  395   -
                             break;
    -  396   -
                         }
    -  397  218
                     }
    -  398  95
                     sb.append(' ');
    -  399  95
                     if (temp == null) {
    -  400  88
                         LuceneUtils.appendEscapedLuceneQuery(sb, word);
    -  401   -
                     } else {
    -  402  7
                         sb.append(temp);
    -  403   +  216  14
                 if (dependency.getProductEvidence().contains(confidence)) {
    +  217  8
                     products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
    +  218  8
                     LOGGER.debug("product search: {}", products);
    +  219   +
                 }
    +  220  14
                 if (!vendors.isEmpty() && !products.isEmpty()) {
    +  221  22
                     final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getVendorEvidence().getWeighting(),
    +  222  11
                             dependency.getProductEvidence().getWeighting());
    +  223  11
                     if (entries == null) {
    +  224  0
                         continue;
    +  225  
                     }
    -  404  95
                 }
    -  405   +  226  11
                     boolean identifierAdded = false;
    +  227  11
                     for (IndexEntry e : entries) {
    +  228  21
                         LOGGER.debug("Verifying entry: {}", e);
    +  229  21
                         if (verifyEntry(e, dependency)) {
    +  230  4
                             final String vendor = e.getVendor();
    +  231  4
                             final String product = e.getProduct();
    +  232  4
                             LOGGER.debug("identified vendor/product: {}/{}", vendor, product);
    +  233  4
                             identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
    +  234   +
                         }
    +  235  21
                     }
    +  236  11
                     if (identifierAdded) {
    +  237  1
                         break;
    +  238   +
                     }
    +  239   +
                 }
    +  240  
             }
    -  406  22
             sb.append(" ) ");
    -  407  22
             return true;
    -  408   -
         }
    -  409   +  241  4
         }
    +  242  
     
    -  410   +  243  
         /**
    -  411   -
          * Removes characters from the input text that are not used within the CPE
    -  412   -
          * index.
    -  413   +  244   +
          * Returns the text created by concatenating the text and the values from
    +  245   +
          * the EvidenceCollection (filtered for a specific confidence). This
    +  246   +
          * attempts to prevent duplicate terms from being added.<br/<br/> Note, if
    +  247   +
          * the evidence is longer then 200 characters it will be truncated.
    +  248  
          *
    -  414   -
          * @param text is the text to remove the characters from.
    -  415   -
          * @return the text having removed some characters.
    -  416   -
          */
    -  417   -
         private String cleanseText(String text) {
    -  418  247
             return text.replaceAll(CLEANSE_CHARACTER_RX, " ");
    -  419   -
         }
    -  420   -
     
    -  421   -
         /**
    -  422   -
          * Compares two strings after lower casing them and removing the non-alpha
    -  423   -
          * characters.
    -  424   -
          *
    -  425   -
          * @param l string one to compare.
    -  426   -
          * @param r string two to compare.
    -  427   -
          * @return whether or not the two strings are similar.
    -  428   -
          */
    -  429   -
         private boolean equalsIgnoreCaseAndNonAlpha(String l, String r) {
    -  430  225
             if (l == null || r == null) {
    -  431  0
                 return false;
    -  432   -
             }
    -  433   -
     
    -  434  225
             final String left = l.replaceAll(CLEANSE_NONALPHA_RX, "");
    -  435  225
             final String right = r.replaceAll(CLEANSE_NONALPHA_RX, "");
    -  436  225
             return left.equalsIgnoreCase(right);
    -  437   -
         }
    -  438   -
     
    -  439   -
         /**
    -  440   -
          * Ensures that the CPE Identified matches the dependency. This validates
    -  441   -
          * that the product, vendor, and version information for the CPE are
    -  442   -
          * contained within the dependencies evidence.
    -  443   -
          *
    -  444   -
          * @param entry a CPE entry.
    -  445   -
          * @param dependency the dependency that the CPE entries could be for.
    -  446   -
          * @return whether or not the entry is valid.
    -  447   -
          */
    -  448   -
         private boolean verifyEntry(final IndexEntry entry, final Dependency dependency) {
    -  449  20
             boolean isValid = false;
    -  450   -
     
    -  451   -
             //TODO - does this nullify some of the fuzzy matching that happens in the lucene search?
    -  452   -
             // for instance CPE some-component and in the evidence we have SomeComponent.
    -  453  20
             if (collectionContainsString(dependency.getProductEvidence(), entry.getProduct())
    -  454  4
                     && collectionContainsString(dependency.getVendorEvidence(), entry.getVendor())) {
    -  455   -
                 //&& collectionContainsVersion(dependency.getVersionEvidence(), entry.getVersion())
    -  456  4
                 isValid = true;
    -  457   -
             }
    -  458  20
             return isValid;
    -  459   -
         }
    -  460   -
     
    -  461   -
         /**
    -  462   -
          * Used to determine if the EvidenceCollection contains a specific string.
    -  463   -
          *
    -  464   +  249   +
          * @param text the base text.
    +  250  
          * @param ec an EvidenceCollection
    -  465   -
          * @param text the text to search for
    -  466   -
          * @return whether or not the EvidenceCollection contains the string
    -  467   +  251   +
          * @param confidenceFilter a Confidence level to filter the evidence by.
    +  252   +
          * @return the new evidence text
    +  253  
          */
    -  468   -
         private boolean collectionContainsString(EvidenceCollection ec, String text) {
    -  469   -
             //TODO - likely need to change the split... not sure if this will work for CPE with special chars
    -  470  24
             if (text == null) {
    -  471  0
                 return false;
    -  472   -
             }
    -  473  24
             final String[] words = text.split("[\\s_-]");
    -  474  24
             final List<String> list = new ArrayList<String>();
    -  475  24
             String tempWord = null;
    -  476  85
             for (String word : words) {
    -  477   -
                 /*
    -  478   -
                  single letter words should be concatenated with the next word.
    -  479   -
                  so { "m", "core", "sample" } -> { "mcore", "sample" }
    -  480   -
                  */
    -  481  61
                 if (tempWord != null) {
    -  482  2
                     list.add(tempWord + word);
    -  483  2
                     tempWord = null;
    -  484  59
                 } else if (word.length() <= 2) {
    -  485  2
                     tempWord = word;
    -  486   -
                 } else {
    -  487  57
                     list.add(word);
    -  488   +  254   +
         private String addEvidenceWithoutDuplicateTerms(final String text, final EvidenceCollection ec, Confidence confidenceFilter) {
    +  255  17
             final String txt = (text == null) ? "" : text;
    +  256  17
             final StringBuilder sb = new StringBuilder(txt.length() + (20 * ec.size()));
    +  257  17
             sb.append(' ').append(txt).append(' ');
    +  258  17
             for (Evidence e : ec.iterator(confidenceFilter)) {
    +  259  36
                 String value = e.getValue();
    +  260   +
     
    +  261   +
                 //hack to get around the fact that lucene does a really good job of recognizing domains and not
    +  262   +
                 // splitting them. TODO - put together a better lucene analyzer specific to the domain.
    +  263  36
                 if (value.startsWith("http://")) {
    +  264  2
                     value = value.substring(7).replaceAll("\\.", " ");
    +  265  
                 }
    -  489   +  266  36
                 if (value.startsWith("https://")) {
    +  267  1
                     value = value.substring(8).replaceAll("\\.", " ");
    +  268   +
                 }
    +  269  36
                 if (sb.indexOf(" " + value + " ") < 0) {
    +  270  34
                     sb.append(value).append(' ');
    +  271   +
                 }
    +  272  36
             }
    +  273  17
             return sb.toString().trim();
    +  274   +
         }
    +  275   +
     
    +  276   +
         /**
    +  277   +
          * <p>
    +  278   +
          * Searches the Lucene CPE index to identify possible CPE entries associated
    +  279   +
          * with the supplied vendor, product, and version.</p>
    +  280   +
          *
    +  281   +
          * <p>
    +  282   +
          * If either the vendorWeightings or productWeightings lists have been
    +  283   +
          * populated this data is used to add weighting factors to the search.</p>
    +  284   +
          *
    +  285   +
          * @param vendor the text used to search the vendor field
    +  286   +
          * @param product the text used to search the product field
    +  287   +
          * @param vendorWeightings a list of strings to use to add weighting factors
    +  288   +
          * to the vendor field
    +  289   +
          * @param productWeightings Adds a list of strings that will be used to add
    +  290   +
          * weighting factors to the product search
    +  291   +
          * @return a list of possible CPE values
    +  292   +
          */
    +  293   +
         protected List<IndexEntry> searchCPE(String vendor, String product,
    +  294   +
                 Set<String> vendorWeightings, Set<String> productWeightings) {
    +  295   +
     
    +  296  11
             final List<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
    +  297   +
     
    +  298  11
             final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
    +  299  11
             if (searchString == null) {
    +  300  0
                 return ret;
    +  301  
             }
    -  490  24
             if (tempWord != null) {
    -  491  0
                 if (!list.isEmpty()) {
    -  492  0
                     final String tmp = list.get(list.size() - 1) + tempWord;
    -  493  0
                     list.add(tmp);
    -  494  0
                 } else {
    -  495  0
                     list.add(tempWord);
    +  302   +
             try {
    +  303  11
                 final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
    +  304  76
                 for (ScoreDoc d : docs.scoreDocs) {
    +  305  65
                     if (d.score >= 0.08) {
    +  306  21
                         final Document doc = cpe.getDocument(d.doc);
    +  307  21
                         final IndexEntry entry = new IndexEntry();
    +  308  21
                         entry.setVendor(doc.get(Fields.VENDOR));
    +  309  21
                         entry.setProduct(doc.get(Fields.PRODUCT));
    +  310  21
                         entry.setSearchScore(d.score);
    +  311  21
                         if (!ret.contains(entry)) {
    +  312  21
                             ret.add(entry);
    +  313   +
                         }
    +  314   +
                     }
    +  315   +
                 }
    +  316  11
                 return ret;
    +  317  0
             } catch (ParseException ex) {
    +  318  0
                 LOGGER.warn("An error occurred querying the CPE data. See the log for more details.");
    +  319  0
                 LOGGER.info("Unable to parse: {}", searchString, ex);
    +  320  0
             } catch (IOException ex) {
    +  321  0
                 LOGGER.warn("An error occurred reading CPE data. See the log for more details.");
    +  322  0
                 LOGGER.info("IO Error with search string: {}", searchString, ex);
    +  323  0
             }
    +  324  0
             return null;
    +  325   +
         }
    +  326   +
     
    +  327   +
         /**
    +  328   +
          * <p>
    +  329   +
          * Builds a Lucene search string by properly escaping data and constructing
    +  330   +
          * a valid search query.</p>
    +  331   +
          *
    +  332   +
          * <p>
    +  333   +
          * If either the possibleVendor or possibleProducts lists have been
    +  334   +
          * populated this data is used to add weighting factors to the search string
    +  335   +
          * generated.</p>
    +  336   +
          *
    +  337   +
          * @param vendor text to search the vendor field
    +  338   +
          * @param product text to search the product field
    +  339   +
          * @param vendorWeighting a list of strings to apply to the vendor to boost
    +  340   +
          * the terms weight
    +  341   +
          * @param productWeightings a list of strings to apply to the product to
    +  342   +
          * boost the terms weight
    +  343   +
          * @return the Lucene query
    +  344   +
          */
    +  345   +
         protected String buildSearch(String vendor, String product,
    +  346   +
                 Set<String> vendorWeighting, Set<String> productWeightings) {
    +  347  11
             final String v = vendor; //.replaceAll("[^\\w\\d]", " ");
    +  348  11
             final String p = product; //.replaceAll("[^\\w\\d]", " ");
    +  349  11
             final StringBuilder sb = new StringBuilder(v.length() + p.length()
    +  350  11
                     + Fields.PRODUCT.length() + Fields.VENDOR.length() + STRING_BUILDER_BUFFER);
    +  351   +
     
    +  352  11
             if (!appendWeightedSearch(sb, Fields.PRODUCT, p, productWeightings)) {
    +  353  0
                 return null;
    +  354   +
             }
    +  355  11
             sb.append(" AND ");
    +  356  11
             if (!appendWeightedSearch(sb, Fields.VENDOR, v, vendorWeighting)) {
    +  357  0
                 return null;
    +  358   +
             }
    +  359  11
             return sb.toString();
    +  360   +
         }
    +  361   +
     
    +  362   +
         /**
    +  363   +
          * This method constructs a Lucene query for a given field. The searchText
    +  364   +
          * is split into separate words and if the word is within the list of
    +  365   +
          * weighted words then an additional weighting is applied to the term as it
    +  366   +
          * is appended into the query.
    +  367   +
          *
    +  368   +
          * @param sb a StringBuilder that the query text will be appended to.
    +  369   +
          * @param field the field within the Lucene index that the query is
    +  370   +
          * searching.
    +  371   +
          * @param searchText text used to construct the query.
    +  372   +
          * @param weightedText a list of terms that will be considered higher
    +  373   +
          * importance when searching.
    +  374   +
          * @return if the append was successful.
    +  375   +
          */
    +  376   +
         private boolean appendWeightedSearch(StringBuilder sb, String field, String searchText, Set<String> weightedText) {
    +  377  22
             sb.append(' ').append(field).append(":( ");
    +  378   +
     
    +  379  22
             final String cleanText = cleanseText(searchText);
    +  380   +
     
    +  381  22
             if (cleanText.isEmpty()) {
    +  382  0
                 return false;
    +  383   +
             }
    +  384   +
     
    +  385  22
             if (weightedText == null || weightedText.isEmpty()) {
    +  386  14
                 LuceneUtils.appendEscapedLuceneQuery(sb, cleanText);
    +  387   +
             } else {
    +  388  8
                 final StringTokenizer tokens = new StringTokenizer(cleanText);
    +  389  103
                 while (tokens.hasMoreElements()) {
    +  390  95
                     final String word = tokens.nextToken();
    +  391  95
                     StringBuilder temp = null;
    +  392  95
                     for (String weighted : weightedText) {
    +  393  225
                         final String weightedStr = cleanseText(weighted);
    +  394  225
                         if (equalsIgnoreCaseAndNonAlpha(word, weightedStr)) {
    +  395  7
                             temp = new StringBuilder(word.length() + 2);
    +  396  7
                             LuceneUtils.appendEscapedLuceneQuery(temp, word);
    +  397  7
                             temp.append(WEIGHTING_BOOST);
    +  398  7
                             if (!word.equalsIgnoreCase(weightedStr)) {
    +  399  0
                                 temp.append(' ');
    +  400  0
                                 LuceneUtils.appendEscapedLuceneQuery(temp, weightedStr);
    +  401  0
                                 temp.append(WEIGHTING_BOOST);
    +  402   +
                             }
    +  403   +
                             break;
    +  404   +
                         }
    +  405  218
                     }
    +  406  95
                     sb.append(' ');
    +  407  95
                     if (temp == null) {
    +  408  88
                         LuceneUtils.appendEscapedLuceneQuery(sb, word);
    +  409   +
                     } else {
    +  410  7
                         sb.append(temp);
    +  411   +
                     }
    +  412  95
                 }
    +  413   +
             }
    +  414  22
             sb.append(" ) ");
    +  415  22
             return true;
    +  416   +
         }
    +  417   +
     
    +  418   +
         /**
    +  419   +
          * Removes characters from the input text that are not used within the CPE
    +  420   +
          * index.
    +  421   +
          *
    +  422   +
          * @param text is the text to remove the characters from.
    +  423   +
          * @return the text having removed some characters.
    +  424   +
          */
    +  425   +
         private String cleanseText(String text) {
    +  426  247
             return text.replaceAll(CLEANSE_CHARACTER_RX, " ");
    +  427   +
         }
    +  428   +
     
    +  429   +
         /**
    +  430   +
          * Compares two strings after lower casing them and removing the non-alpha
    +  431   +
          * characters.
    +  432   +
          *
    +  433   +
          * @param l string one to compare.
    +  434   +
          * @param r string two to compare.
    +  435   +
          * @return whether or not the two strings are similar.
    +  436   +
          */
    +  437   +
         private boolean equalsIgnoreCaseAndNonAlpha(String l, String r) {
    +  438  225
             if (l == null || r == null) {
    +  439  0
                 return false;
    +  440   +
             }
    +  441   +
     
    +  442  225
             final String left = l.replaceAll(CLEANSE_NONALPHA_RX, "");
    +  443  225
             final String right = r.replaceAll(CLEANSE_NONALPHA_RX, "");
    +  444  225
             return left.equalsIgnoreCase(right);
    +  445   +
         }
    +  446   +
     
    +  447   +
         /**
    +  448   +
          * Ensures that the CPE Identified matches the dependency. This validates
    +  449   +
          * that the product, vendor, and version information for the CPE are
    +  450   +
          * contained within the dependencies evidence.
    +  451   +
          *
    +  452   +
          * @param entry a CPE entry.
    +  453   +
          * @param dependency the dependency that the CPE entries could be for.
    +  454   +
          * @return whether or not the entry is valid.
    +  455   +
          */
    +  456   +
         private boolean verifyEntry(final IndexEntry entry, final Dependency dependency) {
    +  457  21
             boolean isValid = false;
    +  458   +
     
    +  459   +
             //TODO - does this nullify some of the fuzzy matching that happens in the lucene search?
    +  460   +
             // for instance CPE some-component and in the evidence we have SomeComponent.
    +  461  21
             if (collectionContainsString(dependency.getProductEvidence(), entry.getProduct())
    +  462  4
                     && collectionContainsString(dependency.getVendorEvidence(), entry.getVendor())) {
    +  463   +
                 //&& collectionContainsVersion(dependency.getVersionEvidence(), entry.getVersion())
    +  464  4
                 isValid = true;
    +  465   +
             }
    +  466  21
             return isValid;
    +  467   +
         }
    +  468   +
     
    +  469   +
         /**
    +  470   +
          * Used to determine if the EvidenceCollection contains a specific string.
    +  471   +
          *
    +  472   +
          * @param ec an EvidenceCollection
    +  473   +
          * @param text the text to search for
    +  474   +
          * @return whether or not the EvidenceCollection contains the string
    +  475   +
          */
    +  476   +
         private boolean collectionContainsString(EvidenceCollection ec, String text) {
    +  477   +
             //TODO - likely need to change the split... not sure if this will work for CPE with special chars
    +  478  25
             if (text == null) {
    +  479  0
                 return false;
    +  480   +
             }
    +  481  25
             final String[] words = text.split("[\\s_-]");
    +  482  25
             final List<String> list = new ArrayList<String>();
    +  483  25
             String tempWord = null;
    +  484  88
             for (String word : words) {
    +  485   +
                 /*
    +  486   +
                  single letter words should be concatenated with the next word.
    +  487   +
                  so { "m", "core", "sample" } -> { "mcore", "sample" }
    +  488   +
                  */
    +  489  63
                 if (tempWord != null) {
    +  490  2
                     list.add(tempWord + word);
    +  491  2
                     tempWord = null;
    +  492  61
                 } else if (word.length() <= 2) {
    +  493  2
                     tempWord = word;
    +  494   +
                 } else {
    +  495  59
                     list.add(word);
     496  
                 }
     497  
             }
    -  498  24
             if (list.isEmpty()) {
    -  499  0
                 return false;
    -  500   +  498  25
             if (tempWord != null) {
    +  499  0
                 if (!list.isEmpty()) {
    +  500  0
                     final String tmp = list.get(list.size() - 1) + tempWord;
    +  501  0
                     list.add(tmp);
    +  502  0
                 } else {
    +  503  0
                     list.add(tempWord);
    +  504   +
                 }
    +  505  
             }
    -  501  24
             boolean contains = true;
    -  502  24
             for (String word : list) {
    -  503  59
                 contains &= ec.containsUsedString(word);
    -  504  59
             }
    -  505  24
             return contains;
    -  506   -
         }
    -  507   -
     
    +  506  25
             if (list.isEmpty()) {
    +  507  0
                 return false;
     508   -
         /**
    -  509   -
          * Analyzes a dependency and attempts to determine if there are any CPE
    -  510   -
          * identifiers for this dependency.
    -  511   -
          *
    -  512   -
          * @param dependency The Dependency to analyze.
    -  513   -
          * @param engine The analysis engine
    +
             }
    +  509  25
             boolean contains = true;
    +  510  25
             for (String word : list) {
    +  511  61
                 contains &= ec.containsUsedString(word);
    +  512  61
             }
    +  513  25
             return contains;
     514   -
          * @throws AnalysisException is thrown if there is an issue analyzing the
    +
         }
     515   -
          * dependency.
    +
     
     516   -
          */
    +
         /**
     517   -
         @Override
    +
          * Analyzes a dependency and attempts to determine if there are any CPE
     518   -
         public synchronized void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    +
          * identifiers for this dependency.
     519   -
             try {
    -  520  4
                 determineCPE(dependency);
    -  521  0
             } catch (CorruptIndexException ex) {
    -  522  0
                 throw new AnalysisException("CPE Index is corrupt.", ex);
    -  523  0
             } catch (IOException ex) {
    -  524  0
                 throw new AnalysisException("Failure opening the CPE Index.", ex);
    -  525  0
             } catch (ParseException ex) {
    -  526  0
                 throw new AnalysisException("Unable to parse the generated Lucene query for this dependency.", ex);
    -  527  4
             }
    -  528  4
         }
    -  529   -
     
    -  530   -
         /**
    -  531   -
          * Retrieves a list of CPE values from the CveDB based on the vendor and
    -  532   -
          * product passed in. The list is then validated to find only CPEs that are
    -  533   -
          * valid for the given dependency. It is possible that the CPE identified is
    -  534   -
          * a best effort "guess" based on the vendor, product, and version
    -  535   -
          * information.
    -  536  
          *
    +  520   +
          * @param dependency The Dependency to analyze.
    +  521   +
          * @param engine The analysis engine
    +  522   +
          * @throws AnalysisException is thrown if there is an issue analyzing the
    +  523   +
          * dependency.
    +  524   +
          */
    +  525   +
         @Override
    +  526   +
         protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  527   +
             try {
    +  528  4
                 determineCPE(dependency);
    +  529  0
             } catch (CorruptIndexException ex) {
    +  530  0
                 throw new AnalysisException("CPE Index is corrupt.", ex);
    +  531  0
             } catch (IOException ex) {
    +  532  0
                 throw new AnalysisException("Failure opening the CPE Index.", ex);
    +  533  0
             } catch (ParseException ex) {
    +  534  0
                 throw new AnalysisException("Unable to parse the generated Lucene query for this dependency.", ex);
    +  535  4
             }
    +  536  4
         }
     537   -
          * @param dependency the Dependency being analyzed
    +
     
     538   -
          * @param vendor the vendor for the CPE being analyzed
    +
         /**
     539   -
          * @param product the product for the CPE being analyzed
    +
          * Retrieves a list of CPE values from the CveDB based on the vendor and
     540   -
          * @param currentConfidence the current confidence being used during
    +
          * product passed in. The list is then validated to find only CPEs that are
     541   -
          * analysis
    +
          * valid for the given dependency. It is possible that the CPE identified is
     542   -
          * @return <code>true</code> if an identifier was added to the dependency;
    +
          * a best effort "guess" based on the vendor, product, and version
     543   -
          * otherwise <code>false</code>
    +
          * information.
     544   -
          * @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
    +
          *
     545   -
          */
    +
          * @param dependency the Dependency being analyzed
     546   -
         protected boolean determineIdentifiers(Dependency dependency, String vendor, String product,
    +
          * @param vendor the vendor for the CPE being analyzed
     547   -
                 Confidence currentConfidence) throws UnsupportedEncodingException {
    -  548  4
             final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
    -  549  4
             DependencyVersion bestGuess = new DependencyVersion("-");
    -  550  4
             Confidence bestGuessConf = null;
    -  551  4
             boolean hasBroadMatch = false;
    -  552  4
             final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
    +
          * @param product the product for the CPE being analyzed
    +  548   +
          * @param currentConfidence the current confidence being used during
    +  549   +
          * analysis
    +  550   +
          * @return <code>true</code> if an identifier was added to the dependency;
    +  551   +
          * otherwise <code>false</code>
    +  552   +
          * @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
     553   -
     
    +
          */
     554   -
             //TODO the following algorithm incorrectly identifies things as a lower version
    +
         protected boolean determineIdentifiers(Dependency dependency, String vendor, String product,
     555   -
             // if there lower confidence evidence when the current (highest) version number
    -  556   -
             // is newer then anything in the NVD.
    -  557  20
             for (Confidence conf : Confidence.values()) {
    -  558  16
                 for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
    -  559  16
                     final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
    -  560  16
                     if (evVer == null) {
    -  561  4
                         continue;
    +
                 Confidence currentConfidence) throws UnsupportedEncodingException {
    +  556  4
             final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
    +  557  4
             DependencyVersion bestGuess = new DependencyVersion("-");
    +  558  4
             Confidence bestGuessConf = null;
    +  559  4
             boolean hasBroadMatch = false;
    +  560  4
             final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
    +  561   +
     
     562   -
                     }
    -  563  12
                     for (VulnerableSoftware vs : cpes) {
    +
             //TODO the following algorithm incorrectly identifies things as a lower version
    +  563   +
             // if there lower confidence evidence when the current (highest) version number
     564   +
             // is newer then anything in the NVD.
    +  565  20
             for (Confidence conf : Confidence.values()) {
    +  566  16
                 for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
    +  567  16
                     final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
    +  568  16
                     if (evVer == null) {
    +  569  4
                         continue;
    +  570   +
                     }
    +  571  12
                     for (VulnerableSoftware vs : cpes) {
    +  572  
                         DependencyVersion dbVer;
    -  565  390
                         if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
    -  566  96
                             dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + '.' + vs.getUpdate());
    -  567   +  573  444
                         if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
    +  574  96
                             dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + '.' + vs.getUpdate());
    +  575  
                         } else {
    -  568  294
                             dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
    -  569   +  576  348
                             dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
    +  577  
                         }
    -  570  390
                         if (dbVer == null) { //special case, no version specified - everything is vulnerable
    -  571  0
                             hasBroadMatch = true;
    -  572  0
                             final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
    -  573  0
                             final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf);
    -  574  0
                             collected.add(match);
    -  575  0
                         } else if (evVer.equals(dbVer)) { //yeah! exact match
    -  576  6
                             final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
    -  577  6
                             final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
    -  578  6
                             collected.add(match);
    -  579   -
     
    -  580   -
                             //TODO the following isn't quite right is it? need to think about this guessing game a bit more.
    -  581  6
                         } else if (evVer.getVersionParts().size() <= dbVer.getVersionParts().size()
    -  582  378
                                 && evVer.matchesAtLeastThreeLevels(dbVer)) {
    -  583  48
                             if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
    -  584  2
                                 if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
    -  585  2
                                     bestGuess = dbVer;
    -  586  2
                                     bestGuessConf = conf;
    +  578  444
                         if (dbVer == null) { //special case, no version specified - everything is vulnerable
    +  579  0
                             hasBroadMatch = true;
    +  580  0
                             final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
    +  581  0
                             final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf);
    +  582  0
                             collected.add(match);
    +  583  0
                         } else if (evVer.equals(dbVer)) { //yeah! exact match
    +  584  6
                             final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
    +  585  6
                             final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
    +  586  6
                             collected.add(match);
     587   -
                                 }
    +
     
     588   -
                             }
    -  589   -
                         }
    -  590  390
                     }
    -  591  12
                     if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
    -  592  2
                         if (bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
    -  593  2
                             bestGuess = evVer;
    -  594  2
                             bestGuessConf = conf;
    +
                             //TODO the following isn't quite right is it? need to think about this guessing game a bit more.
    +  589  6
                         } else if (evVer.getVersionParts().size() <= dbVer.getVersionParts().size()
    +  590  432
                                 && evVer.matchesAtLeastThreeLevels(dbVer)) {
    +  591  48
                             if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
    +  592  2
                                 if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
    +  593  2
                                     bestGuess = dbVer;
    +  594  2
                                     bestGuessConf = conf;
     595   -
                         }
    +
                                 }
     596   -
                     }
    -  597  12
                 }
    -  598   -
             }
    -  599  4
             final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
    -  600  4
             String url = null;
    -  601  4
             if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess.
    -  602  0
                 final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
    -  603  0
                 url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
    +
                             }
    +  597   +
                         }
    +  598  444
                     }
    +  599  12
                     if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
    +  600  2
                         if (bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
    +  601  2
                             bestGuess = evVer;
    +  602  2
                             bestGuessConf = conf;
    +  603   +
                         }
     604   -
             }
    -  605  4
             if (bestGuessConf == null) {
    -  606  0
                 bestGuessConf = Confidence.LOW;
    -  607   -
             }
    -  608  4
             final IdentifierMatch match = new IdentifierMatch("cpe", cpeName, url, IdentifierConfidence.BEST_GUESS, bestGuessConf);
    -  609  4
             collected.add(match);
    -  610   -
     
    -  611  4
             Collections.sort(collected);
    -  612  4
             final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
    -  613  4
             final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
    -  614  4
             boolean identifierAdded = false;
    -  615  4
             for (IdentifierMatch m : collected) {
    -  616  10
                 if (bestIdentifierQuality.equals(m.getConfidence())
    -  617  8
                         && bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
    -  618  4
                     final Identifier i = m.getIdentifier();
    -  619  4
                     if (bestIdentifierQuality == IdentifierConfidence.BEST_GUESS) {
    -  620  2
                         i.setConfidence(Confidence.LOW);
    -  621   -
                     } else {
    -  622  2
                         i.setConfidence(bestEvidenceQuality);
    -  623  
                     }
    -  624  4
                     dependency.addIdentifier(i);
    -  625  4
                     identifierAdded = true;
    -  626   -
                 }
    -  627  10
             }
    -  628  4
             return identifierAdded;
    +  605  12
                 }
    +  606   +
             }
    +  607  4
             final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
    +  608  4
             String url = null;
    +  609  4
             if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess.
    +  610  0
                 final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
    +  611  0
                 url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
    +  612   +
             }
    +  613  4
             if (bestGuessConf == null) {
    +  614  0
                 bestGuessConf = Confidence.LOW;
    +  615   +
             }
    +  616  4
             final IdentifierMatch match = new IdentifierMatch("cpe", cpeName, url, IdentifierConfidence.BEST_GUESS, bestGuessConf);
    +  617  4
             collected.add(match);
    +  618   +
     
    +  619  4
             Collections.sort(collected);
    +  620  4
             final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
    +  621  4
             final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
    +  622  4
             boolean identifierAdded = false;
    +  623  4
             for (IdentifierMatch m : collected) {
    +  624  10
                 if (bestIdentifierQuality.equals(m.getConfidence())
    +  625  8
                         && bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
    +  626  4
                     final Identifier i = m.getIdentifier();
    +  627  4
                     if (bestIdentifierQuality == IdentifierConfidence.BEST_GUESS) {
    +  628  2
                         i.setConfidence(Confidence.LOW);
     629   -
         }
    -  630   -
     
    +
                     } else {
    +  630  2
                         i.setConfidence(bestEvidenceQuality);
     631   -
         /**
    -  632   -
          * The confidence whether the identifier is an exact match, or a best guess.
    -  633   -
          */
    -  634  4
         private enum IdentifierConfidence {
    -  635   -
     
    -  636   -
             /**
    +
                     }
    +  632  4
                     dependency.addIdentifier(i);
    +  633  4
                     identifierAdded = true;
    +  634   +
                 }
    +  635  10
             }
    +  636  4
             return identifierAdded;
     637   -
              * An exact match for the CPE.
    +
         }
     638   -
              */
    -  639  1
             EXACT_MATCH,
    -  640   -
             /**
    -  641   -
              * A best guess for the CPE.
    -  642   -
              */
    -  643  1
             BEST_GUESS,
    -  644   -
             /**
    -  645   -
              * The entire vendor/product group must be added (without a guess at
    -  646   -
              * version) because there is a CVE with a VS that only specifies
    -  647   -
              * vendor/product.
    -  648   -
              */
    -  649  1
             BROAD_MATCH
    -  650   -
         }
    -  651  
     
    -  652   +  639  
         /**
    -  653   -
          * A simple object to hold an identifier and carry information about the
    -  654   -
          * confidence in the identifier.
    -  655   +  640   +
          * <p>
    +  641   +
          * Returns the setting key to determine if the analyzer is enabled.</p>
    +  642   +
          *
    +  643   +
          * @return the key for the analyzer's enabled property
    +  644  
          */
    -  656  6
         private static class IdentifierMatch implements Comparable<IdentifierMatch> {
    -  657   -
     
    -  658   -
             /**
    -  659   -
              * Constructs an IdentifierMatch.
    -  660   -
              *
    -  661   -
              * @param type the type of identifier (such as CPE)
    -  662   -
              * @param value the value of the identifier
    -  663   -
              * @param url the URL of the identifier
    -  664   -
              * @param identifierConfidence the confidence in the identifier: best
    -  665   -
              * guess or exact match
    -  666   -
              * @param evidenceConfidence the confidence of the evidence used to find
    -  667   -
              * the identifier
    -  668   -
              */
    -  669  10
             IdentifierMatch(String type, String value, String url, IdentifierConfidence identifierConfidence, Confidence evidenceConfidence) {
    -  670  10
                 this.identifier = new Identifier(type, value, url);
    -  671  10
                 this.confidence = identifierConfidence;
    -  672  10
                 this.evidenceConfidence = evidenceConfidence;
    -  673  10
             }
    -  674   -
             //<editor-fold defaultstate="collapsed" desc="Property implementations: evidenceConfidence, confidence, identifier">
    -  675   -
             /**
    -  676   -
              * The confidence in the evidence used to identify this match.
    -  677   -
              */
    -  678   -
             private Confidence evidenceConfidence;
    -  679   -
     
    -  680   -
             /**
    -  681   -
              * Get the value of evidenceConfidence
    -  682   -
              *
    -  683   -
              * @return the value of evidenceConfidence
    -  684   -
              */
    -  685   -
             public Confidence getEvidenceConfidence() {
    -  686  12
                 return evidenceConfidence;
    -  687   -
             }
    -  688   -
     
    -  689   -
             /**
    -  690   -
              * Set the value of evidenceConfidence
    -  691   -
              *
    -  692   -
              * @param evidenceConfidence new value of evidenceConfidence
    -  693   -
              */
    -  694   -
             public void setEvidenceConfidence(Confidence evidenceConfidence) {
    -  695  0
                 this.evidenceConfidence = evidenceConfidence;
    -  696  0
             }
    -  697   -
             /**
    -  698   -
              * The confidence whether this is an exact match, or a best guess.
    -  699   -
              */
    -  700   -
             private IdentifierConfidence confidence;
    -  701   -
     
    -  702   -
             /**
    -  703   -
              * Get the value of confidence.
    -  704   -
              *
    -  705   -
              * @return the value of confidence
    -  706   -
              */
    -  707   -
             public IdentifierConfidence getConfidence() {
    -  708  14
                 return confidence;
    -  709   -
             }
    -  710   -
     
    -  711   -
             /**
    -  712   -
              * Set the value of confidence.
    -  713   -
              *
    -  714   -
              * @param confidence new value of confidence
    -  715   -
              */
    -  716   -
             public void setConfidence(IdentifierConfidence confidence) {
    -  717  0
                 this.confidence = confidence;
    -  718  0
             }
    -  719   -
             /**
    -  720   -
              * The CPE identifier.
    -  721   -
              */
    -  722   -
             private Identifier identifier;
    -  723   -
     
    -  724   -
             /**
    -  725   -
              * Get the value of identifier.
    -  726   -
              *
    -  727   -
              * @return the value of identifier
    -  728   -
              */
    -  729   -
             public Identifier getIdentifier() {
    -  730  4
                 return identifier;
    -  731   -
             }
    -  732   -
     
    -  733   -
             /**
    -  734   -
              * Set the value of identifier.
    -  735   -
              *
    -  736   -
              * @param identifier new value of identifier
    -  737   -
              */
    -  738   -
             public void setIdentifier(Identifier identifier) {
    -  739  0
                 this.identifier = identifier;
    -  740  0
             }
    -  741   -
             //</editor-fold>
    -  742   -
             //<editor-fold defaultstate="collapsed" desc="Standard implementations of toString, hashCode, and equals">
    -  743   -
     
    -  744   -
             /**
    -  745   -
              * Standard toString() implementation.
    -  746   -
              *
    -  747   -
              * @return the string representation of the object
    -  748   -
              */
    -  749   -
             @Override
    -  750   -
             public String toString() {
    -  751  0
                 return "IdentifierMatch{" + "evidenceConfidence=" + evidenceConfidence
    -  752   -
                         + ", confidence=" + confidence + ", identifier=" + identifier + '}';
    -  753   -
             }
    -  754   -
     
    -  755   -
             /**
    -  756   -
              * Standard hashCode() implementation.
    -  757   -
              *
    -  758   -
              * @return the hashCode
    -  759   -
              */
    -  760   -
             @Override
    -  761   -
             public int hashCode() {
    -  762  0
                 int hash = 5;
    -  763  0
                 hash = 97 * hash + (this.evidenceConfidence != null ? this.evidenceConfidence.hashCode() : 0);
    -  764  0
                 hash = 97 * hash + (this.confidence != null ? this.confidence.hashCode() : 0);
    -  765  0
                 hash = 97 * hash + (this.identifier != null ? this.identifier.hashCode() : 0);
    -  766  0
                 return hash;
    -  767   -
             }
    -  768   -
     
    -  769   -
             /**
    -  770   -
              * Standard equals implementation.
    -  771   -
              *
    -  772   -
              * @param obj the object to compare
    -  773   -
              * @return true if the objects are equal, otherwise false
    -  774   -
              */
    -  775   -
             @Override
    -  776   -
             public boolean equals(Object obj) {
    -  777  0
                 if (obj == null) {
    -  778  0
                     return false;
    -  779   -
                 }
    -  780  0
                 if (getClass() != obj.getClass()) {
    -  781  0
                     return false;
    -  782   -
                 }
    -  783  0
                 final IdentifierMatch other = (IdentifierMatch) obj;
    -  784  0
                 if (this.evidenceConfidence != other.evidenceConfidence) {
    -  785  0
                     return false;
    -  786   -
                 }
    -  787  0
                 if (this.confidence != other.confidence) {
    -  788  0
                     return false;
    -  789   -
                 }
    -  790  0
                 if (this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier))) {
    -  791  0
                     return false;
    -  792   -
                 }
    -  793  0
                 return true;
    -  794   -
             }
    -  795   -
             //</editor-fold>
    -  796   -
     
    -  797   -
             /**
    -  798   -
              * Standard implementation of compareTo that compares identifier
    -  799   -
              * confidence, evidence confidence, and then the identifier.
    -  800   -
              *
    -  801   -
              * @param o the IdentifierMatch to compare to
    -  802   -
              * @return the natural ordering of IdentifierMatch
    -  803   -
              */
    -  804   -
             @Override
    -  805   -
             public int compareTo(IdentifierMatch o) {
    -  806  12
                 return new CompareToBuilder()
    -  807  6
                         .append(confidence, o.confidence)
    -  808  6
                         .append(evidenceConfidence, o.evidenceConfidence)
    -  809  6
                         .append(identifier, o.identifier)
    -  810  6
                         .toComparison();
    -  811   -
                 /*
    -  812   -
                 int conf = this.confidence.compareTo(o.confidence);
    -  813   -
                 if (conf == 0) {
    -  814   -
                     conf = this.evidenceConfidence.compareTo(o.evidenceConfidence);
    -  815   -
                     if (conf == 0) {
    -  816   -
                         conf = identifier.compareTo(o.identifier);
    -  817   -
                     }
    -  818   -
                 }
    -  819   -
                 return conf;
    -  820   -
                  */
    -  821   -
             }
    -  822   +  645   +
         @Override
    +  646   +
         protected String getAnalyzerEnabledSettingKey() {
    +  647  2
             return Settings.KEYS.ANALYZER_CPE_ENABLED;
    +  648  
         }
    +  649   +
     
    +  650   +
         /**
    +  651   +
          * The confidence whether the identifier is an exact match, or a best guess.
    +  652   +
          */
    +  653  4
         private enum IdentifierConfidence {
    +  654   +
     
    +  655   +
             /**
    +  656   +
              * An exact match for the CPE.
    +  657   +
              */
    +  658  1
             EXACT_MATCH,
    +  659   +
             /**
    +  660   +
              * A best guess for the CPE.
    +  661   +
              */
    +  662  1
             BEST_GUESS,
    +  663   +
             /**
    +  664   +
              * The entire vendor/product group must be added (without a guess at
    +  665   +
              * version) because there is a CVE with a VS that only specifies
    +  666   +
              * vendor/product.
    +  667   +
              */
    +  668  1
             BROAD_MATCH
    +  669   +
         }
    +  670   +
     
    +  671   +
         /**
    +  672   +
          * A simple object to hold an identifier and carry information about the
    +  673   +
          * confidence in the identifier.
    +  674   +
          */
    +  675  6
         private static class IdentifierMatch implements Comparable<IdentifierMatch> {
    +  676   +
     
    +  677   +
             /**
    +  678   +
              * Constructs an IdentifierMatch.
    +  679   +
              *
    +  680   +
              * @param type the type of identifier (such as CPE)
    +  681   +
              * @param value the value of the identifier
    +  682   +
              * @param url the URL of the identifier
    +  683   +
              * @param identifierConfidence the confidence in the identifier: best
    +  684   +
              * guess or exact match
    +  685   +
              * @param evidenceConfidence the confidence of the evidence used to find
    +  686   +
              * the identifier
    +  687   +
              */
    +  688  10
             IdentifierMatch(String type, String value, String url, IdentifierConfidence identifierConfidence, Confidence evidenceConfidence) {
    +  689  10
                 this.identifier = new Identifier(type, value, url);
    +  690  10
                 this.confidence = identifierConfidence;
    +  691  10
                 this.evidenceConfidence = evidenceConfidence;
    +  692  10
             }
    +  693   +
             //<editor-fold defaultstate="collapsed" desc="Property implementations: evidenceConfidence, confidence, identifier">
    +  694   +
             /**
    +  695   +
              * The confidence in the evidence used to identify this match.
    +  696   +
              */
    +  697   +
             private Confidence evidenceConfidence;
    +  698   +
     
    +  699   +
             /**
    +  700   +
              * Get the value of evidenceConfidence
    +  701   +
              *
    +  702   +
              * @return the value of evidenceConfidence
    +  703   +
              */
    +  704   +
             public Confidence getEvidenceConfidence() {
    +  705  12
                 return evidenceConfidence;
    +  706   +
             }
    +  707   +
     
    +  708   +
             /**
    +  709   +
              * Set the value of evidenceConfidence
    +  710   +
              *
    +  711   +
              * @param evidenceConfidence new value of evidenceConfidence
    +  712   +
              */
    +  713   +
             public void setEvidenceConfidence(Confidence evidenceConfidence) {
    +  714  0
                 this.evidenceConfidence = evidenceConfidence;
    +  715  0
             }
    +  716   +
             /**
    +  717   +
              * The confidence whether this is an exact match, or a best guess.
    +  718   +
              */
    +  719   +
             private IdentifierConfidence confidence;
    +  720   +
     
    +  721   +
             /**
    +  722   +
              * Get the value of confidence.
    +  723   +
              *
    +  724   +
              * @return the value of confidence
    +  725   +
              */
    +  726   +
             public IdentifierConfidence getConfidence() {
    +  727  14
                 return confidence;
    +  728   +
             }
    +  729   +
     
    +  730   +
             /**
    +  731   +
              * Set the value of confidence.
    +  732   +
              *
    +  733   +
              * @param confidence new value of confidence
    +  734   +
              */
    +  735   +
             public void setConfidence(IdentifierConfidence confidence) {
    +  736  0
                 this.confidence = confidence;
    +  737  0
             }
    +  738   +
             /**
    +  739   +
              * The CPE identifier.
    +  740   +
              */
    +  741   +
             private Identifier identifier;
    +  742   +
     
    +  743   +
             /**
    +  744   +
              * Get the value of identifier.
    +  745   +
              *
    +  746   +
              * @return the value of identifier
    +  747   +
              */
    +  748   +
             public Identifier getIdentifier() {
    +  749  4
                 return identifier;
    +  750   +
             }
    +  751   +
     
    +  752   +
             /**
    +  753   +
              * Set the value of identifier.
    +  754   +
              *
    +  755   +
              * @param identifier new value of identifier
    +  756   +
              */
    +  757   +
             public void setIdentifier(Identifier identifier) {
    +  758  0
                 this.identifier = identifier;
    +  759  0
             }
    +  760   +
             //</editor-fold>
    +  761   +
             //<editor-fold defaultstate="collapsed" desc="Standard implementations of toString, hashCode, and equals">
    +  762   +
     
    +  763   +
             /**
    +  764   +
              * Standard toString() implementation.
    +  765   +
              *
    +  766   +
              * @return the string representation of the object
    +  767   +
              */
    +  768   +
             @Override
    +  769   +
             public String toString() {
    +  770  0
                 return "IdentifierMatch{" + "evidenceConfidence=" + evidenceConfidence
    +  771   +
                         + ", confidence=" + confidence + ", identifier=" + identifier + '}';
    +  772   +
             }
    +  773   +
     
    +  774   +
             /**
    +  775   +
              * Standard hashCode() implementation.
    +  776   +
              *
    +  777   +
              * @return the hashCode
    +  778   +
              */
    +  779   +
             @Override
    +  780   +
             public int hashCode() {
    +  781  0
                 int hash = 5;
    +  782  0
                 hash = 97 * hash + (this.evidenceConfidence != null ? this.evidenceConfidence.hashCode() : 0);
    +  783  0
                 hash = 97 * hash + (this.confidence != null ? this.confidence.hashCode() : 0);
    +  784  0
                 hash = 97 * hash + (this.identifier != null ? this.identifier.hashCode() : 0);
    +  785  0
                 return hash;
    +  786   +
             }
    +  787   +
     
    +  788   +
             /**
    +  789   +
              * Standard equals implementation.
    +  790   +
              *
    +  791   +
              * @param obj the object to compare
    +  792   +
              * @return true if the objects are equal, otherwise false
    +  793   +
              */
    +  794   +
             @Override
    +  795   +
             public boolean equals(Object obj) {
    +  796  0
                 if (obj == null) {
    +  797  0
                     return false;
    +  798   +
                 }
    +  799  0
                 if (getClass() != obj.getClass()) {
    +  800  0
                     return false;
    +  801   +
                 }
    +  802  0
                 final IdentifierMatch other = (IdentifierMatch) obj;
    +  803  0
                 if (this.evidenceConfidence != other.evidenceConfidence) {
    +  804  0
                     return false;
    +  805   +
                 }
    +  806  0
                 if (this.confidence != other.confidence) {
    +  807  0
                     return false;
    +  808   +
                 }
    +  809  0
                 if (this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier))) {
    +  810  0
                     return false;
    +  811   +
                 }
    +  812  0
                 return true;
    +  813   +
             }
    +  814   +
             //</editor-fold>
    +  815   +
     
    +  816   +
             /**
    +  817   +
              * Standard implementation of compareTo that compares identifier
    +  818   +
              * confidence, evidence confidence, and then the identifier.
    +  819   +
              *
    +  820   +
              * @param o the IdentifierMatch to compare to
    +  821   +
              * @return the natural ordering of IdentifierMatch
    +  822   +
              */
     823   +
             @Override
    +  824   +
             public int compareTo(IdentifierMatch o) {
    +  825  12
                 return new CompareToBuilder()
    +  826  6
                         .append(confidence, o.confidence)
    +  827  6
                         .append(evidenceConfidence, o.evidenceConfidence)
    +  828  6
                         .append(identifier, o.identifier)
    +  829  6
                         .toComparison();
    +  830   +
             }
    +  831   +
         }
    +  832  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CentralAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CentralAnalyzer.html index 25da0013a..45b72a709 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CentralAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CentralAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    CentralAnalyzer
    24%
    18/74
    9%
    3/32
    4
    CentralAnalyzer
    25%
    19/74
    9%
    3/32
    4
     
    @@ -202,7 +202,7 @@
         @Override
     95  
         public boolean isEnabled() {
    -  96  0
             return enabled;
    +  96  864
             return enabled;
     97  
         }
     98   @@ -294,7 +294,7 @@
         @Override
     153  
         public String getName() {
    -  154  22
             return ANALYZER_NAME;
    +  154  20
             return ANALYZER_NAME;
     155  
         }
     156   @@ -315,7 +315,7 @@
         @Override
     164  
         protected String getAnalyzerEnabledSettingKey() {
    -  165  8
             return Settings.KEYS.ANALYZER_CENTRAL_ENABLED;
    +  165  2
             return Settings.KEYS.ANALYZER_CENTRAL_ENABLED;
     166  
         }
     167   @@ -352,7 +352,7 @@
         @Override
     184  
         protected FileFilter getFileFilter() {
    -  185  862
             return FILTER;
    +  185  858
             return FILTER;
     186  
         }
     187   @@ -374,7 +374,7 @@  195  
         @Override
     196   -
         public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
    +
         public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
     197  0
             if (errorFlag || !isEnabled()) {
     198  0
                 return;
     199   @@ -443,6 +443,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer.html index d08378f5d..93dfc17e1 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer.html @@ -175,7 +175,7 @@
         @Override
     81  
         protected FileFilter getFileFilter() {
    -  82  863
             return PODSPEC_FILTER;
    +  82  859
             return PODSPEC_FILTER;
     83  
         }
     84   @@ -203,7 +203,7 @@
         @Override
     96  
         public String getName() {
    -  97  21
             return ANALYZER_NAME;
    +  97  17
             return ANALYZER_NAME;
     98  
         }
     99   @@ -243,7 +243,7 @@
         @Override
     117  
         protected String getAnalyzerEnabledSettingKey() {
    -  118  14
             return Settings.KEYS.ANALYZER_COCOAPODS_ENABLED;
    +  118  8
             return Settings.KEYS.ANALYZER_COCOAPODS_ENABLED;
     119  
         }
     120   @@ -251,7 +251,7 @@  121  
         @Override
     122   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     123  
                 throws AnalysisException {
     124   @@ -380,6 +380,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer.html index cafbcee75..344a2b301 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer.html @@ -164,7 +164,7 @@
         @Override
     75  
         protected FileFilter getFileFilter() {
    -  76  863
             return FILE_FILTER;
    +  76  859
             return FILE_FILTER;
     77  
         }
     78   @@ -212,7 +212,7 @@  102  
         @Override
     103   -
         protected void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
    +
         protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
     104  1
             FileInputStream fis = null;
     105  
             try {
    @@ -267,7 +267,7 @@
         @Override
     144  
         protected String getAnalyzerEnabledSettingKey() {
    -  145  13
             return Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED;
    +  145  7
             return Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED;
     146  
         }
     147   @@ -286,7 +286,7 @@
         @Override
     154  
         public String getName() {
    -  155  21
             return ANALYZER_NAME;
    +  155  17
             return ANALYZER_NAME;
     156  
         }
     157   @@ -336,6 +336,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer.html index bae628e0a..2a6930830 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    CpeSuppressionAnalyzer
    90%
    9/10
    66%
    4/6
    2.333
    CpeSuppressionAnalyzer
    90%
    10/11
    66%
    4/6
    2
     
    @@ -62,103 +62,126 @@  22  
     import org.owasp.dependencycheck.dependency.Dependency;
     23   -
     import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
    +
     import org.owasp.dependencycheck.utils.Settings;
     24   -
     
    +
     import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
     25   -
     /**
    +
     
     26   -
      * The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
    +
     /**
     27   -
      * Any identified CPE entries within the dependencies that match will be removed.
    +
      * The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
     28   -
      *
    +
      * Any identified CPE entries within the dependencies that match will be removed.
     29   -
      * @author Jeremy Long
    +
      *
     30   +
      * @author Jeremy Long
    +  31  
      */
    -  31  8
     public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
    -  32   -
     
    +  32  8
     public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
     33   -
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
    +
     
     34   -
         /**
    +
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
     35   -
          * The name of the analyzer.
    +
         /**
     36   -
          */
    +
          * The name of the analyzer.
     37   -
         private static final String ANALYZER_NAME = "Cpe Suppression Analyzer";
    +
          */
     38   -
         /**
    +
         private static final String ANALYZER_NAME = "Cpe Suppression Analyzer";
     39   -
          * The phase that this analyzer is intended to run in.
    +
         /**
     40   +
          * The phase that this analyzer is intended to run in.
    +  41  
          */
    -  41  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
    -  42   -
     
    +  42  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
     43   -
         /**
    +
     
     44   -
          * Returns the name of the analyzer.
    -  45   -
          *
    -  46   -
          * @return the name of the analyzer.
    -  47   -
          */
    -  48   -
         @Override
    -  49   -
         public String getName() {
    -  50  26
             return ANALYZER_NAME;
    -  51   -
         }
    -  52   -
     
    -  53  
         /**
    -  54   -
          * Returns the phase that the analyzer is intended to run in.
    -  55   +  45   +
          * Returns the name of the analyzer.
    +  46  
          *
    -  56   -
          * @return the phase that the analyzer is intended to run in.
    -  57   +  47   +
          * @return the name of the analyzer.
    +  48  
          */
    -  58   +  49  
         @Override
    -  59   -
         public AnalysisPhase getAnalysisPhase() {
    -  60  6
             return ANALYSIS_PHASE;
    -  61   +  50   +
         public String getName() {
    +  51  26
             return ANALYZER_NAME;
    +  52  
         }
    -  62   -
         //</editor-fold>
    -  63   +  53  
     
    -  64   +  54   +
         /**
    +  55   +
          * Returns the phase that the analyzer is intended to run in.
    +  56   +
          *
    +  57   +
          * @return the phase that the analyzer is intended to run in.
    +  58   +
          */
    +  59  
         @Override
    +  60   +
         public AnalysisPhase getAnalysisPhase() {
    +  61  6
             return ANALYSIS_PHASE;
    +  62   +
         }
    +  63   +
         //</editor-fold>
    +  64   +
     
     65   -
         public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
    +
         @Override
     66   +
         protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  67  
     
    -  67  4
             if (getRules() == null || getRules().size() <= 0) {
    -  68  0
                 return;
    -  69   -
             }
    +  68  4
             if (getRules() == null || getRules().size() <= 0) {
    +  69  0
                 return;
     70   +
             }
    +  71  
     
    -  71  4
             for (final SuppressionRule rule : getRules()) {
    -  72  240
                 rule.process(dependency);
    -  73  240
             }
    -  74  4
         }
    -  75   +  72  4
             for (final SuppressionRule rule : getRules()) {
    +  73  264
                 rule.process(dependency);
    +  74  264
             }
    +  75  4
         }
    +  76   +
     
    +  77   +
         /**
    +  78   +
          * <p>
    +  79   +
          * Returns the setting key to determine if the analyzer is enabled.</p>
    +  80   +
          *
    +  81   +
          * @return the key for the analyzer's enabled property
    +  82   +
          */
    +  83   +
         @Override
    +  84   +
         protected String getAnalyzerEnabledSettingKey() {
    +  85  2
             return Settings.KEYS.ANALYZER_CPE_SUPPRESSION_ENABLED;
    +  86   +
         }
    +  87  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer.html index d9c5f2918..527320780 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    DependencyBundlingAnalyzer
    42%
    85/201
    30%
    65/210
    7.2
    DependencyBundlingAnalyzer
    42%
    72/168
    31%
    54/174
    6.5
     
    @@ -82,673 +82,683 @@  32  
     import org.owasp.dependencycheck.utils.DependencyVersionUtil;
     33   -
     import org.slf4j.Logger;
    +
     import org.owasp.dependencycheck.utils.Settings;
     34   -
     import org.slf4j.LoggerFactory;
    +
     import org.slf4j.Logger;
     35   -
     
    +
     import org.slf4j.LoggerFactory;
     36   -
     /**
    +
     
     37   -
      * <p>
    +
     /**
     38   -
      * This analyzer ensures dependencies that should be grouped together, to remove
    -  39   -
      * excess noise from the report, are grouped. An example would be Spring, Spring
    -  40   -
      * Beans, Spring MVC, etc. If they are all for the same version and have the
    -  41   -
      * same relative path then these should be grouped into a single dependency
    -  42   -
      * under the core/main library.</p>
    -  43  
      * <p>
    +  39   +
      * This analyzer ensures dependencies that should be grouped together, to remove
    +  40   +
      * excess noise from the report, are grouped. An example would be Spring, Spring
    +  41   +
      * Beans, Spring MVC, etc. If they are all for the same version and have the
    +  42   +
      * same relative path then these should be grouped into a single dependency
    +  43   +
      * under the core/main library.</p>
     44   -
      * Note, this grouping only works on dependencies with identified CVE
    +
      * <p>
     45   -
      * entries</p>
    +
      * Note, this grouping only works on dependencies with identified CVE
     46   -
      *
    +
      * entries</p>
     47   -
      * @author Jeremy Long
    +
      *
     48   +
      * @author Jeremy Long
    +  49  
      */
    -  49  13
     public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
    -  50   -
     
    +  50  13
     public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
     51   -
         /**
    +
     
     52   -
          * The Logger.
    +
         /**
     53   +
          * The Logger.
    +  54  
          */
    -  54  1
         private static final Logger LOGGER = LoggerFactory.getLogger(DependencyBundlingAnalyzer.class);
    -  55   -
     
    +  55  1
         private static final Logger LOGGER = LoggerFactory.getLogger(DependencyBundlingAnalyzer.class);
     56   -
         //<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
    +
     
     57   -
         /**
    +
         //<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
     58   -
          * A pattern for obtaining the first part of a filename.
    +
         /**
     59   +
          * A pattern for obtaining the first part of a filename.
    +  60  
          */
    -  60  1
         private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z0-9]*");
    -  61   -
     
    +  61  1
         private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z0-9]*");
     62   -
         /**
    +
     
     63   -
          * a flag indicating if this analyzer has run. This analyzer only runs once.
    +
         /**
     64   +
          * a flag indicating if this analyzer has run. This analyzer only runs once.
    +  65  
          */
    -  65  13
         private boolean analyzed = false;
    -  66   -
     
    +  66  13
         private boolean analyzed = false;
     67   -
         /**
    +
     
     68   -
          * Returns a flag indicating if this analyzer has run. This analyzer only
    +
         /**
     69   -
          * runs once. Note this is currently only used in the unit tests.
    +
          * Returns a flag indicating if this analyzer has run. This analyzer only
     70   -
          *
    +
          * runs once. Note this is currently only used in the unit tests.
     71   -
          * @return a flag indicating if this analyzer has run. This analyzer only
    +
          *
     72   -
          * runs once
    +
          * @return a flag indicating if this analyzer has run. This analyzer only
     73   -
          */
    +
          * runs once
     74   +
          */
    +  75  
         protected boolean getAnalyzed() {
    -  75  3
             return analyzed;
    -  76   -
         }
    +  76  3
             return analyzed;
     77   -
     
    +
         }
     78   -
         //</editor-fold>
    +
     
     79   -
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
    -  80   -
         /**
    -  81   -
          * The name of the analyzer.
    -  82   -
          */
    -  83   -
         private static final String ANALYZER_NAME = "Dependency Bundling Analyzer";
    -  84   -
         /**
    -  85   -
          * The phase that this analyzer is intended to run in.
    -  86   -
          */
    -  87  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_FINDING_ANALYSIS;
    -  88   -
     
    -  89   -
         /**
    -  90   -
          * Returns the name of the analyzer.
    -  91   -
          *
    -  92   -
          * @return the name of the analyzer.
    -  93   -
          */
    -  94   -
         @Override
    -  95   -
         public String getName() {
    -  96  27
             return ANALYZER_NAME;
    -  97   -
         }
    -  98   -
     
    -  99   -
         /**
    -  100   -
          * Returns the phase that the analyzer is intended to run in.
    -  101   -
          *
    -  102   -
          * @return the phase that the analyzer is intended to run in.
    -  103   -
          */
    -  104   -
         @Override
    -  105   -
         public AnalysisPhase getAnalysisPhase() {
    -  106  7
             return ANALYSIS_PHASE;
    -  107   -
         }
    -  108  
         //</editor-fold>
    -  109   -
     
    -  110   +  80   +
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
    +  81  
         /**
    -  111   -
          * Does not support parallel processing as it only runs once and then
    -  112   -
          * operates on <em>all</em> dependencies.
    -  113   -
          *
    -  114   -
          * @return whether or not parallel processing is enabled
    -  115   -
          * @see #analyze(Dependency, Engine)
    -  116   +  82   +
          * The name of the analyzer.
    +  83  
          */
    -  117   -
         @Override
    -  118   -
         public boolean supportsParallelProcessing() {
    -  119  2
             return false;
    -  120   -
         }
    -  121   -
     
    -  122   +  84   +
         private static final String ANALYZER_NAME = "Dependency Bundling Analyzer";
    +  85  
         /**
    +  86   +
          * The phase that this analyzer is intended to run in.
    +  87   +
          */
    +  88  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.FINAL;
    +  89   +
     
    +  90   +
         /**
    +  91   +
          * Returns the name of the analyzer.
    +  92   +
          *
    +  93   +
          * @return the name of the analyzer.
    +  94   +
          */
    +  95   +
         @Override
    +  96   +
         public String getName() {
    +  97  27
             return ANALYZER_NAME;
    +  98   +
         }
    +  99   +
     
    +  100   +
         /**
    +  101   +
          * Returns the phase that the analyzer is intended to run in.
    +  102   +
          *
    +  103   +
          * @return the phase that the analyzer is intended to run in.
    +  104   +
          */
    +  105   +
         @Override
    +  106   +
         public AnalysisPhase getAnalysisPhase() {
    +  107  7
             return ANALYSIS_PHASE;
    +  108   +
         }
    +  109   +
         //</editor-fold>
    +  110   +
     
    +  111   +
         /**
    +  112   +
          * Does not support parallel processing as it only runs once and then
    +  113   +
          * operates on <em>all</em> dependencies.
    +  114   +
          *
    +  115   +
          * @return whether or not parallel processing is enabled
    +  116   +
          * @see #analyze(Dependency, Engine)
    +  117   +
          */
    +  118   +
         @Override
    +  119   +
         public boolean supportsParallelProcessing() {
    +  120  2
             return false;
    +  121   +
         }
    +  122   +
     
     123   -
          * Analyzes a set of dependencies. If they have been found to have the same
    +
         /**
     124   -
          * base path and the same set of identifiers they are likely related. The
    +
          * <p>
     125   -
          * related dependencies are bundled into a single reportable item.
    +
          * Returns the setting key to determine if the analyzer is enabled.</p>
     126  
          *
     127   -
          * @param ignore this analyzer ignores the dependency being analyzed
    +
          * @return the key for the analyzer's enabled property
     128   -
          * @param engine the engine that is scanning the dependencies
    +
          */
     129   -
          * @throws AnalysisException is thrown if there is an error reading the JAR
    -  130   -
          * file.
    -  131   -
          */
    -  132  
         @Override
    +  130   +
         protected String getAnalyzerEnabledSettingKey() {
    +  131  2
             return Settings.KEYS.ANALYZER_DEPENDENCY_BUNDLING_ENABLED;
    +  132   +
         }
     133   -
         public void analyze(Dependency ignore, Engine engine) throws AnalysisException {
    -  134  8
             if (!analyzed) {
    -  135  3
                 analyzed = true;
    -  136  3
                 final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
    -  137  3
                 final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
    +
     
    +  134   +
         /**
    +  135   +
          * Analyzes a set of dependencies. If they have been found to have the same
    +  136   +
          * base path and the same set of identifiers they are likely related. The
    +  137   +
          * related dependencies are bundled into a single reportable item.
     138   -
                 //for (Dependency nextDependency : engine.getDependencies()) {
    -  139  7
                 while (mainIterator.hasNext()) {
    -  140  4
                     final Dependency dependency = mainIterator.next();
    -  141  4
                     if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
    -  142  2
                         final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
    -  143  4
                         while (subIterator.hasNext()) {
    -  144  2
                             final Dependency nextDependency = subIterator.next();
    -  145  2
                             Dependency main = null;
    -  146  2
                             if (hashesMatch(dependency, nextDependency) && !containedInWar(dependency.getFilePath())
    -  147  0
                                     && !containedInWar(nextDependency.getFilePath())) {
    -  148  0
                                 if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
    -  149  0
                                     mergeDependencies(dependency, nextDependency, dependenciesToRemove);
    +
          *
    +  139   +
          * @param ignore this analyzer ignores the dependency being analyzed
    +  140   +
          * @param engine the engine that is scanning the dependencies
    +  141   +
          * @throws AnalysisException is thrown if there is an error reading the JAR
    +  142   +
          * file.
    +  143   +
          */
    +  144   +
         @Override
    +  145   +
         protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
    +  146  8
             if (!analyzed) {
    +  147  3
                 analyzed = true;
    +  148  3
                 final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
    +  149  3
                 final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
     150   -
                                 } else {
    -  151  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    -  152  0
                                     break; //since we merged into the next dependency - skip forward to the next in mainIterator
    -  153   -
                                 }
    -  154  2
                             } else if (isShadedJar(dependency, nextDependency)) {
    -  155  0
                                 if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
    -  156  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    -  157  0
                                     nextDependency.getRelatedDependencies().remove(dependency);
    -  158  0
                                     break;
    -  159   -
                                 } else {
    +
                 //for (Dependency nextDependency : engine.getDependencies()) {
    +  151  7
                 while (mainIterator.hasNext()) {
    +  152  4
                     final Dependency dependency = mainIterator.next();
    +  153  4
                     if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
    +  154  2
                         final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
    +  155  4
                         while (subIterator.hasNext()) {
    +  156  2
                             final Dependency nextDependency = subIterator.next();
    +  157  2
                             if (hashesMatch(dependency, nextDependency) && !containedInWar(dependency.getFilePath())
    +  158  0
                                     && !containedInWar(nextDependency.getFilePath())) {
    +  159  0
                                 if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
     160  0
                                     mergeDependencies(dependency, nextDependency, dependenciesToRemove);
    -  161  0
                                     dependency.getRelatedDependencies().remove(nextDependency);
    -  162   -
                                 }
    -  163  2
                             } else if (cpeIdentifiersMatch(dependency, nextDependency)
    -  164  0
                                     && hasSameBasePath(dependency, nextDependency)
    -  165  0
                                     && fileNameMatch(dependency, nextDependency)) {
    -  166  0
                                 if (isCore(dependency, nextDependency)) {
    -  167  0
                                     mergeDependencies(dependency, nextDependency, dependenciesToRemove);
    -  168   +  161  
                                 } else {
    -  169  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    -  170  0
                                     break; //since we merged into the next dependency - skip forward to the next in mainIterator
    -  171   +  162  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    +  163  0
                                     break; //since we merged into the next dependency - skip forward to the next in mainIterator
    +  164  
                                 }
    -  172  2
                             } else if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
    -  173  0
                                 if (main == dependency) {
    -  174  0
                                     mergeDependencies(dependency, nextDependency, dependenciesToRemove);
    -  175   +  165  2
                             } else if (isShadedJar(dependency, nextDependency)) {
    +  166  0
                                 if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
    +  167  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    +  168  0
                                     nextDependency.getRelatedDependencies().remove(dependency);
    +  169  0
                                     break;
    +  170  
                                 } else {
    -  176  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    -  177  0
                                     break; //since we merged into the next dependency - skip forward to the next in mainIterator
    -  178   +  171  0
                                     mergeDependencies(dependency, nextDependency, dependenciesToRemove);
    +  172  0
                                     dependency.getRelatedDependencies().remove(nextDependency);
    +  173  
                                 }
    -  179  2
                             } else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) {
    -  180  0
                                 if (main == dependency) {
    -  181  0
                                     mergeDependencies(dependency, nextDependency, dependenciesToRemove);
    -  182   +  174  2
                             } else if (cpeIdentifiersMatch(dependency, nextDependency)
    +  175  0
                                     && hasSameBasePath(dependency, nextDependency)
    +  176  0
                                     && vulnCountMatches(dependency, nextDependency)
    +  177  0
                                     && fileNameMatch(dependency, nextDependency)) {
    +  178  0
                                 if (isCore(dependency, nextDependency)) {
    +  179  0
                                     mergeDependencies(dependency, nextDependency, dependenciesToRemove);
    +  180  
                                 } else {
    -  183  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    -  184  0
                                     break; //since we merged into the next dependency - skip forward to the next in mainIterator
    -  185   +  181  0
                                     mergeDependencies(nextDependency, dependency, dependenciesToRemove);
    +  182  0
                                     break; //since we merged into the next dependency - skip forward to the next in mainIterator
    +  183  
                                 }
    -  186   +  184  
                             }
    -  187  2
                         }
    -  188   +  185  2
                         }
    +  186  
                     }
    -  189  4
                 }
    -  190   +  187  4
                 }
    +  188  
                 //removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
    -  191   +  189  
                 // was difficult because of the inner iterator.
    -  192  3
                 engine.getDependencies().removeAll(dependenciesToRemove);
    +  190  3
                 engine.getDependencies().removeAll(dependenciesToRemove);
    +  191   +
             }
    +  192  8
         }
     193   -
             }
    -  194  8
         }
    +
     
    +  194   +
         /**
     195   -
     
    -  196   -
         /**
    -  197  
          * Adds the relatedDependency to the dependency's related dependencies.
    -  198   +  196  
          *
    -  199   +  197  
          * @param dependency the main dependency
    -  200   +  198  
          * @param relatedDependency a collection of dependencies to be removed from
    -  201   +  199  
          * the main analysis loop, this is the source of dependencies to remove
    -  202   +  200  
          * @param dependenciesToRemove a collection of dependencies that will be
    -  203   +  201  
          * removed from the main analysis loop, this function adds to this
    -  204   +  202  
          * collection
    -  205   +  203  
          */
    -  206   +  204  
         private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
    -  207  0
             dependency.addRelatedDependency(relatedDependency);
    -  208  0
             final Iterator<Dependency> i = relatedDependency.getRelatedDependencies().iterator();
    -  209  0
             while (i.hasNext()) {
    -  210  0
                 dependency.addRelatedDependency(i.next());
    -  211  0
                 i.remove();
    -  212   +  205  0
             dependency.addRelatedDependency(relatedDependency);
    +  206  0
             final Iterator<Dependency> i = relatedDependency.getRelatedDependencies().iterator();
    +  207  0
             while (i.hasNext()) {
    +  208  0
                 dependency.addRelatedDependency(i.next());
    +  209  0
                 i.remove();
    +  210  
             }
    -  213  0
             if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
    -  214  0
                 dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
    -  215   +  211  0
             if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
    +  212  0
                 dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
    +  213  
             }
    -  216  0
             dependenciesToRemove.add(relatedDependency);
    -  217  0
         }
    -  218   +  214  0
             dependenciesToRemove.add(relatedDependency);
    +  215  0
         }
    +  216  
     
    -  219   +  217  
         /**
    -  220   +  218  
          * Attempts to trim a maven repo to a common base path. This is typically
    -  221   +  219  
          * [drive]\[repo_location]\repository\[path1]\[path2].
    -  222   +  220  
          *
    -  223   +  221  
          * @param path the path to trim
    -  224   +  222  
          * @return a string representing the base path.
    -  225   +  223  
          */
    -  226   +  224  
         private String getBaseRepoPath(final String path) {
    -  227  0
             int pos = path.indexOf("repository" + File.separator) + 11;
    -  228  0
             if (pos < 0) {
    -  229  0
                 return path;
    +  225   +
             int pos;
    +  226  0
             if (path.contains("local-repo")) {
    +  227  0
                 pos = path.indexOf("local-repo" + File.separator) + 11;
    +  228   +
             } else {
    +  229  0
                 pos = path.indexOf("repository" + File.separator) + 11;
     230  
             }
    -  231  0
             int tmp = path.indexOf(File.separator, pos);
    -  232  0
             if (tmp <= 0) {
    -  233  0
                 return path;
    -  234   +  231  0
             if (pos < 0) {
    +  232  0
                 return path;
    +  233  
             }
    -  235  0
             if (tmp > 0) {
    -  236  0
                 pos = tmp + 1;
    +  234  0
             int tmp = path.indexOf(File.separator, pos);
    +  235  0
             if (tmp <= 0) {
    +  236  0
                 return path;
     237  
             }
    -  238  0
             tmp = path.indexOf(File.separator, pos);
    -  239  0
             if (tmp > 0) {
    -  240  0
                 pos = tmp + 1;
    -  241   +  238  0
             if (tmp > 0) {
    +  239  0
                 pos = tmp + 1;
    +  240  
             }
    -  242  0
             return path.substring(0, pos);
    -  243   -
         }
    +  241  0
             tmp = path.indexOf(File.separator, pos);
    +  242  0
             if (tmp > 0) {
    +  243  0
                 pos = tmp + 1;
     244   -
     
    -  245   -
         /**
    +
             }
    +  245  0
             return path.substring(0, pos);
     246   -
          * Returns true if the file names (and version if it exists) of the two
    -  247   -
          * dependencies are sufficiently similar.
    -  248   -
          *
    -  249   -
          * @param dependency1 a dependency2 to compare
    -  250   -
          * @param dependency2 a dependency2 to compare
    -  251   -
          * @return true if the identifiers in the two supplied dependencies are
    -  252   -
          * equal
    -  253   -
          */
    -  254   -
         private boolean fileNameMatch(Dependency dependency1, Dependency dependency2) {
    -  255  0
             if (dependency1 == null || dependency1.getFileName() == null
    -  256  0
                     || dependency2 == null || dependency2.getFileName() == null) {
    -  257  0
                 return false;
    -  258   -
             }
    -  259  0
             final String fileName1 = dependency1.getActualFile().getName();
    -  260  0
             final String fileName2 = dependency2.getActualFile().getName();
    -  261   -
     
    -  262   -
             //version check
    -  263  0
             final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
    -  264  0
             final DependencyVersion version2 = DependencyVersionUtil.parseVersion(fileName2);
    -  265  0
             if (version1 != null && version2 != null && !version1.equals(version2)) {
    -  266  0
                 return false;
    -  267   -
             }
    -  268   -
     
    -  269   -
             //filename check
    -  270  0
             final Matcher match1 = STARTING_TEXT_PATTERN.matcher(fileName1);
    -  271  0
             final Matcher match2 = STARTING_TEXT_PATTERN.matcher(fileName2);
    -  272  0
             if (match1.find() && match2.find()) {
    -  273  0
                 return match1.group().equals(match2.group());
    -  274   -
             }
    -  275   -
     
    -  276  0
             return false;
    -  277  
         }
    +  247   +
     
    +  248   +
         /**
    +  249   +
          * Returns true if the file names (and version if it exists) of the two
    +  250   +
          * dependencies are sufficiently similar.
    +  251   +
          *
    +  252   +
          * @param dependency1 a dependency2 to compare
    +  253   +
          * @param dependency2 a dependency2 to compare
    +  254   +
          * @return true if the identifiers in the two supplied dependencies are
    +  255   +
          * equal
    +  256   +
          */
    +  257   +
         private boolean fileNameMatch(Dependency dependency1, Dependency dependency2) {
    +  258  0
             if (dependency1 == null || dependency1.getFileName() == null
    +  259  0
                     || dependency2 == null || dependency2.getFileName() == null) {
    +  260  0
                 return false;
    +  261   +
             }
    +  262  0
             final String fileName1 = dependency1.getActualFile().getName();
    +  263  0
             final String fileName2 = dependency2.getActualFile().getName();
    +  264   +
     
    +  265   +
             //version check
    +  266  0
             final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
    +  267  0
             final DependencyVersion version2 = DependencyVersionUtil.parseVersion(fileName2);
    +  268  0
             if (version1 != null && version2 != null && !version1.equals(version2)) {
    +  269  0
                 return false;
    +  270   +
             }
    +  271   +
     
    +  272   +
             //filename check
    +  273  0
             final Matcher match1 = STARTING_TEXT_PATTERN.matcher(fileName1);
    +  274  0
             final Matcher match2 = STARTING_TEXT_PATTERN.matcher(fileName2);
    +  275  0
             if (match1.find() && match2.find()) {
    +  276  0
                 return match1.group().equals(match2.group());
    +  277   +
             }
     278  
     
    -  279   -
         /**
    +  279  0
             return false;
     280   -
          * Returns true if the CPE identifiers in the two supplied dependencies are
    +
         }
     281   -
          * equal.
    +
     
     282   -
          *
    -  283   -
          * @param dependency1 a dependency2 to compare
    -  284   -
          * @param dependency2 a dependency2 to compare
    -  285   -
          * @return true if the identifiers in the two supplied dependencies are
    -  286   -
          * equal
    -  287   -
          */
    -  288   -
         private boolean cpeIdentifiersMatch(Dependency dependency1, Dependency dependency2) {
    -  289  2
             if (dependency1 == null || dependency1.getIdentifiers() == null
    -  290  2
                     || dependency2 == null || dependency2.getIdentifiers() == null) {
    -  291  0
                 return false;
    -  292   -
             }
    -  293  2
             boolean matches = false;
    -  294  2
             int cpeCount1 = 0;
    -  295  2
             int cpeCount2 = 0;
    -  296  2
             for (Identifier i : dependency1.getIdentifiers()) {
    -  297  0
                 if ("cpe".equals(i.getType())) {
    -  298  0
                     cpeCount1 += 1;
    -  299   -
                 }
    -  300  0
             }
    -  301  2
             for (Identifier i : dependency2.getIdentifiers()) {
    -  302  4
                 if ("cpe".equals(i.getType())) {
    -  303  4
                     cpeCount2 += 1;
    -  304   -
                 }
    -  305  4
             }
    -  306  2
             if (cpeCount1 > 0 && cpeCount1 == cpeCount2) {
    -  307  0
                 for (Identifier i : dependency1.getIdentifiers()) {
    -  308  0
                     if ("cpe".equals(i.getType())) {
    -  309  0
                         matches |= dependency2.getIdentifiers().contains(i);
    -  310  0
                         if (!matches) {
    -  311  0
                             break;
    -  312   -
                         }
    -  313   -
                     }
    -  314  0
                 }
    -  315   -
             }
    -  316  2
             LOGGER.debug("IdentifiersMatch={} ({}, {})", matches, dependency1.getFileName(), dependency2.getFileName());
    -  317  2
             return matches;
    -  318   -
         }
    -  319   -
     
    -  320  
         /**
    -  321   -
          * Determines if the two dependencies have the same base path.
    -  322   +  283   +
          * Returns true if the CPE identifiers in the two supplied dependencies are
    +  284   +
          * equal.
    +  285  
          *
    -  323   -
          * @param dependency1 a Dependency object
    -  324   -
          * @param dependency2 a Dependency object
    -  325   -
          * @return true if the base paths of the dependencies are identical
    -  326   +  286   +
          * @param dependency1 a dependency2 to compare
    +  287   +
          * @param dependency2 a dependency2 to compare
    +  288   +
          * @return true if the identifiers in the two supplied dependencies are
    +  289   +
          * equal
    +  290  
          */
    -  327   -
         private boolean hasSameBasePath(Dependency dependency1, Dependency dependency2) {
    -  328  0
             if (dependency1 == null || dependency2 == null) {
    -  329  0
                 return false;
    -  330   +  291   +
         private boolean cpeIdentifiersMatch(Dependency dependency1, Dependency dependency2) {
    +  292  2
             if (dependency1 == null || dependency1.getIdentifiers() == null
    +  293  2
                     || dependency2 == null || dependency2.getIdentifiers() == null) {
    +  294  0
                 return false;
    +  295  
             }
    -  331  0
             final File lFile = new File(dependency1.getFilePath());
    -  332  0
             String left = lFile.getParent();
    -  333  0
             final File rFile = new File(dependency2.getFilePath());
    -  334  0
             String right = rFile.getParent();
    -  335  0
             if (left == null) {
    -  336  0
                 return right == null;
    -  337  0
             } else if (right == null) {
    -  338  0
                 return false;
    -  339   -
             }
    -  340  0
             if (left.equalsIgnoreCase(right)) {
    -  341  0
                 return true;
    -  342   -
             }
    -  343   -
     
    -  344  0
             if (left.matches(".*[/\\\\]repository[/\\\\].*") && right.matches(".*[/\\\\]repository[/\\\\].*")) {
    -  345  0
                 left = getBaseRepoPath(left);
    -  346  0
                 right = getBaseRepoPath(right);
    -  347   -
             }
    -  348  0
             if (left.equalsIgnoreCase(right)) {
    -  349  0
                 return true;
    -  350   -
             }
    -  351   -
             //new code
    -  352  0
             for (Dependency child : dependency2.getRelatedDependencies()) {
    -  353  0
                 if (hasSameBasePath(dependency1, child)) {
    -  354  0
                     return true;
    -  355   +  296  2
             boolean matches = false;
    +  297  2
             int cpeCount1 = 0;
    +  298  2
             int cpeCount2 = 0;
    +  299  2
             for (Identifier i : dependency1.getIdentifiers()) {
    +  300  0
                 if ("cpe".equals(i.getType())) {
    +  301  0
                     cpeCount1 += 1;
    +  302  
                 }
    -  356  0
             }
    -  357  0
             return false;
    -  358   +  303  0
             }
    +  304  2
             for (Identifier i : dependency2.getIdentifiers()) {
    +  305  4
                 if ("cpe".equals(i.getType())) {
    +  306  4
                     cpeCount2 += 1;
    +  307   +
                 }
    +  308  4
             }
    +  309  2
             if (cpeCount1 > 0 && cpeCount1 == cpeCount2) {
    +  310  0
                 for (Identifier i : dependency1.getIdentifiers()) {
    +  311  0
                     if ("cpe".equals(i.getType())) {
    +  312  0
                         matches |= dependency2.getIdentifiers().contains(i);
    +  313  0
                         if (!matches) {
    +  314  0
                             break;
    +  315   +
                         }
    +  316   +
                     }
    +  317  0
                 }
    +  318   +
             }
    +  319  2
             LOGGER.debug("IdentifiersMatch={} ({}, {})", matches, dependency1.getFileName(), dependency2.getFileName());
    +  320  2
             return matches;
    +  321  
         }
    +  322   +
     
    +  323   +
         /**
    +  324   +
          * Returns true if the two dependencies have the same vulnerability count.
    +  325   +
          *
    +  326   +
          * @param dependency1 a dependency2 to compare
    +  327   +
          * @param dependency2 a dependency2 to compare
    +  328   +
          * @return true if the two dependencies have the same vulnerability count
    +  329   +
          */
    +  330   +
         private boolean vulnCountMatches(Dependency dependency1, Dependency dependency2) {
    +  331  0
             return dependency1.getVulnerabilities() != null && dependency2.getVulnerabilities() != null
    +  332  0
                     && dependency1.getVulnerabilities().size() == dependency2.getVulnerabilities().size();
    +  333   +
     
    +  334   +
         }
    +  335   +
     
    +  336   +
         /**
    +  337   +
          * Determines if the two dependencies have the same base path.
    +  338   +
          *
    +  339   +
          * @param dependency1 a Dependency object
    +  340   +
          * @param dependency2 a Dependency object
    +  341   +
          * @return true if the base paths of the dependencies are identical
    +  342   +
          */
    +  343   +
         private boolean hasSameBasePath(Dependency dependency1, Dependency dependency2) {
    +  344  0
             if (dependency1 == null || dependency2 == null) {
    +  345  0
                 return false;
    +  346   +
             }
    +  347  0
             final File lFile = new File(dependency1.getFilePath());
    +  348  0
             String left = lFile.getParent();
    +  349  0
             final File rFile = new File(dependency2.getFilePath());
    +  350  0
             String right = rFile.getParent();
    +  351  0
             if (left == null) {
    +  352  0
                 return right == null;
    +  353  0
             } else if (right == null) {
    +  354  0
                 return false;
    +  355   +
             }
    +  356  0
             if (left.equalsIgnoreCase(right)) {
    +  357  0
                 return true;
    +  358   +
             }
     359  
     
    -  360   -
         /**
    -  361   -
          * Bundling Ruby gems that are identified from different .gemspec files but
    -  362   -
          * denote the same package path. This happens when Ruby bundler installs an
    +  360  0
             if (left.matches(".*[/\\\\](repository|local-repo)[/\\\\].*") && right.matches(".*[/\\\\](repository|local-repo)[/\\\\].*")) {
    +  361  0
                 left = getBaseRepoPath(left);
    +  362  0
                 right = getBaseRepoPath(right);
     363   -
          * application's dependencies by running "bundle install".
    -  364   -
          *
    -  365   -
          * @param dependency1 dependency to compare
    +
             }
    +  364  0
             if (left.equalsIgnoreCase(right)) {
    +  365  0
                 return true;
     366   -
          * @param dependency2 dependency to compare
    +
             }
     367   -
          * @return true if the the dependencies being analyzed appear to be the
    -  368   -
          * same; otherwise false
    -  369   -
          */
    -  370   -
         private boolean isSameRubyGem(Dependency dependency1, Dependency dependency2) {
    -  371  2
             if (dependency1 == null || dependency2 == null
    -  372  2
                     || !dependency1.getFileName().endsWith(".gemspec")
    -  373  0
                     || !dependency2.getFileName().endsWith(".gemspec")
    -  374  0
                     || dependency1.getPackagePath() == null
    -  375  0
                     || dependency2.getPackagePath() == null) {
    -  376  2
                 return false;
    +
             //new code
    +  368  0
             for (Dependency child : dependency2.getRelatedDependencies()) {
    +  369  0
                 if (hasSameBasePath(dependency1, child)) {
    +  370  0
                     return true;
    +  371   +
                 }
    +  372  0
             }
    +  373  0
             return false;
    +  374   +
         }
    +  375   +
     
    +  376   +
         /**
     377   -
             }
    -  378  0
             return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
    +
          * This is likely a very broken attempt at determining if the 'left'
    +  378   +
          * dependency is the 'core' library in comparison to the 'right' library.
     379   -
         }
    +
          *
     380   -
     
    +
          * @param left the dependency to test
     381   -
         /**
    +
          * @param right the dependency to test against
     382   -
          * Ruby gems installed by "bundle install" can have zero or more *.gemspec
    +
          * @return a boolean indicating whether or not the left dependency should be
     383   -
          * files, all of which have the same packagePath and should be grouped. If
    +
          * considered the "core" version.
     384   -
          * one of these gemspec is from <parent>/specifications/*.gemspec, because
    +
          */
     385   -
          * it is a stub with fully resolved gem meta-data created by Ruby bundler,
    -  386   -
          * this dependency should be the main one. Otherwise, use dependency2 as
    -  387   -
          * main.
    +
         boolean isCore(Dependency left, Dependency right) {
    +  386  2
             final String leftName = left.getFileName().toLowerCase();
    +  387  2
             final String rightName = right.getFileName().toLowerCase();
     388   -
          *
    +
     
     389   -
          * This method returns null if any dependency is not from *.gemspec, or the
    -  390   -
          * two do not have the same packagePath. In this case, they should not be
    -  391   -
          * grouped.
    -  392   -
          *
    -  393   -
          * @param dependency1 dependency to compare
    -  394   -
          * @param dependency2 dependency to compare
    -  395   -
          * @return the main dependency; or null if a gemspec is not included in the
    -  396   -
          * analysis
    -  397   -
          */
    +
             final boolean returnVal;
    +  390  2
             if (!rightName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+") && leftName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+")
    +  391  2
                     || rightName.contains("core") && !leftName.contains("core")
    +  392  2
                     || rightName.contains("kernel") && !leftName.contains("kernel")) {
    +  393  0
                 returnVal = false;
    +  394  2
             } else if (rightName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+") && !leftName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+")
    +  395  1
                     || !rightName.contains("core") && leftName.contains("core")
    +  396  1
                     || !rightName.contains("kernel") && leftName.contains("kernel")) {
    +  397  2
                 returnVal = true;
     398   -
         private Dependency getMainGemspecDependency(Dependency dependency1, Dependency dependency2) {
    -  399  2
             if (isSameRubyGem(dependency1, dependency2)) {
    -  400  0
                 final File lFile = dependency1.getActualFile();
    -  401  0
                 final File left = lFile.getParentFile();
    -  402  0
                 if (left != null && left.getName().equalsIgnoreCase("specifications")) {
    -  403  0
                     return dependency1;
    +
             } else {
    +  399   +
                 /*
    +  400   +
                  * considered splitting the names up and comparing the components,
    +  401   +
                  * but decided that the file name length should be sufficient as the
    +  402   +
                  * "core" component, if this follows a normal naming protocol should
    +  403   +
                  * be shorter:
     404   -
                 }
    -  405  0
                 return dependency2;
    +
                  * axis2-saaj-1.4.1.jar
    +  405   +
                  * axis2-1.4.1.jar       <-----
     406   -
             }
    -  407  2
             return null;
    -  408   -
         }
    +
                  * axis2-kernel-1.4.1.jar
    +  407   +
                  */
    +  408  0
                 returnVal = leftName.length() <= rightName.length();
     409   -
     
    -  410   -
         /**
    -  411   -
          * Bundling same swift dependencies with the same packagePath but identified
    -  412   -
          * by different analyzers.
    -  413   -
          *
    -  414   -
          * @param dependency1 dependency to test
    -  415   -
          * @param dependency2 dependency to test
    -  416   -
          * @return <code>true</code> if the dependencies appear to be the same;
    -  417   -
          * otherwise <code>false</code>
    -  418   -
          */
    -  419   -
         private boolean isSameSwiftPackage(Dependency dependency1, Dependency dependency2) {
    -  420  2
             if (dependency1 == null || dependency2 == null
    -  421  2
                     || (!dependency1.getFileName().endsWith(".podspec")
    -  422  2
                     && !dependency1.getFileName().equals("Package.swift"))
    -  423  0
                     || (!dependency2.getFileName().endsWith(".podspec")
    -  424  0
                     && !dependency2.getFileName().equals("Package.swift"))
    -  425  0
                     || dependency1.getPackagePath() == null
    -  426  0
                     || dependency2.getPackagePath() == null) {
    -  427  2
                 return false;
    -  428  
             }
    -  429  0
             return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
    -  430   +  410  2
             LOGGER.debug("IsCore={} ({}, {})", returnVal, left.getFileName(), right.getFileName());
    +  411  2
             return returnVal;
    +  412  
         }
    -  431   +  413  
     
    -  432   +  414  
         /**
    -  433   -
          * Determines which of the swift dependencies should be considered the
    -  434   -
          * primary.
    -  435   +  415   +
          * Compares the SHA1 hashes of two dependencies to determine if they are
    +  416   +
          * equal.
    +  417  
          *
    -  436   -
          * @param dependency1 the first swift dependency to compare
    -  437   -
          * @param dependency2 the second swift dependency to compare
    -  438   -
          * @return the primary swift dependency
    -  439   +  418   +
          * @param dependency1 a dependency object to compare
    +  419   +
          * @param dependency2 a dependency object to compare
    +  420   +
          * @return true if the sha1 hashes of the two dependencies match; otherwise
    +  421   +
          * false
    +  422  
          */
    -  440   -
         private Dependency getMainSwiftDependency(Dependency dependency1, Dependency dependency2) {
    -  441  2
             if (isSameSwiftPackage(dependency1, dependency2)) {
    -  442  0
                 if (dependency1.getFileName().endsWith(".podspec")) {
    -  443  0
                     return dependency1;
    -  444   -
                 }
    -  445  0
                 return dependency2;
    +  423   +
         private boolean hashesMatch(Dependency dependency1, Dependency dependency2) {
    +  424  2
             if (dependency1 == null || dependency2 == null || dependency1.getSha1sum() == null || dependency2.getSha1sum() == null) {
    +  425  0
                 return false;
    +  426   +
             }
    +  427  2
             return dependency1.getSha1sum().equals(dependency2.getSha1sum());
    +  428   +
         }
    +  429   +
     
    +  430   +
         /**
    +  431   +
          * Determines if the jar is shaded and the created pom.xml identified the
    +  432   +
          * same CPE as the jar - if so, the pom.xml dependency should be removed.
    +  433   +
          *
    +  434   +
          * @param dependency a dependency to check
    +  435   +
          * @param nextDependency another dependency to check
    +  436   +
          * @return true if on of the dependencies is a pom.xml and the identifiers
    +  437   +
          * between the two collections match; otherwise false
    +  438   +
          */
    +  439   +
         private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
    +  440  2
             final String mainName = dependency.getFileName().toLowerCase();
    +  441  2
             final String nextName = nextDependency.getFileName().toLowerCase();
    +  442  2
             if (mainName.endsWith(".jar") && nextName.endsWith("pom.xml")) {
    +  443  0
                 return dependency.getIdentifiers().containsAll(nextDependency.getIdentifiers());
    +  444  2
             } else if (nextName.endsWith(".jar") && mainName.endsWith("pom.xml")) {
    +  445  0
                 return nextDependency.getIdentifiers().containsAll(dependency.getIdentifiers());
     446  
             }
    -  447  2
             return null;
    +  447  2
             return false;
     448  
         }
     449   @@ -756,228 +766,97 @@  450  
         /**
     451   -
          * This is likely a very broken attempt at determining if the 'left'
    +
          * Determines which path is shortest; if path lengths are equal then we use
     452   -
          * dependency is the 'core' library in comparison to the 'right' library.
    +
          * compareTo of the string method to determine if the first path is smaller.
     453  
          *
     454   -
          * @param left the dependency to test
    +
          * @param left the first path to compare
     455   -
          * @param right the dependency to test against
    +
          * @param right the second path to compare
     456   -
          * @return a boolean indicating whether or not the left dependency should be
    +
          * @return <code>true</code> if the leftPath is the shortest; otherwise
     457   -
          * considered the "core" version.
    +
          * <code>false</code>
     458  
          */
     459   -
         boolean isCore(Dependency left, Dependency right) {
    -  460  2
             final String leftName = left.getFileName().toLowerCase();
    -  461  2
             final String rightName = right.getFileName().toLowerCase();
    +
         protected boolean firstPathIsShortest(String left, String right) {
    +  460  5
             if (left.contains("dctemp")) {
    +  461  0
                 return false;
     462   -
     
    -  463   -
             final boolean returnVal;
    -  464  2
             if (!rightName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+") && leftName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+")
    -  465  2
                     || rightName.contains("core") && !leftName.contains("core")
    -  466  2
                     || rightName.contains("kernel") && !leftName.contains("kernel")) {
    -  467  0
                 returnVal = false;
    -  468  2
             } else if (rightName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+") && !leftName.matches(".*\\.(tar|tgz|gz|zip|ear|war).+")
    -  469  1
                     || !rightName.contains("core") && leftName.contains("core")
    -  470  1
                     || !rightName.contains("kernel") && leftName.contains("kernel")) {
    -  471  2
                 returnVal = true;
    -  472   -
     //        } else if (leftName.matches(".*struts2\\-core.*") && rightName.matches(".*xwork\\-core.*")) {
    -  473   -
     //            returnVal = true;
    -  474   -
     //        } else if (rightName.matches(".*struts2\\-core.*") && leftName.matches(".*xwork\\-core.*")) {
    -  475   -
     //            returnVal = false;
    -  476   -
             } else {
    -  477   -
                 /*
    -  478   -
                  * considered splitting the names up and comparing the components,
    -  479   -
                  * but decided that the file name length should be sufficient as the
    -  480   -
                  * "core" component, if this follows a normal naming protocol should
    -  481   -
                  * be shorter:
    -  482   -
                  * axis2-saaj-1.4.1.jar
    -  483   -
                  * axis2-1.4.1.jar       <-----
    -  484   -
                  * axis2-kernel-1.4.1.jar
    -  485   -
                  */
    -  486  0
                 returnVal = leftName.length() <= rightName.length();
    -  487  
             }
    -  488  2
             LOGGER.debug("IsCore={} ({}, {})", returnVal, left.getFileName(), right.getFileName());
    -  489  2
             return returnVal;
    -  490   -
         }
    -  491   +  463  5
             final String leftPath = left.replace('\\', '/');
    +  464  5
             final String rightPath = right.replace('\\', '/');
    +  465  
     
    -  492   +  466  5
             final int leftCount = countChar(leftPath, '/');
    +  467  5
             final int rightCount = countChar(rightPath, '/');
    +  468  5
             if (leftCount == rightCount) {
    +  469  3
                 return leftPath.compareTo(rightPath) <= 0;
    +  470   +
             } else {
    +  471  2
                 return leftCount < rightCount;
    +  472   +
             }
    +  473   +
         }
    +  474   +
     
    +  475  
         /**
    +  476   +
          * Counts the number of times the character is present in the string.
    +  477   +
          *
    +  478   +
          * @param string the string to count the characters in
    +  479   +
          * @param c the character to count
    +  480   +
          * @return the number of times the character is present in the string
    +  481   +
          */
    +  482   +
         private int countChar(String string, char c) {
    +  483  10
             int count = 0;
    +  484  10
             final int max = string.length();
    +  485  116
             for (int i = 0; i < max; i++) {
    +  486  106
                 if (c == string.charAt(i)) {
    +  487  28
                     count++;
    +  488   +
                 }
    +  489   +
             }
    +  490  10
             return count;
    +  491   +
         }
    +  492   +
     
     493   -
          * Compares the SHA1 hashes of two dependencies to determine if they are
    +
         /**
     494   -
          * equal.
    +
          * Checks if the given file path is contained within a war or ear file.
     495  
          *
     496   -
          * @param dependency1 a dependency object to compare
    -  497   -
          * @param dependency2 a dependency object to compare
    -  498   -
          * @return true if the sha1 hashes of the two dependencies match; otherwise
    -  499   -
          * false
    -  500   -
          */
    -  501   -
         private boolean hashesMatch(Dependency dependency1, Dependency dependency2) {
    -  502  2
             if (dependency1 == null || dependency2 == null || dependency1.getSha1sum() == null || dependency2.getSha1sum() == null) {
    -  503  0
                 return false;
    -  504   -
             }
    -  505  2
             return dependency1.getSha1sum().equals(dependency2.getSha1sum());
    -  506   -
         }
    -  507   -
     
    -  508   -
         /**
    -  509   -
          * Determines if the jar is shaded and the created pom.xml identified the
    -  510   -
          * same CPE as the jar - if so, the pom.xml dependency should be removed.
    -  511   -
          *
    -  512   -
          * @param dependency a dependency to check
    -  513   -
          * @param nextDependency another dependency to check
    -  514   -
          * @return true if on of the dependencies is a pom.xml and the identifiers
    -  515   -
          * between the two collections match; otherwise false
    -  516   -
          */
    -  517   -
         private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
    -  518  2
             final String mainName = dependency.getFileName().toLowerCase();
    -  519  2
             final String nextName = nextDependency.getFileName().toLowerCase();
    -  520  2
             if (mainName.endsWith(".jar") && nextName.endsWith("pom.xml")) {
    -  521  0
                 return dependency.getIdentifiers().containsAll(nextDependency.getIdentifiers());
    -  522  2
             } else if (nextName.endsWith(".jar") && mainName.endsWith("pom.xml")) {
    -  523  0
                 return nextDependency.getIdentifiers().containsAll(dependency.getIdentifiers());
    -  524   -
             }
    -  525  2
             return false;
    -  526   -
         }
    -  527   -
     
    -  528   -
         /**
    -  529   -
          * Determines which path is shortest; if path lengths are equal then we use
    -  530   -
          * compareTo of the string method to determine if the first path is smaller.
    -  531   -
          *
    -  532   -
          * @param left the first path to compare
    -  533   -
          * @param right the second path to compare
    -  534   -
          * @return <code>true</code> if the leftPath is the shortest; otherwise
    -  535   -
          * <code>false</code>
    -  536   -
          */
    -  537   -
         protected boolean firstPathIsShortest(String left, String right) {
    -  538  5
             if (left.contains("dctemp")) {
    -  539  0
                 return false;
    -  540   -
             }
    -  541  5
             final String leftPath = left.replace('\\', '/');
    -  542  5
             final String rightPath = right.replace('\\', '/');
    -  543   -
     
    -  544  5
             final int leftCount = countChar(leftPath, '/');
    -  545  5
             final int rightCount = countChar(rightPath, '/');
    -  546  5
             if (leftCount == rightCount) {
    -  547  3
                 return leftPath.compareTo(rightPath) <= 0;
    -  548   -
             } else {
    -  549  2
                 return leftCount < rightCount;
    -  550   -
             }
    -  551   -
         }
    -  552   -
     
    -  553   -
         /**
    -  554   -
          * Counts the number of times the character is present in the string.
    -  555   -
          *
    -  556   -
          * @param string the string to count the characters in
    -  557   -
          * @param c the character to count
    -  558   -
          * @return the number of times the character is present in the string
    -  559   -
          */
    -  560   -
         private int countChar(String string, char c) {
    -  561  10
             int count = 0;
    -  562  10
             final int max = string.length();
    -  563  116
             for (int i = 0; i < max; i++) {
    -  564  106
                 if (c == string.charAt(i)) {
    -  565  28
                     count++;
    -  566   -
                 }
    -  567   -
             }
    -  568  10
             return count;
    -  569   -
         }
    -  570   -
     
    -  571   -
         /**
    -  572   -
          * Checks if the given file path is contained within a war or ear file.
    -  573   -
          *
    -  574  
          * @param filePath the file path to check
    -  575   +  497  
          * @return true if the path contains '.war\' or '.ear\'.
    -  576   +  498  
          */
    -  577   +  499  
         private boolean containedInWar(String filePath) {
    -  578  0
             return filePath == null ? false : filePath.matches(".*\\.(ear|war)[\\\\/].*");
    -  579   +  500  0
             return filePath == null ? false : filePath.matches(".*\\.(ear|war)[\\\\/].*");
    +  501  
         }
    -  580   +  502   +
     
    +  503  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Experimental.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Experimental.html index 1bd2812f2..0dbd7a582 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Experimental.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.Experimental.html @@ -87,6 +87,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer.html index 1d5cea998..0d2696ad1 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    FalsePositiveAnalyzer
    46%
    106/227
    25%
    58/230
    10.385
    FalsePositiveAnalyzer
    46%
    107/228
    25%
    58/230
    9.714
     
    @@ -90,678 +90,699 @@  36  
     import org.owasp.dependencycheck.utils.FileFilterBuilder;
     37   -
     import org.slf4j.Logger;
    +
     import org.owasp.dependencycheck.utils.Settings;
     38   -
     import org.slf4j.LoggerFactory;
    +
     import org.slf4j.Logger;
     39   -
     
    +
     import org.slf4j.LoggerFactory;
     40   -
     /**
    +
     
     41   -
      * This analyzer attempts to remove some well known false positives - specifically regarding the java runtime.
    +
     /**
     42   -
      *
    +
      * This analyzer attempts to remove some well known false positives - specifically regarding the java runtime.
     43   -
      * @author Jeremy Long
    +
      *
     44   +
      * @author Jeremy Long
    +  45  
      */
    -  45  11
     public class FalsePositiveAnalyzer extends AbstractAnalyzer {
    -  46   -
     
    +  46  11
     public class FalsePositiveAnalyzer extends AbstractAnalyzer {
     47   -
         /**
    +
     
     48   -
          * The Logger.
    +
         /**
     49   +
          * The Logger.
    +  50  
          */
    -  50  1
         private static final Logger LOGGER = LoggerFactory.getLogger(FalsePositiveAnalyzer.class);
    -  51   -
     
    +  51  1
         private static final Logger LOGGER = LoggerFactory.getLogger(FalsePositiveAnalyzer.class);
     52   -
         /**
    +
     
     53   -
          * The file filter used to find DLL and EXE.
    +
         /**
     54   +
          * The file filter used to find DLL and EXE.
    +  55  
          */
    -  55  1
         private static final FileFilter DLL_EXE_FILTER = FileFilterBuilder.newInstance().addExtensions("dll", "exe").build();
    -  56   -
     
    +  56  1
         private static final FileFilter DLL_EXE_FILTER = FileFilterBuilder.newInstance().addExtensions("dll", "exe").build();
     57   -
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
    +
     
     58   -
         /**
    +
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
     59   -
          * The name of the analyzer.
    +
         /**
     60   -
          */
    +
          * The name of the analyzer.
     61   -
         private static final String ANALYZER_NAME = "False Positive Analyzer";
    +
          */
     62   -
         /**
    +
         private static final String ANALYZER_NAME = "False Positive Analyzer";
     63   -
          * The phase that this analyzer is intended to run in.
    +
         /**
     64   +
          * The phase that this analyzer is intended to run in.
    +  65  
          */
    -  65  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
    -  66   -
     
    +  66  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
     67   -
         /**
    +
     
     68   -
          * Returns the name of the analyzer.
    +
         /**
     69   -
          *
    +
          * Returns the name of the analyzer.
     70   -
          * @return the name of the analyzer.
    -  71   -
          */
    -  72   -
         @Override
    -  73   -
         public String getName() {
    -  74  27
             return ANALYZER_NAME;
    -  75   -
         }
    -  76   -
     
    -  77   -
         /**
    -  78   -
          * Returns the phase that the analyzer is intended to run in.
    -  79  
          *
    -  80   -
          * @return the phase that the analyzer is intended to run in.
    -  81   +  71   +
          * @return the name of the analyzer.
    +  72  
          */
    -  82   +  73  
         @Override
    -  83   -
         public AnalysisPhase getAnalysisPhase() {
    -  84  7
             return ANALYSIS_PHASE;
    -  85   +  74   +
         public String getName() {
    +  75  26
             return ANALYZER_NAME;
    +  76  
         }
    -  86   -
         //</editor-fold>
    -  87   +  77  
     
    -  88   +  78  
         /**
    +  79   +
          * Returns the phase that the analyzer is intended to run in.
    +  80   +
          *
    +  81   +
          * @return the phase that the analyzer is intended to run in.
    +  82   +
          */
    +  83   +
         @Override
    +  84   +
         public AnalysisPhase getAnalysisPhase() {
    +  85  7
             return ANALYSIS_PHASE;
    +  86   +
         }
    +  87   +
         /**
    +  88   +
          * <p>
     89   -
          * Analyzes the dependencies and removes bad/incorrect CPE associations based on various heuristics.
    +
          * Returns the setting key to determine if the analyzer is enabled.</p>
     90  
          *
     91   -
          * @param dependency the dependency to analyze.
    +
          * @return the key for the analyzer's enabled property
     92   -
          * @param engine the engine that is scanning the dependencies
    +
          */
     93   -
          * @throws AnalysisException is thrown if there is an error reading the JAR file.
    -  94   -
          */
    -  95  
         @Override
    +  94   +
         protected String getAnalyzerEnabledSettingKey() {
    +  95  2
             return Settings.KEYS.ANALYZER_FALSE_POSITIVE_ENABLED;
     96   -
         public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    -  97  5
             removeJreEntries(dependency);
    -  98  5
             removeBadMatches(dependency);
    -  99  5
             removeBadSpringMatches(dependency);
    -  100  5
             removeWrongVersionMatches(dependency);
    -  101  5
             removeSpuriousCPE(dependency);
    -  102  5
             removeDuplicativeEntriesFromJar(dependency, engine);
    -  103  5
             addFalseNegativeCPEs(dependency);
    -  104  5
         }
    +
         }
    +  97   +
         //</editor-fold>
    +  98   +
     
    +  99   +
         /**
    +  100   +
          * Analyzes the dependencies and removes bad/incorrect CPE associations based on various heuristics.
    +  101   +
          *
    +  102   +
          * @param dependency the dependency to analyze.
    +  103   +
          * @param engine the engine that is scanning the dependencies
    +  104   +
          * @throws AnalysisException is thrown if there is an error reading the JAR file.
     105   -
     
    +
          */
     106   -
         /**
    +
         @Override
     107   +
         protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  108  4
             removeJreEntries(dependency);
    +  109  4
             removeBadMatches(dependency);
    +  110  4
             removeBadSpringMatches(dependency);
    +  111  4
             removeWrongVersionMatches(dependency);
    +  112  4
             removeSpuriousCPE(dependency);
    +  113  4
             removeDuplicativeEntriesFromJar(dependency, engine);
    +  114  4
             addFalseNegativeCPEs(dependency);
    +  115  5
         }
    +  116   +
     
    +  117   +
         /**
    +  118  
          * Removes inaccurate matches on springframework CPEs.
    -  108   +  119  
          *
    -  109   -
          * @param dependency the dependency to test for and remove known inaccurate CPE matches
    -  110   -
          */
    -  111   -
         private void removeBadSpringMatches(Dependency dependency) {
    -  112  5
             String mustContain = null;
    -  113  5
             for (Identifier i : dependency.getIdentifiers()) {
    -  114  4
                 if ("maven".contains(i.getType())) {
    -  115  0
                     if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
    -  116  0
                         final int endPoint = i.getValue().indexOf(':', 19);
    -  117  0
                         if (endPoint >= 0) {
    -  118  0
                             mustContain = i.getValue().substring(19, endPoint).toLowerCase();
    -  119  0
                             break;
     120   -
                         }
    +
          * @param dependency the dependency to test for and remove known inaccurate CPE matches
     121   -
                     }
    +
          */
     122   -
                 }
    -  123  4
             }
    -  124  5
             if (mustContain != null) {
    -  125  0
                 final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
    -  126  0
                 while (itr.hasNext()) {
    -  127  0
                     final Identifier i = itr.next();
    -  128  0
                     if ("cpe".contains(i.getType())
    -  129  0
                             && i.getValue() != null
    -  130  0
                             && i.getValue().startsWith("cpe:/a:springsource:")
    -  131  0
                             && !i.getValue().toLowerCase().contains(mustContain)) {
    -  132  0
                         itr.remove();
    -  133   -
                         //dependency.getIdentifiers().remove(i);
    -  134   -
                     }
    -  135  0
                 }
    -  136   -
             }
    -  137  5
         }
    -  138   -
     
    -  139   -
         /**
    -  140   -
          * <p>
    -  141   -
          * Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
    -  142   -
          * <p>
    -  143   -
          * Example:</p>
    -  144   -
          * <code>
    -  145   -
          * cpe:/a:some-vendor:some-product
    -  146   -
          * cpe:/a:some-vendor:some-product:1.5
    -  147   -
          * cpe:/a:some-vendor:some-product:1.5.2
    -  148   -
          * </code>
    -  149   -
          * <p>
    -  150   -
          * Should be trimmed to:</p>
    -  151   -
          * <code>
    -  152   -
          * cpe:/a:some-vendor:some-product:1.5.2
    -  153   -
          * </code>
    -  154   -
          *
    -  155   -
          * @param dependency the dependency being analyzed
    -  156   -
          */
    -  157   -
         @SuppressWarnings("null")
    -  158   -
         private void removeSpuriousCPE(Dependency dependency) {
    -  159  5
             final List<Identifier> ids = new ArrayList<Identifier>(dependency.getIdentifiers());
    -  160  5
             Collections.sort(ids);
    -  161  5
             final ListIterator<Identifier> mainItr = ids.listIterator();
    -  162  9
             while (mainItr.hasNext()) {
    -  163  4
                 final Identifier currentId = mainItr.next();
    -  164  4
                 final VulnerableSoftware currentCpe = parseCpe(currentId.getType(), currentId.getValue());
    -  165  4
                 if (currentCpe == null) {
    -  166  0
                     continue;
    -  167   -
                 }
    -  168  4
                 final ListIterator<Identifier> subItr = ids.listIterator(mainItr.nextIndex());
    -  169  10
                 while (subItr.hasNext()) {
    -  170  6
                     final Identifier nextId = subItr.next();
    -  171  6
                     final VulnerableSoftware nextCpe = parseCpe(nextId.getType(), nextId.getValue());
    -  172  6
                     if (nextCpe == null) {
    -  173  0
                         continue;
    -  174   -
                     }
    -  175   -
                     //TODO fix the version problem below
    -  176  6
                     if (currentCpe.getVendor().equals(nextCpe.getVendor())) {
    -  177  0
                         if (currentCpe.getProduct().equals(nextCpe.getProduct())) {
    -  178   -
                             // see if one is contained in the other.. remove the contained one from dependency.getIdentifier
    -  179  0
                             final String currentVersion = currentCpe.getVersion();
    -  180  0
                             final String nextVersion = nextCpe.getVersion();
    -  181  0
                             if (currentVersion == null && nextVersion == null) {
    -  182   -
                                 //how did we get here?
    -  183  0
                                 LOGGER.debug("currentVersion and nextVersion are both null?");
    -  184  0
                             } else if (currentVersion == null && nextVersion != null) {
    -  185  0
                                 dependency.getIdentifiers().remove(currentId);
    -  186  0
                             } else if (nextVersion == null && currentVersion != null) {
    -  187  0
                                 dependency.getIdentifiers().remove(nextId);
    -  188  0
                             } else if (currentVersion.length() < nextVersion.length()) {
    -  189  0
                                 if (nextVersion.startsWith(currentVersion) || "-".equals(currentVersion)) {
    -  190  0
                                     dependency.getIdentifiers().remove(currentId);
    -  191   -
                                 }
    -  192   -
                             } else {
    -  193  0
                                 if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
    -  194  0
                                     dependency.getIdentifiers().remove(nextId);
    -  195   -
                                 }
    -  196   -
                             }
    -  197   +
         private void removeBadSpringMatches(Dependency dependency) {
    +  123  4
             String mustContain = null;
    +  124  4
             for (Identifier i : dependency.getIdentifiers()) {
    +  125  4
                 if ("maven".contains(i.getType())) {
    +  126  0
                     if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
    +  127  0
                         final int endPoint = i.getValue().indexOf(':', 19);
    +  128  0
                         if (endPoint >= 0) {
    +  129  0
                             mustContain = i.getValue().substring(19, endPoint).toLowerCase();
    +  130  0
                             break;
    +  131  
                         }
    -  198   +  132  
                     }
    -  199  6
                 }
    -  200  4
             }
    -  201  5
         }
    -  202   -
         /**
    -  203   -
          * Regex to identify core java libraries and a few other commonly misidentified ones.
    -  204   -
          */
    -  205  1
         public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
    -  206   -
                 + "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
    -  207   -
                 + "jdk|jre|jsse)($|:.*)");
    -  208   +  133   +
                 }
    +  134  4
             }
    +  135  4
             if (mustContain != null) {
    +  136  0
                 final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
    +  137  0
                 while (itr.hasNext()) {
    +  138  0
                     final Identifier i = itr.next();
    +  139  0
                     if ("cpe".contains(i.getType())
    +  140  0
                             && i.getValue() != null
    +  141  0
                             && i.getValue().startsWith("cpe:/a:springsource:")
    +  142  0
                             && !i.getValue().toLowerCase().contains(mustContain)) {
    +  143  0
                         itr.remove();
    +  144   +
                         //dependency.getIdentifiers().remove(i);
    +  145   +
                     }
    +  146  0
                 }
    +  147   +
             }
    +  148  4
         }
    +  149  
     
    -  209   +  150  
         /**
    -  210   -
          * Regex to identify core jsf libraries.
    -  211   +  151   +
          * <p>
    +  152   +
          * Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
    +  153   +
          * <p>
    +  154   +
          * Example:</p>
    +  155   +
          * <code>
    +  156   +
          * cpe:/a:some-vendor:some-product
    +  157   +
          * cpe:/a:some-vendor:some-product:1.5
    +  158   +
          * cpe:/a:some-vendor:some-product:1.5.2
    +  159   +
          * </code>
    +  160   +
          * <p>
    +  161   +
          * Should be trimmed to:</p>
    +  162   +
          * <code>
    +  163   +
          * cpe:/a:some-vendor:some-product:1.5.2
    +  164   +
          * </code>
    +  165   +
          *
    +  166   +
          * @param dependency the dependency being analyzed
    +  167  
          */
    -  212  1
         public static final Pattern CORE_JAVA_JSF = Pattern.compile("^cpe:/a:(sun|oracle|ibm):jsf($|:.*)");
    +  168   +
         @SuppressWarnings("null")
    +  169   +
         private void removeSpuriousCPE(Dependency dependency) {
    +  170  5
             final List<Identifier> ids = new ArrayList<Identifier>(dependency.getIdentifiers());
    +  171  4
             Collections.sort(ids);
    +  172  4
             final ListIterator<Identifier> mainItr = ids.listIterator();
    +  173  8
             while (mainItr.hasNext()) {
    +  174  4
                 final Identifier currentId = mainItr.next();
    +  175  4
                 final VulnerableSoftware currentCpe = parseCpe(currentId.getType(), currentId.getValue());
    +  176  4
                 if (currentCpe == null) {
    +  177  0
                     continue;
    +  178   +
                 }
    +  179  4
                 final ListIterator<Identifier> subItr = ids.listIterator(mainItr.nextIndex());
    +  180  10
                 while (subItr.hasNext()) {
    +  181  6
                     final Identifier nextId = subItr.next();
    +  182  6
                     final VulnerableSoftware nextCpe = parseCpe(nextId.getType(), nextId.getValue());
    +  183  6
                     if (nextCpe == null) {
    +  184  0
                         continue;
    +  185   +
                     }
    +  186   +
                     //TODO fix the version problem below
    +  187  6
                     if (currentCpe.getVendor().equals(nextCpe.getVendor())) {
    +  188  0
                         if (currentCpe.getProduct().equals(nextCpe.getProduct())) {
    +  189   +
                             // see if one is contained in the other.. remove the contained one from dependency.getIdentifier
    +  190  0
                             final String currentVersion = currentCpe.getVersion();
    +  191  0
                             final String nextVersion = nextCpe.getVersion();
    +  192  0
                             if (currentVersion == null && nextVersion == null) {
    +  193   +
                                 //how did we get here?
    +  194  0
                                 LOGGER.debug("currentVersion and nextVersion are both null?");
    +  195  0
                             } else if (currentVersion == null && nextVersion != null) {
    +  196  0
                                 dependency.getIdentifiers().remove(currentId);
    +  197  0
                             } else if (nextVersion == null && currentVersion != null) {
    +  198  0
                                 dependency.getIdentifiers().remove(nextId);
    +  199  0
                             } else if (currentVersion.length() < nextVersion.length()) {
    +  200  0
                                 if (nextVersion.startsWith(currentVersion) || "-".equals(currentVersion)) {
    +  201  0
                                     dependency.getIdentifiers().remove(currentId);
    +  202   +
                                 }
    +  203   +
                             } else {
    +  204  0
                                 if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
    +  205  0
                                     dependency.getIdentifiers().remove(nextId);
    +  206   +
                                 }
    +  207   +
                             }
    +  208   +
                         }
    +  209   +
                     }
    +  210  6
                 }
    +  211  4
             }
    +  212  4
         }
     213  
         /**
     214   -
          * Regex to identify core java library files. This is currently incomplete.
    +
          * Regex to identify core java libraries and a few other commonly misidentified ones.
     215  
          */
    -  216  1
         public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
    +  216  1
         public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
     217   -
         /**
    +
                 + "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
     218   -
          * Regex to identify core jsf java library files. This is currently incomplete.
    +
                 + "jdk|jre|jsse)($|:.*)");
     219   -
          */
    -  220  1
         public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
    -  221  
     
    -  222   +  220  
         /**
    -  223   -
          * Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
    +  221   +
          * Regex to identify core jsf libraries.
    +  222   +
          */
    +  223  1
         public static final Pattern CORE_JAVA_JSF = Pattern.compile("^cpe:/a:(sun|oracle|ibm):jsf($|:.*)");
     224   -
          *
    +
         /**
     225   -
          * @param dependency the dependency to remove JRE CPEs from
    +
          * Regex to identify core java library files. This is currently incomplete.
     226  
          */
    -  227   -
         private void removeJreEntries(Dependency dependency) {
    -  228  5
             final Set<Identifier> identifiers = dependency.getIdentifiers();
    -  229  5
             final Iterator<Identifier> itr = identifiers.iterator();
    -  230  10
             while (itr.hasNext()) {
    -  231  5
                 final Identifier i = itr.next();
    -  232  5
                 final Matcher coreCPE = CORE_JAVA.matcher(i.getValue());
    -  233  5
                 final Matcher coreFiles = CORE_FILES.matcher(dependency.getFileName());
    -  234  5
                 if (coreCPE.matches() && !coreFiles.matches()) {
    -  235  0
                     itr.remove();
    +  227  1
         public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
    +  228   +
         /**
    +  229   +
          * Regex to identify core jsf java library files. This is currently incomplete.
    +  230   +
          */
    +  231  1
         public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
    +  232   +
     
    +  233   +
         /**
    +  234   +
          * Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
    +  235   +
          *
     236   -
                 }
    -  237  5
                 final Matcher coreJsfCPE = CORE_JAVA_JSF.matcher(i.getValue());
    -  238  5
                 final Matcher coreJsfFiles = CORE_JSF_FILES.matcher(dependency.getFileName());
    -  239  5
                 if (coreJsfCPE.matches() && !coreJsfFiles.matches()) {
    -  240  0
                     itr.remove();
    -  241   -
                 }
    -  242  5
             }
    -  243  5
         }
    -  244   -
     
    -  245   -
         /**
    -  246   -
          * Parses a CPE string into an IndexEntry.
    +
          * @param dependency the dependency to remove JRE CPEs from
    +  237   +
          */
    +  238   +
         private void removeJreEntries(Dependency dependency) {
    +  239  4
             final Set<Identifier> identifiers = dependency.getIdentifiers();
    +  240  4
             final Iterator<Identifier> itr = identifiers.iterator();
    +  241  9
             while (itr.hasNext()) {
    +  242  5
                 final Identifier i = itr.next();
    +  243  5
                 final Matcher coreCPE = CORE_JAVA.matcher(i.getValue());
    +  244  5
                 final Matcher coreFiles = CORE_FILES.matcher(dependency.getFileName());
    +  245  5
                 if (coreCPE.matches() && !coreFiles.matches()) {
    +  246  0
                     itr.remove();
     247   -
          *
    -  248   -
          * @param type the type of identifier
    -  249   -
          * @param value the cpe identifier to parse
    -  250   -
          * @return an VulnerableSoftware object constructed from the identifier
    -  251   -
          */
    +
                 }
    +  248  5
                 final Matcher coreJsfCPE = CORE_JAVA_JSF.matcher(i.getValue());
    +  249  5
                 final Matcher coreJsfFiles = CORE_JSF_FILES.matcher(dependency.getFileName());
    +  250  5
                 if (coreJsfCPE.matches() && !coreJsfFiles.matches()) {
    +  251  0
                     itr.remove();
     252   -
         private VulnerableSoftware parseCpe(String type, String value) {
    -  253  10
             if (!"cpe".equals(type)) {
    -  254  0
                 return null;
    +
                 }
    +  253  5
             }
    +  254  4
         }
     255   -
             }
    -  256  10
             final VulnerableSoftware cpe = new VulnerableSoftware();
    +
     
    +  256   +
         /**
     257   -
             try {
    -  258  10
                 cpe.parseName(value);
    -  259  0
             } catch (UnsupportedEncodingException ex) {
    -  260  0
                 LOGGER.trace("", ex);
    -  261  0
                 return null;
    -  262  10
             }
    -  263  10
             return cpe;
    -  264   -
         }
    -  265   -
     
    +
          * Parses a CPE string into an IndexEntry.
    +  258   +
          *
    +  259   +
          * @param type the type of identifier
    +  260   +
          * @param value the cpe identifier to parse
    +  261   +
          * @return an VulnerableSoftware object constructed from the identifier
    +  262   +
          */
    +  263   +
         private VulnerableSoftware parseCpe(String type, String value) {
    +  264  10
             if (!"cpe".equals(type)) {
    +  265  0
                 return null;
     266   -
         /**
    -  267   -
          * Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific problems
    +
             }
    +  267  10
             final VulnerableSoftware cpe = new VulnerableSoftware();
     268   -
          * identified when testing this on a LARGE volume of jar files.
    -  269   -
          *
    -  270   -
          * @param dependency the dependency to analyze
    -  271   -
          */
    -  272   -
         private void removeBadMatches(Dependency dependency) {
    -  273  5
             final Set<Identifier> identifiers = dependency.getIdentifiers();
    -  274  5
             final Iterator<Identifier> itr = identifiers.iterator();
    +
             try {
    +  269  10
                 cpe.parseName(value);
    +  270  0
             } catch (UnsupportedEncodingException ex) {
    +  271  0
                 LOGGER.trace("", ex);
    +  272  0
                 return null;
    +  273  10
             }
    +  274  10
             return cpe;
     275   -
     
    +
         }
     276   -
             /* TODO - can we utilize the pom's groupid and artifactId to filter??? most of
    +
     
     277   -
              * these are due to low quality data.  Other idea would be to say any CPE
    +
         /**
     278   -
              * found based on LOW confidence evidence should have a different CPE type? (this
    +
          * Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific problems
     279   -
              * might be a better solution then just removing the URL for "best-guess" matches).
    +
          * identified when testing this on a LARGE volume of jar files.
     280   -
              */
    +
          *
     281   -
             //Set<Evidence> groupId = dependency.getVendorEvidence().getEvidence("pom", "groupid");
    -  282   -
             //Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
    -  283  10
             while (itr.hasNext()) {
    -  284  5
                 final Identifier i = itr.next();
    -  285   -
                 //TODO move this startsWith expression to the base suppression file
    -  286  5
                 if ("cpe".equals(i.getType())) {
    -  287  5
                     if ((i.getValue().matches(".*c\\+\\+.*")
    -  288  5
                             || i.getValue().startsWith("cpe:/a:file:file")
    -  289  4
                             || i.getValue().startsWith("cpe:/a:mozilla:mozilla")
    -  290  4
                             || i.getValue().startsWith("cpe:/a:cvs:cvs")
    -  291  4
                             || i.getValue().startsWith("cpe:/a:ftp:ftp")
    -  292  4
                             || i.getValue().startsWith("cpe:/a:tcp:tcp")
    -  293  4
                             || i.getValue().startsWith("cpe:/a:ssh:ssh")
    -  294  4
                             || i.getValue().startsWith("cpe:/a:lookup:lookup"))
    -  295  1
                             && (dependency.getFileName().toLowerCase().endsWith(".jar")
    -  296  1
                             || dependency.getFileName().toLowerCase().endsWith("pom.xml")
    -  297  0
                             || dependency.getFileName().toLowerCase().endsWith(".dll")
    -  298  0
                             || dependency.getFileName().toLowerCase().endsWith(".exe")
    -  299  0
                             || dependency.getFileName().toLowerCase().endsWith(".nuspec")
    -  300  0
                             || dependency.getFileName().toLowerCase().endsWith(".zip")
    -  301  0
                             || dependency.getFileName().toLowerCase().endsWith(".sar")
    -  302  0
                             || dependency.getFileName().toLowerCase().endsWith(".apk")
    -  303  0
                             || dependency.getFileName().toLowerCase().endsWith(".tar")
    -  304  0
                             || dependency.getFileName().toLowerCase().endsWith(".gz")
    -  305  0
                             || dependency.getFileName().toLowerCase().endsWith(".tgz")
    -  306  0
                             || dependency.getFileName().toLowerCase().endsWith(".ear")
    -  307  0
                             || dependency.getFileName().toLowerCase().endsWith(".war"))) {
    -  308  1
                         itr.remove();
    -  309  4
                     } else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
    -  310  4
                             || i.getValue().startsWith("cpe:/a:prototypejs:prototype")
    -  311  4
                             || i.getValue().startsWith("cpe:/a:yahoo:yui"))
    -  312  0
                             && (dependency.getFileName().toLowerCase().endsWith(".jar")
    -  313  0
                             || dependency.getFileName().toLowerCase().endsWith("pom.xml")
    -  314  0
                             || dependency.getFileName().toLowerCase().endsWith(".dll")
    -  315  0
                             || dependency.getFileName().toLowerCase().endsWith(".exe"))) {
    -  316  0
                         itr.remove();
    -  317  4
                     } else if ((i.getValue().startsWith("cpe:/a:microsoft:excel")
    -  318  4
                             || i.getValue().startsWith("cpe:/a:microsoft:word")
    -  319  4
                             || i.getValue().startsWith("cpe:/a:microsoft:visio")
    -  320  4
                             || i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
    -  321  4
                             || i.getValue().startsWith("cpe:/a:microsoft:office")
    -  322  4
                             || i.getValue().startsWith("cpe:/a:core_ftp:core_ftp"))
    -  323  0
                             && (dependency.getFileName().toLowerCase().endsWith(".jar")
    -  324  0
                             || dependency.getFileName().toLowerCase().endsWith(".ear")
    -  325  0
                             || dependency.getFileName().toLowerCase().endsWith(".war")
    -  326  0
                             || dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
    -  327  0
                         itr.remove();
    -  328  4
                     } else if (i.getValue().startsWith("cpe:/a:apache:maven")
    -  329  0
                             && !dependency.getFileName().toLowerCase().matches("maven-core-[\\d\\.]+\\.jar")) {
    -  330  0
                         itr.remove();
    -  331  4
                     } else if (i.getValue().startsWith("cpe:/a:m-core:m-core")
    -  332  0
                             && !dependency.getEvidenceUsed().containsUsedString("m-core")) {
    -  333  0
                         itr.remove();
    -  334  4
                     } else if (i.getValue().startsWith("cpe:/a:jboss:jboss")
    -  335  0
                             && !dependency.getFileName().toLowerCase().matches("jboss-?[\\d\\.-]+(GA)?\\.jar")) {
    -  336  0
                         itr.remove();
    -  337   -
                     }
    -  338   -
                 }
    -  339  5
             }
    -  340  5
         }
    -  341   -
     
    -  342   -
         /**
    -  343   -
          * Removes CPE matches for the wrong version of a dependency. Currently, this only covers Axis 1 & 2.
    -  344   -
          *
    -  345  
          * @param dependency the dependency to analyze
    -  346   +  282  
          */
    -  347   +  283   +
         private void removeBadMatches(Dependency dependency) {
    +  284  4
             final Set<Identifier> identifiers = dependency.getIdentifiers();
    +  285  4
             final Iterator<Identifier> itr = identifiers.iterator();
    +  286   +
     
    +  287   +
             /* TODO - can we utilize the pom's groupid and artifactId to filter??? most of
    +  288   +
              * these are due to low quality data.  Other idea would be to say any CPE
    +  289   +
              * found based on LOW confidence evidence should have a different CPE type? (this
    +  290   +
              * might be a better solution then just removing the URL for "best-guess" matches).
    +  291   +
              */
    +  292   +
             //Set<Evidence> groupId = dependency.getVendorEvidence().getEvidence("pom", "groupid");
    +  293   +
             //Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
    +  294  9
             while (itr.hasNext()) {
    +  295  5
                 final Identifier i = itr.next();
    +  296   +
                 //TODO move this startsWith expression to the base suppression file
    +  297  5
                 if ("cpe".equals(i.getType())) {
    +  298  5
                     if ((i.getValue().matches(".*c\\+\\+.*")
    +  299  5
                             || i.getValue().startsWith("cpe:/a:file:file")
    +  300  4
                             || i.getValue().startsWith("cpe:/a:mozilla:mozilla")
    +  301  4
                             || i.getValue().startsWith("cpe:/a:cvs:cvs")
    +  302  4
                             || i.getValue().startsWith("cpe:/a:ftp:ftp")
    +  303  4
                             || i.getValue().startsWith("cpe:/a:tcp:tcp")
    +  304  4
                             || i.getValue().startsWith("cpe:/a:ssh:ssh")
    +  305  4
                             || i.getValue().startsWith("cpe:/a:lookup:lookup"))
    +  306  1
                             && (dependency.getFileName().toLowerCase().endsWith(".jar")
    +  307  1
                             || dependency.getFileName().toLowerCase().endsWith("pom.xml")
    +  308  0
                             || dependency.getFileName().toLowerCase().endsWith(".dll")
    +  309  0
                             || dependency.getFileName().toLowerCase().endsWith(".exe")
    +  310  0
                             || dependency.getFileName().toLowerCase().endsWith(".nuspec")
    +  311  0
                             || dependency.getFileName().toLowerCase().endsWith(".zip")
    +  312  0
                             || dependency.getFileName().toLowerCase().endsWith(".sar")
    +  313  0
                             || dependency.getFileName().toLowerCase().endsWith(".apk")
    +  314  0
                             || dependency.getFileName().toLowerCase().endsWith(".tar")
    +  315  0
                             || dependency.getFileName().toLowerCase().endsWith(".gz")
    +  316  0
                             || dependency.getFileName().toLowerCase().endsWith(".tgz")
    +  317  0
                             || dependency.getFileName().toLowerCase().endsWith(".ear")
    +  318  0
                             || dependency.getFileName().toLowerCase().endsWith(".war"))) {
    +  319  1
                         itr.remove();
    +  320  4
                     } else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
    +  321  4
                             || i.getValue().startsWith("cpe:/a:prototypejs:prototype")
    +  322  4
                             || i.getValue().startsWith("cpe:/a:yahoo:yui"))
    +  323  0
                             && (dependency.getFileName().toLowerCase().endsWith(".jar")
    +  324  0
                             || dependency.getFileName().toLowerCase().endsWith("pom.xml")
    +  325  0
                             || dependency.getFileName().toLowerCase().endsWith(".dll")
    +  326  0
                             || dependency.getFileName().toLowerCase().endsWith(".exe"))) {
    +  327  0
                         itr.remove();
    +  328  4
                     } else if ((i.getValue().startsWith("cpe:/a:microsoft:excel")
    +  329  4
                             || i.getValue().startsWith("cpe:/a:microsoft:word")
    +  330  4
                             || i.getValue().startsWith("cpe:/a:microsoft:visio")
    +  331  4
                             || i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
    +  332  4
                             || i.getValue().startsWith("cpe:/a:microsoft:office")
    +  333  4
                             || i.getValue().startsWith("cpe:/a:core_ftp:core_ftp"))
    +  334  0
                             && (dependency.getFileName().toLowerCase().endsWith(".jar")
    +  335  0
                             || dependency.getFileName().toLowerCase().endsWith(".ear")
    +  336  0
                             || dependency.getFileName().toLowerCase().endsWith(".war")
    +  337  0
                             || dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
    +  338  0
                         itr.remove();
    +  339  4
                     } else if (i.getValue().startsWith("cpe:/a:apache:maven")
    +  340  0
                             && !dependency.getFileName().toLowerCase().matches("maven-core-[\\d\\.]+\\.jar")) {
    +  341  0
                         itr.remove();
    +  342  4
                     } else if (i.getValue().startsWith("cpe:/a:m-core:m-core")
    +  343  0
                             && !dependency.getEvidenceUsed().containsUsedString("m-core")) {
    +  344  0
                         itr.remove();
    +  345  4
                     } else if (i.getValue().startsWith("cpe:/a:jboss:jboss")
    +  346  0
                             && !dependency.getFileName().toLowerCase().matches("jboss-?[\\d\\.-]+(GA)?\\.jar")) {
    +  347  0
                         itr.remove();
    +  348   +
                     }
    +  349   +
                 }
    +  350  5
             }
    +  351  4
         }
    +  352   +
     
    +  353   +
         /**
    +  354   +
          * Removes CPE matches for the wrong version of a dependency. Currently, this only covers Axis 1 & 2.
    +  355   +
          *
    +  356   +
          * @param dependency the dependency to analyze
    +  357   +
          */
    +  358  
         private void removeWrongVersionMatches(Dependency dependency) {
    -  348  5
             final Set<Identifier> identifiers = dependency.getIdentifiers();
    -  349  5
             final Iterator<Identifier> itr = identifiers.iterator();
    -  350   +  359  4
             final Set<Identifier> identifiers = dependency.getIdentifiers();
    +  360  5
             final Iterator<Identifier> itr = identifiers.iterator();
    +  361  
     
    -  351  5
             final String fileName = dependency.getFileName();
    -  352  5
             if (fileName != null && fileName.contains("axis2")) {
    -  353  0
                 while (itr.hasNext()) {
    -  354  0
                     final Identifier i = itr.next();
    -  355  0
                     if ("cpe".equals(i.getType())) {
    -  356  0
                         final String cpe = i.getValue();
    -  357  0
                         if (cpe != null && (cpe.startsWith("cpe:/a:apache:axis:") || "cpe:/a:apache:axis".equals(cpe))) {
    -  358  0
                             itr.remove();
    -  359   -
                         }
    -  360   -
                     }
    -  361  0
                 }
    -  362  5
             } else if (fileName != null && fileName.contains("axis")) {
    -  363  0
                 while (itr.hasNext()) {
    -  364  0
                     final Identifier i = itr.next();
    -  365  0
                     if ("cpe".equals(i.getType())) {
    -  366  0
                         final String cpe = i.getValue();
    -  367  0
                         if (cpe != null && (cpe.startsWith("cpe:/a:apache:axis2:") || "cpe:/a:apache:axis2".equals(cpe))) {
    -  368  0
                             itr.remove();
    -  369   -
                         }
    +  362  5
             final String fileName = dependency.getFileName();
    +  363  4
             if (fileName != null && fileName.contains("axis2")) {
    +  364  0
                 while (itr.hasNext()) {
    +  365  0
                     final Identifier i = itr.next();
    +  366  0
                     if ("cpe".equals(i.getType())) {
    +  367  0
                         final String cpe = i.getValue();
    +  368  0
                         if (cpe != null && (cpe.startsWith("cpe:/a:apache:axis:") || "cpe:/a:apache:axis".equals(cpe))) {
    +  369  0
                             itr.remove();
     370   -
                     }
    -  371  0
                 }
    -  372   -
             }
    -  373  5
         }
    -  374   -
     
    -  375   -
         /**
    -  376   -
          * There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and changes in
    -  377   -
          * product names, that based on given evidence we can add the related CPE entries to ensure a complete list of CVE entries.
    -  378   -
          *
    -  379   -
          * @param dependency the dependency being analyzed
    -  380   -
          */
    -  381   -
         private void addFalseNegativeCPEs(Dependency dependency) {
    -  382   -
             //TODO move this to the hint analyzer
    -  383  5
             for (final Identifier identifier : dependency.getIdentifiers()) {
    -  384  4
                 if ("cpe".equals(identifier.getType()) && identifier.getValue() != null
    -  385  4
                         && (identifier.getValue().startsWith("cpe:/a:oracle:opensso:")
    -  386  4
                         || identifier.getValue().startsWith("cpe:/a:oracle:opensso_enterprise:")
    -  387  4
                         || identifier.getValue().startsWith("cpe:/a:sun:opensso_enterprise:")
    -  388  4
                         || identifier.getValue().startsWith("cpe:/a:sun:opensso:"))) {
    -  389  0
                     final String newCpe = String.format("cpe:/a:sun:opensso_enterprise:%s", identifier.getValue().substring(22));
    -  390  0
                     final String newCpe2 = String.format("cpe:/a:oracle:opensso_enterprise:%s", identifier.getValue().substring(22));
    -  391  0
                     final String newCpe3 = String.format("cpe:/a:sun:opensso:%s", identifier.getValue().substring(22));
    -  392  0
                     final String newCpe4 = String.format("cpe:/a:oracle:opensso:%s", identifier.getValue().substring(22));
    -  393   -
                     try {
    -  394  0
                         dependency.addIdentifier("cpe",
    -  395   -
                                 newCpe,
    -  396  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe, "UTF-8")));
    -  397  0
                         dependency.addIdentifier("cpe",
    -  398   -
                                 newCpe2,
    -  399  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe2, "UTF-8")));
    -  400  0
                         dependency.addIdentifier("cpe",
    -  401   -
                                 newCpe3,
    -  402  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe3, "UTF-8")));
    -  403  0
                         dependency.addIdentifier("cpe",
    -  404   -
                                 newCpe4,
    -  405  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
    -  406  0
                     } catch (UnsupportedEncodingException ex) {
    -  407  0
                         LOGGER.debug("", ex);
    -  408  0
                     }
    -  409   -
                 }
    -  410  4
             }
    -  411  5
         }
    -  412   -
     
    -  413   -
         /**
    -  414   -
          * Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM entries or
    -  415   -
          * other types of files (such as DLLs and EXEs) being contained within the JAR.
    -  416   -
          *
    -  417   -
          * @param dependency the dependency that might be a duplicate
    -  418   -
          * @param engine the engine used to scan all dependencies
    -  419   -
          */
    -  420   -
         private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
    -  421  5
             if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
    -  422  4
                     || DLL_EXE_FILTER.accept(dependency.getActualFile())) {
    -  423  1
                 String parentPath = dependency.getFilePath().toLowerCase();
    -  424  1
                 if (parentPath.contains(".jar")) {
    -  425  0
                     parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
    -  426  0
                     final List<Dependency> dependencies = engine.getDependencies();
    -  427  0
                     synchronized (dependencies) {
    -  428  0
                         final Dependency parent = findDependency(parentPath, dependencies);
    -  429  0
                         if (parent != null) {
    -  430  0
                             boolean remove = false;
    -  431  0
                             for (Identifier i : dependency.getIdentifiers()) {
    -  432  0
                                 if ("cpe".equals(i.getType())) {
    -  433  0
                                     final String trimmedCPE = trimCpeToVendor(i.getValue());
    -  434  0
                                     for (Identifier parentId : parent.getIdentifiers()) {
    -  435  0
                                         if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
    -  436  0
                                             remove |= true;
    -  437   -
                                         }
    -  438  0
                                     }
    -  439   -
                                 }
    -  440  0
                                 if (!remove) { //we can escape early
    -  441  0
                                     return;
    -  442   -
                                 }
    -  443  0
                             }
    -  444  0
                             if (remove) {
    -  445  0
                                 dependencies.remove(dependency);
    -  446   -
                             }
    -  447  
                         }
    -  448  0
                     }
    -  449   +  371   +
                     }
    +  372  0
                 }
    +  373  4
             } else if (fileName != null && fileName.contains("axis")) {
    +  374  0
                 while (itr.hasNext()) {
    +  375  0
                     final Identifier i = itr.next();
    +  376  0
                     if ("cpe".equals(i.getType())) {
    +  377  0
                         final String cpe = i.getValue();
    +  378  0
                         if (cpe != null && (cpe.startsWith("cpe:/a:apache:axis2:") || "cpe:/a:apache:axis2".equals(cpe))) {
    +  379  0
                             itr.remove();
    +  380   +
                         }
    +  381   +
                     }
    +  382  0
                 }
    +  383   +
             }
    +  384  4
         }
    +  385   +
     
    +  386   +
         /**
    +  387   +
          * There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and changes in
    +  388   +
          * product names, that based on given evidence we can add the related CPE entries to ensure a complete list of CVE entries.
    +  389   +
          *
    +  390   +
          * @param dependency the dependency being analyzed
    +  391   +
          */
    +  392   +
         private void addFalseNegativeCPEs(Dependency dependency) {
    +  393   +
             //TODO move this to the hint analyzer
    +  394  4
             for (final Identifier identifier : dependency.getIdentifiers()) {
    +  395  4
                 if ("cpe".equals(identifier.getType()) && identifier.getValue() != null
    +  396  4
                         && (identifier.getValue().startsWith("cpe:/a:oracle:opensso:")
    +  397  4
                         || identifier.getValue().startsWith("cpe:/a:oracle:opensso_enterprise:")
    +  398  4
                         || identifier.getValue().startsWith("cpe:/a:sun:opensso_enterprise:")
    +  399  4
                         || identifier.getValue().startsWith("cpe:/a:sun:opensso:"))) {
    +  400  0
                     final String newCpe = String.format("cpe:/a:sun:opensso_enterprise:%s", identifier.getValue().substring(22));
    +  401  0
                     final String newCpe2 = String.format("cpe:/a:oracle:opensso_enterprise:%s", identifier.getValue().substring(22));
    +  402  0
                     final String newCpe3 = String.format("cpe:/a:sun:opensso:%s", identifier.getValue().substring(22));
    +  403  0
                     final String newCpe4 = String.format("cpe:/a:oracle:opensso:%s", identifier.getValue().substring(22));
    +  404   +
                     try {
    +  405  0
                         dependency.addIdentifier("cpe",
    +  406   +
                                 newCpe,
    +  407  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe, "UTF-8")));
    +  408  0
                         dependency.addIdentifier("cpe",
    +  409   +
                                 newCpe2,
    +  410  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe2, "UTF-8")));
    +  411  0
                         dependency.addIdentifier("cpe",
    +  412   +
                                 newCpe3,
    +  413  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe3, "UTF-8")));
    +  414  0
                         dependency.addIdentifier("cpe",
    +  415   +
                                 newCpe4,
    +  416  0
                                 String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
    +  417  0
                     } catch (UnsupportedEncodingException ex) {
    +  418  0
                         LOGGER.debug("", ex);
    +  419  0
                     }
    +  420  
                 }
    +  421  4
             }
    +  422  4
         }
    +  423   +
     
    +  424   +
         /**
    +  425   +
          * Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM entries or
    +  426   +
          * other types of files (such as DLLs and EXEs) being contained within the JAR.
    +  427   +
          *
    +  428   +
          * @param dependency the dependency that might be a duplicate
    +  429   +
          * @param engine the engine used to scan all dependencies
    +  430   +
          */
    +  431   +
         private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
    +  432  4
             if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
    +  433  4
                     || DLL_EXE_FILTER.accept(dependency.getActualFile())) {
    +  434  1
                 String parentPath = dependency.getFilePath().toLowerCase();
    +  435  1
                 if (parentPath.contains(".jar")) {
    +  436  0
                     parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
    +  437  0
                     final List<Dependency> dependencies = engine.getDependencies();
    +  438  0
                     synchronized (dependencies) {
    +  439  0
                         final Dependency parent = findDependency(parentPath, dependencies);
    +  440  0
                         if (parent != null) {
    +  441  0
                             boolean remove = false;
    +  442  0
                             for (Identifier i : dependency.getIdentifiers()) {
    +  443  0
                                 if ("cpe".equals(i.getType())) {
    +  444  0
                                     final String trimmedCPE = trimCpeToVendor(i.getValue());
    +  445  0
                                     for (Identifier parentId : parent.getIdentifiers()) {
    +  446  0
                                         if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
    +  447  0
                                             remove |= true;
    +  448   +
                                         }
    +  449  0
                                     }
     450   -
             }
    -  451  5
         }
    -  452   -
     
    +
                                 }
    +  451  0
                                 if (!remove) { //we can escape early
    +  452  0
                                     return;
     453   -
         /**
    -  454   -
          * Retrieves a given dependency, based on a given path, from a list of dependencies.
    -  455   -
          *
    -  456   -
          * @param dependencyPath the path of the dependency to return
    +
                                 }
    +  454  0
                             }
    +  455  0
                             if (remove) {
    +  456  0
                                 dependencies.remove(dependency);
     457   -
          * @param dependencies the collection of dependencies to search
    +
                             }
     458   -
          * @return the dependency object for the given path, otherwise null
    -  459   -
          */
    +
                         }
    +  459  0
                     }
     460   -
         private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) {
    -  461  0
             for (Dependency d : dependencies) {
    -  462  0
                 if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
    -  463  0
                     return d;
    -  464  
                 }
    -  465  0
             }
    -  466  0
             return null;
    -  467   -
         }
    -  468   -
     
    -  469   -
         /**
    -  470   -
          * Takes a full CPE and returns the CPE trimmed to include only vendor and product.
    -  471   -
          *
    -  472   -
          * @param value the CPE value to trim
    -  473   -
          * @return a CPE value that only includes the vendor and product
    -  474   -
          */
    -  475   -
         private String trimCpeToVendor(String value) {
    -  476   -
             //cpe:/a:jruby:jruby:1.0.8
    -  477  0
             final int pos1 = value.indexOf(':', 7); //right of vendor
    -  478  0
             final int pos2 = value.indexOf(':', pos1 + 1); //right of product
    -  479  0
             if (pos2 < 0) {
    -  480  0
                 return value;
    -  481   -
             } else {
    -  482  0
                 return value.substring(0, pos2);
    -  483   +  461  
             }
    -  484   +  462  4
         }
    +  463   +
     
    +  464   +
         /**
    +  465   +
          * Retrieves a given dependency, based on a given path, from a list of dependencies.
    +  466   +
          *
    +  467   +
          * @param dependencyPath the path of the dependency to return
    +  468   +
          * @param dependencies the collection of dependencies to search
    +  469   +
          * @return the dependency object for the given path, otherwise null
    +  470   +
          */
    +  471   +
         private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) {
    +  472  0
             for (Dependency d : dependencies) {
    +  473  0
                 if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
    +  474  0
                     return d;
    +  475   +
                 }
    +  476  0
             }
    +  477  0
             return null;
    +  478  
         }
    +  479   +
     
    +  480   +
         /**
    +  481   +
          * Takes a full CPE and returns the CPE trimmed to include only vendor and product.
    +  482   +
          *
    +  483   +
          * @param value the CPE value to trim
    +  484   +
          * @return a CPE value that only includes the vendor and product
     485   +
          */
    +  486   +
         private String trimCpeToVendor(String value) {
    +  487   +
             //cpe:/a:jruby:jruby:1.0.8
    +  488  0
             final int pos1 = value.indexOf(':', 7); //right of vendor
    +  489  0
             final int pos2 = value.indexOf(':', pos1 + 1); //right of product
    +  490  0
             if (pos2 < 0) {
    +  491  0
                 return value;
    +  492   +
             } else {
    +  493  0
                 return value.substring(0, pos2);
    +  494   +
             }
    +  495   +
         }
    +  496  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileNameAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileNameAnalyzer.html index a49ea7cd9..5fe3978c5 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileNameAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileNameAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    FileNameAnalyzer
    90%
    18/20
    62%
    5/8
    2.333
    FileNameAnalyzer
    90%
    19/21
    62%
    5/8
    2
     
    @@ -76,169 +76,190 @@  29  
     import org.owasp.dependencycheck.utils.DependencyVersionUtil;
     30   -
     
    +
     import org.owasp.dependencycheck.utils.Settings;
     31   -
     /**
    +
     
     32   -
      *
    +
     /**
     33   -
      * Takes a dependency and analyzes the filename and determines the hashes.
    -  34  
      *
    +  34   +
      * Takes a dependency and analyzes the filename and determines the hashes.
     35   -
      * @author Jeremy Long
    +
      *
     36   +
      * @author Jeremy Long
    +  37  
      */
    -  37  13
     public class FileNameAnalyzer extends AbstractAnalyzer {
    -  38   -
     
    +  38  13
     public class FileNameAnalyzer extends AbstractAnalyzer {
     39   -
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
    +
     
     40   -
         /**
    +
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
     41   -
          * The name of the analyzer.
    +
         /**
     42   -
          */
    +
          * The name of the analyzer.
     43   -
         private static final String ANALYZER_NAME = "File Name Analyzer";
    +
          */
     44   -
         /**
    +
         private static final String ANALYZER_NAME = "File Name Analyzer";
     45   -
          * The phase that this analyzer is intended to run in.
    +
         /**
     46   +
          * The phase that this analyzer is intended to run in.
    +  47  
          */
    -  47  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
    -  48   -
     
    +  48  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
     49   -
         /**
    +
     
     50   -
          * Returns the name of the analyzer.
    +
         /**
     51   -
          *
    +
          * Returns the name of the analyzer.
     52   -
          * @return the name of the analyzer.
    +
          *
     53   -
          */
    +
          * @return the name of the analyzer.
     54   -
         @Override
    +
          */
     55   +
         @Override
    +  56  
         public String getName() {
    -  56  27
             return ANALYZER_NAME;
    -  57   -
         }
    +  57  26
             return ANALYZER_NAME;
     58   -
     
    -  59   -
         /**
    -  60   -
          * Returns the phase that the analyzer is intended to run in.
    -  61   -
          *
    -  62   -
          * @return the phase that the analyzer is intended to run in.
    -  63   -
          */
    -  64   -
         @Override
    -  65   -
         public AnalysisPhase getAnalysisPhase() {
    -  66  7
             return ANALYSIS_PHASE;
    -  67  
         }
    -  68   -
         //</editor-fold>
    -  69   +  59  
     
    -  70   +  60  
         /**
    -  71   -
          * Python init files
    -  72   -
          */
    -  73   -
         //CSOFF: WhitespaceAfter
    -  74  1
         private static final NameFileFilter IGNORED_FILES = new NameFileFilter(new String[]{
    -  75   -
             "__init__.py",
    -  76   -
             "__init__.pyc",
    -  77   -
             "__init__.pyo",});
    -  78   -
         //CSON: WhitespaceAfter
    -  79   -
     
    -  80   -
         /**
    -  81   -
          * Collects information about the file name.
    -  82   +  61   +
          * Returns the phase that the analyzer is intended to run in.
    +  62  
          *
    -  83   -
          * @param dependency the dependency to analyze.
    -  84   -
          * @param engine the engine that is scanning the dependencies
    -  85   -
          * @throws AnalysisException is thrown if there is an error reading the JAR
    -  86   -
          * file.
    -  87   +  63   +
          * @return the phase that the analyzer is intended to run in.
    +  64  
          */
    -  88   +  65  
         @Override
    +  66   +
         public AnalysisPhase getAnalysisPhase() {
    +  67  7
             return ANALYSIS_PHASE;
    +  68   +
         }
    +  69   +
         /**
    +  70   +
          * <p>
    +  71   +
          * Returns the setting key to determine if the analyzer is enabled.</p>
    +  72   +
          *
    +  73   +
          * @return the key for the analyzer's enabled property
    +  74   +
          */
    +  75   +
         @Override
    +  76   +
         protected String getAnalyzerEnabledSettingKey() {
    +  77  3
             return Settings.KEYS.ANALYZER_FILE_NAME_ENABLED;
    +  78   +
         }
    +  79   +
         //</editor-fold>
    +  80   +
     
    +  81   +
         /**
    +  82   +
          * Python init files
    +  83   +
          */
    +  84   +
         //CSOFF: WhitespaceAfter
    +  85  1
         private static final NameFileFilter IGNORED_FILES = new NameFileFilter(new String[]{
    +  86   +
             "__init__.py",
    +  87   +
             "__init__.pyc",
    +  88   +
             "__init__.pyo",});
     89   -
         public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    +
         //CSON: WhitespaceAfter
     90  
     
     91   -
             //strip any path information that may get added by ArchiveAnalyzer, etc.
    -  92  6
             final File f = dependency.getActualFile();
    -  93  6
             final String fileName = FilenameUtils.removeExtension(f.getName());
    +
         /**
    +  92   +
          * Collects information about the file name.
    +  93   +
          *
     94   -
     
    +
          * @param dependency the dependency to analyze.
     95   -
             //add version evidence
    -  96  6
             final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName);
    -  97  6
             final String packageName = DependencyVersionUtil.parsePreVersion(fileName);
    -  98  6
             if (version != null) {
    +
          * @param engine the engine that is scanning the dependencies
    +  96   +
          * @throws AnalysisException is thrown if there is an error reading the JAR
    +  97   +
          * file.
    +  98   +
          */
     99   -
                 // If the version number is just a number like 2 or 23, reduce the confidence
    +
         @Override
     100   -
                 // a shade. This should hopefully correct for cases like log4j.jar or
    +
         protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
     101   -
                 // struts2-core.jar
    -  102  5
                 if (version.getVersionParts() == null || version.getVersionParts().size() < 2) {
    -  103  0
                     dependency.getVersionEvidence().addEvidence("file", "version",
    -  104  0
                             version.toString(), Confidence.MEDIUM);
    -  105   -
                 } else {
    -  106  10
                     dependency.getVersionEvidence().addEvidence("file", "version",
    -  107  5
                             version.toString(), Confidence.HIGHEST);
    -  108   -
                 }
    -  109  5
                 dependency.getVersionEvidence().addEvidence("file", "name",
    -  110   -
                         packageName, Confidence.MEDIUM);
    -  111   -
             }
    -  112  
     
    -  113  6
             if (!IGNORED_FILES.accept(f)) {
    -  114  6
                 dependency.getProductEvidence().addEvidence("file", "name",
    -  115   -
                         packageName, Confidence.HIGH);
    -  116  6
                 dependency.getVendorEvidence().addEvidence("file", "name",
    -  117   -
                         packageName, Confidence.HIGH);
    -  118   +  102   +
             //strip any path information that may get added by ArchiveAnalyzer, etc.
    +  103  6
             final File f = dependency.getActualFile();
    +  104  6
             final String fileName = FilenameUtils.removeExtension(f.getName());
    +  105   +
     
    +  106   +
             //add version evidence
    +  107  5
             final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName);
    +  108  6
             final String packageName = DependencyVersionUtil.parsePreVersion(fileName);
    +  109  6
             if (version != null) {
    +  110   +
                 // If the version number is just a number like 2 or 23, reduce the confidence
    +  111   +
                 // a shade. This should hopefully correct for cases like log4j.jar or
    +  112   +
                 // struts2-core.jar
    +  113  4
                 if (version.getVersionParts() == null || version.getVersionParts().size() < 2) {
    +  114  0
                     dependency.getVersionEvidence().addEvidence("file", "version",
    +  115  0
                             version.toString(), Confidence.MEDIUM);
    +  116   +
                 } else {
    +  117  8
                     dependency.getVersionEvidence().addEvidence("file", "version",
    +  118  5
                             version.toString(), Confidence.HIGHEST);
    +  119   +
                 }
    +  120  5
                 dependency.getVersionEvidence().addEvidence("file", "name",
    +  121   +
                         packageName, Confidence.MEDIUM);
    +  122  
             }
    -  119  6
         }
    -  120   +  123   +
     
    +  124  6
             if (!IGNORED_FILES.accept(f)) {
    +  125  5
                 dependency.getProductEvidence().addEvidence("file", "name",
    +  126   +
                         packageName, Confidence.HIGH);
    +  127  6
                 dependency.getVendorEvidence().addEvidence("file", "name",
    +  128   +
                         packageName, Confidence.HIGH);
    +  129   +
             }
    +  130  6
         }
    +  131  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileTypeAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileTypeAnalyzer.html index 8ddc8954c..cb6511ac1 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileTypeAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.FileTypeAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    FileTypeAnalyzer
    N/A
    N/A
    1
    FileTypeAnalyzer
    N/A
    N/A
    0
     
    @@ -74,17 +74,9 @@  28  
     
     29   -
         /**
    -  30   -
          * Resets the analyzers state.
    -  31   -
          */
    -  32   -
         void reset();
    -  33  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.HintAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.HintAnalyzer.html index ede9a4ab4..8f008ad0e 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.HintAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.HintAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    HintAnalyzer
    44%
    50/113
    57%
    29/50
    9.2
    HintAnalyzer
    44%
    50/113
    57%
    29/50
    7.833
     
    @@ -182,456 +182,474 @@  84  
         }
     85   -
     
    -  86  
         /**
    +  86   +
          * <p>
     87   -
          * The initialize method does nothing for this Analyzer.
    +
          * Returns the setting key to determine if the analyzer is enabled.</p>
     88  
          *
     89   -
          * @throws InitializationException thrown if there is an exception
    +
          * @return the key for the analyzer's enabled property
     90  
          */
     91  
         @Override
     92   -
         public void initialize() throws InitializationException {
    -  93   -
             try {
    -  94  2
                 super.initialize();
    -  95  2
                 loadHintRules();
    -  96  0
             } catch (HintParseException ex) {
    -  97  0
                 LOGGER.debug("Unable to parse hint file", ex);
    -  98  0
                 throw new InitializationException("Unable to parse the hint file", ex);
    -  99  2
             }
    -  100  2
         }
    +
         protected String getAnalyzerEnabledSettingKey() {
    +  93  2
             return Settings.KEYS.ANALYZER_HINT_ENABLED;
    +  94   +
         }
    +  95   +
     
    +  96   +
         /**
    +  97   +
          * The initialize method does nothing for this Analyzer.
    +  98   +
          *
    +  99   +
          * @throws InitializationException thrown if there is an exception
    +  100   +
          */
     101   -
         //</editor-fold>
    +
         @Override
     102   -
     
    +
         public void initializeAnalyzer() throws InitializationException {
     103   -
         /**
    -  104   -
          * The Logger for use throughout the class
    -  105   -
          */
    -  106  1
         private static final Logger LOGGER = LoggerFactory.getLogger(HintAnalyzer.class);
    -  107   -
         /**
    -  108   -
          * The name of the hint rule file
    -  109   -
          */
    +
             try {
    +  104  2
                 loadHintRules();
    +  105  0
             } catch (HintParseException ex) {
    +  106  0
                 LOGGER.debug("Unable to parse hint file", ex);
    +  107  0
                 throw new InitializationException("Unable to parse the hint file", ex);
    +  108  2
             }
    +  109  2
         }
     110   -
         private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
    +
         //</editor-fold>
     111   -
         /**
    -  112   -
          * The collection of hints.
    -  113   -
          */
    -  114   -
         private Hints hints;
    -  115  
     
    +  112   +
         /**
    +  113   +
          * The Logger for use throughout the class
    +  114   +
          */
    +  115  1
         private static final Logger LOGGER = LoggerFactory.getLogger(HintAnalyzer.class);
     116  
         /**
     117   -
          * The HintAnalyzer uses knowledge about a dependency to add additional
    +
          * The name of the hint rule file
     118   -
          * information to help in identification of identifiers or vulnerabilities.
    -  119   -
          *
    -  120   -
          * @param dependency The dependency being analyzed
    -  121   -
          * @param engine The scanning engine
    -  122   -
          * @throws AnalysisException is thrown if there is an exception analyzing
    -  123   -
          * the dependency.
    -  124  
          */
    +  119   +
         private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
    +  120   +
         /**
    +  121   +
          * The collection of hints.
    +  122   +
          */
    +  123   +
         private Hints hints;
    +  124   +
     
     125   -
         @Override
    +
         /**
     126   -
         public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    -  127  4
             for (HintRule hint : hints.getHintRules()) {
    -  128  48
                 boolean shouldAdd = false;
    -  129  47
                 for (Evidence given : hint.getGivenVendor()) {
    -  130  8
                     if (dependency.getVendorEvidence().getEvidence().contains(given)) {
    -  131  0
                         shouldAdd = true;
    -  132  0
                         break;
    +
          * The HintAnalyzer uses knowledge about a dependency to add additional
    +  127   +
          * information to help in identification of identifiers or vulnerabilities.
    +  128   +
          *
    +  129   +
          * @param dependency The dependency being analyzed
    +  130   +
          * @param engine The scanning engine
    +  131   +
          * @throws AnalysisException is thrown if there is an exception analyzing
    +  132   +
          * the dependency.
     133   -
                     }
    -  134  8
                 }
    -  135  48
                 if (!shouldAdd) {
    -  136  46
                     for (Evidence given : hint.getGivenProduct()) {
    -  137  29
                         if (dependency.getProductEvidence().getEvidence().contains(given)) {
    -  138  1
                             shouldAdd = true;
    -  139  1
                             break;
    -  140   -
                         }
    -  141  30
                     }
    +
          */
    +  134   +
         @Override
    +  135   +
         protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  136  4
             for (HintRule hint : hints.getHintRules()) {
    +  137  48
                 boolean shouldAdd = false;
    +  138  48
                 for (Evidence given : hint.getGivenVendor()) {
    +  139  8
                     if (dependency.getVendorEvidence().getEvidence().contains(given)) {
    +  140  0
                         shouldAdd = true;
    +  141  0
                         break;
     142   -
                 }
    -  143  48
                 if (!shouldAdd) {
    -  144  47
                     for (PropertyType pt : hint.getFilenames()) {
    -  145  24
                         if (pt.matches(dependency.getFileName())) {
    -  146  0
                             shouldAdd = true;
    -  147   -
                         }
    -  148  24
                     }
    -  149   -
                 }
    -  150  48
                 if (shouldAdd) {
    -  151  1
                     for (Evidence e : hint.getAddVendor()) {
    -  152  3
                         dependency.getVendorEvidence().addEvidence(e);
    -  153  3
                     }
    -  154  1
                     for (Evidence e : hint.getAddProduct()) {
    -  155  1
                         dependency.getProductEvidence().addEvidence(e);
    -  156  1
                     }
    -  157  1
                     for (Evidence e : hint.getAddVersion()) {
    -  158  0
                         dependency.getVersionEvidence().addEvidence(e);
    -  159  0
                     }
    -  160   -
                 }
    -  161  48
             }
    -  162   -
     
    -  163  4
             final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
    -  164  3
             final List<Evidence> newEntries = new ArrayList<Evidence>();
    -  165  29
             while (itr.hasNext()) {
    -  166  25
                 final Evidence e = itr.next();
    -  167  24
                 for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
    -  168  49
                     if (dhr.getValue().equalsIgnoreCase(e.getValue(false))) {
    -  169  0
                         newEntries.add(new Evidence(e.getSource() + " (hint)",
    -  170  0
                                 e.getName(), dhr.getDuplicate(), e.getConfidence()));
    -  171  
                     }
    -  172  50
                 }
    -  173  25
             }
    -  174  4
             for (Evidence e : newEntries) {
    -  175  0
                 dependency.getVendorEvidence().addEvidence(e);
    -  176  0
             }
    -  177   +  143  8
                 }
    +  144  48
                 if (!shouldAdd) {
    +  145  48
                     for (Evidence given : hint.getGivenProduct()) {
    +  146  31
                         if (dependency.getProductEvidence().getEvidence().contains(given)) {
    +  147  1
                             shouldAdd = true;
    +  148  1
                             break;
    +  149   +
                         }
    +  150  30
                     }
    +  151   +
                 }
    +  152  48
                 if (!shouldAdd) {
    +  153  47
                     for (PropertyType pt : hint.getFilenames()) {
    +  154  24
                         if (pt.matches(dependency.getFileName())) {
    +  155  0
                             shouldAdd = true;
    +  156   +
                         }
    +  157  24
                     }
    +  158   +
                 }
    +  159  48
                 if (shouldAdd) {
    +  160  1
                     for (Evidence e : hint.getAddVendor()) {
    +  161  3
                         dependency.getVendorEvidence().addEvidence(e);
    +  162  3
                     }
    +  163  1
                     for (Evidence e : hint.getAddProduct()) {
    +  164  1
                         dependency.getProductEvidence().addEvidence(e);
    +  165  1
                     }
    +  166  1
                     for (Evidence e : hint.getAddVersion()) {
    +  167  0
                         dependency.getVersionEvidence().addEvidence(e);
    +  168  0
                     }
    +  169   +
                 }
    +  170  48
             }
    +  171  
     
    -  178   -
             //<editor-fold defaultstate="collapsed" desc="Old implementation">
    -  179   -
             /*
    +  172  4
             final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
    +  173  4
             final List<Evidence> newEntries = new ArrayList<Evidence>();
    +  174  29
             while (itr.hasNext()) {
    +  175  25
                 final Evidence e = itr.next();
    +  176  25
                 for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
    +  177  50
                     if (dhr.getValue().equalsIgnoreCase(e.getValue(false))) {
    +  178  0
                         newEntries.add(new Evidence(e.getSource() + " (hint)",
    +  179  0
                                 e.getName(), dhr.getDuplicate(), e.getConfidence()));
     180   -
             final Evidence springTest1 = new Evidence("Manifest",
    -  181   -
                     "Implementation-Title",
    -  182   -
                     "Spring Framework",
    -  183   -
                     Confidence.HIGH);
    -  184   -
     
    -  185   -
             final Evidence springTest2 = new Evidence("Manifest",
    +
                     }
    +  181  50
                 }
    +  182  25
             }
    +  183  4
             for (Evidence e : newEntries) {
    +  184  0
                 dependency.getVendorEvidence().addEvidence(e);
    +  185  0
             }
     186   -
                     "Implementation-Title",
    +
     
     187   -
                     "org.springframework.core",
    +
             //<editor-fold defaultstate="collapsed" desc="Old implementation">
     188   -
                     Confidence.HIGH);
    +
             /*
     189   -
     
    +
             final Evidence springTest1 = new Evidence("Manifest",
     190   -
             final Evidence springTest3 = new Evidence("Manifest",
    -  191  
                     "Implementation-Title",
    +  191   +
                     "Spring Framework",
     192   -
                     "spring-core",
    +
                     Confidence.HIGH);
     193   -
                     Confidence.HIGH);
    +
     
     194   -
     
    +
             final Evidence springTest2 = new Evidence("Manifest",
     195   -
             final Evidence springTest4 = new Evidence("jar",
    +
                     "Implementation-Title",
     196   -
                     "package name",
    +
                     "org.springframework.core",
     197   -
                     "springframework",
    -  198   -
                     Confidence.LOW);
    -  199   -
     
    -  200   -
             final Evidence springSecurityTest1 = new Evidence("Manifest",
    -  201   -
                     "Bundle-Name",
    -  202   -
                     "Spring Security Core",
    -  203   -
                     Confidence.MEDIUM);
    -  204   -
     
    -  205   -
             final Evidence springSecurityTest2 = new Evidence("pom",
    -  206   -
                     "artifactid",
    -  207   -
                     "spring-security-core",
    -  208  
                     Confidence.HIGH);
    +  198   +
     
    +  199   +
             final Evidence springTest3 = new Evidence("Manifest",
    +  200   +
                     "Implementation-Title",
    +  201   +
                     "spring-core",
    +  202   +
                     Confidence.HIGH);
    +  203   +
     
    +  204   +
             final Evidence springTest4 = new Evidence("jar",
    +  205   +
                     "package name",
    +  206   +
                     "springframework",
    +  207   +
                     Confidence.LOW);
    +  208   +
     
     209   -
     
    +
             final Evidence springSecurityTest1 = new Evidence("Manifest",
     210   -
             final Evidence symfony = new Evidence("composer.lock",
    +
                     "Bundle-Name",
     211   -
                 "vendor",
    +
                     "Spring Security Core",
     212   -
                 "symfony",
    +
                     Confidence.MEDIUM);
     213   -
                 Confidence.HIGHEST);
    +
     
     214   -
     
    +
             final Evidence springSecurityTest2 = new Evidence("pom",
     215   -
             final Evidence zendframeworkVendor = new Evidence("composer.lock",
    +
                     "artifactid",
     216   -
                 "vendor",
    +
                     "spring-security-core",
     217   -
                 "zendframework",
    +
                     Confidence.HIGH);
     218   -
                 Confidence.HIGHEST);
    +
     
     219   -
     
    +
             final Evidence symfony = new Evidence("composer.lock",
     220   -
             final Evidence zendframeworkProduct = new Evidence("composer.lock",
    +
                 "vendor",
     221   -
                 "product",
    +
                 "symfony",
     222   -
                 "zendframework",
    -  223  
                 Confidence.HIGHEST);
    -  224   +  223  
     
    +  224   +
             final Evidence zendframeworkVendor = new Evidence("composer.lock",
     225   -
             //springsource/vware problem
    +
                 "vendor",
     226   -
             final Set<Evidence> product = dependency.getProductEvidence().getEvidence();
    +
                 "zendframework",
     227   -
             final Set<Evidence> vendor = dependency.getVendorEvidence().getEvidence();
    +
                 Confidence.HIGHEST);
     228  
     
     229   -
             if (product.contains(springTest1) || product.contains(springTest2) || product.contains(springTest3)
    +
             final Evidence zendframeworkProduct = new Evidence("composer.lock",
     230   -
                     || (dependency.getFileName().contains("spring") && product.contains(springTest4))) {
    +
                 "product",
     231   -
                 dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource spring framework", Confidence.HIGH);
    +
                 "zendframework",
     232   -
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
    +
                 Confidence.HIGHEST);
     233   -
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
    +
     
     234   -
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
    +
             //springsource/vware problem
     235   -
             }
    +
             final Set<Evidence> product = dependency.getProductEvidence().getEvidence();
     236   -
     
    +
             final Set<Evidence> vendor = dependency.getVendorEvidence().getEvidence();
     237   -
             if (vendor.contains(springTest4)) {
    +
     
     238   -
                 dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
    +
             if (product.contains(springTest1) || product.contains(springTest2) || product.contains(springTest3)
     239   -
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
    +
                     || (dependency.getFileName().contains("spring") && product.contains(springTest4))) {
     240   -
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
    +
                 dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource spring framework", Confidence.HIGH);
     241   -
             }
    -  242   -
     
    -  243   -
             if (product.contains(springSecurityTest1) || product.contains(springSecurityTest2)) {
    -  244   -
                 dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_security", Confidence.HIGH);
    -  245  
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
    -  246   +  242  
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
    +  243   +
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
    +  244   +
             }
    +  245   +
     
    +  246   +
             if (vendor.contains(springTest4)) {
     247   -
             }
    +
                 dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
     248   -
     
    +
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
     249   -
             if (vendor.contains(symfony)) {
    +
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
     250   -
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "sensiolabs", Confidence.HIGHEST);
    +
             }
     251   -
             }
    +
     
     252   -
     
    +
             if (product.contains(springSecurityTest1) || product.contains(springSecurityTest2)) {
     253   -
             if (vendor.contains(zendframeworkVendor)) {
    +
                 dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_security", Confidence.HIGH);
     254   -
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "zend", Confidence.HIGHEST);
    +
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
     255   -
             }
    +
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
     256   -
     
    +
             }
     257   -
             if (product.contains(zendframeworkProduct)) {
    +
     
     258   -
                 dependency.getProductEvidence().addEvidence("hint analyzer", "vendor", "zend_framework", Confidence.HIGHEST);
    +
             if (vendor.contains(symfony)) {
     259   -
             }
    +
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "sensiolabs", Confidence.HIGHEST);
     260   -
     
    +
             }
     261   -
             //sun/oracle problem
    +
     
     262   -
             final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
    +
             if (vendor.contains(zendframeworkVendor)) {
     263   -
             final List<Evidence> newEntries = new ArrayList<Evidence>();
    +
                 dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "zend", Confidence.HIGHEST);
     264   -
             while (itr.hasNext()) {
    +
             }
     265   -
                 final Evidence e = itr.next();
    +
     
     266   -
                 if ("sun".equalsIgnoreCase(e.getValue(false))) {
    +
             if (product.contains(zendframeworkProduct)) {
     267   -
                     final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "oracle", e.getConfidence());
    +
                 dependency.getProductEvidence().addEvidence("hint analyzer", "vendor", "zend_framework", Confidence.HIGHEST);
     268   -
                     newEntries.add(newEvidence);
    +
             }
     269   -
                 } else if ("oracle".equalsIgnoreCase(e.getValue(false))) {
    +
     
     270   -
                     final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "sun", e.getConfidence());
    +
             //sun/oracle problem
     271   -
                     newEntries.add(newEvidence);
    +
             final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
     272   -
                 }
    +
             final List<Evidence> newEntries = new ArrayList<Evidence>();
     273   -
             }
    +
             while (itr.hasNext()) {
     274   -
             for (Evidence e : newEntries) {
    +
                 final Evidence e = itr.next();
     275   -
                 dependency.getVendorEvidence().addEvidence(e);
    +
                 if ("sun".equalsIgnoreCase(e.getValue(false))) {
     276   -
             }
    +
                     final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "oracle", e.getConfidence());
     277   -
              */
    +
                     newEntries.add(newEvidence);
     278   -
             //</editor-fold>
    -  279  4
         }
    +
                 } else if ("oracle".equalsIgnoreCase(e.getValue(false))) {
    +  279   +
                     final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "sun", e.getConfidence());
     280   -
     
    +
                     newEntries.add(newEvidence);
     281   -
         /**
    +
                 }
     282   -
          * Loads the hint rules file.
    +
             }
     283   -
          *
    +
             for (Evidence e : newEntries) {
     284   -
          * @throws HintParseException thrown if the XML cannot be parsed.
    +
                 dependency.getVendorEvidence().addEvidence(e);
     285   -
          */
    +
             }
     286   -
         private void loadHintRules() throws HintParseException {
    -  287  2
             final HintParser parser = new HintParser();
    -  288  2
             File file = null;
    +
              */
    +  287   +
             //</editor-fold>
    +  288  4
         }
     289   -
             try {
    -  290  2
                 hints = parser.parseHints(this.getClass().getClassLoader().getResourceAsStream(HINT_RULE_FILE_NAME));
    -  291  0
             } catch (HintParseException ex) {
    -  292  0
                 LOGGER.error("Unable to parse the base hint data file");
    -  293  0
                 LOGGER.debug("Unable to parse the base hint data file", ex);
    -  294  0
             } catch (SAXException ex) {
    -  295  0
                 LOGGER.error("Unable to parse the base hint data file");
    -  296  0
                 LOGGER.debug("Unable to parse the base hint data file", ex);
    -  297  2
             }
    -  298  2
             final String filePath = Settings.getString(Settings.KEYS.HINTS_FILE);
    -  299  2
             if (filePath == null) {
    -  300  2
                 return;
    -  301   -
             }
    -  302  0
             boolean deleteTempFile = false;
    -  303   -
             try {
    -  304  0
                 final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
    -  305  0
                 if (uriRx.matcher(filePath).matches()) {
    -  306  0
                     deleteTempFile = true;
    -  307  0
                     file = FileUtils.getTempFile("hint", "xml");
    -  308  0
                     final URL url = new URL(filePath);
    -  309   -
                     try {
    -  310  0
                         Downloader.fetchFile(url, file, false);
    -  311  0
                     } catch (DownloadFailedException ex) {
    -  312  0
                         Downloader.fetchFile(url, file, true);
    -  313  0
                     }
    -  314  0
                 } else {
    -  315  0
                     file = new File(filePath);
    -  316  0
                     if (!file.exists()) {
    -  317  0
                         InputStream fromClasspath = null;
    -  318   -
                         try {
    -  319  0
                             fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath);
    -  320  0
                             if (fromClasspath != null) {
    -  321  0
                                 deleteTempFile = true;
    -  322  0
                                 file = FileUtils.getTempFile("hint", "xml");
    -  323   -
                                 try {
    -  324  0
                                     org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
    -  325  0
                                 } catch (IOException ex) {
    -  326  0
                                     throw new HintParseException("Unable to locate hints file in classpath", ex);
    -  327  0
                                 }
    -  328   -
                             }
    -  329   -
                         } finally {
    -  330  0
                             if (fromClasspath != null) {
    -  331  0
                                 fromClasspath.close();
    -  332   -
                             }
    -  333   -
                         }
    -  334   -
                     }
    -  335   -
                 }
    -  336  
     
    -  337  0
                 if (file != null) {
    -  338   -
                     try {
    -  339  0
                         final Hints newHints = parser.parseHints(file);
    -  340  0
                         hints.getHintRules().addAll(newHints.getHintRules());
    -  341  0
                         hints.getVendorDuplicatingHintRules().addAll(newHints.getVendorDuplicatingHintRules());
    -  342  0
                         LOGGER.debug("{} hint rules were loaded.", hints.getHintRules().size());
    -  343  0
                         LOGGER.debug("{} duplicating hint rules were loaded.", hints.getVendorDuplicatingHintRules().size());
    -  344  0
                     } catch (HintParseException ex) {
    -  345  0
                         LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath());
    -  346  0
                         LOGGER.warn(ex.getMessage());
    -  347  0
                         LOGGER.debug("", ex);
    -  348  0
                         throw ex;
    -  349  0
                     }
    -  350   -
                 }
    -  351  0
             } catch (DownloadFailedException ex) {
    -  352  0
                 throw new HintParseException("Unable to fetch the configured hint file", ex);
    -  353  0
             } catch (MalformedURLException ex) {
    -  354  0
                 throw new HintParseException("Configured hint file has an invalid URL", ex);
    -  355  0
             } catch (IOException ex) {
    -  356  0
                 throw new HintParseException("Unable to create temp file for hints", ex);
    -  357   -
             } finally {
    -  358  0
                 if (deleteTempFile && file != null) {
    -  359  0
                     FileUtils.delete(file);
    -  360   -
                 }
    -  361   +  290   +
         /**
    +  291   +
          * Loads the hint rules file.
    +  292   +
          *
    +  293   +
          * @throws HintParseException thrown if the XML cannot be parsed.
    +  294   +
          */
    +  295   +
         private void loadHintRules() throws HintParseException {
    +  296  2
             final HintParser parser = new HintParser();
    +  297  2
             File file = null;
    +  298   +
             try {
    +  299  2
                 hints = parser.parseHints(this.getClass().getClassLoader().getResourceAsStream(HINT_RULE_FILE_NAME));
    +  300  0
             } catch (HintParseException ex) {
    +  301  0
                 LOGGER.error("Unable to parse the base hint data file");
    +  302  0
                 LOGGER.debug("Unable to parse the base hint data file", ex);
    +  303  0
             } catch (SAXException ex) {
    +  304  0
                 LOGGER.error("Unable to parse the base hint data file");
    +  305  0
                 LOGGER.debug("Unable to parse the base hint data file", ex);
    +  306  2
             }
    +  307  2
             final String filePath = Settings.getString(Settings.KEYS.HINTS_FILE);
    +  308  2
             if (filePath == null) {
    +  309  2
                 return;
    +  310  
             }
    -  362  0
         }
    -  363   +  311  0
             boolean deleteTempFile = false;
    +  312   +
             try {
    +  313  0
                 final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
    +  314  0
                 if (uriRx.matcher(filePath).matches()) {
    +  315  0
                     deleteTempFile = true;
    +  316  0
                     file = FileUtils.getTempFile("hint", "xml");
    +  317  0
                     final URL url = new URL(filePath);
    +  318   +
                     try {
    +  319  0
                         Downloader.fetchFile(url, file, false);
    +  320  0
                     } catch (DownloadFailedException ex) {
    +  321  0
                         Downloader.fetchFile(url, file, true);
    +  322  0
                     }
    +  323  0
                 } else {
    +  324  0
                     file = new File(filePath);
    +  325  0
                     if (!file.exists()) {
    +  326  0
                         InputStream fromClasspath = null;
    +  327   +
                         try {
    +  328  0
                             fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath);
    +  329  0
                             if (fromClasspath != null) {
    +  330  0
                                 deleteTempFile = true;
    +  331  0
                                 file = FileUtils.getTempFile("hint", "xml");
    +  332   +
                                 try {
    +  333  0
                                     org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
    +  334  0
                                 } catch (IOException ex) {
    +  335  0
                                     throw new HintParseException("Unable to locate hints file in classpath", ex);
    +  336  0
                                 }
    +  337   +
                             }
    +  338   +
                         } finally {
    +  339  0
                             if (fromClasspath != null) {
    +  340  0
                                 fromClasspath.close();
    +  341   +
                             }
    +  342   +
                         }
    +  343   +
                     }
    +  344   +
                 }
    +  345   +
     
    +  346  0
                 if (file != null) {
    +  347   +
                     try {
    +  348  0
                         final Hints newHints = parser.parseHints(file);
    +  349  0
                         hints.getHintRules().addAll(newHints.getHintRules());
    +  350  0
                         hints.getVendorDuplicatingHintRules().addAll(newHints.getVendorDuplicatingHintRules());
    +  351  0
                         LOGGER.debug("{} hint rules were loaded.", hints.getHintRules().size());
    +  352  0
                         LOGGER.debug("{} duplicating hint rules were loaded.", hints.getVendorDuplicatingHintRules().size());
    +  353  0
                     } catch (HintParseException ex) {
    +  354  0
                         LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath());
    +  355  0
                         LOGGER.warn(ex.getMessage());
    +  356  0
                         LOGGER.debug("", ex);
    +  357  0
                         throw ex;
    +  358  0
                     }
    +  359   +
                 }
    +  360  0
             } catch (DownloadFailedException ex) {
    +  361  0
                 throw new HintParseException("Unable to fetch the configured hint file", ex);
    +  362  0
             } catch (MalformedURLException ex) {
    +  363  0
                 throw new HintParseException("Configured hint file has an invalid URL", ex);
    +  364  0
             } catch (IOException ex) {
    +  365  0
                 throw new HintParseException("Unable to create temp file for hints", ex);
    +  366   +
             } finally {
    +  367  0
                 if (deleteTempFile && file != null) {
    +  368  0
                     FileUtils.delete(file);
    +  369   +
                 }
    +  370   +
             }
    +  371  0
         }
    +  372  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.JarAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.JarAnalyzer.html index 1039eabb7..d852a933f 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.JarAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.JarAnalyzer.html @@ -12,8 +12,8 @@
     
    - - + +
    Classes in this File Line Coverage Branch Coverage Complexity
    JarAnalyzer
    65%
    351/532
    55%
    198/360
    7.677
    JarAnalyzer$ClassNameInformation
    80%
    17/21
    80%
    8/10
    7.677
    JarAnalyzer
    68%
    365/532
    55%
    199/360
    8.207
    JarAnalyzer$ClassNameInformation
    80%
    17/21
    80%
    8/10
    8.207
     
    @@ -69,9 +69,9 @@  25  
     import java.io.InputStreamReader;
     26   -
     import java.io.OutputStream;
    -  27  
     import java.io.Reader;
    +  27   +
     import java.io.UnsupportedEncodingException;
     28  
     import java.util.ArrayList;
     29   @@ -373,7 +373,7 @@
         @Override
     184  
         protected FileFilter getFileFilter() {
    -  185  867
             return FILTER;
    +  185  865
             return FILTER;
     186  
         }
     187   @@ -392,7 +392,7 @@
         @Override
     194  
         public String getName() {
    -  195  25
             return ANALYZER_NAME;
    +  195  23
             return ANALYZER_NAME;
     196  
         }
     197   @@ -434,7 +434,7 @@
         @Override
     216  
         protected String getAnalyzerEnabledSettingKey() {
    -  217  13
             return Settings.KEYS.ANALYZER_JAR_ENABLED;
    +  217  3
             return Settings.KEYS.ANALYZER_JAR_ENABLED;
     218  
         }
     219   @@ -460,7 +460,7 @@  229  
         @Override
     230   -
         public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
    +
         public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
     231  
             try {
     232  6
                 final List<ClassNameInformation> classNames = collectClassNames(dependency);
    @@ -478,7 +478,7 @@  243  6
                 final boolean addPackagesAsEvidence = !(hasManifest && hasPOM);
     244  6
                 analyzePackageNames(classNames, dependency, addPackagesAsEvidence);
     245  0
             } catch (IOException ex) {
    -  246  0
                 throw new AnalysisException("Exception occurred reading the JAR file.", ex);
    +  246  0
                 throw new AnalysisException("Exception occurred reading the JAR file (" + dependency.getFileName() + ").", ex);
     247  6
             }
     248  6
         }
     249   @@ -509,378 +509,366 @@
          */
     262  
         protected boolean analyzePOM(Dependency dependency, List<ClassNameInformation> classes, Engine engine) throws AnalysisException {
    -  263  6
             boolean foundSomething = false;
    -  264   -
             final JarFile jar;
    +  263  6
             JarFile jar = null;
    +  264  6
             List<String> pomEntries = null;
     265  
             try {
     266  6
                 jar = new JarFile(dependency.getActualFilePath());
    -  267  0
             } catch (IOException ex) {
    -  268  0
                 LOGGER.warn("Unable to read JarFile '{}'.", dependency.getActualFilePath());
    -  269  0
                 LOGGER.trace("", ex);
    -  270  0
                 return false;
    -  271  6
             }
    +  267  6
                 pomEntries = retrievePomListing(jar);
    +  268  0
             } catch (IOException ex) {
    +  269  0
                 LOGGER.warn("Unable to read JarFile '{}'.", dependency.getActualFilePath());
    +  270  0
                 LOGGER.trace("", ex);
    +  271  0
                 if (jar != null) {
     272   -
             List<String> pomEntries;
    -  273   -
             try {
    -  274  6
                 pomEntries = retrievePomListing(jar);
    -  275  0
             } catch (IOException ex) {
    -  276  0
                 LOGGER.warn("Unable to read Jar file entries in '{}'.", dependency.getActualFilePath());
    -  277  0
                 LOGGER.trace("", ex);
    +
                     try {
    +  273  0
                         jar.close();
    +  274  0
                     } catch (IOException ex1) {
    +  275  0
                         LOGGER.trace("", ex1);
    +  276  0
                     }
    +  277   +
                 }
     278  0
                 return false;
     279  6
             }
    -  280  6
             File externalPom = null;
    -  281  6
             if (pomEntries.isEmpty()) {
    -  282  4
                 final String pomPath = FilenameUtils.removeExtension(dependency.getActualFilePath()) + ".pom";
    -  283  4
                 externalPom = new File(pomPath);
    -  284  4
                 if (externalPom.isFile()) {
    -  285  0
                     pomEntries.add(pomPath);
    -  286   -
                 } else {
    -  287  4
                     return false;
    -  288   -
                 }
    +  280  6
             if (pomEntries != null && pomEntries.size() <= 1) {
    +  281   +
                 try {
    +  282  6
                     String path = null;
    +  283  6
                     Properties pomProperties = null;
    +  284  6
                     File pomFile = null;
    +  285  6
                     if (pomEntries.size() == 1) {
    +  286  2
                         path = pomEntries.get(0);
    +  287  2
                         pomFile = extractPom(path, jar);
    +  288  2
                         pomProperties = retrievePomProperties(path, jar);
     289   -
             }
    -  290  2
             for (String path : pomEntries) {
    -  291  2
                 LOGGER.debug("Reading pom entry: {}", path);
    -  292  2
                 Properties pomProperties = null;
    -  293   -
                 try {
    -  294  2
                     if (externalPom == null) {
    -  295  2
                         pomProperties = retrievePomProperties(path, jar);
    -  296   +
                     } else {
    +  290  4
                         path = FilenameUtils.removeExtension(dependency.getActualFilePath()) + ".pom";
    +  291  4
                         pomFile = new File(path);
    +  292  
                     }
    -  297  0
                 } catch (IOException ex) {
    -  298  0
                     LOGGER.trace("ignore this, failed reading a non-existent pom.properties", ex);
    -  299  2
                 }
    -  300  2
                 Model pom = null;
    -  301   -
                 try {
    -  302  2
                     if (pomEntries.size() > 1) {
    -  303   -
                         //extract POM to its own directory and add it as its own dependency
    -  304  0
                         final Dependency newDependency = new Dependency();
    -  305  0
                         pom = extractPom(path, jar, newDependency);
    -  306   -
     
    -  307  0
                         final String displayPath = String.format("%s%s%s",
    -  308  0
                                 dependency.getFilePath(),
    -  309   -
                                 File.separator,
    -  310   -
                                 path);
    -  311  0
                         final String displayName = String.format("%s%s%s",
    -  312  0
                                 dependency.getFileName(),
    -  313   -
                                 File.separator,
    -  314   -
                                 path);
    -  315   -
     
    -  316  0
                         newDependency.setFileName(displayName);
    -  317  0
                         newDependency.setFilePath(displayPath);
    -  318  0
                         pom.processProperties(pomProperties);
    -  319  0
                         setPomEvidence(newDependency, pom, null);
    -  320  0
                         engine.getDependencies().add(newDependency);
    -  321  0
                     } else {
    -  322  2
                         if (externalPom == null) {
    -  323  2
                             pom = PomUtils.readPom(path, jar);
    -  324   -
                         } else {
    -  325  0
                             pom = PomUtils.readPom(externalPom);
    -  326   +  293  6
                     if (pomFile.isFile()) {
    +  294  2
                         final Model pom = PomUtils.readPom(pomFile);
    +  295  2
                         if (pom != null && pomProperties != null) {
    +  296  0
                             pom.processProperties(pomProperties);
    +  297  
                         }
    -  327  2
                         if (pom != null) {
    -  328  2
                             pom.processProperties(pomProperties);
    -  329  2
                             foundSomething |= setPomEvidence(dependency, pom, classes);
    -  330   +  298  2
                         if (pom != null) {
    +  299  4
                             return setPomEvidence(dependency, pom, classes);
    +  300  
                         }
    -  331   +  301  0
                         return false;
    +  302   +
                     } else {
    +  303  8
                         return false;
    +  304  
                     }
    -  332  0
                 } catch (AnalysisException ex) {
    -  333  0
                     LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
    -  334  0
                     LOGGER.trace("", ex);
    -  335  2
                 }
    -  336  2
             }
    -  337  2
             return foundSomething;
    -  338   -
         }
    -  339   -
     
    -  340   -
         /**
    -  341   -
          * Given a path to a pom.xml within a JarFile, this method attempts to load
    -  342   -
          * a sibling pom.properties if one exists.
    -  343   -
          *
    -  344   -
          * @param path the path to the pom.xml within the JarFile
    -  345   -
          * @param jar the JarFile to load the pom.properties from
    -  346   -
          * @return a Properties object or null if no pom.properties was found
    -  347   -
          * @throws IOException thrown if there is an exception reading the
    -  348   -
          * pom.properties
    -  349   -
          */
    -  350   -
         private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
    -  351  2
             Properties pomProperties = null;
    -  352  2
             final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
    -  353  2
             final ZipEntry propEntry = jar.getEntry(propPath);
    -  354  2
             if (propEntry != null) {
    -  355  0
                 Reader reader = null;
    -  356   -
                 try {
    -  357  0
                     reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
    -  358  0
                     pomProperties = new Properties();
    -  359  0
                     pomProperties.load(reader);
    -  360  0
                     LOGGER.debug("Read pom.properties: {}", propPath);
    -  361   +  305  
                 } finally {
    -  362  0
                     if (reader != null) {
    -  363   -
                         try {
    -  364  0
                             reader.close();
    -  365  0
                         } catch (IOException ex) {
    -  366  0
                             LOGGER.trace("close error", ex);
    -  367  0
                         }
    -  368   -
                     }
    -  369   +  306  0
                     try {
    +  307  6
                         jar.close();
    +  308  0
                     } catch (IOException ex) {
    +  309  0
                         LOGGER.trace("", ex);
    +  310  6
                     }
    +  311  
                 }
    -  370   +  312  
             }
    -  371  2
             return pomProperties;
    -  372   -
         }
    -  373   +  313  
     
    -  374   -
         /**
    -  375   -
          * Searches a JarFile for pom.xml entries and returns a listing of these
    -  376   -
          * entries.
    -  377   -
          *
    -  378   -
          * @param jar the JarFile to search
    -  379   -
          * @return a list of pom.xml entries
    -  380   -
          * @throws IOException thrown if there is an exception reading a JarEntry
    -  381   -
          */
    -  382   -
         private List<String> retrievePomListing(final JarFile jar) throws IOException {
    -  383  6
             final List<String> pomEntries = new ArrayList<String>();
    -  384  6
             final Enumeration<JarEntry> entries = jar.entries();
    -  385  1852
             while (entries.hasMoreElements()) {
    -  386  1846
                 final JarEntry entry = entries.nextElement();
    -  387  1846
                 final String entryName = (new File(entry.getName())).getName().toLowerCase();
    -  388  1846
                 if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
    -  389  2
                     LOGGER.trace("POM Entry found: {}", entry.getName());
    -  390  2
                     pomEntries.add(entry.getName());
    -  391   -
                 }
    -  392  1846
             }
    -  393  6
             return pomEntries;
    -  394   -
         }
    -  395   +  314   +
             //reported possible null dereference on pomEntries is on a non-feasible path
    +  315  0
             for (String path : pomEntries) {
    +  316   +
                 //TODO - one of these is likely the pom for the main JAR we are analyzing
    +  317  0
                 LOGGER.debug("Reading pom entry: {}", path);
    +  318   +
                 try {
    +  319   +
                     //extract POM to its own directory and add it as its own dependency
    +  320  0
                     final Properties pomProperties = retrievePomProperties(path, jar);
    +  321  0
                     final File pomFile = extractPom(path, jar);
    +  322  0
                     final Model pom = PomUtils.readPom(pomFile);
    +  323  0
                     pom.processProperties(pomProperties);
    +  324  
     
    -  396   -
         /**
    -  397   -
          * Retrieves the specified POM from a jar file and converts it to a Model.
    -  398   -
          *
    -  399   -
          * @param path the path to the pom.xml file within the jar file
    -  400   -
          * @param jar the jar file to extract the pom from
    -  401   -
          * @param dependency the dependency being analyzed
    -  402   -
          * @return returns the POM object
    -  403   -
          * @throws AnalysisException is thrown if there is an exception extracting
    -  404   -
          * or parsing the POM {@link org.owasp.dependencycheck.xml.pom.Model} object
    -  405   -
          */
    -  406   -
         private Model extractPom(String path, JarFile jar, Dependency dependency) throws AnalysisException {
    -  407  0
             InputStream input = null;
    -  408  0
             FileOutputStream fos = null;
    -  409  0
             final File tmpDir = getNextTempDirectory();
    -  410  0
             final File file = new File(tmpDir, "pom.xml");
    -  411   +  325  0
                     final String displayPath = String.format("%s%s%s",
    +  326  0
                             dependency.getFilePath(),
    +  327   +
                             File.separator,
    +  328   +
                             path);
    +  329  0
                     final String displayName = String.format("%s%s%s",
    +  330  0
                             dependency.getFileName(),
    +  331   +
                             File.separator,
    +  332   +
                             path);
    +  333  0
                     final Dependency newDependency = new Dependency();
    +  334  0
                     newDependency.setActualFilePath(pomFile.getAbsolutePath());
    +  335  0
                     newDependency.setFileName(displayName);
    +  336  0
                     newDependency.setFilePath(displayPath);
    +  337  0
                     setPomEvidence(newDependency, pom, null);
    +  338  0
                     engine.getDependencies().add(newDependency);
    +  339  0
                 } catch (AnalysisException ex) {
    +  340  0
                     LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
    +  341  0
                     LOGGER.trace("", ex);
    +  342  0
                 }
    +  343  0
             }
    +  344  
             try {
    -  412  0
                 final ZipEntry entry = jar.getEntry(path);
    -  413  0
                 if (entry == null) {
    -  414  0
                     throw new AnalysisException(String.format("Pom (%s)does not exist in %s", path, jar.getName()));
    -  415   -
                 }
    -  416  0
                 input = jar.getInputStream(entry);
    -  417  0
                 fos = new FileOutputStream(file);
    -  418  0
                 IOUtils.copy(input, fos);
    -  419  0
                 dependency.setActualFilePath(file.getAbsolutePath());
    -  420  0
             } catch (IOException ex) {
    -  421  0
                 LOGGER.warn("An error occurred reading '{}' from '{}'.", path, dependency.getFilePath());
    -  422  0
                 LOGGER.error("", ex);
    -  423   -
             } finally {
    -  424  0
                 closeStream(fos);
    -  425  0
                 closeStream(input);
    -  426  0
             }
    -  427  0
             return PomUtils.readPom(file);
    -  428   +  345  0
                 jar.close();
    +  346  0
             } catch (IOException ex) {
    +  347  0
                 LOGGER.trace("", ex);
    +  348  0
             }
    +  349  0
             return false;
    +  350  
         }
    -  429   +  351  
     
    +  352   +
         /**
    +  353   +
          * Given a path to a pom.xml within a JarFile, this method attempts to load
    +  354   +
          * a sibling pom.properties if one exists.
    +  355   +
          *
    +  356   +
          * @param path the path to the pom.xml within the JarFile
    +  357   +
          * @param jar the JarFile to load the pom.properties from
    +  358   +
          * @return a Properties object or null if no pom.properties was found
    +  359   +
          * @throws IOException thrown if there is an exception reading the
    +  360   +
          * pom.properties
    +  361   +
          */
    +  362   +
         private Properties retrievePomProperties(String path, final JarFile jar) {
    +  363  2
             Properties pomProperties = null;
    +  364  2
             final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
    +  365  2
             final ZipEntry propEntry = jar.getEntry(propPath);
    +  366  2
             if (propEntry != null) {
    +  367  0
                 Reader reader = null;
    +  368   +
                 try {
    +  369  0
                     reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
    +  370  0
                     pomProperties = new Properties();
    +  371  0
                     pomProperties.load(reader);
    +  372  0
                     LOGGER.debug("Read pom.properties: {}", propPath);
    +  373  0
                 } catch (UnsupportedEncodingException ex) {
    +  374  0
                     LOGGER.trace("UTF-8 is not supported", ex);
    +  375  0
                 } catch (IOException ex) {
    +  376  0
                     LOGGER.trace("Unable to read the POM properties", ex);
    +  377   +
                 } finally {
    +  378  0
                     if (reader != null) {
    +  379   +
                         try {
    +  380  0
                             reader.close();
    +  381  0
                         } catch (IOException ex) {
    +  382  0
                             LOGGER.trace("close error", ex);
    +  383  0
                         }
    +  384   +
                     }
    +  385   +
                 }
    +  386   +
             }
    +  387  2
             return pomProperties;
    +  388   +
         }
    +  389   +
     
    +  390   +
         /**
    +  391   +
          * Searches a JarFile for pom.xml entries and returns a listing of these
    +  392   +
          * entries.
    +  393   +
          *
    +  394   +
          * @param jar the JarFile to search
    +  395   +
          * @return a list of pom.xml entries
    +  396   +
          * @throws IOException thrown if there is an exception reading a JarEntry
    +  397   +
          */
    +  398   +
         private List<String> retrievePomListing(final JarFile jar) throws IOException {
    +  399  6
             final List<String> pomEntries = new ArrayList<String>();
    +  400  6
             final Enumeration<JarEntry> entries = jar.entries();
    +  401  1852
             while (entries.hasMoreElements()) {
    +  402  1846
                 final JarEntry entry = entries.nextElement();
    +  403  1846
                 final String entryName = (new File(entry.getName())).getName().toLowerCase();
    +  404  1846
                 if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
    +  405  2
                     LOGGER.trace("POM Entry found: {}", entry.getName());
    +  406  2
                     pomEntries.add(entry.getName());
    +  407   +
                 }
    +  408  1846
             }
    +  409  6
             return pomEntries;
    +  410   +
         }
    +  411   +
     
    +  412   +
         /**
    +  413   +
          * Retrieves the specified POM from a jar.
    +  414   +
          *
    +  415   +
          * @param path the path to the pom.xml file within the jar file
    +  416   +
          * @param jar the jar file to extract the pom from
    +  417   +
          * @return returns the POM file
    +  418   +
          * @throws AnalysisException is thrown if there is an exception extracting
    +  419   +
          * the file
    +  420   +
          */
    +  421   +
         private File extractPom(String path, JarFile jar) throws AnalysisException {
    +  422  2
             InputStream input = null;
    +  423  2
             FileOutputStream fos = null;
    +  424  2
             final File tmpDir = getNextTempDirectory();
    +  425  2
             final File file = new File(tmpDir, "pom.xml");
    +  426   +
             try {
    +  427  2
                 final ZipEntry entry = jar.getEntry(path);
    +  428  2
                 if (entry == null) {
    +  429  0
                     throw new AnalysisException(String.format("Pom (%s)does not exist in %s", path, jar.getName()));
     430   -
         /**
    -  431   -
          * Silently closes an input stream ignoring errors.
    -  432   -
          *
    -  433   -
          * @param stream an input stream to close
    -  434   -
          */
    -  435   -
         private void closeStream(InputStream stream) {
    -  436  0
             if (stream != null) {
    +
                 }
    +  431  2
                 input = jar.getInputStream(entry);
    +  432  2
                 fos = new FileOutputStream(file);
    +  433  2
                 IOUtils.copy(input, fos);
    +  434  0
             } catch (IOException ex) {
    +  435  0
                 LOGGER.warn("An error occurred reading '{}' from '{}'.", path, jar.getName());
    +  436  0
                 LOGGER.error("", ex);
     437   -
                 try {
    -  438  0
                     stream.close();
    -  439  0
                 } catch (IOException ex) {
    -  440  0
                     LOGGER.trace("", ex);
    -  441  0
                 }
    +
             } finally {
    +  438  2
                 FileUtils.close(fos);
    +  439  2
                 FileUtils.close(input);
    +  440  2
             }
    +  441  2
             return file;
     442   -
             }
    -  443  0
         }
    +
         }
    +  443   +
     
     444   -
     
    +
         /**
     445   -
         /**
    -  446   -
          * Silently closes an output stream ignoring errors.
    -  447   -
          *
    -  448   -
          * @param stream an output stream to close
    -  449   -
          */
    -  450   -
         private void closeStream(OutputStream stream) {
    -  451  0
             if (stream != null) {
    -  452   -
                 try {
    -  453  0
                     stream.close();
    -  454  0
                 } catch (IOException ex) {
    -  455  0
                     LOGGER.trace("", ex);
    -  456  0
                 }
    -  457   -
             }
    -  458  0
         }
    -  459   -
     
    -  460   -
         /**
    -  461  
          * Sets evidence from the pom on the supplied dependency.
    -  462   +  446  
          *
    -  463   +  447  
          * @param dependency the dependency to set data on
    -  464   +  448  
          * @param pom the information from the pom
    -  465   +  449  
          * @param classes a collection of ClassNameInformation - containing data
    -  466   +  450  
          * about the fully qualified class names within the JAR file being analyzed
    -  467   +  451  
          * @return true if there was evidence within the pom that we could use;
    -  468   +  452  
          * otherwise false
    -  469   +  453  
          */
    -  470   +  454  
         public static boolean setPomEvidence(Dependency dependency, Model pom, List<ClassNameInformation> classes) {
    -  471  2
             boolean foundSomething = false;
    -  472  2
             boolean addAsIdentifier = true;
    -  473  2
             if (pom == null) {
    -  474  0
                 return foundSomething;
    +  455  2
             boolean foundSomething = false;
    +  456  2
             boolean addAsIdentifier = true;
    +  457  2
             if (pom == null) {
    +  458  0
                 return foundSomething;
    +  459   +
             }
    +  460  2
             String groupid = pom.getGroupId();
    +  461  2
             String parentGroupId = pom.getParentGroupId();
    +  462  2
             String artifactid = pom.getArtifactId();
    +  463  2
             String parentArtifactId = pom.getParentArtifactId();
    +  464  2
             String version = pom.getVersion();
    +  465  2
             String parentVersion = pom.getParentVersion();
    +  466   +
     
    +  467  2
             if ("org.sonatype.oss".equals(parentGroupId) && "oss-parent".equals(parentArtifactId)) {
    +  468  0
                 parentGroupId = null;
    +  469  0
                 parentArtifactId = null;
    +  470  0
                 parentVersion = null;
    +  471   +
             }
    +  472   +
     
    +  473  2
             if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
    +  474  0
                 groupid = parentGroupId;
     475  
             }
    -  476  2
             String groupid = pom.getGroupId();
    -  477  2
             String parentGroupId = pom.getParentGroupId();
    -  478  2
             String artifactid = pom.getArtifactId();
    -  479  2
             String parentArtifactId = pom.getParentArtifactId();
    -  480  2
             String version = pom.getVersion();
    -  481  2
             String parentVersion = pom.getParentVersion();
    -  482   +  476  
     
    -  483  2
             if ("org.sonatype.oss".equals(parentGroupId) && "oss-parent".equals(parentArtifactId)) {
    -  484  0
                 parentGroupId = null;
    -  485  0
                 parentArtifactId = null;
    -  486  0
                 parentVersion = null;
    -  487   +  477  2
             final String originalGroupID = groupid;
    +  478  2
             if (groupid != null && (groupid.startsWith("org.") || groupid.startsWith("com."))) {
    +  479  1
                 groupid = groupid.substring(4);
    +  480  
             }
    -  488   +  481  
     
    -  489  2
             if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
    -  490  0
                 groupid = parentGroupId;
    -  491   +  482  2
             if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
    +  483  0
                 artifactid = parentArtifactId;
    +  484  
             }
    -  492   +  485  
     
    -  493  2
             final String originalGroupID = groupid;
    -  494  2
             if (groupid != null && (groupid.startsWith("org.") || groupid.startsWith("com."))) {
    -  495  1
                 groupid = groupid.substring(4);
    -  496   +  486  2
             final String originalArtifactID = artifactid;
    +  487  2
             if (artifactid != null && (artifactid.startsWith("org.") || artifactid.startsWith("com."))) {
    +  488  0
                 artifactid = artifactid.substring(4);
    +  489  
             }
    -  497   +  490  
     
    -  498  2
             if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
    -  499  0
                 artifactid = parentArtifactId;
    -  500   +  491  2
             if ((version == null || version.isEmpty()) && parentVersion != null && !parentVersion.isEmpty()) {
    +  492  1
                 version = parentVersion;
    +  493  
             }
    -  501   +  494  
     
    -  502  2
             final String originalArtifactID = artifactid;
    -  503  2
             if (artifactid != null && (artifactid.startsWith("org.") || artifactid.startsWith("com."))) {
    -  504  0
                 artifactid = artifactid.substring(4);
    -  505   -
             }
    +  495  2
             if (groupid != null && !groupid.isEmpty()) {
    +  496  2
                 foundSomething = true;
    +  497  2
                 dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGHEST);
    +  498  2
                 dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
    +  499  2
                 addMatchingValues(classes, groupid, dependency.getVendorEvidence());
    +  500  2
                 addMatchingValues(classes, groupid, dependency.getProductEvidence());
    +  501  2
                 if (parentGroupId != null && !parentGroupId.isEmpty() && !parentGroupId.equals(groupid)) {
    +  502  1
                     dependency.getVendorEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.MEDIUM);
    +  503  1
                     dependency.getProductEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.LOW);
    +  504  1
                     addMatchingValues(classes, parentGroupId, dependency.getVendorEvidence());
    +  505  1
                     addMatchingValues(classes, parentGroupId, dependency.getProductEvidence());
     506   -
     
    -  507  2
             if ((version == null || version.isEmpty()) && parentVersion != null && !parentVersion.isEmpty()) {
    -  508  1
                 version = parentVersion;
    +
                 }
    +  507   +
             } else {
    +  508  0
                 addAsIdentifier = false;
     509  
             }
     510  
     
    -  511  2
             if (groupid != null && !groupid.isEmpty()) {
    +  511  2
             if (artifactid != null && !artifactid.isEmpty()) {
     512  2
                 foundSomething = true;
    -  513  2
                 dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGHEST);
    -  514  2
                 dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
    -  515  2
                 addMatchingValues(classes, groupid, dependency.getVendorEvidence());
    -  516  2
                 addMatchingValues(classes, groupid, dependency.getProductEvidence());
    -  517  2
                 if (parentGroupId != null && !parentGroupId.isEmpty() && !parentGroupId.equals(groupid)) {
    -  518  1
                     dependency.getVendorEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.MEDIUM);
    -  519  1
                     dependency.getProductEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.LOW);
    -  520  1
                     addMatchingValues(classes, parentGroupId, dependency.getVendorEvidence());
    -  521  1
                     addMatchingValues(classes, parentGroupId, dependency.getProductEvidence());
    +  513  2
                 dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
    +  514  2
                 dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
    +  515  2
                 addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
    +  516  2
                 addMatchingValues(classes, artifactid, dependency.getProductEvidence());
    +  517  2
                 if (parentArtifactId != null && !parentArtifactId.isEmpty() && !parentArtifactId.equals(artifactid)) {
    +  518  1
                     dependency.getProductEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.MEDIUM);
    +  519  1
                     dependency.getVendorEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.LOW);
    +  520  1
                     addMatchingValues(classes, parentArtifactId, dependency.getVendorEvidence());
    +  521  1
                     addMatchingValues(classes, parentArtifactId, dependency.getProductEvidence());
     522  
                 }
     523   @@ -890,1053 +878,1031 @@
             }
     526  
     
    -  527  2
             if (artifactid != null && !artifactid.isEmpty()) {
    +  527  2
             if (version != null && !version.isEmpty()) {
     528  2
                 foundSomething = true;
    -  529  2
                 dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
    -  530  2
                 dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
    -  531  2
                 addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
    -  532  2
                 addMatchingValues(classes, artifactid, dependency.getProductEvidence());
    -  533  2
                 if (parentArtifactId != null && !parentArtifactId.isEmpty() && !parentArtifactId.equals(artifactid)) {
    -  534  1
                     dependency.getProductEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.MEDIUM);
    -  535  1
                     dependency.getVendorEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.LOW);
    -  536  1
                     addMatchingValues(classes, parentArtifactId, dependency.getVendorEvidence());
    -  537  1
                     addMatchingValues(classes, parentArtifactId, dependency.getProductEvidence());
    -  538   +  529  2
                 dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
    +  530  2
                 if (parentVersion != null && !parentVersion.isEmpty() && !parentVersion.equals(version)) {
    +  531  0
                     dependency.getVersionEvidence().addEvidence("pom", "parent-version", version, Confidence.LOW);
    +  532  
                 }
    +  533   +
             } else {
    +  534  0
                 addAsIdentifier = false;
    +  535   +
             }
    +  536   +
     
    +  537  2
             if (addAsIdentifier) {
    +  538  2
                 dependency.addIdentifier("maven", String.format("%s:%s:%s", originalGroupID, originalArtifactID, version), null, Confidence.HIGH);
     539   -
             } else {
    -  540  0
                 addAsIdentifier = false;
    +
             }
    +  540   +
     
     541   -
             }
    -  542   -
     
    -  543  2
             if (version != null && !version.isEmpty()) {
    -  544  2
                 foundSomething = true;
    -  545  2
                 dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
    -  546  2
                 if (parentVersion != null && !parentVersion.isEmpty() && !parentVersion.equals(version)) {
    -  547  0
                     dependency.getVersionEvidence().addEvidence("pom", "parent-version", version, Confidence.LOW);
    -  548   -
                 }
    -  549   -
             } else {
    -  550  0
                 addAsIdentifier = false;
    -  551   -
             }
    -  552   -
     
    -  553  2
             if (addAsIdentifier) {
    -  554  2
                 dependency.addIdentifier("maven", String.format("%s:%s:%s", originalGroupID, originalArtifactID, version), null, Confidence.HIGH);
    -  555   -
             }
    -  556   -
     
    -  557  
             // org name
    -  558  2
             final String org = pom.getOrganization();
    -  559  2
             if (org != null && !org.isEmpty()) {
    -  560  0
                 dependency.getVendorEvidence().addEvidence("pom", "organization name", org, Confidence.HIGH);
    -  561  0
                 dependency.getProductEvidence().addEvidence("pom", "organization name", org, Confidence.LOW);
    -  562  0
                 addMatchingValues(classes, org, dependency.getVendorEvidence());
    -  563  0
                 addMatchingValues(classes, org, dependency.getProductEvidence());
    -  564   +  542  2
             final String org = pom.getOrganization();
    +  543  2
             if (org != null && !org.isEmpty()) {
    +  544  0
                 dependency.getVendorEvidence().addEvidence("pom", "organization name", org, Confidence.HIGH);
    +  545  0
                 dependency.getProductEvidence().addEvidence("pom", "organization name", org, Confidence.LOW);
    +  546  0
                 addMatchingValues(classes, org, dependency.getVendorEvidence());
    +  547  0
                 addMatchingValues(classes, org, dependency.getProductEvidence());
    +  548  
             }
    -  565   +  549  
             //pom name
    -  566  2
             final String pomName = pom.getName();
    -  567  2
             if (pomName
    -  568  2
                     != null && !pomName.isEmpty()) {
    -  569  2
                 foundSomething = true;
    -  570  2
                 dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
    -  571  2
                 dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
    -  572  2
                 addMatchingValues(classes, pomName, dependency.getVendorEvidence());
    -  573  2
                 addMatchingValues(classes, pomName, dependency.getProductEvidence());
    -  574   +  550  2
             final String pomName = pom.getName();
    +  551  2
             if (pomName
    +  552  2
                     != null && !pomName.isEmpty()) {
    +  553  2
                 foundSomething = true;
    +  554  2
                 dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
    +  555  2
                 dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
    +  556  2
                 addMatchingValues(classes, pomName, dependency.getVendorEvidence());
    +  557  2
                 addMatchingValues(classes, pomName, dependency.getProductEvidence());
    +  558  
             }
    -  575   +  559  
     
    -  576   +  560  
             //Description
    -  577  2
             final String description = pom.getDescription();
    -  578  2
             if (description != null && !description.isEmpty() && !description.startsWith("POM was created by")) {
    -  579  1
                 foundSomething = true;
    -  580  1
                 final String trimmedDescription = addDescription(dependency, description, "pom", "description");
    -  581  1
                 addMatchingValues(classes, trimmedDescription, dependency.getVendorEvidence());
    -  582  1
                 addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
    -  583   +  561  2
             final String description = pom.getDescription();
    +  562  2
             if (description != null && !description.isEmpty() && !description.startsWith("POM was created by")) {
    +  563  1
                 foundSomething = true;
    +  564  1
                 final String trimmedDescription = addDescription(dependency, description, "pom", "description");
    +  565  1
                 addMatchingValues(classes, trimmedDescription, dependency.getVendorEvidence());
    +  566  1
                 addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
    +  567  
             }
    -  584   +  568  
     
    -  585  2
             final String projectURL = pom.getProjectURL();
    -  586  2
             if (projectURL != null && !projectURL.trim().isEmpty()) {
    -  587  1
                 dependency.getVendorEvidence().addEvidence("pom", "url", projectURL, Confidence.HIGHEST);
    -  588   +  569  2
             final String projectURL = pom.getProjectURL();
    +  570  2
             if (projectURL != null && !projectURL.trim().isEmpty()) {
    +  571  1
                 dependency.getVendorEvidence().addEvidence("pom", "url", projectURL, Confidence.HIGHEST);
    +  572  
             }
    -  589   +  573  
     
    -  590  2
             extractLicense(pom, dependency);
    -  591  2
             return foundSomething;
    -  592   +  574  2
             extractLicense(pom, dependency);
    +  575  2
             return foundSomething;
    +  576  
         }
    -  593   +  577  
     
    -  594   +  578  
         /**
    -  595   +  579  
          * Analyzes the path information of the classes contained within the
    -  596   +  580  
          * JarAnalyzer to try and determine possible vendor or product names. If any
    -  597   +  581  
          * are found they are stored in the packageVendor and packageProduct
    -  598   +  582  
          * hashSets.
    -  599   +  583  
          *
    -  600   +  584  
          * @param classNames a list of class names
    -  601   +  585  
          * @param dependency a dependency to analyze
    -  602   +  586  
          * @param addPackagesAsEvidence a flag indicating whether or not package
    -  603   +  587  
          * names should be added as evidence.
    -  604   +  588  
          */
    -  605   +  589  
         protected void analyzePackageNames(List<ClassNameInformation> classNames,
    -  606   +  590  
                 Dependency dependency, boolean addPackagesAsEvidence) {
    -  607  6
             final Map<String, Integer> vendorIdentifiers = new HashMap<String, Integer>();
    -  608  6
             final Map<String, Integer> productIdentifiers = new HashMap<String, Integer>();
    -  609  6
             analyzeFullyQualifiedClassNames(classNames, vendorIdentifiers, productIdentifiers);
    -  610   +  591  6
             final Map<String, Integer> vendorIdentifiers = new HashMap<String, Integer>();
    +  592  6
             final Map<String, Integer> productIdentifiers = new HashMap<String, Integer>();
    +  593  6
             analyzeFullyQualifiedClassNames(classNames, vendorIdentifiers, productIdentifiers);
    +  594  
     
    -  611  6
             final int classCount = classNames.size();
    -  612  6
             final EvidenceCollection vendor = dependency.getVendorEvidence();
    -  613  6
             final EvidenceCollection product = dependency.getProductEvidence();
    -  614   +  595  6
             final int classCount = classNames.size();
    +  596  6
             final EvidenceCollection vendor = dependency.getVendorEvidence();
    +  597  6
             final EvidenceCollection product = dependency.getProductEvidence();
    +  598  
     
    -  615  6
             for (Map.Entry<String, Integer> entry : vendorIdentifiers.entrySet()) {
    -  616  48
                 final float ratio = entry.getValue() / (float) classCount;
    -  617  48
                 if (ratio > 0.5) {
    -  618   +  599  6
             for (Map.Entry<String, Integer> entry : vendorIdentifiers.entrySet()) {
    +  600  48
                 final float ratio = entry.getValue() / (float) classCount;
    +  601  48
                 if (ratio > 0.5) {
    +  602  
                     //TODO remove weighting
    -  619  10
                     vendor.addWeighting(entry.getKey());
    -  620  10
                     if (addPackagesAsEvidence && entry.getKey().length() > 1) {
    -  621  8
                         vendor.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
    -  622   +  603  10
                     vendor.addWeighting(entry.getKey());
    +  604  10
                     if (addPackagesAsEvidence && entry.getKey().length() > 1) {
    +  605  8
                         vendor.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
    +  606  
                     }
    -  623   +  607  
                 }
    -  624  48
             }
    -  625  6
             for (Map.Entry<String, Integer> entry : productIdentifiers.entrySet()) {
    -  626  985
                 final float ratio = entry.getValue() / (float) classCount;
    -  627  985
                 if (ratio > 0.5) {
    -  628  5
                     product.addWeighting(entry.getKey());
    -  629  5
                     if (addPackagesAsEvidence && entry.getKey().length() > 1) {
    -  630  4
                         product.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
    -  631   +  608  48
             }
    +  609  6
             for (Map.Entry<String, Integer> entry : productIdentifiers.entrySet()) {
    +  610  985
                 final float ratio = entry.getValue() / (float) classCount;
    +  611  985
                 if (ratio > 0.5) {
    +  612  5
                     product.addWeighting(entry.getKey());
    +  613  5
                     if (addPackagesAsEvidence && entry.getKey().length() > 1) {
    +  614  4
                         product.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
    +  615  
                     }
    -  632   +  616  
                 }
    -  633  985
             }
    -  634  6
         }
    -  635   +  617  985
             }
    +  618  6
         }
    +  619  
     
    -  636   +  620  
         /**
    -  637   +  621  
          * <p>
    -  638   +  622  
          * Reads the manifest from the JAR file and collects the entries. Some
    -  639   +  623  
          * vendorKey entries are:</p>
    -  640   +  624  
          * <ul><li>Implementation Title</li>
    -  641   +  625  
          * <li>Implementation Version</li> <li>Implementation Vendor</li>
    -  642   +  626  
          * <li>Implementation VendorId</li> <li>Bundle Name</li> <li>Bundle
    -  643   +  627  
          * Version</li> <li>Bundle Vendor</li> <li>Bundle Description</li> <li>Main
    -  644   +  628  
          * Class</li> </ul>
    -  645   +  629  
          * However, all but a handful of specific entries are read in.
    -  646   +  630  
          *
    -  647   +  631  
          * @param dependency A reference to the dependency
    -  648   +  632  
          * @param classInformation a collection of class information
    -  649   +  633  
          * @return whether evidence was identified parsing the manifest
    -  650   +  634  
          * @throws IOException if there is an issue reading the JAR file
    -  651   +  635  
          */
    -  652   -
         protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> classInformation) throws IOException {
    -  653  7
             boolean foundSomething = false;
    -  654  7
             JarFile jar = null;
    -  655   +  636   +
         protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> classInformation)
    +  637   +
                 throws IOException {
    +  638  7
             boolean foundSomething = false;
    +  639  7
             JarFile jar = null;
    +  640  
             try {
    -  656  7
                 jar = new JarFile(dependency.getActualFilePath());
    -  657  7
                 final Manifest manifest = jar.getManifest();
    -  658  7
                 if (manifest == null) {
    -  659  0
                     if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
    -  660  0
                             && !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
    -  661  0
                             && !dependency.getFileName().toLowerCase().endsWith("-src.jar")
    -  662  0
                             && !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
    -  663  0
                         LOGGER.debug("Jar file '{}' does not contain a manifest.",
    -  664  0
                                 dependency.getFileName());
    +  641  7
                 jar = new JarFile(dependency.getActualFilePath());
    +  642  7
                 final Manifest manifest = jar.getManifest();
    +  643  7
                 if (manifest == null) {
    +  644  0
                     if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
    +  645  0
                             && !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
    +  646  0
                             && !dependency.getFileName().toLowerCase().endsWith("-src.jar")
    +  647  0
                             && !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
    +  648  0
                         LOGGER.debug("Jar file '{}' does not contain a manifest.",
    +  649  0
                                 dependency.getFileName());
    +  650   +
                     }
    +  651  0
                     return false;
    +  652   +
                 }
    +  653  7
                 final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
    +  654  7
                 final EvidenceCollection productEvidence = dependency.getProductEvidence();
    +  655  7
                 final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
    +  656  7
                 String source = "Manifest";
    +  657  7
                 String specificationVersion = null;
    +  658  7
                 boolean hasImplementationVersion = false;
    +  659  7
                 Attributes atts = manifest.getMainAttributes();
    +  660  7
                 for (Entry<Object, Object> entry : atts.entrySet()) {
    +  661  72
                     String key = entry.getKey().toString();
    +  662  72
                     String value = atts.getValue(key);
    +  663  72
                     if (HTML_DETECTION_PATTERN.matcher(value).find()) {
    +  664  0
                         value = Jsoup.parse(value).text();
     665  
                     }
    -  666  0
                     return false;
    -  667   -
                 }
    -  668  7
                 final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
    -  669  7
                 final EvidenceCollection productEvidence = dependency.getProductEvidence();
    -  670  7
                 final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
    -  671  7
                 String source = "Manifest";
    -  672  7
                 String specificationVersion = null;
    -  673  7
                 boolean hasImplementationVersion = false;
    -  674  7
                 Attributes atts = manifest.getMainAttributes();
    -  675  7
                 for (Entry<Object, Object> entry : atts.entrySet()) {
    -  676  72
                     String key = entry.getKey().toString();
    -  677  72
                     String value = atts.getValue(key);
    -  678  72
                     if (HTML_DETECTION_PATTERN.matcher(value).find()) {
    -  679  0
                         value = Jsoup.parse(value).text();
    -  680   -
                     }
    -  681  72
                     if (IGNORE_VALUES.contains(value)) {
    -  682  0
                         continue;
    -  683  72
                     } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
    -  684  1
                         foundSomething = true;
    -  685  1
                         productEvidence.addEvidence(source, key, value, Confidence.HIGH);
    -  686  1
                         addMatchingValues(classInformation, value, productEvidence);
    -  687  71
                     } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
    -  688  2
                         hasImplementationVersion = true;
    -  689  2
                         foundSomething = true;
    -  690  2
                         versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
    -  691  69
                     } else if ("specification-version".equalsIgnoreCase(key)) {
    -  692  1
                         specificationVersion = value;
    -  693  68
                     } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
    -  694  1
                         foundSomething = true;
    -  695  1
                         vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
    -  696  1
                         addMatchingValues(classInformation, value, vendorEvidence);
    -  697  67
                     } else if (key.equalsIgnoreCase(IMPLEMENTATION_VENDOR_ID)) {
    -  698  0
                         foundSomething = true;
    -  699  0
                         vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  700  0
                         addMatchingValues(classInformation, value, vendorEvidence);
    -  701  67
                     } else if (key.equalsIgnoreCase(BUNDLE_DESCRIPTION)) {
    -  702  2
                         foundSomething = true;
    -  703  2
                         addDescription(dependency, value, "manifest", key);
    -  704  2
                         addMatchingValues(classInformation, value, productEvidence);
    -  705  65
                     } else if (key.equalsIgnoreCase(BUNDLE_NAME)) {
    -  706  3
                         foundSomething = true;
    -  707  3
                         productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  708  3
                         addMatchingValues(classInformation, value, productEvidence);
    -  709   +  666  72
                     if (IGNORE_VALUES.contains(value)) {
    +  667  0
                         continue;
    +  668  72
                     } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
    +  669  1
                         foundSomething = true;
    +  670  1
                         productEvidence.addEvidence(source, key, value, Confidence.HIGH);
    +  671  1
                         addMatchingValues(classInformation, value, productEvidence);
    +  672  71
                     } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
    +  673  2
                         hasImplementationVersion = true;
    +  674  2
                         foundSomething = true;
    +  675  2
                         versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
    +  676  69
                     } else if ("specification-version".equalsIgnoreCase(key)) {
    +  677  1
                         specificationVersion = value;
    +  678  68
                     } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
    +  679  1
                         foundSomething = true;
    +  680  1
                         vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
    +  681  1
                         addMatchingValues(classInformation, value, vendorEvidence);
    +  682  67
                     } else if (key.equalsIgnoreCase(IMPLEMENTATION_VENDOR_ID)) {
    +  683  0
                         foundSomething = true;
    +  684  0
                         vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  685  0
                         addMatchingValues(classInformation, value, vendorEvidence);
    +  686  67
                     } else if (key.equalsIgnoreCase(BUNDLE_DESCRIPTION)) {
    +  687  2
                         foundSomething = true;
    +  688  2
                         addDescription(dependency, value, "manifest", key);
    +  689  2
                         addMatchingValues(classInformation, value, productEvidence);
    +  690  65
                     } else if (key.equalsIgnoreCase(BUNDLE_NAME)) {
    +  691  3
                         foundSomething = true;
    +  692  3
                         productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  693  3
                         addMatchingValues(classInformation, value, productEvidence);
    +  694  
     //                //the following caused false positives.
    -  710   +  695  
     //                } else if (key.equalsIgnoreCase(BUNDLE_VENDOR)) {
    -  711  62
                     } else if (key.equalsIgnoreCase(BUNDLE_VERSION)) {
    -  712  3
                         foundSomething = true;
    -  713  3
                         versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
    -  714  59
                     } else if (key.equalsIgnoreCase(Attributes.Name.MAIN_CLASS.toString())) {
    -  715  3
                         continue;
    -  716   +  696  62
                     } else if (key.equalsIgnoreCase(BUNDLE_VERSION)) {
    +  697  3
                         foundSomething = true;
    +  698  3
                         versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
    +  699  59
                     } else if (key.equalsIgnoreCase(Attributes.Name.MAIN_CLASS.toString())) {
    +  700  3
                         continue;
    +  701  
                         //skipping main class as if this has important information to add it will be added during class name analysis...
    -  717   +  702  
                     } else {
    -  718  56
                         key = key.toLowerCase();
    -  719  56
                         if (!IGNORE_KEYS.contains(key)
    -  720  15
                                 && !key.endsWith("jdk")
    -  721  15
                                 && !key.contains("lastmodified")
    -  722  14
                                 && !key.endsWith("package")
    -  723  14
                                 && !key.endsWith("classpath")
    -  724  14
                                 && !key.endsWith("class-path")
    -  725  14
                                 && !key.endsWith("-scm") //todo change this to a regex?
    -  726  14
                                 && !key.startsWith("scm-")
    -  727  14
                                 && !value.trim().startsWith("scm:")
    -  728  14
                                 && !isImportPackage(key, value)
    -  729  14
                                 && !isPackage(key, value)) {
    -  730  13
                             foundSomething = true;
    -  731  13
                             if (key.contains("version")) {
    -  732  0
                                 if (!key.contains("specification")) {
    -  733  0
                                     versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  734   +  703  56
                         key = key.toLowerCase();
    +  704  56
                         if (!IGNORE_KEYS.contains(key)
    +  705  15
                                 && !key.endsWith("jdk")
    +  706  15
                                 && !key.contains("lastmodified")
    +  707  14
                                 && !key.endsWith("package")
    +  708  14
                                 && !key.endsWith("classpath")
    +  709  14
                                 && !key.endsWith("class-path")
    +  710  14
                                 && !key.endsWith("-scm") //todo change this to a regex?
    +  711  14
                                 && !key.startsWith("scm-")
    +  712  14
                                 && !value.trim().startsWith("scm:")
    +  713  14
                                 && !isImportPackage(key, value)
    +  714  14
                                 && !isPackage(key, value)) {
    +  715  13
                             foundSomething = true;
    +  716  13
                             if (key.contains("version")) {
    +  717  0
                                 if (!key.contains("specification")) {
    +  718  0
                                     versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  719  
                                 }
    -  735  13
                             } else if ("build-id".equals(key)) {
    -  736  0
                                 int pos = value.indexOf('(');
    -  737  0
                                 if (pos >= 0) {
    -  738  0
                                     value = value.substring(0, pos - 1);
    +  720  13
                             } else if ("build-id".equals(key)) {
    +  721  0
                                 int pos = value.indexOf('(');
    +  722  0
                                 if (pos > 0) {
    +  723  0
                                     value = value.substring(0, pos - 1);
    +  724   +
                                 }
    +  725  0
                                 pos = value.indexOf('[');
    +  726  0
                                 if (pos > 0) {
    +  727  0
                                     value = value.substring(0, pos - 1);
    +  728   +
                                 }
    +  729  0
                                 versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  730  0
                             } else if (key.contains("title")) {
    +  731  1
                                 productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  732  1
                                 addMatchingValues(classInformation, value, productEvidence);
    +  733  12
                             } else if (key.contains("vendor")) {
    +  734  0
                                 if (key.contains("specification")) {
    +  735  0
                                     vendorEvidence.addEvidence(source, key, value, Confidence.LOW);
    +  736   +
                                 } else {
    +  737  0
                                     vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  738  0
                                     addMatchingValues(classInformation, value, vendorEvidence);
     739  
                                 }
    -  740  0
                                 pos = value.indexOf('[');
    -  741  0
                                 if (pos >= 0) {
    -  742  0
                                     value = value.substring(0, pos - 1);
    -  743   -
                                 }
    -  744  0
                                 versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  745  0
                             } else if (key.contains("title")) {
    -  746  1
                                 productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  747  1
                                 addMatchingValues(classInformation, value, productEvidence);
    -  748  12
                             } else if (key.contains("vendor")) {
    -  749  0
                                 if (key.contains("specification")) {
    -  750  0
                                     vendorEvidence.addEvidence(source, key, value, Confidence.LOW);
    -  751   -
                                 } else {
    -  752  0
                                     vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  753  0
                                     addMatchingValues(classInformation, value, vendorEvidence);
    -  754   -
                                 }
    -  755  12
                             } else if (key.contains("name")) {
    -  756  3
                                 productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  757  3
                                 vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  758  3
                                 addMatchingValues(classInformation, value, vendorEvidence);
    -  759  3
                                 addMatchingValues(classInformation, value, productEvidence);
    -  760  9
                             } else if (key.contains("license")) {
    -  761  2
                                 addLicense(dependency, value);
    -  762  7
                             } else if (key.contains("description")) {
    -  763  0
                                 addDescription(dependency, value, "manifest", key);
    -  764   +  740  12
                             } else if (key.contains("name")) {
    +  741  3
                                 productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  742  3
                                 vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  743  3
                                 addMatchingValues(classInformation, value, vendorEvidence);
    +  744  3
                                 addMatchingValues(classInformation, value, productEvidence);
    +  745  9
                             } else if (key.contains("license")) {
    +  746  2
                                 addLicense(dependency, value);
    +  747  7
                             } else if (key.contains("description")) {
    +  748  0
                                 addDescription(dependency, value, "manifest", key);
    +  749  
                             } else {
    -  765  7
                                 productEvidence.addEvidence(source, key, value, Confidence.LOW);
    -  766  7
                                 vendorEvidence.addEvidence(source, key, value, Confidence.LOW);
    -  767  7
                                 addMatchingValues(classInformation, value, vendorEvidence);
    -  768  7
                                 addMatchingValues(classInformation, value, productEvidence);
    -  769  7
                                 if (value.matches(".*\\d.*")) {
    -  770  3
                                     final StringTokenizer tokenizer = new StringTokenizer(value, " ");
    -  771  15
                                     while (tokenizer.hasMoreElements()) {
    -  772  12
                                         final String s = tokenizer.nextToken();
    -  773  12
                                         if (s.matches("^[0-9.]+$")) {
    -  774  1
                                             versionEvidence.addEvidence(source, key, s, Confidence.LOW);
    -  775   +  750  7
                                 productEvidence.addEvidence(source, key, value, Confidence.LOW);
    +  751  7
                                 vendorEvidence.addEvidence(source, key, value, Confidence.LOW);
    +  752  7
                                 addMatchingValues(classInformation, value, vendorEvidence);
    +  753  7
                                 addMatchingValues(classInformation, value, productEvidence);
    +  754  7
                                 if (value.matches(".*\\d.*")) {
    +  755  3
                                     final StringTokenizer tokenizer = new StringTokenizer(value, " ");
    +  756  15
                                     while (tokenizer.hasMoreElements()) {
    +  757  12
                                         final String s = tokenizer.nextToken();
    +  758  12
                                         if (s.matches("^[0-9.]+$")) {
    +  759  1
                                             versionEvidence.addEvidence(source, key, s, Confidence.LOW);
    +  760  
                                         }
    -  776  12
                                     }
    -  777   +  761  12
                                     }
    +  762  
                                 }
    -  778   +  763  
                             }
    -  779   +  764  
                         }
    -  780   +  765  
                     }
    -  781  69
                 }
    -  782  7
                 for (Map.Entry<String, Attributes> item : manifest.getEntries().entrySet()) {
    -  783  8
                     final String name = item.getKey();
    -  784  8
                     source = "manifest: " + name;
    -  785  8
                     atts = item.getValue();
    -  786  8
                     for (Entry<Object, Object> entry : atts.entrySet()) {
    -  787  38
                         final String key = entry.getKey().toString();
    -  788  38
                         final String value = atts.getValue(key);
    -  789  38
                         if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
    -  790  8
                             foundSomething = true;
    -  791  8
                             productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  792  8
                             addMatchingValues(classInformation, value, productEvidence);
    -  793  30
                         } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
    -  794  5
                             foundSomething = true;
    -  795  5
                             versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  796  25
                         } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
    -  797  5
                             foundSomething = true;
    -  798  5
                             vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  799  5
                             addMatchingValues(classInformation, value, vendorEvidence);
    -  800  20
                         } else if (key.equalsIgnoreCase(Attributes.Name.SPECIFICATION_TITLE.toString())) {
    -  801  4
                             foundSomething = true;
    -  802  4
                             productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    -  803  4
                             addMatchingValues(classInformation, value, productEvidence);
    -  804   +  766  69
                 }
    +  767  7
                 for (Map.Entry<String, Attributes> item : manifest.getEntries().entrySet()) {
    +  768  8
                     final String name = item.getKey();
    +  769  8
                     source = "manifest: " + name;
    +  770  8
                     atts = item.getValue();
    +  771  8
                     for (Entry<Object, Object> entry : atts.entrySet()) {
    +  772  38
                         final String key = entry.getKey().toString();
    +  773  38
                         final String value = atts.getValue(key);
    +  774  38
                         if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
    +  775  8
                             foundSomething = true;
    +  776  8
                             productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  777  8
                             addMatchingValues(classInformation, value, productEvidence);
    +  778  30
                         } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
    +  779  5
                             foundSomething = true;
    +  780  5
                             versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  781  25
                         } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
    +  782  5
                             foundSomething = true;
    +  783  5
                             vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  784  5
                             addMatchingValues(classInformation, value, vendorEvidence);
    +  785  20
                         } else if (key.equalsIgnoreCase(Attributes.Name.SPECIFICATION_TITLE.toString())) {
    +  786  4
                             foundSomething = true;
    +  787  4
                             productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
    +  788  4
                             addMatchingValues(classInformation, value, productEvidence);
    +  789  
                         }
    -  805  38
                     }
    -  806  8
                 }
    -  807  7
                 if (specificationVersion != null && !hasImplementationVersion) {
    -  808  0
                     foundSomething = true;
    -  809  0
                     versionEvidence.addEvidence(source, "specification-version", specificationVersion, Confidence.HIGH);
    -  810   +  790  38
                     }
    +  791  8
                 }
    +  792  7
                 if (specificationVersion != null && !hasImplementationVersion) {
    +  793  0
                     foundSomething = true;
    +  794  0
                     versionEvidence.addEvidence(source, "specification-version", specificationVersion, Confidence.HIGH);
    +  795  
                 }
    -  811   +  796  
             } finally {
    -  812  7
                 if (jar != null) {
    -  813  7
                     jar.close();
    -  814   +  797  7
                 if (jar != null) {
    +  798  7
                     jar.close();
    +  799  
                 }
    -  815   +  800  
             }
    -  816  7
             return foundSomething;
    -  817   +  801  7
             return foundSomething;
    +  802  
         }
    -  818   +  803  
     
    -  819   +  804  
         /**
    -  820   +  805  
          * Adds a description to the given dependency. If the description contains
    -  821   +  806  
          * one of the following strings beyond 100 characters, then the description
    -  822   +  807  
          * used will be trimmed to that position:
    -  823   +  808  
          * <ul><li>"such as"</li><li>"like "</li><li>"will use "</li><li>"* uses
    -  824   +  809  
          * "</li></ul>
    -  825   +  810  
          *
    -  826   +  811  
          * @param dependency a dependency
    -  827   +  812  
          * @param description the description
    -  828   +  813  
          * @param source the source of the evidence
    -  829   +  814  
          * @param key the "name" of the evidence
    -  830   +  815  
          * @return if the description is trimmed, the trimmed version is returned;
    -  831   +  816  
          * otherwise the original description is returned
    -  832   +  817  
          */
    -  833   +  818  
         public static String addDescription(Dependency dependency, String description, String source, String key) {
    -  834  10
             if (dependency.getDescription() == null) {
    -  835  10
                 dependency.setDescription(description);
    -  836   +  819  10
             if (dependency.getDescription() == null) {
    +  820  10
                 dependency.setDescription(description);
    +  821  
             }
    -  837   +  822  
             String desc;
    -  838  10
             if (HTML_DETECTION_PATTERN.matcher(description).find()) {
    -  839  0
                 desc = Jsoup.parse(description).text();
    -  840   +  823  10
             if (HTML_DETECTION_PATTERN.matcher(description).find()) {
    +  824  0
                 desc = Jsoup.parse(description).text();
    +  825  
             } else {
    -  841  10
                 desc = description;
    -  842   +  826  10
                 desc = description;
    +  827  
             }
    -  843  10
             dependency.setDescription(desc);
    -  844  10
             if (desc.length() > 100) {
    -  845  0
                 desc = desc.replaceAll("\\s\\s+", " ");
    -  846  0
                 final int posSuchAs = desc.toLowerCase().indexOf("such as ", 100);
    -  847  0
                 final int posLike = desc.toLowerCase().indexOf("like ", 100);
    -  848  0
                 final int posWillUse = desc.toLowerCase().indexOf("will use ", 100);
    -  849  0
                 final int posUses = desc.toLowerCase().indexOf(" uses ", 100);
    -  850  0
                 int pos = -1;
    -  851  0
                 pos = Math.max(pos, posSuchAs);
    -  852  0
                 if (pos >= 0 && posLike >= 0) {
    -  853  0
                     pos = Math.min(pos, posLike);
    -  854   +  828  10
             dependency.setDescription(desc);
    +  829  10
             if (desc.length() > 100) {
    +  830  0
                 desc = desc.replaceAll("\\s\\s+", " ");
    +  831  0
                 final int posSuchAs = desc.toLowerCase().indexOf("such as ", 100);
    +  832  0
                 final int posLike = desc.toLowerCase().indexOf("like ", 100);
    +  833  0
                 final int posWillUse = desc.toLowerCase().indexOf("will use ", 100);
    +  834  0
                 final int posUses = desc.toLowerCase().indexOf(" uses ", 100);
    +  835  0
                 int pos = -1;
    +  836  0
                 pos = Math.max(pos, posSuchAs);
    +  837  0
                 if (pos >= 0 && posLike >= 0) {
    +  838  0
                     pos = Math.min(pos, posLike);
    +  839  
                 } else {
    -  855  0
                     pos = Math.max(pos, posLike);
    -  856   +  840  0
                     pos = Math.max(pos, posLike);
    +  841  
                 }
    -  857  0
                 if (pos >= 0 && posWillUse >= 0) {
    -  858  0
                     pos = Math.min(pos, posWillUse);
    -  859   +  842  0
                 if (pos >= 0 && posWillUse >= 0) {
    +  843  0
                     pos = Math.min(pos, posWillUse);
    +  844  
                 } else {
    -  860  0
                     pos = Math.max(pos, posWillUse);
    -  861   +  845  0
                     pos = Math.max(pos, posWillUse);
    +  846  
                 }
    -  862  0
                 if (pos >= 0 && posUses >= 0) {
    -  863  0
                     pos = Math.min(pos, posUses);
    -  864   +  847  0
                 if (pos >= 0 && posUses >= 0) {
    +  848  0
                     pos = Math.min(pos, posUses);
    +  849  
                 } else {
    -  865  0
                     pos = Math.max(pos, posUses);
    -  866   +  850  0
                     pos = Math.max(pos, posUses);
    +  851  
                 }
    -  867   +  852  
     
    -  868  0
                 if (pos > 0) {
    -  869  0
                     desc = desc.substring(0, pos) + "...";
    -  870   +  853  0
                 if (pos > 0) {
    +  854  0
                     desc = desc.substring(0, pos) + "...";
    +  855  
                 }
    -  871  0
                 dependency.getProductEvidence().addEvidence(source, key, desc, Confidence.LOW);
    -  872  0
                 dependency.getVendorEvidence().addEvidence(source, key, desc, Confidence.LOW);
    -  873  0
             } else {
    -  874  10
                 dependency.getProductEvidence().addEvidence(source, key, desc, Confidence.MEDIUM);
    -  875  10
                 dependency.getVendorEvidence().addEvidence(source, key, desc, Confidence.MEDIUM);
    +  856  0
                 dependency.getProductEvidence().addEvidence(source, key, desc, Confidence.LOW);
    +  857  0
                 dependency.getVendorEvidence().addEvidence(source, key, desc, Confidence.LOW);
    +  858  0
             } else {
    +  859  10
                 dependency.getProductEvidence().addEvidence(source, key, desc, Confidence.MEDIUM);
    +  860  10
                 dependency.getVendorEvidence().addEvidence(source, key, desc, Confidence.MEDIUM);
    +  861   +
             }
    +  862  10
             return desc;
    +  863   +
         }
    +  864   +
     
    +  865   +
         /**
    +  866   +
          * Adds a license to the given dependency.
    +  867   +
          *
    +  868   +
          * @param d a dependency
    +  869   +
          * @param license the license
    +  870   +
          */
    +  871   +
         private void addLicense(Dependency d, String license) {
    +  872  2
             if (d.getLicense() == null) {
    +  873  2
                 d.setLicense(license);
    +  874  0
             } else if (!d.getLicense().contains(license)) {
    +  875  0
                 d.setLicense(d.getLicense() + NEWLINE + license);
     876  
             }
    -  877  10
             return desc;
    +  877  2
         }
     878   -
         }
    +
     
     879   -
     
    +
         /**
     880   -
         /**
    -  881   -
          * Adds a license to the given dependency.
    -  882   -
          *
    -  883   -
          * @param d a dependency
    -  884   -
          * @param license the license
    -  885   -
          */
    -  886   -
         private void addLicense(Dependency d, String license) {
    -  887  2
             if (d.getLicense() == null) {
    -  888  2
                 d.setLicense(license);
    -  889  0
             } else if (!d.getLicense().contains(license)) {
    -  890  0
                 d.setLicense(d.getLicense() + NEWLINE + license);
    -  891   -
             }
    -  892  2
         }
    -  893   -
     
    -  894   -
         /**
    -  895  
          * The parent directory for the individual directories per archive.
    -  896   +  881  
          */
    -  897  13
         private File tempFileLocation = null;
    -  898   +  882  13
         private File tempFileLocation = null;
    +  883  
     
    -  899   +  884  
         /**
    -  900   +  885  
          * Initializes the JarAnalyzer.
    -  901   +  886  
          *
    -  902   +  887  
          * @throws InitializationException is thrown if there is an exception
    -  903   +  888  
          * creating a temporary directory
    -  904   +  889  
          */
    -  905   +  890  
         @Override
    -  906   +  891  
         public void initializeFileTypeAnalyzer() throws InitializationException {
    -  907   +  892  
             try {
    -  908  1
                 final File baseDir = Settings.getTempDirectory();
    -  909  1
                 tempFileLocation = File.createTempFile("check", "tmp", baseDir);
    -  910  1
                 if (!tempFileLocation.delete()) {
    -  911  0
                     final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
    -  912  0
                     setEnabled(false);
    -  913  0
                     throw new InitializationException(msg);
    -  914   +  893  2
                 final File baseDir = Settings.getTempDirectory();
    +  894  2
                 tempFileLocation = File.createTempFile("check", "tmp", baseDir);
    +  895  2
                 if (!tempFileLocation.delete()) {
    +  896  0
                     final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
    +  897  0
                     setEnabled(false);
    +  898  0
                     throw new InitializationException(msg);
    +  899  
                 }
    -  915  1
                 if (!tempFileLocation.mkdirs()) {
    -  916  0
                     final String msg = String.format("Unable to create directory '%s'.", tempFileLocation.getAbsolutePath());
    -  917  0
                     setEnabled(false);
    -  918  0
                     throw new InitializationException(msg);
    -  919   +  900  2
                 if (!tempFileLocation.mkdirs()) {
    +  901  0
                     final String msg = String.format("Unable to create directory '%s'.", tempFileLocation.getAbsolutePath());
    +  902  0
                     setEnabled(false);
    +  903  0
                     throw new InitializationException(msg);
    +  904  
                 }
    -  920  0
             } catch (IOException ex) {
    -  921  0
                 setEnabled(false);
    -  922  0
                 throw new InitializationException("Unable to create a temporary file", ex);
    -  923  1
             }
    -  924  1
         }
    -  925   +  905  0
             } catch (IOException ex) {
    +  906  0
                 setEnabled(false);
    +  907  0
                 throw new InitializationException("Unable to create a temporary file", ex);
    +  908  2
             }
    +  909  2
         }
    +  910  
     
    -  926   +  911  
         /**
    -  927   +  912  
          * Deletes any files extracted from the JAR during analysis.
    -  928   +  913  
          */
    -  929   +  914  
         @Override
    -  930   -
         public void close() {
    -  931  2
             if (tempFileLocation != null && tempFileLocation.exists()) {
    -  932  1
                 LOGGER.debug("Attempting to delete temporary files");
    -  933  1
                 final boolean success = FileUtils.delete(tempFileLocation);
    -  934  1
                 if (!success && tempFileLocation.exists()) {
    -  935  0
                     final String[] l = tempFileLocation.list();
    -  936  0
                     if (l != null && l.length > 0) {
    -  937  0
                         LOGGER.warn("Failed to delete some temporary files, see the log for more details");
    -  938   +  915   +
         public void closeAnalyzer() {
    +  916  1
             if (tempFileLocation != null && tempFileLocation.exists()) {
    +  917  1
                 LOGGER.debug("Attempting to delete temporary files");
    +  918  1
                 final boolean success = FileUtils.delete(tempFileLocation);
    +  919  1
                 if (!success && tempFileLocation.exists()) {
    +  920  0
                     final String[] l = tempFileLocation.list();
    +  921  0
                     if (l != null && l.length > 0) {
    +  922  0
                         LOGGER.warn("Failed to delete some temporary files, see the log for more details");
    +  923  
                     }
    -  939   +  924  
                 }
    -  940   +  925  
             }
    -  941  2
         }
    +  926  1
         }
    +  927   +
     
    +  928   +
         /**
    +  929   +
          * Determines if the key value pair from the manifest is for an "import"
    +  930   +
          * type entry for package names.
    +  931   +
          *
    +  932   +
          * @param key the key from the manifest
    +  933   +
          * @param value the value from the manifest
    +  934   +
          * @return true or false depending on if it is believed the entry is an
    +  935   +
          * "import" entry
    +  936   +
          */
    +  937   +
         private boolean isImportPackage(String key, String value) {
    +  938  14
             final Pattern packageRx = Pattern.compile("^([a-zA-Z0-9_#\\$\\*\\.]+\\s*[,;]\\s*)+([a-zA-Z0-9_#\\$\\*\\.]+\\s*)?$");
    +  939  14
             final boolean matches = packageRx.matcher(value).matches();
    +  940  14
             return matches && (key.contains("import") || key.contains("include") || value.length() > 10);
    +  941   +
         }
     942  
     
     943  
         /**
     944   -
          * Determines if the key value pair from the manifest is for an "import"
    -  945   -
          * type entry for package names.
    -  946   -
          *
    -  947   -
          * @param key the key from the manifest
    -  948   -
          * @param value the value from the manifest
    -  949   -
          * @return true or false depending on if it is believed the entry is an
    -  950   -
          * "import" entry
    -  951   -
          */
    -  952   -
         private boolean isImportPackage(String key, String value) {
    -  953  14
             final Pattern packageRx = Pattern.compile("^([a-zA-Z0-9_#\\$\\*\\.]+\\s*[,;]\\s*)+([a-zA-Z0-9_#\\$\\*\\.]+\\s*)?$");
    -  954  14
             final boolean matches = packageRx.matcher(value).matches();
    -  955  14
             return matches && (key.contains("import") || key.contains("include") || value.length() > 10);
    -  956   -
         }
    -  957   -
     
    -  958   -
         /**
    -  959  
          * Cycles through an enumeration of JarEntries, contained within the
    -  960   +  945  
          * dependency, and returns a list of the class names. This does not include
    -  961   +  946  
          * core Java package names (i.e. java.* or javax.*).
    -  962   +  947  
          *
    -  963   +  948  
          * @param dependency the dependency being analyzed
    -  964   +  949  
          * @return an list of fully qualified class names
    -  965   +  950  
          */
    -  966   +  951  
         private List<ClassNameInformation> collectClassNames(Dependency dependency) {
    -  967  6
             final List<ClassNameInformation> classNames = new ArrayList<ClassNameInformation>();
    -  968  6
             JarFile jar = null;
    -  969   +  952  6
             final List<ClassNameInformation> classNames = new ArrayList<ClassNameInformation>();
    +  953  6
             JarFile jar = null;
    +  954  
             try {
    -  970  6
                 jar = new JarFile(dependency.getActualFilePath());
    -  971  6
                 final Enumeration<JarEntry> entries = jar.entries();
    -  972  1848
                 while (entries.hasMoreElements()) {
    -  973  1842
                     final JarEntry entry = entries.nextElement();
    -  974  1842
                     final String name = entry.getName().toLowerCase();
    -  975   +  955  6
                 jar = new JarFile(dependency.getActualFilePath());
    +  956  6
                 final Enumeration<JarEntry> entries = jar.entries();
    +  957  1795
                 while (entries.hasMoreElements()) {
    +  958  1769
                     final JarEntry entry = entries.nextElement();
    +  959  1750
                     final String name = entry.getName().toLowerCase();
    +  960  
                     //no longer stripping "|com\\.sun" - there are some com.sun jar files with CVEs.
    -  976  1846
                     if (name.endsWith(".class") && !name.matches("^javax?\\..*$")) {
    -  977  1535
                         final ClassNameInformation className = new ClassNameInformation(name.substring(0, name.length() - 6));
    -  978  1535
                         classNames.add(className);
    -  979   +  961  1823
                     if (name.endsWith(".class") && !name.matches("^javax?\\..*$")) {
    +  962  1429
                         final ClassNameInformation className = new ClassNameInformation(name.substring(0, name.length() - 6));
    +  963  1453
                         classNames.add(className);
    +  964  
                     }
    -  980  1841
                 }
    -  981  0
             } catch (IOException ex) {
    -  982  0
                 LOGGER.warn("Unable to open jar file '{}'.", dependency.getFileName());
    -  983  0
                 LOGGER.debug("", ex);
    -  984   +  965  1800
                 }
    +  966  0
             } catch (IOException ex) {
    +  967  0
                 LOGGER.warn("Unable to open jar file '{}'.", dependency.getFileName());
    +  968  0
                 LOGGER.debug("", ex);
    +  969  
             } finally {
    -  985  6
                 if (jar != null) {
    -  986   +  970  6
                 if (jar != null) {
    +  971  
                     try {
    -  987  6
                         jar.close();
    -  988  0
                     } catch (IOException ex) {
    -  989  0
                         LOGGER.trace("", ex);
    -  990  6
                     }
    -  991   +  972  6
                         jar.close();
    +  973  0
                     } catch (IOException ex) {
    +  974  0
                         LOGGER.trace("", ex);
    +  975  6
                     }
    +  976  
                 }
    -  992   +  977  
             }
    -  993  6
             return classNames;
    -  994   +  978  6
             return classNames;
    +  979  
         }
    -  995   +  980  
     
    -  996   +  981  
         /**
    -  997   +  982  
          * Cycles through the list of class names and places the package levels 0-3
    -  998   +  983  
          * into the provided maps for vendor and product. This is helpful when
    -  999   +  984  
          * analyzing vendor/product as many times this is included in the package
    -  1000   +  985  
          * name.
    -  1001   +  986  
          *
    -  1002   +  987  
          * @param classNames a list of class names
    -  1003   +  988  
          * @param vendor HashMap of possible vendor names from package names (e.g.
    -  1004   +  989  
          * owasp)
    -  1005   +  990  
          * @param product HashMap of possible product names from package names (e.g.
    -  1006   +  991  
          * dependencycheck)
    -  1007   +  992  
          */
    -  1008   +  993  
         private void analyzeFullyQualifiedClassNames(List<ClassNameInformation> classNames,
    -  1009   +  994  
                 Map<String, Integer> vendor, Map<String, Integer> product) {
    -  1010  6
             for (ClassNameInformation entry : classNames) {
    -  1011  1535
                 final List<String> list = entry.getPackageStructure();
    -  1012  1535
                 addEntry(vendor, list.get(0));
    -  1013   +  995  6
             for (ClassNameInformation entry : classNames) {
    +  996  1535
                 final List<String> list = entry.getPackageStructure();
    +  997  1535
                 addEntry(vendor, list.get(0));
    +  998  
     
    -  1014  1535
                 if (list.size() == 2) {
    -  1015  0
                     addEntry(product, list.get(1));
    -  1016   +  999  1535
                 if (list.size() == 2) {
    +  1000  0
                     addEntry(product, list.get(1));
    +  1001  1535
                 } else if (list.size() == 3) {
    +  1002  345
                     addEntry(vendor, list.get(1));
    +  1003  345
                     addEntry(product, list.get(1));
    +  1004  345
                     addEntry(product, list.get(2));
    +  1005  1190
                 } else if (list.size() >= 4) {
    +  1006  1190
                     addEntry(vendor, list.get(1));
    +  1007  1190
                     addEntry(vendor, list.get(2));
    +  1008  1190
                     addEntry(product, list.get(1));
    +  1009  1190
                     addEntry(product, list.get(2));
    +  1010  1190
                     addEntry(product, list.get(3));
    +  1011  
                 }
    -  1017  1535
                 if (list.size() == 3) {
    -  1018  345
                     addEntry(vendor, list.get(1));
    -  1019  345
                     addEntry(product, list.get(1));
    -  1020  345
                     addEntry(product, list.get(2));
    -  1021   -
                 }
    -  1022  1535
                 if (list.size() >= 4) {
    -  1023  1190
                     addEntry(vendor, list.get(1));
    -  1024  1190
                     addEntry(vendor, list.get(2));
    -  1025  1190
                     addEntry(product, list.get(1));
    -  1026  1190
                     addEntry(product, list.get(2));
    -  1027  1190
                     addEntry(product, list.get(3));
    -  1028   -
                 }
    -  1029  1535
             }
    -  1030  6
         }
    -  1031   +  1012  1535
             }
    +  1013  6
         }
    +  1014  
     
    -  1032   +  1015  
         /**
    -  1033   +  1016  
          * Adds an entry to the specified collection and sets the Integer (e.g. the
    -  1034   +  1017  
          * count) to 1. If the entry already exists in the collection then the
    -  1035   +  1018  
          * Integer is incremented by 1.
    +  1019   +
          *
    +  1020   +
          * @param collection a collection of strings and their occurrence count
    +  1021   +
          * @param key the key to add to the collection
    +  1022   +
          */
    +  1023   +
         private void addEntry(Map<String, Integer> collection, String key) {
    +  1024  8520
             if (collection.containsKey(key)) {
    +  1025  7487
                 collection.put(key, collection.get(key) + 1);
    +  1026   +
             } else {
    +  1027  1033
                 collection.put(key, 1);
    +  1028   +
             }
    +  1029  8520
         }
    +  1030   +
     
    +  1031   +
         /**
    +  1032   +
          * Cycles through the collection of class name information to see if parts
    +  1033   +
          * of the package names are contained in the provided value. If found, it
    +  1034   +
          * will be added as the HIGHEST confidence evidence because we have more
    +  1035   +
          * then one source corroborating the value.
     1036  
          *
     1037   -
          * @param collection a collection of strings and their occurrence count
    -  1038   -
          * @param key the key to add to the collection
    -  1039   -
          */
    -  1040   -
         private void addEntry(Map<String, Integer> collection, String key) {
    -  1041  8520
             if (collection.containsKey(key)) {
    -  1042  7487
                 collection.put(key, collection.get(key) + 1);
    -  1043   -
             } else {
    -  1044  1033
                 collection.put(key, 1);
    -  1045   -
             }
    -  1046  8520
         }
    -  1047   -
     
    -  1048   -
         /**
    -  1049   -
          * Cycles through the collection of class name information to see if parts
    -  1050   -
          * of the package names are contained in the provided value. If found, it
    -  1051   -
          * will be added as the HIGHEST confidence evidence because we have more
    -  1052   -
          * then one source corroborating the value.
    -  1053   -
          *
    -  1054  
          * @param classes a collection of class name information
    -  1055   +  1038  
          * @param value the value to check to see if it contains a package name
    -  1056   +  1039  
          * @param evidence the evidence collection to add new entries too
    -  1057   +  1040  
          */
    -  1058   +  1041  
         private static void addMatchingValues(List<ClassNameInformation> classes, String value, EvidenceCollection evidence) {
    -  1059  63
             if (value == null || value.isEmpty() || classes == null || classes.isEmpty()) {
    -  1060  21
                 return;
    -  1061   +  1042  63
             if (value == null || value.isEmpty() || classes == null || classes.isEmpty()) {
    +  1043  21
                 return;
    +  1044  
             }
    -  1062  42
             final String text = value.toLowerCase();
    -  1063  42
             for (ClassNameInformation cni : classes) {
    -  1064  16320
                 for (String key : cni.getPackageStructure()) {
    -  1065  62390
                     final Pattern p = Pattern.compile("\b" + key + "\b");
    -  1066  62417
                     if (p.matcher(text).find()) {
    -  1067   +  1045  42
             final String text = value.toLowerCase();
    +  1046  42
             for (ClassNameInformation cni : classes) {
    +  1047  16314
                 for (String key : cni.getPackageStructure()) {
    +  1048  62344
                     final Pattern p = Pattern.compile("\b" + key + "\b");
    +  1049  62348
                     if (p.matcher(text).find()) {
    +  1050  
                         //if (text.contains(key)) { //note, package structure elements are already lowercase.
    -  1068  0
                         evidence.addEvidence("jar", "package name", key, Confidence.HIGHEST);
    -  1069   +  1051  0
                         evidence.addEvidence("jar", "package name", key, Confidence.HIGHEST);
    +  1052  
                     }
    -  1070  62390
                 }
    -  1071  16318
             }
    -  1072  42
         }
    -  1073   +  1053  62360
                 }
    +  1054  16317
             }
    +  1055  42
         }
    +  1056  
     
    -  1074   +  1057  
         /**
    -  1075   +  1058  
          * Simple check to see if the attribute from a manifest is just a package
    -  1076   +  1059  
          * name.
    -  1077   +  1060  
          *
    -  1078   +  1061  
          * @param key the key of the value to check
    -  1079   +  1062  
          * @param value the value to check
    -  1080   +  1063  
          * @return true if the value looks like a java package name, otherwise false
    -  1081   +  1064  
          */
    -  1082   +  1065  
         private boolean isPackage(String key, String value) {
    -  1083   +  1066  
     
    -  1084  28
             return !key.matches(".*(version|title|vendor|name|license|description).*")
    -  1085  8
                     && value.matches("^([a-zA-Z_][a-zA-Z0-9_\\$]*(\\.[a-zA-Z_][a-zA-Z0-9_\\$]*)*)?$");
    -  1086   +  1067  28
             return !key.matches(".*(version|title|vendor|name|license|description).*")
    +  1068  8
                     && value.matches("^([a-zA-Z_][a-zA-Z0-9_\\$]*(\\.[a-zA-Z_][a-zA-Z0-9_\\$]*)*)?$");
    +  1069  
     
    -  1087   +  1070  
         }
    -  1088   +  1071  
     
    -  1089   +  1072  
         /**
    -  1090   +  1073  
          * Extracts the license information from the pom and adds it to the
    -  1091   +  1074  
          * dependency.
    -  1092   +  1075  
          *
    -  1093   +  1076  
          * @param pom the pom object
    -  1094   +  1077  
          * @param dependency the dependency to add license information too
    -  1095   +  1078  
          */
    -  1096   +  1079  
         public static void extractLicense(Model pom, Dependency dependency) {
    -  1097   +  1080  
             //license
    -  1098  2
             if (pom.getLicenses() != null) {
    -  1099  2
                 String license = null;
    -  1100  2
                 for (License lic : pom.getLicenses()) {
    -  1101  0
                     String tmp = null;
    -  1102  0
                     if (lic.getName() != null) {
    -  1103  0
                         tmp = lic.getName();
    -  1104   +  1081  2
             if (pom.getLicenses() != null) {
    +  1082  2
                 String license = null;
    +  1083  2
                 for (License lic : pom.getLicenses()) {
    +  1084  0
                     String tmp = null;
    +  1085  0
                     if (lic.getName() != null) {
    +  1086  0
                         tmp = lic.getName();
    +  1087  
                     }
    -  1105  0
                     if (lic.getUrl() != null) {
    -  1106  0
                         if (tmp == null) {
    -  1107  0
                             tmp = lic.getUrl();
    -  1108   +  1088  0
                     if (lic.getUrl() != null) {
    +  1089  0
                         if (tmp == null) {
    +  1090  0
                             tmp = lic.getUrl();
    +  1091  
                         } else {
    -  1109  0
                             tmp += ": " + lic.getUrl();
    -  1110   +  1092  0
                             tmp += ": " + lic.getUrl();
    +  1093  
                         }
    -  1111   +  1094  
                     }
    -  1112  0
                     if (tmp == null) {
    -  1113  0
                         continue;
    -  1114   +  1095  0
                     if (tmp == null) {
    +  1096  0
                         continue;
    +  1097  
                     }
    -  1115  0
                     if (HTML_DETECTION_PATTERN.matcher(tmp).find()) {
    -  1116  0
                         tmp = Jsoup.parse(tmp).text();
    -  1117   +  1098  0
                     if (HTML_DETECTION_PATTERN.matcher(tmp).find()) {
    +  1099  0
                         tmp = Jsoup.parse(tmp).text();
    +  1100  
                     }
    -  1118  0
                     if (license == null) {
    -  1119  0
                         license = tmp;
    -  1120   +  1101  0
                     if (license == null) {
    +  1102  0
                         license = tmp;
    +  1103  
                     } else {
    -  1121  0
                         license += "\n" + tmp;
    -  1122   +  1104  0
                         license += "\n" + tmp;
    +  1105  
                     }
    -  1123  0
                 }
    -  1124  2
                 if (license != null) {
    -  1125  0
                     dependency.setLicense(license);
    -  1126   +  1106  0
                 }
    +  1107  2
                 if (license != null) {
    +  1108  0
                     dependency.setLicense(license);
    +  1109  
     
    -  1127   +  1110  
                 }
    -  1128   +  1111  
             }
    -  1129  2
         }
    -  1130   +  1112  2
         }
    +  1113  
     
    -  1131   +  1114  
         /**
    -  1132   +  1115  
          * Stores information about a class name.
    -  1133   +  1116  
          */
    -  1134   +  1117  
         protected static class ClassNameInformation {
    -  1135   +  1118  
     
    -  1136   +  1119  
             /**
    -  1137   +  1120  
              * <p>
    -  1138   +  1121  
              * Stores information about a given class name. This class will keep the
    -  1139   +  1122  
              * fully qualified class name and a list of the important parts of the
    -  1140   +  1123  
              * package structure. Up to the first four levels of the package
    -  1141   +  1124  
              * structure are stored, excluding a leading "org" or "com".
    -  1142   +  1125  
              * Example:</p>
    -  1143   +  1126  
              * <code>ClassNameInformation obj = new ClassNameInformation("org.owasp.dependencycheck.analyzer.JarAnalyzer");
    -  1144   +  1127  
              * System.out.println(obj.getName());
    -  1145   +  1128  
              * for (String p : obj.getPackageStructure())
    -  1146   +  1129  
              *     System.out.println(p);
    -  1147   +  1130  
              * </code>
    -  1148   +  1131  
              * <p>
    -  1149   +  1132  
              * Would result in:</p>
    -  1150   +  1133  
              * <code>org.owasp.dependencycheck.analyzer.JarAnalyzer
    -  1151   +  1134  
              * owasp
    -  1152   +  1135  
              * dependencycheck
    -  1153   +  1136  
              * analyzer
    -  1154   +  1137  
              * jaranalyzer</code>
    -  1155   +  1138  
              *
    -  1156   +  1139  
              * @param className a fully qualified class name
    -  1157   +  1140  
              */
    -  1158  1535
             ClassNameInformation(String className) {
    -  1159  1535
                 name = className;
    -  1160  1535
                 if (name.contains("/")) {
    -  1161  1535
                     final String[] tmp = className.toLowerCase().split("/");
    -  1162  1535
                     int start = 0;
    -  1163  1535
                     int end = 3;
    -  1164  1535
                     if ("com".equals(tmp[0]) || "org".equals(tmp[0])) {
    -  1165  1535
                         start = 1;
    -  1166  1535
                         end = 4;
    -  1167   +  1141  1430
             ClassNameInformation(String className) {
    +  1142  1463
                 name = className;
    +  1143  1458
                 if (name.contains("/")) {
    +  1144  1469
                     final String[] tmp = className.toLowerCase().split("/");
    +  1145  1492
                     int start = 0;
    +  1146  1489
                     int end = 3;
    +  1147  1489
                     if ("com".equals(tmp[0]) || "org".equals(tmp[0])) {
    +  1148  1532
                         start = 1;
    +  1149  1531
                         end = 4;
    +  1150  
                     }
    -  1168  1535
                     if (tmp.length <= end) {
    -  1169  345
                         end = tmp.length - 1;
    -  1170   +  1151  1530
                     if (tmp.length <= end) {
    +  1152  343
                         end = tmp.length - 1;
    +  1153  
                     }
    -  1171  7330
                     for (int i = start; i <= end; i++) {
    -  1172  5795
                         packageStructure.add(tmp[i]);
    -  1173   +  1154  7171
                     for (int i = start; i <= end; i++) {
    +  1155  5668
                         packageStructure.add(tmp[i]);
    +  1156  
                     }
    -  1174  1535
                 } else {
    -  1175  0
                     packageStructure.add(name);
    -  1176   +  1157  1507
                 } else {
    +  1158  0
                     packageStructure.add(name);
    +  1159  
                 }
    -  1177  1535
             }
    -  1178   +  1160  1493
             }
    +  1161  
             /**
    -  1179   +  1162  
              * The fully qualified class name.
    -  1180   +  1163  
              */
    -  1181   +  1164  
             private String name;
    -  1182   +  1165  
     
    +  1166   +
             /**
    +  1167   +
              * Get the value of name
    +  1168   +
              *
    +  1169   +
              * @return the value of name
    +  1170   +
              */
    +  1171   +
             public String getName() {
    +  1172  0
                 return name;
    +  1173   +
             }
    +  1174   +
     
    +  1175   +
             /**
    +  1176   +
              * Set the value of name
    +  1177   +
              *
    +  1178   +
              * @param name new value of name
    +  1179   +
              */
    +  1180   +
             public void setName(String name) {
    +  1181  0
                 this.name = name;
    +  1182  0
             }
     1183  
             /**
     1184   -
              * Get the value of name
    -  1185   -
              *
    -  1186   -
              * @return the value of name
    -  1187   -
              */
    -  1188   -
             public String getName() {
    -  1189  0
                 return name;
    -  1190   -
             }
    -  1191   -
     
    -  1192   -
             /**
    -  1193   -
              * Set the value of name
    -  1194   -
              *
    -  1195   -
              * @param name new value of name
    -  1196   -
              */
    -  1197   -
             public void setName(String name) {
    -  1198  0
                 this.name = name;
    -  1199  0
             }
    -  1200   -
             /**
    -  1201  
              * Up to the first four levels of the package structure, excluding a
    -  1202   +  1185  
              * leading "org" or "com".
    -  1203   +  1186  
              */
    -  1204  1535
             private final ArrayList<String> packageStructure = new ArrayList<String>();
    -  1205   +  1187  1435
             private final ArrayList<String> packageStructure = new ArrayList<String>();
    +  1188  
     
    -  1206   +  1189  
             /**
    -  1207   +  1190  
              * Get the value of packageStructure
    -  1208   +  1191  
              *
    -  1209   +  1192  
              * @return the value of packageStructure
    -  1210   +  1193  
              */
    -  1211   +  1194  
             public ArrayList<String> getPackageStructure() {
    -  1212  17855
                 return packageStructure;
    -  1213   +  1195  17855
                 return packageStructure;
    +  1196  
             }
    -  1214   +  1197  
         }
    -  1215   +  1198  
     
    -  1216   +  1199  
         /**
    -  1217   +  1200  
          * Retrieves the next temporary directory to extract an archive too.
    -  1218   +  1201  
          *
    -  1219   +  1202  
          * @return a directory
    -  1220   +  1203  
          * @throws AnalysisException thrown if unable to create temporary directory
    -  1221   +  1204  
          */
    -  1222   +  1205  
         private File getNextTempDirectory() throws AnalysisException {
    -  1223  0
             final int dirCount = DIR_COUNT.incrementAndGet();
    -  1224  0
             final File directory = new File(tempFileLocation, String.valueOf(dirCount));
    -  1225   +  1206  2
             final int dirCount = DIR_COUNT.incrementAndGet();
    +  1207  2
             final File directory = new File(tempFileLocation, String.valueOf(dirCount));
    +  1208  
             //getting an exception for some directories not being able to be created; might be because the directory already exists?
    -  1226  0
             if (directory.exists()) {
    -  1227  0
                 return getNextTempDirectory();
    -  1228   +  1209  2
             if (directory.exists()) {
    +  1210  0
                 return getNextTempDirectory();
    +  1211  
             }
    -  1229  0
             if (!directory.mkdirs()) {
    -  1230  0
                 final String msg = String.format("Unable to create temp directory '%s'.", directory.getAbsolutePath());
    -  1231  0
                 throw new AnalysisException(msg);
    -  1232   +  1212  2
             if (!directory.mkdirs()) {
    +  1213  0
                 final String msg = String.format("Unable to create temp directory '%s'.", directory.getAbsolutePath());
    +  1214  0
                 throw new AnalysisException(msg);
    +  1215  
             }
    -  1233  0
             return directory;
    -  1234   +  1216  2
             return directory;
    +  1217  
         }
    -  1235   +  1218  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NexusAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NexusAnalyzer.html index 380af31c7..5763702e5 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NexusAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NexusAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    NexusAnalyzer
    18%
    14/77
    3%
    1/30
    3.778
    NexusAnalyzer
    19%
    15/77
    3%
    1/30
    3.778
     
    @@ -193,321 +193,327 @@  89  
     
     90   -
         private boolean useProxy;
    +
         /**
     91   -
         /**
    +
          * Whether or not the Nexus analyzer should use a proxy if configured.
     92   -
          * The Nexus Search to be set up for this analyzer.
    +
          */
     93   -
          */
    +
         private boolean useProxy;
     94   -
         private NexusSearch searcher;
    +
         /**
     95   -
     
    +
          * The Nexus Search to be set up for this analyzer.
     96   -
         /**
    +
          */
     97   -
          * Field indicating if the analyzer is enabled.
    +
         private NexusSearch searcher;
     98   -
          */
    -  99  8
         private final boolean enabled = checkEnabled();
    -  100  
     
    -  101   +  99  
         /**
    -  102   -
          * Determines if this analyzer is enabled
    -  103   -
          *
    -  104   -
          * @return <code>true</code> if the analyzer is enabled; otherwise
    -  105   -
          * <code>false</code>
    -  106   +  100   +
          * Field indicating if the analyzer is enabled.
    +  101  
          */
    -  107   -
         private boolean checkEnabled() {
    -  108   -
             /* Enable this analyzer ONLY if the Nexus URL has been set to something
    -  109   -
              other than the default one (if it's the default one, we'll use the
    -  110   -
              central one) and it's enabled by the user.
    -  111   -
              */
    -  112  8
             boolean retval = false;
    -  113   -
             try {
    -  114  8
                 if (!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))
    -  115  0
                         && Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
    -  116  0
                     LOGGER.info("Enabling Nexus analyzer");
    -  117  0
                     retval = true;
    -  118   -
                 } else {
    -  119  8
                     LOGGER.debug("Nexus analyzer disabled, using Central instead");
    -  120   -
                 }
    -  121  0
             } catch (InvalidSettingException ise) {
    -  122  0
                 LOGGER.warn("Invalid setting. Disabling Nexus analyzer");
    -  123  8
             }
    -  124   +  102  8
         private final boolean enabled = checkEnabled();
    +  103  
     
    -  125  8
             return retval;
    -  126   -
         }
    +  104   +
         /**
    +  105   +
          * Determines if this analyzer is enabled
    +  106   +
          *
    +  107   +
          * @return <code>true</code> if the analyzer is enabled; otherwise
    +  108   +
          * <code>false</code>
    +  109   +
          */
    +  110   +
         private boolean checkEnabled() {
    +  111   +
             /* Enable this analyzer ONLY if the Nexus URL has been set to something
    +  112   +
              other than the default one (if it's the default one, we'll use the
    +  113   +
              central one) and it's enabled by the user.
    +  114   +
              */
    +  115  8
             boolean retval = false;
    +  116   +
             try {
    +  117  8
                 if (!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))
    +  118  0
                         && Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
    +  119  0
                     LOGGER.info("Enabling Nexus analyzer");
    +  120  0
                     retval = true;
    +  121   +
                 } else {
    +  122  8
                     LOGGER.debug("Nexus analyzer disabled, using Central instead");
    +  123   +
                 }
    +  124  0
             } catch (InvalidSettingException ise) {
    +  125  0
                 LOGGER.warn("Invalid setting. Disabling Nexus analyzer");
    +  126  8
             }
     127  
     
    -  128   -
         /**
    +  128  8
             return retval;
     129   -
          * Determine whether to enable this analyzer or not.
    +
         }
     130   -
          *
    +
     
     131   -
          * @return whether the analyzer should be enabled
    +
         /**
     132   -
          */
    +
          * Determine whether to enable this analyzer or not.
     133   -
         @Override
    +
          *
     134   -
         public boolean isEnabled() {
    -  135  0
             return enabled;
    +
          * @return whether the analyzer should be enabled
    +  135   +
          */
     136   -
         }
    +
         @Override
     137   -
     
    -  138   -
         /**
    +
         public boolean isEnabled() {
    +  138  864
             return enabled;
     139   -
          * Initializes the analyzer once before any analysis is performed.
    +
         }
     140   -
          *
    +
     
     141   -
          * @throws InitializationException if there's an error during initialization
    +
         /**
     142   -
          */
    +
          * Initializes the analyzer once before any analysis is performed.
     143   -
         @Override
    +
          *
     144   +
          * @throws InitializationException if there's an error during initialization
    +  145   +
          */
    +  146   +
         @Override
    +  147  
         public void initializeFileTypeAnalyzer() throws InitializationException {
    -  145  0
             LOGGER.debug("Initializing Nexus Analyzer");
    -  146  0
             LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
    -  147  0
             if (isEnabled()) {
    -  148  0
                 useProxy = useProxy();
    -  149  0
                 final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
    -  150  0
                 LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
    -  151   +  148  0
             LOGGER.debug("Initializing Nexus Analyzer");
    +  149  0
             LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
    +  150  0
             if (isEnabled()) {
    +  151  0
                 useProxy = useProxy();
    +  152  0
                 final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
    +  153  0
                 LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
    +  154  
                 try {
    -  152  0
                     searcher = new NexusSearch(new URL(searchUrl), useProxy);
    -  153  0
                     if (!searcher.preflightRequest()) {
    -  154  0
                         setEnabled(false);
    -  155  0
                         throw new InitializationException("There was an issue getting Nexus status. Disabling analyzer.");
    -  156   +  155  0
                     searcher = new NexusSearch(new URL(searchUrl), useProxy);
    +  156  0
                     if (!searcher.preflightRequest()) {
    +  157  0
                         setEnabled(false);
    +  158  0
                         throw new InitializationException("There was an issue getting Nexus status. Disabling analyzer.");
    +  159  
                     }
    -  157  0
                 } catch (MalformedURLException mue) {
    -  158  0
                     setEnabled(false);
    -  159  0
                     throw new InitializationException("Malformed URL to Nexus: " + searchUrl, mue);
    -  160  0
                 }
    -  161   -
             }
    -  162  0
         }
    -  163   -
     
    +  160  0
                 } catch (MalformedURLException mue) {
    +  161  0
                     setEnabled(false);
    +  162  0
                     throw new InitializationException("Malformed URL to Nexus: " + searchUrl, mue);
    +  163  0
                 }
     164   -
         /**
    -  165   -
          * Returns the analyzer's name.
    +
             }
    +  165  0
         }
     166   -
          *
    +
     
     167   -
          * @return the name of the analyzer
    +
         /**
     168   -
          */
    +
          * Returns the analyzer's name.
     169   -
         @Override
    +
          *
     170   -
         public String getName() {
    -  171  22
             return ANALYZER_NAME;
    +
          * @return the name of the analyzer
    +  171   +
          */
     172   -
         }
    +
         @Override
     173   -
     
    -  174   -
         /**
    +
         public String getName() {
    +  174  20
             return ANALYZER_NAME;
     175   -
          * Returns the key used in the properties file to reference the analyzer's
    +
         }
     176   -
          * enabled property.
    +
     
     177   -
          *
    +
         /**
     178   -
          * @return the analyzer's enabled property setting key
    +
          * Returns the key used in the properties file to reference the analyzer's
     179   -
          */
    +
          * enabled property.
     180   -
         @Override
    +
          *
     181   -
         protected String getAnalyzerEnabledSettingKey() {
    -  182  8
             return Settings.KEYS.ANALYZER_NEXUS_ENABLED;
    +
          * @return the analyzer's enabled property setting key
    +  182   +
          */
     183   -
         }
    +
         @Override
     184   -
     
    -  185   -
         /**
    +
         protected String getAnalyzerEnabledSettingKey() {
    +  185  2
             return Settings.KEYS.ANALYZER_NEXUS_ENABLED;
     186   -
          * Returns the analysis phase under which the analyzer runs.
    +
         }
     187   -
          *
    +
     
     188   -
          * @return the phase under which this analyzer runs
    +
         /**
     189   -
          */
    +
          * Returns the analysis phase under which the analyzer runs.
     190   -
         @Override
    +
          *
     191   -
         public AnalysisPhase getAnalysisPhase() {
    -  192  6
             return ANALYSIS_PHASE;
    +
          * @return the phase under which this analyzer runs
    +  192   +
          */
     193   -
         }
    +
         @Override
     194   -
     
    -  195   -
         /**
    +
         public AnalysisPhase getAnalysisPhase() {
    +  195  6
             return ANALYSIS_PHASE;
     196   -
          * The file filter used to determine which files this analyzer supports.
    +
         }
     197   -
          */
    -  198  1
         private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
    +
     
    +  198   +
         /**
     199   -
     
    +
          * The file filter used to determine which files this analyzer supports.
     200   -
         /**
    -  201   -
          * Returns the FileFilter
    +
          */
    +  201  1
         private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
     202   -
          *
    -  203   -
          * @return the FileFilter
    -  204   -
          */
    -  205   -
         @Override
    -  206   -
         protected FileFilter getFileFilter() {
    -  207  862
             return FILTER;
    -  208   -
         }
    -  209  
     
    -  210   +  203  
         /**
    -  211   -
          * Performs the analysis.
    -  212   +  204   +
          * Returns the FileFilter
    +  205  
          *
    -  213   -
          * @param dependency the dependency to analyze
    -  214   -
          * @param engine the engine
    -  215   -
          * @throws AnalysisException when there's an exception during analysis
    -  216   +  206   +
          * @return the FileFilter
    +  207  
          */
    -  217   +  208  
         @Override
    -  218   -
         public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
    -  219  0
             if (!isEnabled()) {
    -  220  0
                 return;
    -  221   -
             }
    -  222   -
             try {
    -  223  0
                 final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
    -  224  0
                 dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
    -  225  0
                 boolean pomAnalyzed = false;
    -  226  0
                 LOGGER.debug("POM URL {}", ma.getPomUrl());
    -  227  0
                 for (Evidence e : dependency.getVendorEvidence()) {
    -  228  0
                     if ("pom".equals(e.getSource())) {
    -  229  0
                         pomAnalyzed = true;
    -  230  0
                         break;
    -  231   -
                     }
    -  232  0
                 }
    -  233  0
                 if (!pomAnalyzed && ma.getPomUrl() != null) {
    -  234  0
                     File pomFile = null;
    -  235   -
                     try {
    -  236  0
                         final File baseDir = Settings.getTempDirectory();
    -  237  0
                         pomFile = File.createTempFile("pom", ".xml", baseDir);
    -  238  0
                         if (!pomFile.delete()) {
    -  239  0
                             LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; "
    -  240  0
                                     + "this could result in undetected CPE/CVEs.", dependency.getFileName());
    -  241  0
                             LOGGER.debug("Unable to delete temp file");
    -  242   -
                         }
    -  243  0
                         LOGGER.debug("Downloading {}", ma.getPomUrl());
    -  244  0
                         Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
    -  245  0
                         PomUtils.analyzePOM(dependency, pomFile);
    -  246  0
                     } catch (DownloadFailedException ex) {
    -  247  0
                         LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; "
    -  248  0
                                 + "this could result in undetected CPE/CVEs.", dependency.getFileName());
    -  249   -
                     } finally {
    -  250  0
                         if (pomFile != null && pomFile.exists() && !FileUtils.deleteQuietly(pomFile)) {
    -  251  0
                             LOGGER.debug("Failed to delete temporary pom file {}", pomFile.toString());
    -  252  0
                             pomFile.deleteOnExit();
    -  253   -
                         }
    -  254   -
                     }
    -  255   -
                 }
    -  256  0
             } catch (IllegalArgumentException iae) {
    -  257   -
                 //dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
    -  258  0
                 LOGGER.info("invalid sha-1 hash on {}", dependency.getFileName());
    -  259  0
             } catch (FileNotFoundException fnfe) {
    -  260   -
                 //dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
    -  261  0
                 LOGGER.debug("Artifact not found in repository '{}'", dependency.getFileName());
    -  262  0
                 LOGGER.debug(fnfe.getMessage(), fnfe);
    -  263  0
             } catch (IOException ioe) {
    -  264   -
                 //dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
    -  265  0
                 LOGGER.debug("Could not connect to nexus repository", ioe);
    -  266  0
             }
    -  267  0
         }
    -  268   -
         
    -  269   -
         /**
    -  270   -
          * Determine if a proxy should be used.
    -  271   -
          *
    -  272   -
          * @return {@code true} if a proxy should be used
    -  273   -
          */
    -  274   -
         public static boolean useProxy() {
    -  275   -
             try {
    -  276  0
                 return Settings.getString(Settings.KEYS.PROXY_SERVER) != null
    -  277  0
                         && Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY);
    -  278  0
             } catch (InvalidSettingException ise) {
    -  279  0
                 LOGGER.warn("Failed to parse proxy settings.", ise);
    -  280  0
                 return false;
    -  281   -
             }
    -  282   +  209   +
         protected FileFilter getFileFilter() {
    +  210  858
             return FILTER;
    +  211  
         }
    -  283   +  212   +
     
    +  213   +
         /**
    +  214   +
          * Performs the analysis.
    +  215   +
          *
    +  216   +
          * @param dependency the dependency to analyze
    +  217   +
          * @param engine the engine
    +  218   +
          * @throws AnalysisException when there's an exception during analysis
    +  219   +
          */
    +  220   +
         @Override
    +  221   +
         public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  222  0
             if (!isEnabled()) {
    +  223  0
                 return;
    +  224   +
             }
    +  225   +
             try {
    +  226  0
                 final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
    +  227  0
                 dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
    +  228  0
                 boolean pomAnalyzed = false;
    +  229  0
                 LOGGER.debug("POM URL {}", ma.getPomUrl());
    +  230  0
                 for (Evidence e : dependency.getVendorEvidence()) {
    +  231  0
                     if ("pom".equals(e.getSource())) {
    +  232  0
                         pomAnalyzed = true;
    +  233  0
                         break;
    +  234   +
                     }
    +  235  0
                 }
    +  236  0
                 if (!pomAnalyzed && ma.getPomUrl() != null) {
    +  237  0
                     File pomFile = null;
    +  238   +
                     try {
    +  239  0
                         final File baseDir = Settings.getTempDirectory();
    +  240  0
                         pomFile = File.createTempFile("pom", ".xml", baseDir);
    +  241  0
                         if (!pomFile.delete()) {
    +  242  0
                             LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; "
    +  243  0
                                     + "this could result in undetected CPE/CVEs.", dependency.getFileName());
    +  244  0
                             LOGGER.debug("Unable to delete temp file");
    +  245   +
                         }
    +  246  0
                         LOGGER.debug("Downloading {}", ma.getPomUrl());
    +  247  0
                         Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
    +  248  0
                         PomUtils.analyzePOM(dependency, pomFile);
    +  249  0
                     } catch (DownloadFailedException ex) {
    +  250  0
                         LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; "
    +  251  0
                                 + "this could result in undetected CPE/CVEs.", dependency.getFileName());
    +  252   +
                     } finally {
    +  253  0
                         if (pomFile != null && pomFile.exists() && !FileUtils.deleteQuietly(pomFile)) {
    +  254  0
                             LOGGER.debug("Failed to delete temporary pom file {}", pomFile.toString());
    +  255  0
                             pomFile.deleteOnExit();
    +  256   +
                         }
    +  257   +
                     }
    +  258   +
                 }
    +  259  0
             } catch (IllegalArgumentException iae) {
    +  260   +
                 //dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
    +  261  0
                 LOGGER.info("invalid sha-1 hash on {}", dependency.getFileName());
    +  262  0
             } catch (FileNotFoundException fnfe) {
    +  263   +
                 //dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
    +  264  0
                 LOGGER.debug("Artifact not found in repository '{}'", dependency.getFileName());
    +  265  0
                 LOGGER.debug(fnfe.getMessage(), fnfe);
    +  266  0
             } catch (IOException ioe) {
    +  267   +
                 //dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
    +  268  0
                 LOGGER.debug("Could not connect to nexus repository", ioe);
    +  269  0
             }
    +  270  0
         }
    +  271   +
     
    +  272   +
         /**
    +  273   +
          * Determine if a proxy should be used.
    +  274   +
          *
    +  275   +
          * @return {@code true} if a proxy should be used
    +  276   +
          */
    +  277   +
         public static boolean useProxy() {
    +  278   +
             try {
    +  279  0
                 return Settings.getString(Settings.KEYS.PROXY_SERVER) != null
    +  280  0
                         && Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY);
    +  281  0
             } catch (InvalidSettingException ise) {
    +  282  0
                 LOGGER.warn("Failed to parse proxy settings.", ise);
    +  283  0
                 return false;
    +  284   +
             }
    +  285   +
         }
    +  286  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NodePackageAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NodePackageAnalyzer.html index ea964fc47..fd9051e38 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NodePackageAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NodePackageAnalyzer.html @@ -178,7 +178,7 @@
         @Override
     83  
         protected FileFilter getFileFilter() {
    -  84  863
             return PACKAGE_JSON_FILTER;
    +  84  859
             return PACKAGE_JSON_FILTER;
     85  
         }
     86   @@ -206,7 +206,7 @@
         @Override
     98  
         public String getName() {
    -  99  21
             return ANALYZER_NAME;
    +  99  17
             return ANALYZER_NAME;
     100  
         }
     101   @@ -246,7 +246,7 @@
         @Override
     119  
         protected String getAnalyzerEnabledSettingKey() {
    -  120  11
             return Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED;
    +  120  5
             return Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED;
     121  
         }
     122   @@ -254,7 +254,7 @@  123  
         @Override
     124   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     125  
                 throws AnalysisException {
     126  1
             final File file = dependency.getActualFile();
    @@ -348,6 +348,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NuspecAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NuspecAnalyzer.html index 7a68506f5..bbaa2d98b 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NuspecAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NuspecAnalyzer.html @@ -175,7 +175,7 @@
         @Override
     81  
         public String getName() {
    -  82  23
             return ANALYZER_NAME;
    +  82  19
             return ANALYZER_NAME;
     83  
         }
     84   @@ -196,7 +196,7 @@
         @Override
     92  
         protected String getAnalyzerEnabledSettingKey() {
    -  93  11
             return Settings.KEYS.ANALYZER_NUSPEC_ENABLED;
    +  93  5
             return Settings.KEYS.ANALYZER_NUSPEC_ENABLED;
     94  
         }
     95   @@ -244,7 +244,7 @@
         @Override
     118  
         protected FileFilter getFileFilter() {
    -  119  863
             return FILTER;
    +  119  860
             return FILTER;
     120  
         }
     121   @@ -266,7 +266,7 @@  129  
         @Override
     130   -
         public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
    +
         public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
     131  0
             LOGGER.debug("Checking Nuspec file {}", dependency);
     132  
             try {
    @@ -315,6 +315,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NvdCveAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NvdCveAnalyzer.html index 66637e2ef..1159fc0fe 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NvdCveAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.NvdCveAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    NvdCveAnalyzer
    53%
    26/49
    50%
    6/12
    3.125
    NvdCveAnalyzer
    54%
    27/50
    50%
    6/12
    2.889
     
    @@ -78,244 +78,279 @@  30  
     import org.owasp.dependencycheck.exception.InitializationException;
     31   -
     import org.slf4j.LoggerFactory;
    +
     import org.owasp.dependencycheck.utils.Settings;
     32   -
     
    +
     import org.slf4j.LoggerFactory;
     33   -
     /**
    +
     
     34   -
      * NvdCveAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated
    +
     /**
     35   -
      * CVEs. It uses the the identifiers found by other analyzers to lookup the CVE data.
    +
      * NvdCveAnalyzer is a utility class that takes a project dependency and
     36   -
      *
    +
      * attempts to discern if there is an associated CVEs. It uses the the
     37   -
      * @author Jeremy Long
    +
      * identifiers found by other analyzers to lookup the CVE data.
     38   -
      */
    -  39  8
     public class NvdCveAnalyzer extends AbstractAnalyzer {
    +
      *
    +  39   +
      * @author Jeremy Long
     40   -
         /**
    -  41   -
          * The Logger for use throughout the class
    +
      */
    +  41  8
     public class NvdCveAnalyzer extends AbstractAnalyzer {
     42   -
          */
    -  43  1
         private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class);
    +
     
    +  43   +
         /**
     44   -
         /**
    +
          * The Logger for use throughout the class
     45   -
          * The maximum number of query results to return.
    -  46  
          */
    +  46  1
         private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class);
     47   -
         static final int MAX_QUERY_RESULTS = 100;
    +
         /**
     48   -
         /**
    +
          * The maximum number of query results to return.
     49   -
          * The CVE Index.
    +
          */
     50   -
          */
    +
         static final int MAX_QUERY_RESULTS = 100;
     51   -
         private CveDB cveDB;
    +
         /**
     52   -
     
    +
          * The CVE Index.
     53   -
         /**
    +
          */
     54   -
          * Opens the data source.
    +
         private CveDB cveDB;
     55   -
          *
    +
     
     56   -
          * @throws SQLException thrown when there is a SQL Exception
    +
         /**
     57   -
          * @throws IOException thrown when there is an IO Exception
    +
          * Opens the data source.
     58   -
          * @throws DatabaseException thrown when there is a database exceptions
    +
          *
     59   -
          * @throws ClassNotFoundException thrown if the h2 database driver cannot be loaded
    +
          * @throws SQLException thrown when there is a SQL Exception
     60   -
          */
    +
          * @throws IOException thrown when there is an IO Exception
     61   -
         public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
    -  62  2
             cveDB = new CveDB();
    -  63  2
             cveDB.open();
    -  64  2
         }
    +
          * @throws DatabaseException thrown when there is a database exceptions
    +  62   +
          * @throws ClassNotFoundException thrown if the h2 database driver cannot be
    +  63   +
          * loaded
    +  64   +
          */
     65   -
     
    -  66   -
         /**
    -  67   -
          * Closes the data source.
    -  68   -
          */
    +
         public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
    +  66  2
             cveDB = new CveDB();
    +  67  2
             cveDB.open();
    +  68  2
         }
     69   -
         @Override
    +
     
     70   -
         public void close() {
    -  71  2
             cveDB.close();
    -  72  2
             cveDB = null;
    -  73  2
         }
    +
         /**
    +  71   +
          * Closes the data source.
    +  72   +
          */
    +  73   +
         @Override
     74   -
     
    -  75   -
         /**
    -  76   -
          * Returns the status of the data source - is the database open.
    -  77   -
          *
    +
         public void closeAnalyzer() {
    +  75  2
             cveDB.close();
    +  76  2
             cveDB = null;
    +  77  2
         }
     78   -
          * @return true or false.
    +
     
     79   -
          */
    +
         /**
     80   -
         public boolean isOpen() {
    -  81  4
             return cveDB != null;
    +
          * Returns the status of the data source - is the database open.
    +  81   +
          *
     82   -
         }
    +
          * @return true or false.
     83   -
     
    +
          */
     84   -
         /**
    -  85   -
          * Ensures that the CVE Database is closed.
    +
         public boolean isOpen() {
    +  85  6
             return cveDB != null;
     86   -
          *
    +
         }
     87   -
          * @throws Throwable an exception raised by this method
    +
     
     88   -
          */
    +
         /**
     89   -
         @Override
    +
          * Ensures that the CVE Database is closed.
     90   -
         protected void finalize() throws Throwable {
    -  91  4
             super.finalize();
    -  92  4
             if (isOpen()) {
    -  93  0
                 close();
    +
          *
    +  91   +
          * @throws Throwable an exception raised by this method
    +  92   +
          */
    +  93   +
         @Override
     94   -
             }
    -  95  4
         }
    -  96   -
     
    -  97   -
         /**
    +
         protected void finalize() throws Throwable {
    +  95  6
             super.finalize();
    +  96  6
             if (isOpen()) {
    +  97  0
                 close();
     98   -
          * Analyzes a dependency and attempts to determine if there are any CPE identifiers for this dependency.
    -  99   -
          *
    +
             }
    +  99  6
         }
     100   -
          * @param dependency The Dependency to analyze
    +
     
     101   -
          * @param engine The analysis engine
    +
         /**
     102   -
          * @throws AnalysisException thrown if there is an issue analyzing the dependency
    +
          * Analyzes a dependency and attempts to determine if there are any CPE
     103   -
          */
    +
          * identifiers for this dependency.
     104   -
         @Override
    +
          *
     105   -
         public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    -  106  4
             for (Identifier id : dependency.getIdentifiers()) {
    -  107  4
                 if ("cpe".equals(id.getType())) {
    +
          * @param dependency The Dependency to analyze
    +  106   +
          * @param engine The analysis engine
    +  107   +
          * @throws AnalysisException thrown if there is an issue analyzing the
     108   +
          * dependency
    +  109   +
          */
    +  110   +
         @Override
    +  111   +
         protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  112  4
             for (Identifier id : dependency.getIdentifiers()) {
    +  113  4
                 if ("cpe".equals(id.getType())) {
    +  114  
                     try {
    -  109  4
                         final String value = id.getValue();
    -  110  4
                         final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
    -  111  4
                         dependency.getVulnerabilities().addAll(vulns);
    -  112  0
                     } catch (DatabaseException ex) {
    -  113  0
                         throw new AnalysisException(ex);
    -  114  4
                     }
    -  115   +  115  4
                         final String value = id.getValue();
    +  116  4
                         final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
    +  117  4
                         dependency.getVulnerabilities().addAll(vulns);
    +  118  0
                     } catch (DatabaseException ex) {
    +  119  0
                         throw new AnalysisException(ex);
    +  120  4
                     }
    +  121  
                 }
    -  116  4
             }
    -  117  3
             for (Identifier id : dependency.getSuppressedIdentifiers()) {
    -  118  0
                 if ("cpe".equals(id.getType())) {
    -  119   +  122  4
             }
    +  123  4
             for (Identifier id : dependency.getSuppressedIdentifiers()) {
    +  124  0
                 if ("cpe".equals(id.getType())) {
    +  125  
                     try {
    -  120  0
                         final String value = id.getValue();
    -  121  0
                         final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
    -  122  0
                         dependency.getSuppressedVulnerabilities().addAll(vulns);
    -  123  0
                     } catch (DatabaseException ex) {
    -  124  0
                         throw new AnalysisException(ex);
    -  125  0
                     }
    -  126   -
                 }
    -  127  0
             }
    -  128  4
         }
    -  129   -
     
    -  130   -
         /**
    -  131   -
          * Returns the name of this analyzer.
    +  126  0
                         final String value = id.getValue();
    +  127  0
                         final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
    +  128  0
                         dependency.getSuppressedVulnerabilities().addAll(vulns);
    +  129  0
                     } catch (DatabaseException ex) {
    +  130  0
                         throw new AnalysisException(ex);
    +  131  0
                     }
     132   -
          *
    -  133   -
          * @return the name of this analyzer.
    -  134   -
          */
    +
                 }
    +  133  0
             }
    +  134  4
         }
     135   -
         @Override
    +
     
     136   -
         public String getName() {
    -  137  26
             return "NVD CVE Analyzer";
    +
         /**
    +  137   +
          * Returns the name of this analyzer.
     138   -
         }
    +
          *
     139   -
     
    +
          * @return the name of this analyzer.
     140   -
         /**
    +
          */
     141   -
          * Returns the analysis phase that this analyzer should run in.
    +
         @Override
     142   -
          *
    -  143   -
          * @return the analysis phase that this analyzer should run in.
    +
         public String getName() {
    +  143  26
             return "NVD CVE Analyzer";
     144   -
          */
    -  145   -
         @Override
    -  146   -
         public AnalysisPhase getAnalysisPhase() {
    -  147  6
             return AnalysisPhase.FINDING_ANALYSIS;
    -  148  
         }
    -  149   +  145  
     
    -  150   +  146  
         /**
    -  151   -
          * Opens the database used to gather NVD CVE data.
    -  152   +  147   +
          * Returns the analysis phase that this analyzer should run in.
    +  148  
          *
    -  153   -
          * @throws InitializationException is thrown if there is an issue opening the index.
    -  154   +  149   +
          * @return the analysis phase that this analyzer should run in.
    +  150  
          */
    -  155   +  151  
         @Override
    +  152   +
         public AnalysisPhase getAnalysisPhase() {
    +  153  6
             return AnalysisPhase.FINDING_ANALYSIS;
    +  154   +
         }
    +  155   +
     
     156   -
         public void initialize() throws InitializationException {
    +
         /**
     157   -
             try {
    -  158  2
                 this.open();
    -  159  0
             } catch (SQLException ex) {
    -  160  0
                 LOGGER.debug("SQL Exception initializing NvdCveAnalyzer", ex);
    -  161  0
                 throw new InitializationException(ex);
    -  162  0
             } catch (IOException ex) {
    -  163  0
                 LOGGER.debug("IO Exception initializing NvdCveAnalyzer", ex);
    -  164  0
                 throw new InitializationException(ex);
    -  165  0
             } catch (DatabaseException ex) {
    -  166  0
                 LOGGER.debug("Database Exception initializing NvdCveAnalyzer", ex);
    -  167  0
                 throw new InitializationException(ex);
    -  168  0
             } catch (ClassNotFoundException ex) {
    -  169  0
                 LOGGER.debug("Exception initializing NvdCveAnalyzer", ex);
    -  170  0
                 throw new InitializationException(ex);
    -  171  2
             }
    -  172  2
         }
    +
          * <p>
    +  158   +
          * Returns the setting key to determine if the analyzer is enabled.</p>
    +  159   +
          *
    +  160   +
          * @return the key for the analyzer's enabled property
    +  161   +
          */
    +  162   +
         @Override
    +  163   +
         protected String getAnalyzerEnabledSettingKey() {
    +  164  2
             return Settings.KEYS.ANALYZER_NVD_CVE_ENABLED;
    +  165   +
         }
    +  166   +
     
    +  167   +
         /**
    +  168   +
          * Opens the database used to gather NVD CVE data.
    +  169   +
          *
    +  170   +
          * @throws InitializationException is thrown if there is an issue opening
    +  171   +
          * the index.
    +  172   +
          */
     173   +
         @Override
    +  174   +
         public void initializeAnalyzer() throws InitializationException {
    +  175   +
             try {
    +  176  2
                 this.open();
    +  177  0
             } catch (SQLException ex) {
    +  178  0
                 LOGGER.debug("SQL Exception initializing NvdCveAnalyzer", ex);
    +  179  0
                 throw new InitializationException(ex);
    +  180  0
             } catch (IOException ex) {
    +  181  0
                 LOGGER.debug("IO Exception initializing NvdCveAnalyzer", ex);
    +  182  0
                 throw new InitializationException(ex);
    +  183  0
             } catch (DatabaseException ex) {
    +  184  0
                 LOGGER.debug("Database Exception initializing NvdCveAnalyzer", ex);
    +  185  0
                 throw new InitializationException(ex);
    +  186  0
             } catch (ClassNotFoundException ex) {
    +  187  0
                 LOGGER.debug("Exception initializing NvdCveAnalyzer", ex);
    +  188  0
                 throw new InitializationException(ex);
    +  189  2
             }
    +  190  2
         }
    +  191  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer.html index d341f226c..b6445fca9 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer.html @@ -250,7 +250,7 @@
         @Override
     122  
         public String getName() {
    -  123  23
             return "OpenSSL Source Analyzer";
    +  123  19
             return "OpenSSL Source Analyzer";
     124  
         }
     125   @@ -288,7 +288,7 @@
         @Override
     142  
         protected FileFilter getFileFilter() {
    -  143  863
             return OPENSSLV_FILTER;
    +  143  859
             return OPENSSLV_FILTER;
     144  
         }
     145   @@ -331,7 +331,7 @@  164  
         @Override
     165   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     166  
                 throws AnalysisException {
     167  1
             final File file = dependency.getActualFile();
    @@ -405,13 +405,13 @@
         @Override
     211  
         protected String getAnalyzerEnabledSettingKey() {
    -  212  12
             return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
    +  212  6
             return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
     213  
         }
     214  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonDistributionAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonDistributionAnalyzer.html index 33210a790..554590524 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonDistributionAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonDistributionAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    PythonDistributionAnalyzer
    79%
    96/121
    55%
    32/58
    4
    PythonDistributionAnalyzer
    79%
    96/121
    53%
    31/58
    4
     
    @@ -299,7 +299,7 @@
         @Override
     148  
         protected FileFilter getFileFilter() {
    -  149  867
             return FILTER;
    +  149  863
             return FILTER;
     150  
         }
     151   @@ -318,7 +318,7 @@
         @Override
     158  
         public String getName() {
    -  159  21
             return ANALYZER_NAME;
    +  159  17
             return ANALYZER_NAME;
     160  
         }
     161   @@ -358,7 +358,7 @@
         @Override
     179  
         protected String getAnalyzerEnabledSettingKey() {
    -  180  16
             return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
    +  180  10
             return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
     181  
         }
     182   @@ -366,7 +366,7 @@  183  
         @Override
     184   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     185  
                 throws AnalysisException {
     186  6
             final File actualFile = dependency.getActualFile();
    @@ -503,8 +503,8 @@  275  
         @Override
     276   -
         public void close() {
    -  277  10
             if (tempFileLocation != null && tempFileLocation.exists()) {
    +
         public void closeAnalyzer() {
    +  277  8
             if (tempFileLocation != null && tempFileLocation.exists()) {
     278  8
                 LOGGER.debug("Attempting to delete temporary files");
     279  8
                 final boolean success = FileUtils.delete(tempFileLocation);
     280  8
                 if (!success && tempFileLocation.exists()) {
    @@ -517,7 +517,7 @@
                 }
     286  
             }
    -  287  10
         }
    +  287  8
         }
     288  
     
     289   @@ -712,6 +712,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonPackageAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonPackageAnalyzer.html index 6a88689c2..958bab598 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonPackageAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.PythonPackageAnalyzer.html @@ -235,7 +235,7 @@
         @Override
     114  
         public String getName() {
    -  115  21
             return "Python Package Analyzer";
    +  115  17
             return "Python Package Analyzer";
     116  
         }
     117   @@ -282,7 +282,7 @@
         @Override
     139  
         protected FileFilter getFileFilter() {
    -  140  863
             return FILTER;
    +  140  859
             return FILTER;
     141  
         }
     142   @@ -347,7 +347,7 @@  173  
         @Override
     174   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     175  
                 throws AnalysisException {
     176  1
             final File file = dependency.getActualFile();
    @@ -579,13 +579,13 @@
         @Override
     315  
         protected String getAnalyzerEnabledSettingKey() {
    -  316  11
             return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
    +  316  5
             return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
     317  
         }
     318  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.html index 68c4c05a0..7627c91b8 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    RubyBundleAuditAnalyzer
    14%
    32/221
    2%
    2/80
    6.231
    RubyBundleAuditAnalyzer
    16%
    38/227
    4%
    4/86
    6.462
     
    @@ -213,7 +213,7 @@
         @Override
     100  
         protected FileFilter getFileFilter() {
    -  101  861
             return FILTER;
    +  101  859
             return FILTER;
     102  
         }
     103   @@ -242,572 +242,582 @@
             }
     116  4
             final List<String> args = new ArrayList<String>();
     117  4
             final String bundleAuditPath = Settings.getString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH);
    -  118  4
             args.add(null == bundleAuditPath ? "bundle-audit" : bundleAuditPath);
    -  119  4
             args.add("check");
    -  120  4
             args.add("--verbose");
    -  121  4
             final ProcessBuilder builder = new ProcessBuilder(args);
    -  122  4
             builder.directory(folder);
    -  123   -
             try {
    -  124  4
                 LOGGER.info("Launching: " + args + " from " + folder);
    -  125  4
                 return builder.start();
    -  126  4
             } catch (IOException ioe) {
    -  127  4
                 throw new AnalysisException("bundle-audit failure", ioe);
    -  128   +  118  4
             File bundleAudit = null;
    +  119  4
             if (bundleAuditPath != null) {
    +  120  4
                 bundleAudit = new File(bundleAuditPath);
    +  121  4
                 if (!bundleAudit.isFile()) {
    +  122  4
                     LOGGER.warn("Supplied `bundleAudit` path is incorrect: " + bundleAuditPath);
    +  123  4
                     bundleAudit = null;
    +  124   +
                 }
    +  125  
             }
    -  129   -
         }
    -  130   -
     
    +  126  4
             args.add(bundleAudit != null && bundleAudit.isFile() ? bundleAudit.getAbsolutePath() : "bundle-audit");
    +  127  4
             args.add("check");
    +  128  4
             args.add("--verbose");
    +  129  4
             final ProcessBuilder builder = new ProcessBuilder(args);
    +  130  4
             builder.directory(folder);
     131   -
         /**
    -  132   -
          * Initialize the analyzer. In this case, extract GrokAssembly.exe to a
    -  133   -
          * temporary location.
    -  134   -
          *
    -  135   -
          * @throws InitializationException if anything goes wrong
    +
             try {
    +  132  4
                 LOGGER.info("Launching: " + args + " from " + folder);
    +  133  4
                 return builder.start();
    +  134  4
             } catch (IOException ioe) {
    +  135  4
                 throw new AnalysisException("bundle-audit failure", ioe);
     136   -
          */
    +
             }
     137   -
         @Override
    +
         }
     138   -
         public void initializeFileTypeAnalyzer() throws InitializationException {
    +
     
     139   +
         /**
    +  140   +
          * Initialize the analyzer. In this case, extract GrokAssembly.exe to a
    +  141   +
          * temporary location.
    +  142   +
          *
    +  143   +
          * @throws InitializationException if anything goes wrong
    +  144   +
          */
    +  145   +
         @Override
    +  146   +
         public void initializeFileTypeAnalyzer() throws InitializationException {
    +  147  
             try {
    -  140  4
                 cvedb = new CveDB();
    -  141  4
                 cvedb.open();
    -  142  0
             } catch (DatabaseException ex) {
    -  143  0
                 LOGGER.warn("Exception opening the database");
    -  144  0
                 LOGGER.debug("error", ex);
    -  145  0
                 setEnabled(false);
    -  146  0
                 throw new InitializationException("Error connecting to the database", ex);
    -  147  4
             }
    -  148   +  148  4
                 cvedb = new CveDB();
    +  149  4
                 cvedb.open();
    +  150  0
             } catch (DatabaseException ex) {
    +  151  0
                 LOGGER.warn("Exception opening the database");
    +  152  0
                 LOGGER.debug("error", ex);
    +  153  0
                 setEnabled(false);
    +  154  0
                 throw new InitializationException("Error connecting to the database", ex);
    +  155  4
             }
    +  156  
             // Now, need to see if bundle-audit actually runs from this location.
    -  149  4
             Process process = null;
    -  150   +  157  4
             Process process = null;
    +  158  
             try {
    -  151  4
                 process = launchBundleAudit(Settings.getTempDirectory());
    -  152  4
             } catch (AnalysisException ae) {
    -  153   +  159  4
                 process = launchBundleAudit(Settings.getTempDirectory());
    +  160  4
             } catch (AnalysisException ae) {
    +  161  
     
    -  154  4
                 setEnabled(false);
    -  155  4
                 cvedb.close();
    -  156  4
                 cvedb = null;
    -  157  4
                 final String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
    -  158  4
                 throw new InitializationException(msg, ae);
    -  159  0
             } catch (IOException ex) {
    -  160  0
                 setEnabled(false);
    -  161  0
                 throw new InitializationException("Unable to create temporary file, the Ruby Bundle Audit Analyzer will be disabled", ex);
    -  162  0
             }
    -  163   -
     
    -  164   -
             final int exitValue;
    -  165   -
             try {
    -  166  0
                 exitValue = process.waitFor();
    -  167  0
             } catch (InterruptedException ex) {
    +  162  4
                 setEnabled(false);
    +  163  4
                 cvedb.close();
    +  164  4
                 cvedb = null;
    +  165  4
                 final String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
    +  166  4
                 throw new InitializationException(msg, ae);
    +  167  0
             } catch (IOException ex) {
     168  0
                 setEnabled(false);
    -  169  0
                 final String msg = String.format("Bundle-audit process was interupted. Disabling %s", ANALYZER_NAME);
    -  170  0
                 throw new InitializationException(msg);
    -  171  0
             }
    -  172  0
             if (0 == exitValue) {
    -  173  0
                 setEnabled(false);
    -  174  0
                 final String msg = String.format("Unexpected exit code from bundle-audit process. Disabling %s: %s", ANALYZER_NAME, exitValue);
    -  175  0
                 throw new InitializationException(msg);
    -  176   -
             } else {
    -  177  0
                 BufferedReader reader = null;
    -  178   -
                 try {
    -  179  0
                     reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
    -  180  0
                     if (!reader.ready()) {
    -  181  0
                         LOGGER.warn("Bundle-audit error stream unexpectedly not ready. Disabling " + ANALYZER_NAME);
    -  182  0
                         setEnabled(false);
    -  183  0
                         throw new InitializationException("Bundle-audit error stream unexpectedly not ready.");
    -  184   -
                     } else {
    -  185  0
                         final String line = reader.readLine();
    -  186  0
                         if (line == null || !line.contains("Errno::ENOENT")) {
    -  187  0
                             LOGGER.warn("Unexpected bundle-audit output. Disabling {}: {}", ANALYZER_NAME, line);
    -  188  0
                             setEnabled(false);
    -  189  0
                             throw new InitializationException("Unexpected bundle-audit output.");
    -  190   -
                         }
    -  191   -
                     }
    -  192  0
                 } catch (UnsupportedEncodingException ex) {
    -  193  0
                     setEnabled(false);
    -  194  0
                     throw new InitializationException("Unexpected bundle-audit encoding.", ex);
    -  195  0
                 } catch (IOException ex) {
    -  196  0
                     setEnabled(false);
    -  197  0
                     throw new InitializationException("Unable to read bundle-audit output.", ex);
    -  198   -
                 } finally {
    -  199  0
                     if (null != reader) {
    -  200   -
                         try {
    -  201  0
                             reader.close();
    -  202  0
                         } catch (IOException ex) {
    -  203  0
                             LOGGER.debug("Error closing reader", ex);
    -  204  0
                         }
    -  205   -
                     }
    -  206   -
                 }
    -  207   -
             }
    -  208   +  169  0
                 throw new InitializationException("Unable to create temporary file, the Ruby Bundle Audit Analyzer will be disabled", ex);
    +  170  0
             }
    +  171  
     
    -  209  0
             if (isEnabled()) {
    -  210  0
                 LOGGER.info(ANALYZER_NAME + " is enabled. It is necessary to manually run \"bundle-audit update\" "
    -  211   -
                         + "occasionally to keep its database up to date.");
    -  212   -
             }
    -  213  0
         }
    -  214   -
     
    -  215   -
         /**
    -  216   -
          * Returns the name of the analyzer.
    -  217   -
          *
    -  218   -
          * @return the name of the analyzer.
    -  219   -
          */
    -  220   -
         @Override
    -  221   -
         public String getName() {
    -  222  19
             return ANALYZER_NAME;
    -  223   -
         }
    -  224   -
     
    -  225   -
         /**
    -  226   -
          * Returns the phase that the analyzer is intended to run in.
    -  227   -
          *
    -  228   -
          * @return the phase that the analyzer is intended to run in.
    -  229   -
          */
    -  230   -
         @Override
    -  231   -
         public AnalysisPhase getAnalysisPhase() {
    -  232  6
             return ANALYSIS_PHASE;
    -  233   -
         }
    -  234   -
     
    -  235   -
         /**
    -  236   -
          * Returns the key used in the properties file to reference the analyzer's
    -  237   -
          * enabled property.
    -  238   -
          *
    -  239   -
          * @return the analyzer's enabled property setting key
    -  240   -
          */
    -  241   -
         @Override
    -  242   -
         protected String getAnalyzerEnabledSettingKey() {
    -  243  14
             return Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED;
    -  244   -
         }
    -  245   -
     
    -  246   -
         /**
    -  247   -
          * If {@link #analyzeFileType(Dependency, Engine)} is called, then we have
    -  248   -
          * successfully initialized, and it will be necessary to disable
    -  249   -
          * {@link RubyGemspecAnalyzer}.
    -  250   -
          */
    -  251  14
         private boolean needToDisableGemspecAnalyzer = true;
    -  252   -
     
    -  253   -
         /**
    -  254   -
          * Determines if the analyzer can analyze the given file type.
    -  255   -
          *
    -  256   -
          * @param dependency the dependency to determine if it can analyze
    -  257   -
          * @param engine the dependency-check engine
    -  258   -
          * @throws AnalysisException thrown if there is an analysis exception.
    -  259   -
          */
    -  260   -
         @Override
    -  261   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    -  262   -
                 throws AnalysisException {
    -  263  0
             if (needToDisableGemspecAnalyzer) {
    -  264  0
                 boolean failed = true;
    -  265  0
                 final String className = RubyGemspecAnalyzer.class.getName();
    -  266  0
                 for (FileTypeAnalyzer analyzer : engine.getFileTypeAnalyzers()) {
    -  267  0
                     if (analyzer instanceof RubyBundlerAnalyzer) {
    -  268  0
                         ((RubyBundlerAnalyzer) analyzer).setEnabled(false);
    -  269  0
                         LOGGER.info("Disabled " + RubyBundlerAnalyzer.class.getName() + " to avoid noisy duplicate results.");
    -  270  0
                     } else if (analyzer instanceof RubyGemspecAnalyzer) {
    -  271  0
                         ((RubyGemspecAnalyzer) analyzer).setEnabled(false);
    -  272  0
                         LOGGER.info("Disabled " + className + " to avoid noisy duplicate results.");
    -  273  0
                         failed = false;
    -  274   -
                     }
    -  275  0
                 }
    -  276  0
                 if (failed) {
    -  277  0
                     LOGGER.warn("Did not find " + className + '.');
    -  278   -
                 }
    -  279  0
                 needToDisableGemspecAnalyzer = false;
    -  280   -
             }
    -  281  0
             final File parentFile = dependency.getActualFile().getParentFile();
    -  282  0
             final Process process = launchBundleAudit(parentFile);
    -  283   +  172  
             final int exitValue;
    -  284   +  173  
             try {
    -  285  0
                 exitValue = process.waitFor();
    -  286  0
             } catch (InterruptedException ie) {
    -  287  0
                 throw new AnalysisException("bundle-audit process interrupted", ie);
    -  288  0
             }
    -  289  0
             if (exitValue < 0 || exitValue > 1) {
    -  290  0
                 final String msg = String.format("Unexpected exit code from bundle-audit process; exit code: %s", exitValue);
    -  291  0
                 throw new AnalysisException(msg);
    -  292   -
             }
    -  293  0
             BufferedReader rdr = null;
    -  294  0
             BufferedReader errReader = null;
    -  295   -
             try {
    -  296  0
                 errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
    -  297  0
                 while (errReader.ready()) {
    -  298  0
                     final String error = errReader.readLine();
    -  299  0
                     LOGGER.warn(error);
    -  300  0
                 }
    -  301  0
                 rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
    -  302  0
                 processBundlerAuditOutput(dependency, engine, rdr);
    -  303  0
             } catch (IOException ioe) {
    -  304  0
                 LOGGER.warn("bundle-audit failure", ioe);
    -  305   -
             } finally {
    -  306  0
                 if (errReader != null) {
    -  307   -
                     try {
    -  308  0
                         errReader.close();
    -  309  0
                     } catch (IOException ioe) {
    -  310  0
                         LOGGER.warn("bundle-audit close failure", ioe);
    -  311  0
                     }
    -  312   -
                 }
    -  313  0
                 if (null != rdr) {
    -  314   -
                     try {
    -  315  0
                         rdr.close();
    -  316  0
                     } catch (IOException ioe) {
    -  317  0
                         LOGGER.warn("bundle-audit close failure", ioe);
    -  318  0
                     }
    -  319   -
                 }
    -  320   -
             }
    -  321   -
     
    -  322  0
         }
    -  323   -
     
    -  324   -
         /**
    -  325   -
          * Processes the bundler audit output.
    -  326   -
          *
    -  327   -
          * @param original the dependency
    -  328   -
          * @param engine the dependency-check engine
    -  329   -
          * @param rdr the reader of the report
    -  330   -
          * @throws IOException thrown if the report cannot be read.
    -  331   -
          */
    -  332   -
         private void processBundlerAuditOutput(Dependency original, Engine engine, BufferedReader rdr) throws IOException {
    -  333  0
             final String parentName = original.getActualFile().getParentFile().getName();
    -  334  0
             final String fileName = original.getFileName();
    -  335  0
             final String filePath = original.getFilePath();
    -  336  0
             Dependency dependency = null;
    -  337  0
             Vulnerability vulnerability = null;
    -  338  0
             String gem = null;
    -  339  0
             final Map<String, Dependency> map = new HashMap<String, Dependency>();
    -  340  0
             boolean appendToDescription = false;
    -  341  0
             while (rdr.ready()) {
    -  342  0
                 final String nextLine = rdr.readLine();
    -  343  0
                 if (null == nextLine) {
    -  344  0
                     break;
    -  345  0
                 } else if (nextLine.startsWith(NAME)) {
    -  346  0
                     appendToDescription = false;
    -  347  0
                     gem = nextLine.substring(NAME.length());
    -  348  0
                     if (!map.containsKey(gem)) {
    -  349  0
                         map.put(gem, createDependencyForGem(engine, parentName, fileName, filePath, gem));
    -  350   -
                     }
    -  351  0
                     dependency = map.get(gem);
    -  352  0
                     LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    -  353  0
                 } else if (nextLine.startsWith(VERSION)) {
    -  354  0
                     vulnerability = createVulnerability(parentName, dependency, gem, nextLine);
    -  355  0
                 } else if (nextLine.startsWith(ADVISORY)) {
    -  356  0
                     setVulnerabilityName(parentName, dependency, vulnerability, nextLine);
    -  357  0
                 } else if (nextLine.startsWith(CRITICALITY)) {
    -  358  0
                     addCriticalityToVulnerability(parentName, vulnerability, nextLine);
    -  359  0
                 } else if (nextLine.startsWith("URL: ")) {
    -  360  0
                     addReferenceToVulnerability(parentName, vulnerability, nextLine);
    -  361  0
                 } else if (nextLine.startsWith("Description:")) {
    -  362  0
                     appendToDescription = true;
    -  363  0
                     if (null != vulnerability) {
    -  364  0
                         vulnerability.setDescription("*** Vulnerability obtained from bundle-audit verbose report. "
    -  365   -
                                 + "Title link may not work. CPE below is guessed. CVSS score is estimated (-1.0 "
    -  366   -
                                 + " indicates unknown). See link below for full details. *** ");
    -  367   -
                     }
    -  368  0
                 } else if (appendToDescription) {
    -  369  0
                     if (null != vulnerability) {
    -  370  0
                         vulnerability.setDescription(vulnerability.getDescription() + nextLine + "\n");
    -  371   -
                     }
    -  372   -
                 }
    -  373  0
             }
    -  374  0
         }
    -  375   -
     
    -  376   -
         /**
    -  377   -
          * Sets the vulnerability name.
    -  378   -
          *
    -  379   -
          * @param parentName the parent name
    -  380   -
          * @param dependency the dependency
    -  381   -
          * @param vulnerability the vulnerability
    -  382   -
          * @param nextLine the line to parse
    -  383   -
          */
    -  384   -
         private void setVulnerabilityName(String parentName, Dependency dependency, Vulnerability vulnerability, String nextLine) {
    -  385  0
             final String advisory = nextLine.substring((ADVISORY.length()));
    -  386  0
             if (null != vulnerability) {
    -  387  0
                 vulnerability.setName(advisory);
    -  388   -
             }
    -  389  0
             if (null != dependency) {
    -  390  0
                 dependency.getVulnerabilities().add(vulnerability); // needed to wait for vulnerability name to avoid NPE
    -  391   -
             }
    -  392  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    -  393  0
         }
    -  394   -
     
    -  395   -
         /**
    -  396   -
          * Adds a reference to the vulnerability.
    -  397   -
          *
    -  398   -
          * @param parentName the parent name
    -  399   -
          * @param vulnerability the vulnerability
    -  400   -
          * @param nextLine the line to parse
    -  401   -
          */
    -  402   -
         private void addReferenceToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
    -  403  0
             final String url = nextLine.substring(("URL: ").length());
    -  404  0
             if (null != vulnerability) {
    -  405  0
                 final Reference ref = new Reference();
    -  406  0
                 ref.setName(vulnerability.getName());
    -  407  0
                 ref.setSource("bundle-audit");
    -  408  0
                 ref.setUrl(url);
    -  409  0
                 vulnerability.getReferences().add(ref);
    -  410   -
             }
    -  411  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    -  412  0
         }
    -  413   -
     
    -  414   -
         /**
    -  415   -
          * Adds the criticality to the vulnerability
    -  416   -
          *
    -  417   -
          * @param parentName the parent name
    -  418   -
          * @param vulnerability the vulnerability
    -  419   -
          * @param nextLine the line to parse
    -  420   -
          */
    -  421   -
         private void addCriticalityToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
    -  422  0
             if (null != vulnerability) {
    -  423  0
                 final String criticality = nextLine.substring(CRITICALITY.length()).trim();
    -  424  0
                 float score = -1.0f;
    -  425  0
                 Vulnerability v = null;
    -  426   +  174  0
                 exitValue = process.waitFor();
    +  175  0
             } catch (InterruptedException ex) {
    +  176  0
                 setEnabled(false);
    +  177  0
                 final String msg = String.format("Bundle-audit process was interupted. Disabling %s", ANALYZER_NAME);
    +  178  0
                 throw new InitializationException(msg);
    +  179  0
             }
    +  180  0
             if (0 == exitValue) {
    +  181  0
                 setEnabled(false);
    +  182  0
                 final String msg = String.format("Unexpected exit code from bundle-audit process. Disabling %s: %s", ANALYZER_NAME, exitValue);
    +  183  0
                 throw new InitializationException(msg);
    +  184   +
             } else {
    +  185  0
                 BufferedReader reader = null;
    +  186  
                 try {
    -  427  0
                     v = cvedb.getVulnerability(vulnerability.getName());
    -  428  0
                 } catch (DatabaseException ex) {
    -  429  0
                     LOGGER.debug("Unable to look up vulnerability {}", vulnerability.getName());
    -  430  0
                 }
    -  431  0
                 if (v != null) {
    -  432  0
                     score = v.getCvssScore();
    -  433  0
                 } else if ("High".equalsIgnoreCase(criticality)) {
    -  434  0
                     score = 8.5f;
    -  435  0
                 } else if ("Medium".equalsIgnoreCase(criticality)) {
    -  436  0
                     score = 5.5f;
    -  437  0
                 } else if ("Low".equalsIgnoreCase(criticality)) {
    -  438  0
                     score = 2.0f;
    -  439   +  187  0
                     reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
    +  188  0
                     if (!reader.ready()) {
    +  189  0
                         LOGGER.warn("Bundle-audit error stream unexpectedly not ready. Disabling " + ANALYZER_NAME);
    +  190  0
                         setEnabled(false);
    +  191  0
                         throw new InitializationException("Bundle-audit error stream unexpectedly not ready.");
    +  192   +
                     } else {
    +  193  0
                         final String line = reader.readLine();
    +  194  0
                         if (line == null || !line.contains("Errno::ENOENT")) {
    +  195  0
                             LOGGER.warn("Unexpected bundle-audit output. Disabling {}: {}", ANALYZER_NAME, line);
    +  196  0
                             setEnabled(false);
    +  197  0
                             throw new InitializationException("Unexpected bundle-audit output.");
    +  198   +
                         }
    +  199   +
                     }
    +  200  0
                 } catch (UnsupportedEncodingException ex) {
    +  201  0
                     setEnabled(false);
    +  202  0
                     throw new InitializationException("Unexpected bundle-audit encoding.", ex);
    +  203  0
                 } catch (IOException ex) {
    +  204  0
                     setEnabled(false);
    +  205  0
                     throw new InitializationException("Unable to read bundle-audit output.", ex);
    +  206   +
                 } finally {
    +  207  0
                     if (null != reader) {
    +  208   +
                         try {
    +  209  0
                             reader.close();
    +  210  0
                         } catch (IOException ex) {
    +  211  0
                             LOGGER.debug("Error closing reader", ex);
    +  212  0
                         }
    +  213   +
                     }
    +  214  
                 }
    -  440  0
                 vulnerability.setCvssScore(score);
    -  441   +  215  
             }
    -  442  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    -  443  0
         }
    -  444   +  216  
     
    -  445   +  217  0
             if (isEnabled()) {
    +  218  0
                 LOGGER.info(ANALYZER_NAME + " is enabled. It is necessary to manually run \"bundle-audit update\" "
    +  219   +
                         + "occasionally to keep its database up to date.");
    +  220   +
             }
    +  221  0
         }
    +  222   +
     
    +  223  
         /**
    -  446   -
          * Creates a vulnerability.
    -  447   +  224   +
          * Returns the name of the analyzer.
    +  225  
          *
    -  448   +  226   +
          * @return the name of the analyzer.
    +  227   +
          */
    +  228   +
         @Override
    +  229   +
         public String getName() {
    +  230  17
             return ANALYZER_NAME;
    +  231   +
         }
    +  232   +
     
    +  233   +
         /**
    +  234   +
          * Returns the phase that the analyzer is intended to run in.
    +  235   +
          *
    +  236   +
          * @return the phase that the analyzer is intended to run in.
    +  237   +
          */
    +  238   +
         @Override
    +  239   +
         public AnalysisPhase getAnalysisPhase() {
    +  240  6
             return ANALYSIS_PHASE;
    +  241   +
         }
    +  242   +
     
    +  243   +
         /**
    +  244   +
          * Returns the key used in the properties file to reference the analyzer's
    +  245   +
          * enabled property.
    +  246   +
          *
    +  247   +
          * @return the analyzer's enabled property setting key
    +  248   +
          */
    +  249   +
         @Override
    +  250   +
         protected String getAnalyzerEnabledSettingKey() {
    +  251  5
             return Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED;
    +  252   +
         }
    +  253   +
     
    +  254   +
         /**
    +  255   +
          * If {@link #analyzeDependency(Dependency, Engine)} is called, then we have
    +  256   +
          * successfully initialized, and it will be necessary to disable
    +  257   +
          * {@link RubyGemspecAnalyzer}.
    +  258   +
          */
    +  259  14
         private boolean needToDisableGemspecAnalyzer = true;
    +  260   +
     
    +  261   +
         /**
    +  262   +
          * Determines if the analyzer can analyze the given file type.
    +  263   +
          *
    +  264   +
          * @param dependency the dependency to determine if it can analyze
    +  265   +
          * @param engine the dependency-check engine
    +  266   +
          * @throws AnalysisException thrown if there is an analysis exception.
    +  267   +
          */
    +  268   +
         @Override
    +  269   +
         protected void analyzeDependency(Dependency dependency, Engine engine)
    +  270   +
                 throws AnalysisException {
    +  271  0
             if (needToDisableGemspecAnalyzer) {
    +  272  0
                 boolean failed = true;
    +  273  0
                 final String className = RubyGemspecAnalyzer.class.getName();
    +  274  0
                 for (FileTypeAnalyzer analyzer : engine.getFileTypeAnalyzers()) {
    +  275  0
                     if (analyzer instanceof RubyBundlerAnalyzer) {
    +  276  0
                         ((RubyBundlerAnalyzer) analyzer).setEnabled(false);
    +  277  0
                         LOGGER.info("Disabled " + RubyBundlerAnalyzer.class.getName() + " to avoid noisy duplicate results.");
    +  278  0
                     } else if (analyzer instanceof RubyGemspecAnalyzer) {
    +  279  0
                         ((RubyGemspecAnalyzer) analyzer).setEnabled(false);
    +  280  0
                         LOGGER.info("Disabled " + className + " to avoid noisy duplicate results.");
    +  281  0
                         failed = false;
    +  282   +
                     }
    +  283  0
                 }
    +  284  0
                 if (failed) {
    +  285  0
                     LOGGER.warn("Did not find " + className + '.');
    +  286   +
                 }
    +  287  0
                 needToDisableGemspecAnalyzer = false;
    +  288   +
             }
    +  289  0
             final File parentFile = dependency.getActualFile().getParentFile();
    +  290  0
             final Process process = launchBundleAudit(parentFile);
    +  291   +
             final int exitValue;
    +  292   +
             try {
    +  293  0
                 exitValue = process.waitFor();
    +  294  0
             } catch (InterruptedException ie) {
    +  295  0
                 throw new AnalysisException("bundle-audit process interrupted", ie);
    +  296  0
             }
    +  297  0
             if (exitValue < 0 || exitValue > 1) {
    +  298  0
                 final String msg = String.format("Unexpected exit code from bundle-audit process; exit code: %s", exitValue);
    +  299  0
                 throw new AnalysisException(msg);
    +  300   +
             }
    +  301  0
             BufferedReader rdr = null;
    +  302  0
             BufferedReader errReader = null;
    +  303   +
             try {
    +  304  0
                 errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
    +  305  0
                 while (errReader.ready()) {
    +  306  0
                     final String error = errReader.readLine();
    +  307  0
                     LOGGER.warn(error);
    +  308  0
                 }
    +  309  0
                 rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
    +  310  0
                 processBundlerAuditOutput(dependency, engine, rdr);
    +  311  0
             } catch (IOException ioe) {
    +  312  0
                 LOGGER.warn("bundle-audit failure", ioe);
    +  313   +
             } finally {
    +  314  0
                 if (errReader != null) {
    +  315   +
                     try {
    +  316  0
                         errReader.close();
    +  317  0
                     } catch (IOException ioe) {
    +  318  0
                         LOGGER.warn("bundle-audit close failure", ioe);
    +  319  0
                     }
    +  320   +
                 }
    +  321  0
                 if (null != rdr) {
    +  322   +
                     try {
    +  323  0
                         rdr.close();
    +  324  0
                     } catch (IOException ioe) {
    +  325  0
                         LOGGER.warn("bundle-audit close failure", ioe);
    +  326  0
                     }
    +  327   +
                 }
    +  328   +
             }
    +  329   +
     
    +  330  0
         }
    +  331   +
     
    +  332   +
         /**
    +  333   +
          * Processes the bundler audit output.
    +  334   +
          *
    +  335   +
          * @param original the dependency
    +  336   +
          * @param engine the dependency-check engine
    +  337   +
          * @param rdr the reader of the report
    +  338   +
          * @throws IOException thrown if the report cannot be read.
    +  339   +
          */
    +  340   +
         private void processBundlerAuditOutput(Dependency original, Engine engine, BufferedReader rdr) throws IOException {
    +  341  0
             final String parentName = original.getActualFile().getParentFile().getName();
    +  342  0
             final String fileName = original.getFileName();
    +  343  0
             final String filePath = original.getFilePath();
    +  344  0
             Dependency dependency = null;
    +  345  0
             Vulnerability vulnerability = null;
    +  346  0
             String gem = null;
    +  347  0
             final Map<String, Dependency> map = new HashMap<String, Dependency>();
    +  348  0
             boolean appendToDescription = false;
    +  349  0
             while (rdr.ready()) {
    +  350  0
                 final String nextLine = rdr.readLine();
    +  351  0
                 if (null == nextLine) {
    +  352  0
                     break;
    +  353  0
                 } else if (nextLine.startsWith(NAME)) {
    +  354  0
                     appendToDescription = false;
    +  355  0
                     gem = nextLine.substring(NAME.length());
    +  356  0
                     if (!map.containsKey(gem)) {
    +  357  0
                         map.put(gem, createDependencyForGem(engine, parentName, fileName, filePath, gem));
    +  358   +
                     }
    +  359  0
                     dependency = map.get(gem);
    +  360  0
                     LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    +  361  0
                 } else if (nextLine.startsWith(VERSION)) {
    +  362  0
                     vulnerability = createVulnerability(parentName, dependency, gem, nextLine);
    +  363  0
                 } else if (nextLine.startsWith(ADVISORY)) {
    +  364  0
                     setVulnerabilityName(parentName, dependency, vulnerability, nextLine);
    +  365  0
                 } else if (nextLine.startsWith(CRITICALITY)) {
    +  366  0
                     addCriticalityToVulnerability(parentName, vulnerability, nextLine);
    +  367  0
                 } else if (nextLine.startsWith("URL: ")) {
    +  368  0
                     addReferenceToVulnerability(parentName, vulnerability, nextLine);
    +  369  0
                 } else if (nextLine.startsWith("Description:")) {
    +  370  0
                     appendToDescription = true;
    +  371  0
                     if (null != vulnerability) {
    +  372  0
                         vulnerability.setDescription("*** Vulnerability obtained from bundle-audit verbose report. "
    +  373   +
                                 + "Title link may not work. CPE below is guessed. CVSS score is estimated (-1.0 "
    +  374   +
                                 + " indicates unknown). See link below for full details. *** ");
    +  375   +
                     }
    +  376  0
                 } else if (appendToDescription) {
    +  377  0
                     if (null != vulnerability) {
    +  378  0
                         vulnerability.setDescription(vulnerability.getDescription() + nextLine + "\n");
    +  379   +
                     }
    +  380   +
                 }
    +  381  0
             }
    +  382  0
         }
    +  383   +
     
    +  384   +
         /**
    +  385   +
          * Sets the vulnerability name.
    +  386   +
          *
    +  387  
          * @param parentName the parent name
    -  449   +  388  
          * @param dependency the dependency
    -  450   -
          * @param gem the gem name
    -  451   +  389   +
          * @param vulnerability the vulnerability
    +  390  
          * @param nextLine the line to parse
    -  452   -
          * @return the vulnerability
    -  453   +  391  
          */
    -  454   -
         private Vulnerability createVulnerability(String parentName, Dependency dependency, String gem, String nextLine) {
    -  455  0
             Vulnerability vulnerability = null;
    -  456  0
             if (null != dependency) {
    -  457  0
                 final String version = nextLine.substring(VERSION.length());
    -  458  0
                 dependency.getVersionEvidence().addEvidence(
    -  459   -
                         "bundler-audit",
    -  460   -
                         "Version",
    -  461   -
                         version,
    -  462   -
                         Confidence.HIGHEST);
    -  463  0
                 vulnerability = new Vulnerability(); // don't add to dependency until we have name set later
    -  464  0
                 vulnerability.setMatchedCPE(
    -  465  0
                         String.format("cpe:/a:%1$s_project:%1$s:%2$s::~~~ruby~~", gem, version),
    -  466   -
                         null);
    -  467  0
                 vulnerability.setCvssAccessVector("-");
    -  468  0
                 vulnerability.setCvssAccessComplexity("-");
    -  469  0
                 vulnerability.setCvssAuthentication("-");
    -  470  0
                 vulnerability.setCvssAvailabilityImpact("-");
    -  471  0
                 vulnerability.setCvssConfidentialityImpact("-");
    -  472  0
                 vulnerability.setCvssIntegrityImpact("-");
    -  473   +  392   +
         private void setVulnerabilityName(String parentName, Dependency dependency, Vulnerability vulnerability, String nextLine) {
    +  393  0
             final String advisory = nextLine.substring((ADVISORY.length()));
    +  394  0
             if (null != vulnerability) {
    +  395  0
                 vulnerability.setName(advisory);
    +  396  
             }
    -  474  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    -  475  0
             return vulnerability;
    -  476   -
         }
    -  477   +  397  0
             if (null != dependency) {
    +  398  0
                 dependency.getVulnerabilities().add(vulnerability); // needed to wait for vulnerability name to avoid NPE
    +  399   +
             }
    +  400  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    +  401  0
         }
    +  402  
     
    -  478   +  403  
         /**
    -  479   -
          * Creates the dependency based off of the gem.
    -  480   +  404   +
          * Adds a reference to the vulnerability.
    +  405  
          *
    -  481   -
          * @param engine the engine used for scanning
    -  482   -
          * @param parentName the gem parent
    -  483   -
          * @param fileName the file name
    -  484   -
          * @param filePath the file path
    -  485   -
          * @param gem the gem name
    -  486   -
          * @return the dependency to add
    -  487   -
          * @throws IOException thrown if a temporary gem file could not be written
    -  488   +  406   +
          * @param parentName the parent name
    +  407   +
          * @param vulnerability the vulnerability
    +  408   +
          * @param nextLine the line to parse
    +  409  
          */
    -  489   -
         private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String filePath, String gem) throws IOException {
    -  490  0
             final File gemFile = new File(Settings.getTempDirectory(), gem + "_Gemfile.lock");
    -  491  0
             if (!gemFile.createNewFile()) {
    -  492  0
                 throw new IOException("Unable to create temporary gem file");
    -  493   +  410   +
         private void addReferenceToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
    +  411  0
             final String url = nextLine.substring(("URL: ").length());
    +  412  0
             if (null != vulnerability) {
    +  413  0
                 final Reference ref = new Reference();
    +  414  0
                 ref.setName(vulnerability.getName());
    +  415  0
                 ref.setSource("bundle-audit");
    +  416  0
                 ref.setUrl(url);
    +  417  0
                 vulnerability.getReferences().add(ref);
    +  418  
             }
    -  494  0
             final String displayFileName = String.format("%s%c%s:%s", parentName, File.separatorChar, fileName, gem);
    -  495   +  419  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    +  420  0
         }
    +  421  
     
    -  496  0
             FileUtils.write(gemFile, displayFileName, Charset.defaultCharset()); // unique contents to avoid dependency bundling
    -  497  0
             final Dependency dependency = new Dependency(gemFile);
    -  498  0
             dependency.getProductEvidence().addEvidence("bundler-audit", "Name", gem, Confidence.HIGHEST);
    -  499  0
             dependency.setDisplayFileName(displayFileName);
    -  500  0
             dependency.setFileName(fileName);
    -  501  0
             dependency.setFilePath(filePath);
    -  502  0
             engine.getDependencies().add(dependency);
    -  503  0
             return dependency;
    -  504   +  422   +
         /**
    +  423   +
          * Adds the criticality to the vulnerability
    +  424   +
          *
    +  425   +
          * @param parentName the parent name
    +  426   +
          * @param vulnerability the vulnerability
    +  427   +
          * @param nextLine the line to parse
    +  428   +
          */
    +  429   +
         private void addCriticalityToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
    +  430  0
             if (null != vulnerability) {
    +  431  0
                 final String criticality = nextLine.substring(CRITICALITY.length()).trim();
    +  432  0
                 float score = -1.0f;
    +  433  0
                 Vulnerability v = null;
    +  434   +
                 try {
    +  435  0
                     v = cvedb.getVulnerability(vulnerability.getName());
    +  436  0
                 } catch (DatabaseException ex) {
    +  437  0
                     LOGGER.debug("Unable to look up vulnerability {}", vulnerability.getName());
    +  438  0
                 }
    +  439  0
                 if (v != null) {
    +  440  0
                     score = v.getCvssScore();
    +  441  0
                 } else if ("High".equalsIgnoreCase(criticality)) {
    +  442  0
                     score = 8.5f;
    +  443  0
                 } else if ("Medium".equalsIgnoreCase(criticality)) {
    +  444  0
                     score = 5.5f;
    +  445  0
                 } else if ("Low".equalsIgnoreCase(criticality)) {
    +  446  0
                     score = 2.0f;
    +  447   +
                 }
    +  448  0
                 vulnerability.setCvssScore(score);
    +  449   +
             }
    +  450  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    +  451  0
         }
    +  452   +
     
    +  453   +
         /**
    +  454   +
          * Creates a vulnerability.
    +  455   +
          *
    +  456   +
          * @param parentName the parent name
    +  457   +
          * @param dependency the dependency
    +  458   +
          * @param gem the gem name
    +  459   +
          * @param nextLine the line to parse
    +  460   +
          * @return the vulnerability
    +  461   +
          */
    +  462   +
         private Vulnerability createVulnerability(String parentName, Dependency dependency, String gem, String nextLine) {
    +  463  0
             Vulnerability vulnerability = null;
    +  464  0
             if (null != dependency) {
    +  465  0
                 final String version = nextLine.substring(VERSION.length());
    +  466  0
                 dependency.getVersionEvidence().addEvidence(
    +  467   +
                         "bundler-audit",
    +  468   +
                         "Version",
    +  469   +
                         version,
    +  470   +
                         Confidence.HIGHEST);
    +  471  0
                 vulnerability = new Vulnerability(); // don't add to dependency until we have name set later
    +  472  0
                 vulnerability.setMatchedCPE(
    +  473  0
                         String.format("cpe:/a:%1$s_project:%1$s:%2$s::~~~ruby~~", gem, version),
    +  474   +
                         null);
    +  475  0
                 vulnerability.setCvssAccessVector("-");
    +  476  0
                 vulnerability.setCvssAccessComplexity("-");
    +  477  0
                 vulnerability.setCvssAuthentication("-");
    +  478  0
                 vulnerability.setCvssAvailabilityImpact("-");
    +  479  0
                 vulnerability.setCvssConfidentialityImpact("-");
    +  480  0
                 vulnerability.setCvssIntegrityImpact("-");
    +  481   +
             }
    +  482  0
             LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
    +  483  0
             return vulnerability;
    +  484  
         }
    -  505   +  485   +
     
    +  486   +
         /**
    +  487   +
          * Creates the dependency based off of the gem.
    +  488   +
          *
    +  489   +
          * @param engine the engine used for scanning
    +  490   +
          * @param parentName the gem parent
    +  491   +
          * @param fileName the file name
    +  492   +
          * @param filePath the file path
    +  493   +
          * @param gem the gem name
    +  494   +
          * @return the dependency to add
    +  495   +
          * @throws IOException thrown if a temporary gem file could not be written
    +  496   +
          */
    +  497   +
         private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String filePath, String gem) throws IOException {
    +  498  0
             final File gemFile = new File(Settings.getTempDirectory(), gem + "_Gemfile.lock");
    +  499  0
             if (!gemFile.createNewFile()) {
    +  500  0
                 throw new IOException("Unable to create temporary gem file");
    +  501   +
             }
    +  502  0
             final String displayFileName = String.format("%s%c%s:%s", parentName, File.separatorChar, fileName, gem);
    +  503   +
     
    +  504  0
             FileUtils.write(gemFile, displayFileName, Charset.defaultCharset()); // unique contents to avoid dependency bundling
    +  505  0
             final Dependency dependency = new Dependency(gemFile);
    +  506  0
             dependency.getProductEvidence().addEvidence("bundler-audit", "Name", gem, Confidence.HIGHEST);
    +  507  0
             dependency.setDisplayFileName(displayFileName);
    +  508  0
             dependency.setFileName(fileName);
    +  509  0
             dependency.setFilePath(filePath);
    +  510  0
             engine.getDependencies().add(dependency);
    +  511  0
             return dependency;
    +  512   +
         }
    +  513  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer.html index 70f462ea4..9008fcbe6 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer.html @@ -77,198 +77,200 @@  29  
      * (http://bundler.io) for better evidence results. It also tries to resolve the
     30   -
      * dependency packagePath to where the gem is actually installed. Then during {@link org.owasp.dependencycheck.analyzer.AnalysisPhase#PRE_FINDING_ANALYSIS}
    +
      * dependency packagePath to where the gem is actually installed. Then during
     31   -
      * {@link DependencyBundlingAnalyzer} will merge two .gemspec dependencies
    +
      * the {@link org.owasp.dependencycheck.analyzer.AnalysisPhase#PRE_FINDING_ANALYSIS}
     32   -
      * together if <code>Dependency.getPackagePath()</code> are the same.
    +
      * {@link DependencyMergingAnalyzer} will merge two .gemspec dependencies
     33   -
      *
    +
      * together if <code>Dependency.getPackagePath()</code> are the same.
     34   -
      * Ruby bundler creates new .gemspec files under a folder called
    +
      *
     35   -
      * "specifications" at deploy time, in addition to the original .gemspec files
    +
      * Ruby bundler creates new .gemspec files under a folder called
     36   -
      * from source. The bundler generated .gemspec files always contain fully
    +
      * "specifications" at deploy time, in addition to the original .gemspec files
     37   -
      * resolved attributes thus provide more accurate evidences, whereas the
    +
      * from source. The bundler generated .gemspec files always contain fully
     38   -
      * original .gemspec from source often contain variables for attributes that
    +
      * resolved attributes thus provide more accurate evidences, whereas the
     39   -
      * can't be used for evidences.
    +
      * original .gemspec from source often contain variables for attributes that
     40   -
      *
    +
      * can't be used for evidences.
     41   -
      * Note this analyzer share the same
    -  42   -
      * {@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_RUBY_GEMSPEC_ENABLED} as
    -  43   -
      * {@link RubyGemspecAnalyzer}, so it will enabled/disabled with
    -  44   -
      * {@link RubyGemspecAnalyzer}.
    -  45  
      *
    +  42   +
      * Note this analyzer share the same
    +  43   +
      * {@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_RUBY_GEMSPEC_ENABLED}
    +  44   +
      * as {@link RubyGemspecAnalyzer}, so it will enabled/disabled with
    +  45   +
      * {@link RubyGemspecAnalyzer}.
     46   -
      * @author Bianca Jiang (https://twitter.com/biancajiang)
    +
      *
     47   -
      */
    +
      * @author Bianca Jiang (https://twitter.com/biancajiang)
     48   +
      */
    +  49  
     @Experimental
    -  49  11
     public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer {
    -  50   -
     
    +  50  11
     public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer {
     51   -
         /**
    +
     
     52   -
          * The name of the analyzer.
    +
         /**
     53   -
          */
    +
          * The name of the analyzer.
     54   -
         private static final String ANALYZER_NAME = "Ruby Bundler Analyzer";
    +
          */
     55   -
     
    +
         private static final String ANALYZER_NAME = "Ruby Bundler Analyzer";
     56   -
         /**
    +
     
     57   -
          * Folder name that contains .gemspec files created by "bundle install"
    +
         /**
     58   -
          */
    +
          * Folder name that contains .gemspec files created by "bundle install"
     59   -
         private static final String SPECIFICATIONS = "specifications";
    +
          */
     60   -
     
    +
         private static final String SPECIFICATIONS = "specifications";
     61   -
         /**
    +
     
     62   -
          * Folder name that contains the gems by "bundle install"
    +
         /**
     63   -
          */
    +
          * Folder name that contains the gems by "bundle install"
     64   -
         private static final String GEMS = "gems";
    +
          */
     65   -
     
    +
         private static final String GEMS = "gems";
     66   -
         /**
    +
     
     67   -
          * Returns the name of the analyzer.
    -  68   -
          *
    -  69   -
          * @return the name of the analyzer.
    -  70   -
          */
    -  71   -
         @Override
    -  72   -
         public String getName() {
    -  73  22
             return ANALYZER_NAME;
    -  74   -
         }
    -  75   -
     
    -  76  
         /**
    -  77   -
          * Only accept *.gemspec files generated by "bundle install --deployment"
    -  78   -
          * under "specifications" folder.
    -  79   +  68   +
          * Returns the name of the analyzer.
    +  69  
          *
    -  80   -
          * @param pathname the path name to test
    -  81   -
          * @return true if the analyzer can process the given file; otherwise false
    -  82   +  70   +
          * @return the name of the analyzer.
    +  71  
          */
    -  83   +  72  
         @Override
    -  84   -
         public boolean accept(File pathname) {
    -  85   -
     
    -  86  864
             boolean accepted = super.accept(pathname);
    -  87  864
             if (accepted) {
    -  88  4
                 final File parentDir = pathname.getParentFile();
    -  89  4
                 accepted = parentDir != null && parentDir.getName().equals(SPECIFICATIONS);
    -  90   -
             }
    -  91   -
     
    -  92  864
             return accepted;
    -  93   +  73   +
         public String getName() {
    +  74  20
             return ANALYZER_NAME;
    +  75  
         }
    -  94   +  76  
     
    -  95   +  77   +
         /**
    +  78   +
          * Only accept *.gemspec files generated by "bundle install --deployment"
    +  79   +
          * under "specifications" folder.
    +  80   +
          *
    +  81   +
          * @param pathname the path name to test
    +  82   +
          * @return true if the analyzer can process the given file; otherwise false
    +  83   +
          */
    +  84  
         @Override
    -  96   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    -  97   -
                 throws AnalysisException {
    -  98  2
             super.analyzeFileType(dependency, engine);
    -  99   +  85   +
         public boolean accept(File pathname) {
    +  86  
     
    -  100   -
             //find the corresponding gem folder for this .gemspec stub by "bundle install --deployment"
    -  101  2
             final File gemspecFile = dependency.getActualFile();
    -  102  2
             final String gemFileName = gemspecFile.getName();
    -  103  2
             final String gemName = gemFileName.substring(0, gemFileName.lastIndexOf(".gemspec"));
    -  104  2
             final File specificationsDir = gemspecFile.getParentFile();
    -  105  2
             if (specificationsDir != null && specificationsDir.getName().equals(SPECIFICATIONS) && specificationsDir.exists()) {
    -  106  2
                 final File parentDir = specificationsDir.getParentFile();
    -  107  2
                 if (parentDir != null && parentDir.exists()) {
    -  108  2
                     final File gemsDir = new File(parentDir, GEMS);
    -  109  2
                     if (gemsDir.exists()) {
    -  110  2
                         final File[] matchingFiles = gemsDir.listFiles(new FilenameFilter() {
    -  111   -
                             @Override
    -  112   -
                             public boolean accept(File dir, String name) {
    -  113  2
                                 return name.equals(gemName);
    -  114   -
                             }
    -  115   -
                         });
    -  116   -
     
    -  117  2
                         if (matchingFiles != null && matchingFiles.length > 0) {
    -  118  0
                             final String gemPath = matchingFiles[0].getAbsolutePath();
    -  119  0
                             if (dependency.getActualFilePath().equals(dependency.getFilePath())) {
    -  120  0
                                 if (gemPath != null) {
    -  121  0
                                     dependency.setPackagePath(gemPath);
    -  122   -
                                 }
    -  123   -
                             } else {
    -  124   -
                                 //.gemspec's actualFilePath and filePath are different when it's from a compressed file
    -  125   -
                                 //in which case actualFilePath is the temp directory used by decompression.
    -  126   -
                                 //packagePath should use the filePath of the identified gem file in "gems" folder
    -  127  0
                                 final File gemspecStub = new File(dependency.getFilePath());
    -  128  0
                                 final File specDir = gemspecStub.getParentFile();
    -  129  0
                                 if (specDir != null && specDir.getName().equals(SPECIFICATIONS)) {
    -  130  0
                                     final File gemsDir2 = new File(specDir.getParentFile(), GEMS);
    -  131  0
                                     final File packageDir = new File(gemsDir2, gemName);
    -  132  0
                                     dependency.setPackagePath(packageDir.getAbsolutePath());
    -  133   -
                                 }
    -  134   -
                             }
    -  135   -
                         }
    -  136   -
                     }
    -  137   -
                 }
    -  138   +  87  862
             boolean accepted = super.accept(pathname);
    +  88  862
             if (accepted) {
    +  89  4
                 final File parentDir = pathname.getParentFile();
    +  90  4
                 accepted = parentDir != null && parentDir.getName().equals(SPECIFICATIONS);
    +  91  
             }
    -  139  2
         }
    -  140   +  92   +
     
    +  93  862
             return accepted;
    +  94   +
         }
    +  95   +
     
    +  96   +
         @Override
    +  97   +
         protected void analyzeDependency(Dependency dependency, Engine engine)
    +  98   +
                 throws AnalysisException {
    +  99  2
             super.analyzeDependency(dependency, engine);
    +  100   +
     
    +  101   +
             //find the corresponding gem folder for this .gemspec stub by "bundle install --deployment"
    +  102  2
             final File gemspecFile = dependency.getActualFile();
    +  103  2
             final String gemFileName = gemspecFile.getName();
    +  104  2
             final String gemName = gemFileName.substring(0, gemFileName.lastIndexOf(".gemspec"));
    +  105  2
             final File specificationsDir = gemspecFile.getParentFile();
    +  106  2
             if (specificationsDir != null && specificationsDir.getName().equals(SPECIFICATIONS) && specificationsDir.exists()) {
    +  107  2
                 final File parentDir = specificationsDir.getParentFile();
    +  108  2
                 if (parentDir != null && parentDir.exists()) {
    +  109  2
                     final File gemsDir = new File(parentDir, GEMS);
    +  110  2
                     if (gemsDir.exists()) {
    +  111  2
                         final File[] matchingFiles = gemsDir.listFiles(new FilenameFilter() {
    +  112   +
                             @Override
    +  113   +
                             public boolean accept(File dir, String name) {
    +  114  2
                                 return name.equals(gemName);
    +  115   +
                             }
    +  116   +
                         });
    +  117   +
     
    +  118  2
                         if (matchingFiles != null && matchingFiles.length > 0) {
    +  119  0
                             final String gemPath = matchingFiles[0].getAbsolutePath();
    +  120  0
                             if (dependency.getActualFilePath().equals(dependency.getFilePath())) {
    +  121  0
                                 if (gemPath != null) {
    +  122  0
                                     dependency.setPackagePath(gemPath);
    +  123   +
                                 }
    +  124   +
                             } else {
    +  125   +
                                 //.gemspec's actualFilePath and filePath are different when it's from a compressed file
    +  126   +
                                 //in which case actualFilePath is the temp directory used by decompression.
    +  127   +
                                 //packagePath should use the filePath of the identified gem file in "gems" folder
    +  128  0
                                 final File gemspecStub = new File(dependency.getFilePath());
    +  129  0
                                 final File specDir = gemspecStub.getParentFile();
    +  130  0
                                 if (specDir != null && specDir.getName().equals(SPECIFICATIONS)) {
    +  131  0
                                     final File gemsDir2 = new File(specDir.getParentFile(), GEMS);
    +  132  0
                                     final File packageDir = new File(gemsDir2, gemName);
    +  133  0
                                     dependency.setPackagePath(packageDir.getAbsolutePath());
    +  134   +
                                 }
    +  135   +
                             }
    +  136   +
                         }
    +  137   +
                     }
    +  138   +
                 }
    +  139   +
             }
    +  140  2
         }
    +  141  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer.html index 7085cb2c7..bd104581a 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer.html @@ -188,7 +188,7 @@
         @Override
     87  
         protected FileFilter getFileFilter() {
    -  88  1727
             return FILTER;
    +  88  1723
             return FILTER;
     89  
         }
     90   @@ -216,7 +216,7 @@
         @Override
     102  
         public String getName() {
    -  103  22
             return ANALYZER_NAME;
    +  103  20
             return ANALYZER_NAME;
     104  
         }
     105   @@ -256,7 +256,7 @@
         @Override
     123  
         protected String getAnalyzerEnabledSettingKey() {
    -  124  22
             return Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED;
    +  124  10
             return Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED;
     125  
         }
     126   @@ -273,7 +273,7 @@  132  
         @Override
     133   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     134  
                 throws AnalysisException {
     135   @@ -451,6 +451,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer.html index 5d52397ac..7e4d0214f 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer.html @@ -169,7 +169,7 @@
         @Override
     78  
         protected FileFilter getFileFilter() {
    -  79  862
             return SPM_FILE_FILTER;
    +  79  859
             return SPM_FILE_FILTER;
     80  
         }
     81   @@ -197,7 +197,7 @@
         @Override
     93  
         public String getName() {
    -  94  21
             return ANALYZER_NAME;
    +  94  17
             return ANALYZER_NAME;
     95  
         }
     96   @@ -237,7 +237,7 @@
         @Override
     114  
         protected String getAnalyzerEnabledSettingKey() {
    -  115  14
             return Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED;
    +  115  8
             return Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED;
     116  
         }
     117   @@ -245,7 +245,7 @@  118  
         @Override
     119   -
         protected void analyzeFileType(Dependency dependency, Engine engine)
    +
         protected void analyzeDependency(Dependency dependency, Engine engine)
     120  
                 throws AnalysisException {
     121   @@ -363,6 +363,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer.html index 2d8b742bd..9c1e096f8 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    VulnerabilitySuppressionAnalyzer
    90%
    9/10
    66%
    4/6
    2.333
    VulnerabilitySuppressionAnalyzer
    90%
    10/11
    66%
    4/6
    2
     
    @@ -62,103 +62,144 @@  22  
     import org.owasp.dependencycheck.dependency.Dependency;
     23   -
     import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
    +
     import org.owasp.dependencycheck.utils.Settings;
     24   -
     
    +
     import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
     25   -
     /**
    +
     
     26   -
      * The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
    +
     /**
     27   -
      * Any identified Vulnerability entries within the dependencies that match will be removed.
    +
      * The suppression analyzer processes an externally defined XML document that
     28   -
      *
    +
      * complies with the suppressions.xsd schema. Any identified Vulnerability
     29   -
      * @author Jeremy Long
    +
      * entries within the dependencies that match will be removed.
     30   -
      */
    -  31  8
     public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
    +
      *
    +  31   +
      * @author Jeremy Long
     32   -
     
    -  33   -
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
    +
      */
    +  33  8
     public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
     34   -
         /**
    +
     
     35   -
          * The name of the analyzer.
    +
         //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
     36   -
          */
    +
         /**
     37   -
         private static final String ANALYZER_NAME = "Vulnerability Suppression Analyzer";
    +
          * The name of the analyzer.
     38   -
         /**
    +
          */
     39   -
          * The phase that this analyzer is intended to run in.
    +
         private static final String ANALYZER_NAME = "Vulnerability Suppression Analyzer";
     40   -
          */
    -  41  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_FINDING_ANALYSIS;
    +
         /**
    +  41   +
          * The phase that this analyzer is intended to run in.
     42   -
     
    -  43   -
         /**
    +
          */
    +  43  1
         private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_FINDING_ANALYSIS;
     44   -
          * Returns the name of the analyzer.
    +
     
     45   -
          *
    -  46   -
          * @return the name of the analyzer.
    -  47   -
          */
    -  48   -
         @Override
    -  49   -
         public String getName() {
    -  50  26
             return ANALYZER_NAME;
    -  51   -
         }
    -  52   -
     
    -  53  
         /**
    -  54   -
          * Returns the phase that the analyzer is intended to run in.
    -  55   +  46   +
          * Returns the name of the analyzer.
    +  47  
          *
    -  56   -
          * @return the phase that the analyzer is intended to run in.
    -  57   +  48   +
          * @return the name of the analyzer.
    +  49  
          */
    -  58   +  50  
         @Override
    -  59   -
         public AnalysisPhase getAnalysisPhase() {
    -  60  6
             return ANALYSIS_PHASE;
    -  61   +  51   +
         public String getName() {
    +  52  26
             return ANALYZER_NAME;
    +  53  
         }
    -  62   -
         //</editor-fold>
    -  63   +  54  
     
    -  64   +  55   +
         /**
    +  56   +
          * Returns the phase that the analyzer is intended to run in.
    +  57   +
          *
    +  58   +
          * @return the phase that the analyzer is intended to run in.
    +  59   +
          */
    +  60  
         @Override
    +  61   +
         public AnalysisPhase getAnalysisPhase() {
    +  62  6
             return ANALYSIS_PHASE;
    +  63   +
         }
    +  64   +
     
     65   -
         public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
    +
         /**
     66   -
     
    -  67  4
             if (getRules() == null || getRules().size() <= 0) {
    -  68  0
                 return;
    +
          * <p>
    +  67   +
          * Returns the setting key to determine if the analyzer is enabled.</p>
    +  68   +
          *
     69   -
             }
    +
          * @return the key for the analyzer's enabled property
     70   -
     
    -  71  4
             for (final SuppressionRule rule : getRules()) {
    -  72  240
                 rule.process(dependency);
    -  73  240
             }
    -  74  4
         }
    +
          */
    +  71   +
         @Override
    +  72   +
         protected String getAnalyzerEnabledSettingKey() {
    +  73  2
             return Settings.KEYS.ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED;
    +  74   +
         }
     75   +
         //</editor-fold>
    +  76   +
     
    +  77   +
         /**
    +  78   +
          * Analyzes a dependency's vulnerabilities against the configured CVE
    +  79   +
          * suppressions.
    +  80   +
          *
    +  81   +
          * @param dependency the dependency being analyzed
    +  82   +
          * @param engine a reference to the engine orchestrating the analysis
    +  83   +
          * @throws AnalysisException thrown if there is an error during analysis
    +  84   +
          */
    +  85   +
         @Override
    +  86   +
         protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
    +  87   +
     
    +  88  4
             if (getRules() == null || getRules().size() <= 0) {
    +  89  0
                 return;
    +  90   +
             }
    +  91   +
     
    +  92  4
             for (final SuppressionRule rule : getRules()) {
    +  93  264
                 rule.process(dependency);
    +  94  264
             }
    +  95  4
         }
    +  96  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.AnalysisException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.AnalysisException.html index 4668d32ab..0d8d6ad5e 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.AnalysisException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.AnalysisException.html @@ -143,6 +143,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException.html index 2790ca61a..b974fff48 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException.html @@ -143,6 +143,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.central.CentralSearch.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.central.CentralSearch.html index b989cafbc..4b970bc5c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.central.CentralSearch.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.central.CentralSearch.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    CentralSearch
    87%
    55/63
    87%
    21/24
    9.5
    CentralSearch
    86%
    53/61
    87%
    21/24
    9.5
     
    @@ -70,19 +70,19 @@  26  
     import javax.xml.parsers.DocumentBuilder;
     27   -
     import javax.xml.parsers.DocumentBuilderFactory;
    -  28  
     import javax.xml.xpath.XPath;
    -  29   +  28  
     import javax.xml.xpath.XPathConstants;
    -  30   +  29  
     import javax.xml.xpath.XPathFactory;
    -  31   +  30  
     import org.owasp.dependencycheck.data.nexus.MavenArtifact;
    -  32   +  31  
     import org.owasp.dependencycheck.utils.Settings;
    -  33   +  32  
     import org.owasp.dependencycheck.utils.URLConnectionFactory;
    +  33   +
     import org.owasp.dependencycheck.utils.XmlUtils;
     34  
     import org.slf4j.Logger;
     35   @@ -221,79 +221,77 @@  111  3
                 boolean missing = false;
     112  
                 try {
    -  113  3
                     final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    -  114  3
                     factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  115  3
                     final DocumentBuilder builder = factory.newDocumentBuilder();
    -  116  3
                     final Document doc = builder.parse(conn.getInputStream());
    -  117  3
                     final XPath xpath = XPathFactory.newInstance().newXPath();
    -  118  3
                     final String numFound = xpath.evaluate("/response/result/@numFound", doc);
    -  119  3
                     if ("0".equals(numFound)) {
    -  120  1
                         missing = true;
    -  121   +  113  3
                     final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder();
    +  114  3
                     final Document doc = builder.parse(conn.getInputStream());
    +  115  3
                     final XPath xpath = XPathFactory.newInstance().newXPath();
    +  116  3
                     final String numFound = xpath.evaluate("/response/result/@numFound", doc);
    +  117  3
                     if ("0".equals(numFound)) {
    +  118  1
                         missing = true;
    +  119  
                     } else {
    -  122  2
                         result = new ArrayList<MavenArtifact>();
    -  123  2
                         final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
    -  124  5
                         for (int i = 0; i < docs.getLength(); i++) {
    -  125  3
                             final String g = xpath.evaluate("./str[@name='g']", docs.item(i));
    -  126  3
                             LOGGER.trace("GroupId: {}", g);
    -  127  3
                             final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
    -  128  3
                             LOGGER.trace("ArtifactId: {}", a);
    -  129  3
                             final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
    -  130  3
                             NodeList atts = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET);
    -  131  3
                             boolean pomAvailable = false;
    -  132  3
                             boolean jarAvailable = false;
    -  133  14
                             for (int x = 0; x < atts.getLength(); x++) {
    -  134  11
                                 final String tmp = xpath.evaluate(".", atts.item(x));
    -  135  11
                                 if (".pom".equals(tmp)) {
    -  136  3
                                     pomAvailable = true;
    -  137  8
                                 } else if (".jar".equals(tmp)) {
    -  138  3
                                     jarAvailable = true;
    +  120  2
                         result = new ArrayList<MavenArtifact>();
    +  121  2
                         final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
    +  122  5
                         for (int i = 0; i < docs.getLength(); i++) {
    +  123  3
                             final String g = xpath.evaluate("./str[@name='g']", docs.item(i));
    +  124  3
                             LOGGER.trace("GroupId: {}", g);
    +  125  3
                             final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
    +  126  3
                             LOGGER.trace("ArtifactId: {}", a);
    +  127  3
                             final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
    +  128  3
                             NodeList atts = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET);
    +  129  3
                             boolean pomAvailable = false;
    +  130  3
                             boolean jarAvailable = false;
    +  131  14
                             for (int x = 0; x < atts.getLength(); x++) {
    +  132  11
                                 final String tmp = xpath.evaluate(".", atts.item(x));
    +  133  11
                                 if (".pom".equals(tmp)) {
    +  134  3
                                     pomAvailable = true;
    +  135  8
                                 } else if (".jar".equals(tmp)) {
    +  136  3
                                     jarAvailable = true;
    +  137   +
                                 }
    +  138   +
                             }
     139   -
                                 }
    -  140   -
                             }
    -  141  
     
    -  142  3
                             atts = (NodeList) xpath.evaluate("./arr[@name='tags']/str", docs.item(i), XPathConstants.NODESET);
    -  143  3
                             boolean useHTTPS = false;
    -  144  21
                             for (int x = 0; x < atts.getLength(); x++) {
    -  145  18
                                 final String tmp = xpath.evaluate(".", atts.item(x));
    -  146  18
                                 if ("https".equals(tmp)) {
    -  147  0
                                     useHTTPS = true;
    -  148   +  140  3
                             atts = (NodeList) xpath.evaluate("./arr[@name='tags']/str", docs.item(i), XPathConstants.NODESET);
    +  141  3
                             boolean useHTTPS = false;
    +  142  21
                             for (int x = 0; x < atts.getLength(); x++) {
    +  143  18
                                 final String tmp = xpath.evaluate(".", atts.item(x));
    +  144  18
                                 if ("https".equals(tmp)) {
    +  145  0
                                     useHTTPS = true;
    +  146  
                                 }
    -  149   +  147  
                             }
    -  150  3
                             LOGGER.trace("Version: {}", v);
    -  151  3
                             result.add(new MavenArtifact(g, a, v, jarAvailable, pomAvailable, useHTTPS));
    -  152   +  148  3
                             LOGGER.trace("Version: {}", v);
    +  149  3
                             result.add(new MavenArtifact(g, a, v, jarAvailable, pomAvailable, useHTTPS));
    +  150  
                         }
    -  153   +  151  
                     }
    -  154  0
                 } catch (Throwable e) {
    -  155   +  152  0
                 } catch (Throwable e) {
    +  153  
                     // Anything else is jacked up XML stuff that we really can't recover from well
    -  156  0
                     throw new IOException(e.getMessage(), e);
    -  157  3
                 }
    -  158   +  154  0
                     throw new IOException(e.getMessage(), e);
    +  155  3
                 }
    +  156  
     
    -  159  3
                 if (missing) {
    -  160  1
                     throw new FileNotFoundException("Artifact not found in Central");
    -  161   +  157  3
                 if (missing) {
    +  158  1
                     throw new FileNotFoundException("Artifact not found in Central");
    +  159  
                 }
    -  162  2
             } else {
    -  163  0
                 LOGGER.debug("Could not connect to Central received response code: {} {}",
    -  164  0
                         conn.getResponseCode(), conn.getResponseMessage());
    -  165  0
                 throw new IOException("Could not connect to Central");
    -  166   +  160  2
             } else {
    +  161  0
                 LOGGER.debug("Could not connect to Central received response code: {} {}",
    +  162  0
                         conn.getResponseCode(), conn.getResponseMessage());
    +  163  0
                 throw new IOException("Could not connect to Central");
    +  164  
             }
    -  167  2
             return result;
    -  168   +  165  2
             return result;
    +  166  
         }
    -  169   +  167  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerDependency.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerDependency.html index ba38075c3..6df37b26c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerDependency.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerDependency.html @@ -217,6 +217,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerException.html index 2f39b42b7..1db795723 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerException.html @@ -127,6 +127,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerLockParser.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerLockParser.html index a96650828..bdbff5a0a 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerLockParser.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.composer.ComposerLockParser.html @@ -228,6 +228,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.CpeMemoryIndex.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.CpeMemoryIndex.html index 876a6739c..e50be028c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.CpeMemoryIndex.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.CpeMemoryIndex.html @@ -385,14 +385,14 @@  211  2
                     for (Pair<String, String> pair : data) {
     212  
                         //todo figure out why there are null products
    -  213  52774
                         if (pair.getLeft() != null && pair.getRight() != null) {
    -  214  52772
                             v.setStringValue(pair.getLeft());
    -  215  52772
                             p.setStringValue(pair.getRight());
    -  216  52772
                             indexWriter.addDocument(doc);
    -  217  52772
                             resetFieldAnalyzer();
    +  213  53114
                         if (pair.getLeft() != null && pair.getRight() != null) {
    +  214  53112
                             v.setStringValue(pair.getLeft());
    +  215  53112
                             p.setStringValue(pair.getRight());
    +  216  53112
                             indexWriter.addDocument(doc);
    +  217  53112
                             resetFieldAnalyzer();
     218  
                         }
    -  219  52774
                     }
    +  219  53114
                     }
     220  0
                 } catch (DatabaseException ex) {
     221  0
                     LOGGER.debug("", ex);
     222  0
                     throw new IndexException("Error reading CPE data", ex);
    @@ -437,15 +437,15 @@
          */
     251  
         private void resetFieldAnalyzer() {
    -  252  52783
             if (productFieldAnalyzer != null) {
    -  253  52783
                 productFieldAnalyzer.clear();
    +  252  53123
             if (productFieldAnalyzer != null) {
    +  253  53123
                 productFieldAnalyzer.clear();
     254  
             }
    -  255  52783
             if (vendorFieldAnalyzer != null) {
    -  256  52783
                 vendorFieldAnalyzer.clear();
    +  255  53123
             if (vendorFieldAnalyzer != null) {
    +  256  53123
                 vendorFieldAnalyzer.clear();
     257  
             }
    -  258  52783
         }
    +  258  53123
         }
     259  
     
     260   @@ -523,7 +523,7 @@
          */
     300  
         public Document getDocument(int documentId) throws IOException {
    -  301  20
             return indexSearcher.doc(documentId);
    +  301  21
             return indexSearcher.doc(documentId);
     302  
         }
     303   @@ -551,6 +551,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.Fields.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.Fields.html index 5abc697c2..5dbba1b43 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.Fields.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.Fields.html @@ -107,6 +107,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexEntry.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexEntry.html index 8842af660..63b22f804 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexEntry.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexEntry.html @@ -73,7 +73,7 @@
      * @author Jeremy Long
     28  
      */
    -  29  1690
     public class IndexEntry implements Serializable {
    +  29  1805
     public class IndexEntry implements Serializable {
     30  
     
     31   @@ -151,7 +151,7 @@
          */
     70  
         public String getVendor() {
    -  71  42
             return vendor;
    +  71  43
             return vendor;
     72  
         }
     73   @@ -168,8 +168,8 @@
          */
     79  
         public void setVendor(String vendor) {
    -  80  1692
             this.vendor = vendor;
    -  81  1692
         }
    +  80  1809
             this.vendor = vendor;
    +  81  1809
         }
     82  
         /**
     83   @@ -192,7 +192,7 @@
          */
     92  
         public String getProduct() {
    -  93  46
             return product;
    +  93  48
             return product;
     94  
         }
     95   @@ -209,8 +209,8 @@
          */
     101  
         public void setProduct(String product) {
    -  102  1691
             this.product = product;
    -  103  1691
         }
    +  102  1808
             this.product = product;
    +  103  1808
         }
     104  
         /**
     105   @@ -250,8 +250,8 @@
          */
     123  
         public void setSearchScore(float searchScore) {
    -  124  20
             this.searchScore = searchScore;
    -  125  20
         }
    +  124  21
             this.searchScore = searchScore;
    +  125  21
         }
     126  
     
     127   @@ -320,21 +320,21 @@
         @Override
     164  
         public boolean equals(Object obj) {
    -  165  90
             if (obj == null) {
    +  165  100
             if (obj == null) {
     166  0
                 return false;
     167  
             }
    -  168  90
             if (getClass() != obj.getClass()) {
    +  168  100
             if (getClass() != obj.getClass()) {
     169  0
                 return false;
     170  
             }
    -  171  90
             final IndexEntry other = (IndexEntry) obj;
    -  172  90
             if ((this.vendor == null) ? (other.vendor != null) : !this.vendor.equals(other.vendor)) {
    -  173  87
                 return false;
    +  171  100
             final IndexEntry other = (IndexEntry) obj;
    +  172  100
             if ((this.vendor == null) ? (other.vendor != null) : !this.vendor.equals(other.vendor)) {
    +  173  95
                 return false;
     174  
             }
    -  175  3
             if ((this.product == null) ? (other.product != null) : !this.product.equals(other.product)) {
    -  176  3
                 return false;
    +  175  5
             if ((this.product == null) ? (other.product != null) : !this.product.equals(other.product)) {
    +  176  5
                 return false;
     177  
             }
     178  0
             return true;
    @@ -363,6 +363,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexException.html index d977699eb..5b28c1ab4 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cpe.IndexException.html @@ -143,6 +143,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweDB.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweDB.html index 3aea7b56c..812dd794c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweDB.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweDB.html @@ -175,8 +175,8 @@
          */
     90  
         public static String getCweName(String cweId) {
    -  91  9
             if (cweId != null) {
    -  92  9
                 return CWE.get(cweId);
    +  91  10
             if (cweId != null) {
    +  92  10
                 return CWE.get(cweId);
     93  
             }
     94  0
             return null;
    @@ -186,6 +186,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweHandler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweHandler.html index 0e736122e..38ae01762 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweHandler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.cwe.CweHandler.html @@ -121,6 +121,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AbstractTokenizingFilter.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AbstractTokenizingFilter.html index 2c4fffea1..a61b1e430 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AbstractTokenizingFilter.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AbstractTokenizingFilter.html @@ -85,7 +85,7 @@
          * The char term attribute.
     34  
          */
    -  35  19
         private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
    +  35  17
         private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
     36  
     
     37   @@ -100,7 +100,7 @@
          */
     42  
         protected CharTermAttribute getTermAtt() {
    -  43  605054
             return termAtt;
    +  43  622332
             return termAtt;
     44  
         }
     45   @@ -125,7 +125,7 @@
          */
     55  
         protected LinkedList<String> getTokens() {
    -  56  605051
             return tokens;
    +  56  622323
             return tokens;
     57  
         }
     58   @@ -142,9 +142,9 @@
          */
     64  
         public AbstractTokenizingFilter(TokenStream stream) {
    -  65  19
             super(stream);
    -  66  19
             tokens = new LinkedList<String>();
    -  67  19
         }
    +  65  17
             super(stream);
    +  66  17
             tokens = new LinkedList<String>();
    +  67  17
         }
     68  
     
     69   @@ -159,20 +159,20 @@
          */
     74  
         protected boolean addTerm() {
    -  75  604999
             final boolean termAdded = !tokens.isEmpty();
    -  76  605001
             if (termAdded) {
    -  77  207956
                 final String term = tokens.pop();
    -  78  207956
                 clearAttributes();
    -  79  207953
                 termAtt.append(term);
    +  75  622235
             final boolean termAdded = !tokens.isEmpty();
    +  76  622235
             if (termAdded) {
    +  77  218514
                 final String term = tokens.pop();
    +  78  218516
                 clearAttributes();
    +  79  218519
                 termAtt.append(term);
     80  
             }
    -  81  605000
             return termAdded;
    +  81  622246
             return termAdded;
     82  
         }
     83  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AlphaNumericTokenizer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AlphaNumericTokenizer.html index 66256f094..ee2230eb1 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AlphaNumericTokenizer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.AlphaNumericTokenizer.html @@ -91,8 +91,8 @@
          */
     37  
         public AlphaNumericTokenizer(Version matchVersion, Reader in) {
    -  38  15
             super(matchVersion, in);
    -  39  15
         }
    +  38  11
             super(matchVersion, in);
    +  39  11
         }
     40  
     
     41   @@ -131,13 +131,13 @@
         @Override
     59  
         protected boolean isTokenChar(int c) {
    -  60  1271270
             return Character.isLetter(c) || Character.isDigit(c);
    +  60  1279696
             return Character.isLetter(c) || Character.isDigit(c);
     61  
         }
     62  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.DependencySimilarity.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.DependencySimilarity.html index 142192d28..d0511cde2 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.DependencySimilarity.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.DependencySimilarity.html @@ -111,6 +111,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.FieldAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.FieldAnalyzer.html index c37b5efe2..ab07dee2b 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.FieldAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.FieldAnalyzer.html @@ -178,6 +178,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.LuceneUtils.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.LuceneUtils.html index c8be04cf3..c55dd7c1b 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.LuceneUtils.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.LuceneUtils.html @@ -212,6 +212,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer.html index 6f977e89e..9bf793c24 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer.html @@ -140,13 +140,13 @@
         @Override
     63  
         protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
    -  64  14
             final Tokenizer source = new AlphaNumericTokenizer(version, reader);
    +  64  10
             final Tokenizer source = new AlphaNumericTokenizer(version, reader);
     65  
     
    -  66  14
             TokenStream stream = source;
    +  66  10
             TokenStream stream = source;
     67  
     
    -  68  14
             stream = new WordDelimiterFilter(stream,
    +  68  10
             stream = new WordDelimiterFilter(stream,
     69  
                     WordDelimiterFilter.GENERATE_WORD_PARTS
     70   @@ -161,14 +161,14 @@
                     | WordDelimiterFilter.STEM_ENGLISH_POSSESSIVE, null);
     75  
     
    -  76  14
             stream = new LowerCaseFilter(version, stream);
    -  77  14
             stream = new UrlTokenizingFilter(stream);
    -  78  14
             concatenatingFilter = new TokenPairConcatenatingFilter(stream);
    -  79  14
             stream = concatenatingFilter;
    -  80  14
             stream = new StopFilter(version, stream, StopAnalyzer.ENGLISH_STOP_WORDS_SET);
    +  76  10
             stream = new LowerCaseFilter(version, stream);
    +  77  10
             stream = new UrlTokenizingFilter(stream);
    +  78  10
             concatenatingFilter = new TokenPairConcatenatingFilter(stream);
    +  79  10
             stream = concatenatingFilter;
    +  80  10
             stream = new StopFilter(version, stream, StopAnalyzer.ENGLISH_STOP_WORDS_SET);
     81  
     
    -  82  14
             return new TokenStreamComponents(source, stream);
    +  82  10
             return new TokenStreamComponents(source, stream);
     83  
         }
     84   @@ -187,15 +187,15 @@
          */
     91  
         public void clear() {
    -  92  105568
             if (concatenatingFilter != null) {
    -  93  105568
                 concatenatingFilter.clear();
    +  92  106248
             if (concatenatingFilter != null) {
    +  93  106248
                 concatenatingFilter.clear();
     94  
             }
    -  95  105568
         }
    +  95  106248
         }
     96  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.TokenPairConcatenatingFilter.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.TokenPairConcatenatingFilter.html index 14082126e..b2f732e7c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.TokenPairConcatenatingFilter.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.TokenPairConcatenatingFilter.html @@ -93,7 +93,7 @@
          * The char term attribute.
     38  
          */
    -  39  16
         private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
    +  39  12
         private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
     40  
         /**
     41   @@ -158,9 +158,9 @@
          */
     72  
         public TokenPairConcatenatingFilter(TokenStream stream) {
    -  73  16
             super(stream);
    -  74  16
             words = new LinkedList<String>();
    -  75  16
         }
    +  73  12
             super(stream);
    +  74  12
             words = new LinkedList<String>();
    +  75  12
         }
     76  
     
     77   @@ -185,35 +185,35 @@
     
     87  
             //collect all the terms into the words collection
    -  88  586499
             while (input.incrementToken()) {
    -  89  195451
                 final String word = new String(termAtt.buffer(), 0, termAtt.length());
    -  90  195451
                 words.add(word);
    -  91  195451
             }
    +  88  590551
             while (input.incrementToken()) {
    +  89  196801
                 final String word = new String(termAtt.buffer(), 0, termAtt.length());
    +  90  196801
                 words.add(word);
    +  91  196801
             }
     92  
     
     93  
             //if we have a previousTerm - write it out as its own token concatenated
     94  
             // with the current word (if one is available).
    -  95  391048
             if (previousWord != null && !words.isEmpty()) {
    -  96  89881
                 final String word = words.getFirst();
    -  97  89881
                 clearAttributes();
    -  98  89881
                 termAtt.append(previousWord).append(word);
    -  99  89881
                 previousWord = null;
    -  100  89881
                 return true;
    +  95  393750
             if (previousWord != null && !words.isEmpty()) {
    +  96  90553
                 final String word = words.getFirst();
    +  97  90553
                 clearAttributes();
    +  98  90553
                 termAtt.append(previousWord).append(word);
    +  99  90553
                 previousWord = null;
    +  100  90553
                 return true;
     101  
             }
     102  
             //if we have words, write it out as a single token
    -  103  301167
             if (!words.isEmpty()) {
    -  104  195451
                 final String word = words.removeFirst();
    -  105  195451
                 clearAttributes();
    -  106  195451
                 termAtt.append(word);
    -  107  195451
                 previousWord = word;
    -  108  195451
                 return true;
    +  103  303197
             if (!words.isEmpty()) {
    +  104  196801
                 final String word = words.removeFirst();
    +  105  196801
                 clearAttributes();
    +  106  196801
                 termAtt.append(word);
    +  107  196801
                 previousWord = word;
    +  108  196801
                 return true;
     109  
             }
    -  110  105716
             return false;
    +  110  106396
             return false;
     111  
         }
     112   @@ -232,9 +232,9 @@
          */
     119  
         public void clear() {
    -  120  105569
             previousWord = null;
    -  121  105569
             words.clear();
    -  122  105569
         }
    +  120  106249
             previousWord = null;
    +  121  106249
             words.clear();
    +  122  106249
         }
     123  
     
     124   @@ -306,6 +306,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.UrlTokenizingFilter.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.UrlTokenizingFilter.html index a752b0672..30abc0239 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.UrlTokenizingFilter.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.lucene.UrlTokenizingFilter.html @@ -116,8 +116,8 @@
          */
     50  
         public UrlTokenizingFilter(TokenStream stream) {
    -  51  19
             super(stream);
    -  52  19
         }
    +  51  17
             super(stream);
    +  52  17
         }
     53  
     
     54   @@ -138,11 +138,11 @@
         @Override
     62  
         public boolean incrementToken() throws IOException {
    -  63  605049
             final LinkedList<String> tokens = getTokens();
    -  64  605055
             final CharTermAttribute termAtt = getTermAtt();
    -  65  605054
             if (tokens.isEmpty() && input.incrementToken()) {
    -  66  207951
                 final String text = new String(termAtt.buffer(), 0, termAtt.length());
    -  67  207951
                 if (UrlStringUtils.containsUrl(text)) {
    +  63  622316
             final LinkedList<String> tokens = getTokens();
    +  64  622322
             final CharTermAttribute termAtt = getTermAtt();
    +  65  622331
             if (tokens.isEmpty() && input.incrementToken()) {
    +  66  218511
                 final String text = new String(termAtt.buffer(), 0, termAtt.length());
    +  67  218513
                 if (UrlStringUtils.containsUrl(text)) {
     68  6
                     final String[] parts = text.split("\\s");
     69  12
                     for (String part : parts) {
     70  6
                         if (UrlStringUtils.isUrl(part)) {
    @@ -162,18 +162,18 @@  81  
                     }
     82  6
                 } else {
    -  83  207945
                     tokens.add(text);
    +  83  218505
                     tokens.add(text);
     84  
                 }
     85  
             }
    -  86  605000
             return addTerm();
    +  86  622236
             return addTerm();
     87  
         }
     88  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.MavenArtifact.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.MavenArtifact.html index b8698ba55..215f5a3aa 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.MavenArtifact.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.MavenArtifact.html @@ -426,6 +426,6 @@
     // vim: cc=120:sw=4:ts=4:sts=4
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.NexusSearch.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.NexusSearch.html index ff906f379..3309bca91 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.NexusSearch.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nexus.NexusSearch.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    NexusSearch
    0%
    0/58
    0%
    0/19
    7.667
    NexusSearch
    0%
    0/56
    0%
    0/19
    7.667
     
    @@ -66,269 +66,265 @@  24  
     import javax.xml.parsers.DocumentBuilder;
     25   -
     import javax.xml.parsers.DocumentBuilderFactory;
    -  26  
     import javax.xml.xpath.XPath;
    -  27   +  26  
     import javax.xml.xpath.XPathFactory;
    +  27   +
     
     28   -
     
    -  29   -
     import org.owasp.dependencycheck.utils.InvalidSettingException;
    -  30   -
     import org.owasp.dependencycheck.utils.Settings;
    -  31  
     import org.owasp.dependencycheck.utils.URLConnectionFactory;
    -  32   +  29   +
     import org.owasp.dependencycheck.utils.XmlUtils;
    +  30  
     import org.slf4j.Logger;
    -  33   +  31  
     import org.slf4j.LoggerFactory;
    -  34   +  32  
     import org.w3c.dom.Document;
    -  35   +  33  
     
    -  36   +  34  
     /**
    -  37   +  35  
      * Class of methods to search Nexus repositories.
    -  38   +  36  
      *
    -  39   +  37  
      * @author colezlaw
    -  40   +  38  
      */
    -  41   +  39  
     public class NexusSearch {
    +  40   +
     
    +  41   +
         /**
     42   -
     
    -  43   -
         /**
    -  44  
          * The root URL for the Nexus repository service.
    -  45   +  43  
          */
    -  46   +  44  
         private final URL rootURL;
    +  45   +
     
    +  46   +
         /**
     47   -
     
    -  48   -
         /**
    -  49  
          * Whether to use the Proxy when making requests.
    -  50   +  48  
          */
    -  51   +  49  
         private final boolean useProxy;
    -  52   +  50  
         /**
    -  53   +  51  
          * Used for logging.
    +  52   +
          */
    +  53  0
         private static final Logger LOGGER = LoggerFactory.getLogger(NexusSearch.class);
     54   -
          */
    -  55  0
         private static final Logger LOGGER = LoggerFactory.getLogger(NexusSearch.class);
    +
     
    +  55   +
         /**
     56   -
     
    -  57   -
         /**
    -  58  
          * Creates a NexusSearch for the given repository URL.
    -  59   +  57  
          *
    -  60   +  58  
          * @param rootURL the root URL of the repository on which searches should
    -  61   +  59  
          * execute. full URL's are calculated relative to this URL, so it should end
    -  62   +  60  
          * with a /
    -  63   +  61  
          * @param useProxy flag indicating if the proxy settings should be used
    -  64   +  62  
          */
    -  65  0
         public NexusSearch(URL rootURL, boolean useProxy) {
    -  66  0
             this.rootURL = rootURL;
    -  67  0
             this.useProxy = useProxy;
    -  68  0
             LOGGER.debug("Using proxy: {}", useProxy);
    -  69  0
         }
    -  70   +  63  0
         public NexusSearch(URL rootURL, boolean useProxy) {
    +  64  0
             this.rootURL = rootURL;
    +  65  0
             this.useProxy = useProxy;
    +  66  0
             LOGGER.debug("Using proxy: {}", useProxy);
    +  67  0
         }
    +  68  
     
    -  71   +  69  
         /**
    -  72   +  70  
          * Searches the configured Nexus repository for the given sha1 hash. If the
    -  73   +  71  
          * artifact is found, a <code>MavenArtifact</code> is populated with the
    -  74   +  72  
          * coordinate information.
    -  75   +  73  
          *
    -  76   +  74  
          * @param sha1 The SHA-1 hash string for which to search
    -  77   +  75  
          * @return the populated Maven coordinates
    -  78   +  76  
          * @throws IOException if it's unable to connect to the specified repository
    -  79   +  77  
          * or if the specified artifact is not found.
    -  80   +  78  
          */
    -  81   +  79  
         public MavenArtifact searchSha1(String sha1) throws IOException {
    -  82  0
             if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
    -  83  0
                 throw new IllegalArgumentException("Invalid SHA1 format");
    -  84   +  80  0
             if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
    +  81  0
                 throw new IllegalArgumentException("Invalid SHA1 format");
    +  82  
             }
    -  85   +  83  
     
    -  86  0
             final URL url = new URL(rootURL, String.format("identify/sha1/%s",
    -  87  0
                     sha1.toLowerCase()));
    +  84  0
             final URL url = new URL(rootURL, String.format("identify/sha1/%s",
    +  85  0
                     sha1.toLowerCase()));
    +  86   +
     
    +  87  0
             LOGGER.debug("Searching Nexus url {}", url);
     88  
     
    -  89  0
             LOGGER.debug("Searching Nexus url {}", url);
    -  90   -
     
    -  91   +  89  
             // Determine if we need to use a proxy. The rules:
    -  92   +  90  
             // 1) If the proxy is set, AND the setting is set to true, use the proxy
    -  93   +  91  
             // 2) Otherwise, don't use the proxy (either the proxy isn't configured,
    -  94   +  92  
             // or proxy is specifically set to false
    -  95   +  93  
             HttpURLConnection conn;
    -  96  0
             conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
    -  97  0
             conn.setDoOutput(true);
    -  98   +  94  0
             conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
    +  95  0
             conn.setDoOutput(true);
    +  96  
     
    -  99   +  97  
             // JSON would be more elegant, but there's not currently a dependency
    -  100   +  98  
             // on JSON, so don't want to add one just for this
    -  101  0
             conn.addRequestProperty("Accept", "application/xml");
    -  102  0
             conn.connect();
    -  103   +  99  0
             conn.addRequestProperty("Accept", "application/xml");
    +  100  0
             conn.connect();
    +  101  
     
    -  104  0
             switch (conn.getResponseCode()) {
    -  105   +  102  0
             switch (conn.getResponseCode()) {
    +  103  
                 case 200:
    -  106   +  104  
                     try {
    -  107  0
                         final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    -  108  0
                         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  109  0
                         final DocumentBuilder builder = factory.newDocumentBuilder();
    -  110  0
                         final Document doc = builder.parse(conn.getInputStream());
    -  111  0
                         final XPath xpath = XPathFactory.newInstance().newXPath();
    -  112  0
                         final String groupId = xpath
    -  113  0
                                 .evaluate(
    -  114   +  105  0
                         final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder();
    +  106  0
                         final Document doc = builder.parse(conn.getInputStream());
    +  107  0
                         final XPath xpath = XPathFactory.newInstance().newXPath();
    +  108  0
                         final String groupId = xpath
    +  109  0
                                 .evaluate(
    +  110  
                                         "/org.sonatype.nexus.rest.model.NexusArtifact/groupId",
    -  115   +  111  
                                         doc);
    -  116  0
                         final String artifactId = xpath.evaluate(
    -  117   +  112  0
                         final String artifactId = xpath.evaluate(
    +  113  
                                 "/org.sonatype.nexus.rest.model.NexusArtifact/artifactId",
    -  118   +  114  
                                 doc);
    -  119  0
                         final String version = xpath
    +  115  0
                         final String version = xpath
    +  116  0
                                 .evaluate(
    +  117   +
                                         "/org.sonatype.nexus.rest.model.NexusArtifact/version",
    +  118   +
                                         doc);
    +  119  0
                         final String link = xpath
     120  0
                                 .evaluate(
     121   -
                                         "/org.sonatype.nexus.rest.model.NexusArtifact/version",
    +
                                         "/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
     122  
                                         doc);
    -  123  0
                         final String link = xpath
    +  123  0
                         final String pomLink = xpath
     124  0
                                 .evaluate(
     125   -
                                         "/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
    +
                                         "/org.sonatype.nexus.rest.model.NexusArtifact/pomLink",
     126  
                                         doc);
    -  127  0
                         final String pomLink = xpath
    -  128  0
                                 .evaluate(
    -  129   -
                                         "/org.sonatype.nexus.rest.model.NexusArtifact/pomLink",
    +  127  0
                         final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
    +  128  0
                         if (link != null && !link.isEmpty()) {
    +  129  0
                             ma.setArtifactUrl(link);
     130   -
                                         doc);
    -  131  0
                         final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
    -  132  0
                         if (link != null && !link.isEmpty()) {
    -  133  0
                             ma.setArtifactUrl(link);
    -  134  
                         }
    -  135  0
                         if (pomLink != null && !pomLink.isEmpty()) {
    -  136  0
                             ma.setPomUrl(pomLink);
    -  137   +  131  0
                         if (pomLink != null && !pomLink.isEmpty()) {
    +  132  0
                             ma.setPomUrl(pomLink);
    +  133  
                         }
    -  138  0
                         return ma;
    -  139  0
                     } catch (Throwable e) {
    -  140   +  134  0
                         return ma;
    +  135  0
                     } catch (Throwable e) {
    +  136  
                         // Anything else is jacked-up XML stuff that we really can't recover
    -  141   +  137  
                         // from well
    -  142  0
                         throw new IOException(e.getMessage(), e);
    -  143   +  138  0
                         throw new IOException(e.getMessage(), e);
    +  139  
                     }
    -  144   +  140  
                 case 404:
    -  145  0
                     throw new FileNotFoundException("Artifact not found in Nexus");
    -  146   +  141  0
                     throw new FileNotFoundException("Artifact not found in Nexus");
    +  142  
                 default:
    -  147  0
                     LOGGER.debug("Could not connect to Nexus received response code: {} {}",
    -  148  0
                             conn.getResponseCode(), conn.getResponseMessage());
    -  149  0
                     throw new IOException("Could not connect to Nexus");
    -  150   +  143  0
                     LOGGER.debug("Could not connect to Nexus received response code: {} {}",
    +  144  0
                             conn.getResponseCode(), conn.getResponseMessage());
    +  145  0
                     throw new IOException("Could not connect to Nexus");
    +  146  
             }
    -  151   +  147  
         }
    -  152   +  148  
     
    -  153   +  149  
         /**
    -  154   +  150  
          * Do a preflight request to see if the repository is actually working.
    -  155   +  151  
          *
    -  156   +  152  
          * @return whether the repository is listening and returns the /status URL
    -  157   +  153  
          * correctly
    -  158   +  154  
          */
    -  159   +  155  
         public boolean preflightRequest() {
    -  160   +  156  
             HttpURLConnection conn;
    -  161   +  157  
             try {
    -  162  0
                 final URL url = new URL(rootURL, "status");
    -  163  0
                 conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
    -  164  0
                 conn.addRequestProperty("Accept", "application/xml");
    -  165  0
                 conn.connect();
    -  166  0
                 if (conn.getResponseCode() != 200) {
    -  167  0
                     LOGGER.warn("Expected 200 result from Nexus, got {}", conn.getResponseCode());
    -  168  0
                     return false;
    -  169   +  158  0
                 final URL url = new URL(rootURL, "status");
    +  159  0
                 conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
    +  160  0
                 conn.addRequestProperty("Accept", "application/xml");
    +  161  0
                 conn.connect();
    +  162  0
                 if (conn.getResponseCode() != 200) {
    +  163  0
                     LOGGER.warn("Expected 200 result from Nexus, got {}", conn.getResponseCode());
    +  164  0
                     return false;
    +  165  
                 }
    -  170  0
                 final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    -  171  0
                 final Document doc = builder.parse(conn.getInputStream());
    -  172  0
                 if (!"status".equals(doc.getDocumentElement().getNodeName())) {
    -  173  0
                     LOGGER.warn("Expected root node name of status, got {}", doc.getDocumentElement().getNodeName());
    -  174  0
                     return false;
    -  175   -
                 }
    -  176  0
             } catch (Throwable e) {
    -  177  0
                 return false;
    -  178  0
             }
    -  179   +  166  0
                 final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder();
    +  167  
     
    -  180  0
             return true;
    -  181   +  168  0
                 final Document doc = builder.parse(conn.getInputStream());
    +  169  0
                 if (!"status".equals(doc.getDocumentElement().getNodeName())) {
    +  170  0
                     LOGGER.warn("Expected root node name of status, got {}", doc.getDocumentElement().getNodeName());
    +  171  0
                     return false;
    +  172   +
                 }
    +  173  0
             } catch (Throwable e) {
    +  174  0
                 return false;
    +  175  0
             }
    +  176   +
     
    +  177  0
             return true;
    +  178  
         }
    -  182   +  179  
     }
    -  183   +  180  
     
    -  184   +  181  
     // vim: cc=120:sw=4:ts=4:sts=4
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NugetPackage.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NugetPackage.html index 86a0975f2..ade7073a8 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NugetPackage.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NugetPackage.html @@ -352,6 +352,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParseException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParseException.html index 589605ed5..64788f521 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParseException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParseException.html @@ -147,6 +147,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParser.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParser.html index 6d83da5d4..446e248ee 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParser.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.NuspecParser.html @@ -93,6 +93,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.XPathNuspecParser.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.XPathNuspecParser.html index 63528ce2a..06e28b685 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.XPathNuspecParser.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nuget.XPathNuspecParser.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    XPathNuspecParser
    95%
    22/23
    60%
    6/10
    6
    XPathNuspecParser
    95%
    21/22
    60%
    6/10
    6
     
    @@ -58,7 +58,7 @@  20  
     import java.io.InputStream;
     21   -
     import javax.xml.parsers.DocumentBuilderFactory;
    +
     import javax.xml.parsers.DocumentBuilder;
     22  
     import javax.xml.xpath.XPath;
     23   @@ -66,74 +66,75 @@  24  
     import javax.xml.xpath.XPathFactory;
     25   -
     import org.w3c.dom.Document;
    +
     import org.owasp.dependencycheck.utils.XmlUtils;
     26   -
     import org.w3c.dom.Node;
    +
     import org.w3c.dom.Document;
     27   -
     
    +
     import org.w3c.dom.Node;
     28   -
     /**
    +
     
     29   -
      * Parse a Nuspec file using XPath.
    +
     /**
     30   -
      *
    +
      * Parse a Nuspec file using XPath.
     31   -
      * @author colezlaw
    +
      *
     32   +
      * @author colezlaw
    +  33  
      */
    -  33  3
     public class XPathNuspecParser implements NuspecParser {
    -  34   -
     
    +  34  3
     public class XPathNuspecParser implements NuspecParser {
     35   -
         /**
    -  36   -
          * Gets the string value of a node or null if it's not present
    -  37   -
          *
    -  38   -
          * @param n the node to test
    -  39   -
          * @return the string content of the node, or null if the node itself is
    -  40   -
          * null
    -  41   -
          */
    -  42   -
         private String getOrNull(Node n) {
    -  43  3
             if (n != null) {
    -  44  3
                 return n.getTextContent();
    -  45   -
             } else {
    -  46  0
                 return null;
    -  47   -
             }
    -  48   -
         }
    -  49  
     
    -  50   +  36  
         /**
    -  51   -
          * Parse an input stream and return the resulting {@link NugetPackage}.
    -  52   +  37   +
          * Gets the string value of a node or null if it's not present
    +  38  
          *
    -  53   -
          * @param stream the input stream to parse
    -  54   -
          * @return the populated bean
    -  55   -
          * @throws NuspecParseException when an exception occurs
    -  56   +  39   +
          * @param n the node to test
    +  40   +
          * @return the string content of the node, or null if the node itself is
    +  41   +
          * null
    +  42  
          */
    +  43   +
         private String getOrNull(Node n) {
    +  44  3
             if (n != null) {
    +  45  3
                 return n.getTextContent();
    +  46   +
             } else {
    +  47  0
                 return null;
    +  48   +
             }
    +  49   +
         }
    +  50   +
     
    +  51   +
         /**
    +  52   +
          * Parse an input stream and return the resulting {@link NugetPackage}.
    +  53   +
          *
    +  54   +
          * @param stream the input stream to parse
    +  55   +
          * @return the populated bean
    +  56   +
          * @throws NuspecParseException when an exception occurs
     57   -
         @Override
    +
          */
     58   -
         public NugetPackage parse(InputStream stream) throws NuspecParseException {
    +
         @Override
     59   +
         public NugetPackage parse(InputStream stream) throws NuspecParseException {
    +  60  
             try {
    -  60  3
                 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    -  61  3
                 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  62  3
                 final Document d = factory.newDocumentBuilder().parse(stream);
    +  61  3
                 final DocumentBuilder db = XmlUtils.buildSecureDocumentBuilder();
    +  62  3
                 final Document d = db.parse(stream);
     63  
     
     64  2
                 final XPath xpath = XPathFactory.newInstance().newXPath();
    @@ -166,6 +167,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.ConnectionFactory.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.ConnectionFactory.html index 29e107c5b..29800fdfd 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.ConnectionFactory.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.ConnectionFactory.html @@ -644,6 +644,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CorruptDatabaseException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CorruptDatabaseException.html index 7c79a3ae3..24086bfd1 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CorruptDatabaseException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CorruptDatabaseException.html @@ -115,6 +115,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CveDB.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CveDB.html index dae116f8e..c1f84d018 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CveDB.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.CveDB.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    CveDB
    45%
    201/437
    52%
    74/140
    5.636
    CveDB
    47%
    206/437
    57%
    80/140
    5.636
     
    @@ -220,7 +220,7 @@
          */
     111  
         protected Connection getConnection() {
    -  112  47
             return conn;
    +  112  50
             return conn;
     113  
         }
     114   @@ -258,7 +258,7 @@
          */
     132  
         public synchronized void close() {
    -  133  22
             if (conn != null) {
    +  133  26
             if (conn != null) {
     134  
                 try {
     135  13
                     conn.close();
    @@ -272,7 +272,7 @@  143  13
                 conn = null;
     144  
             }
    -  145  22
         }
    +  145  26
         }
     146  
     
     147   @@ -331,10 +331,10 @@
         @SuppressWarnings("FinalizeDeclaration")
     175  
         protected void finalize() throws Throwable {
    -  176  9
             LOGGER.debug("Entering finalize");
    -  177  9
             close();
    -  178  9
             super.finalize();
    -  179  9
         }
    +  176  13
             LOGGER.debug("Entering finalize");
    +  177  13
             close();
    +  178  13
             super.finalize();
    +  179  13
         }
     180  
         /**
     181   @@ -397,11 +397,11 @@  213  4
                 rs = ps.executeQuery();
     214  
     
    -  215  134
                 while (rs.next()) {
    -  216  130
                     final VulnerableSoftware vs = new VulnerableSoftware();
    -  217  130
                     vs.setCpe(rs.getString(1));
    -  218  130
                     cpe.add(vs);
    -  219  130
                 }
    +  215  152
                 while (rs.next()) {
    +  216  148
                     final VulnerableSoftware vs = new VulnerableSoftware();
    +  217  148
                     vs.setCpe(rs.getString(1));
    +  218  148
                     cpe.add(vs);
    +  219  148
                 }
     220  0
             } catch (SQLException ex) {
     221  0
                 LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
     222  0
                 LOGGER.debug("", ex);
    @@ -438,8 +438,8 @@
             try {
     242  2
                 ps = getConnection().prepareStatement(statementBundle.getString("SELECT_VENDOR_PRODUCT_LIST"));
     243  2
                 rs = ps.executeQuery();
    -  244  52776
                 while (rs.next()) {
    -  245  52774
                     data.add(new Pair<String, String>(rs.getString(1), rs.getString(2)));
    +  244  53116
                 while (rs.next()) {
    +  245  53114
                     data.add(new Pair<String, String>(rs.getString(1), rs.getString(2)));
     246  
                 }
     247  0
             } catch (SQLException ex) {
    @@ -474,8 +474,8 @@
             try {
     267  13
                 ps = getConnection().prepareStatement(statementBundle.getString("SELECT_PROPERTIES"));
     268  13
                 rs = ps.executeQuery();
    -  269  273
                 while (rs.next()) {
    -  270  260
                     prop.setProperty(rs.getString(1), rs.getString(2));
    +  269  286
                 while (rs.next()) {
    +  270  273
                     prop.setProperty(rs.getString(1), rs.getString(2));
     271  
                 }
     272  0
             } catch (SQLException ex) {
    @@ -588,34 +588,34 @@  349  
     
     350  4
                 final Map<String, Boolean> vulnSoftware = new HashMap<String, Boolean>();
    -  351  309
                 while (rs.next()) {
    -  352  305
                     final String cveId = rs.getString(1);
    -  353  305
                     if (!currentCVE.equals(cveId)) { //check for match and add
    -  354  12
                         final Entry<String, Boolean> matchedCPE = getMatchingSoftware(vulnSoftware, cpe.getVendor(), cpe.getProduct(), detectedVersion);
    -  355  12
                         if (matchedCPE != null) {
    +  351  341
                 while (rs.next()) {
    +  352  337
                     final String cveId = rs.getString(1);
    +  353  337
                     if (!currentCVE.equals(cveId)) { //check for match and add
    +  354  13
                         final Entry<String, Boolean> matchedCPE = getMatchingSoftware(vulnSoftware, cpe.getVendor(), cpe.getProduct(), detectedVersion);
    +  355  13
                         if (matchedCPE != null) {
     356  6
                             final Vulnerability v = getVulnerability(currentCVE);
     357  6
                             v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
     358  6
                             vulnerabilities.add(v);
     359  
                         }
    -  360  12
                         vulnSoftware.clear();
    -  361  12
                         currentCVE = cveId;
    +  360  13
                         vulnSoftware.clear();
    +  361  13
                         currentCVE = cveId;
     362  
                     }
     363  
     
    -  364  305
                     final String cpeId = rs.getString(2);
    -  365  305
                     final String previous = rs.getString(3);
    -  366  305
                     final Boolean p = previous != null && !previous.isEmpty();
    -  367  305
                     vulnSoftware.put(cpeId, p);
    -  368  305
                 }
    +  364  337
                     final String cpeId = rs.getString(2);
    +  365  337
                     final String previous = rs.getString(3);
    +  366  337
                     final Boolean p = previous != null && !previous.isEmpty();
    +  367  337
                     vulnSoftware.put(cpeId, p);
    +  368  337
                 }
     369  
                 //remember to process the last set of CVE/CPE entries
     370  4
                 final Entry<String, Boolean> matchedCPE = getMatchingSoftware(vulnSoftware, cpe.getVendor(), cpe.getProduct(), detectedVersion);
     371  4
                 if (matchedCPE != null) {
    -  372  2
                     final Vulnerability v = getVulnerability(currentCVE);
    -  373  2
                     v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
    -  374  2
                     vulnerabilities.add(v);
    +  372  3
                     final Vulnerability v = getVulnerability(currentCVE);
    +  373  3
                     v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
    +  374  3
                     vulnerabilities.add(v);
     375  
                 }
     376  0
             } catch (SQLException ex) {
    @@ -646,79 +646,79 @@
          */
     392  
         public synchronized Vulnerability getVulnerability(String cve) throws DatabaseException {
    -  393  8
             PreparedStatement psV = null;
    -  394  8
             PreparedStatement psR = null;
    -  395  8
             PreparedStatement psS = null;
    -  396  8
             ResultSet rsV = null;
    -  397  8
             ResultSet rsR = null;
    -  398  8
             ResultSet rsS = null;
    -  399  8
             Vulnerability vuln = null;
    +  393  9
             PreparedStatement psV = null;
    +  394  9
             PreparedStatement psR = null;
    +  395  9
             PreparedStatement psS = null;
    +  396  9
             ResultSet rsV = null;
    +  397  9
             ResultSet rsR = null;
    +  398  9
             ResultSet rsS = null;
    +  399  9
             Vulnerability vuln = null;
     400  
     
     401  
             try {
    -  402  8
                 psV = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY"));
    -  403  8
                 psV.setString(1, cve);
    -  404  8
                 rsV = psV.executeQuery();
    -  405  8
                 if (rsV.next()) {
    -  406  8
                     vuln = new Vulnerability();
    -  407  8
                     vuln.setName(cve);
    -  408  8
                     vuln.setDescription(rsV.getString(2));
    -  409  8
                     String cwe = rsV.getString(3);
    -  410  8
                     if (cwe != null) {
    -  411  8
                         final String name = CweDB.getCweName(cwe);
    -  412  8
                         if (name != null) {
    -  413  7
                             cwe += ' ' + name;
    +  402  9
                 psV = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY"));
    +  403  9
                 psV.setString(1, cve);
    +  404  9
                 rsV = psV.executeQuery();
    +  405  9
                 if (rsV.next()) {
    +  406  9
                     vuln = new Vulnerability();
    +  407  9
                     vuln.setName(cve);
    +  408  9
                     vuln.setDescription(rsV.getString(2));
    +  409  9
                     String cwe = rsV.getString(3);
    +  410  9
                     if (cwe != null) {
    +  411  9
                         final String name = CweDB.getCweName(cwe);
    +  412  9
                         if (name != null) {
    +  413  8
                             cwe += ' ' + name;
     414  
                         }
     415  
                     }
    -  416  8
                     final int cveId = rsV.getInt(1);
    -  417  8
                     vuln.setCwe(cwe);
    -  418  8
                     vuln.setCvssScore(rsV.getFloat(4));
    -  419  8
                     vuln.setCvssAccessVector(rsV.getString(5));
    -  420  8
                     vuln.setCvssAccessComplexity(rsV.getString(6));
    -  421  8
                     vuln.setCvssAuthentication(rsV.getString(7));
    -  422  8
                     vuln.setCvssConfidentialityImpact(rsV.getString(8));
    -  423  8
                     vuln.setCvssIntegrityImpact(rsV.getString(9));
    -  424  8
                     vuln.setCvssAvailabilityImpact(rsV.getString(10));
    +  416  9
                     final int cveId = rsV.getInt(1);
    +  417  9
                     vuln.setCwe(cwe);
    +  418  9
                     vuln.setCvssScore(rsV.getFloat(4));
    +  419  9
                     vuln.setCvssAccessVector(rsV.getString(5));
    +  420  9
                     vuln.setCvssAccessComplexity(rsV.getString(6));
    +  421  9
                     vuln.setCvssAuthentication(rsV.getString(7));
    +  422  9
                     vuln.setCvssConfidentialityImpact(rsV.getString(8));
    +  423  9
                     vuln.setCvssIntegrityImpact(rsV.getString(9));
    +  424  9
                     vuln.setCvssAvailabilityImpact(rsV.getString(10));
     425  
     
    -  426  8
                     psR = getConnection().prepareStatement(statementBundle.getString("SELECT_REFERENCES"));
    -  427  8
                     psR.setInt(1, cveId);
    -  428  8
                     rsR = psR.executeQuery();
    -  429  76
                     while (rsR.next()) {
    -  430  68
                         vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
    +  426  9
                     psR = getConnection().prepareStatement(statementBundle.getString("SELECT_REFERENCES"));
    +  427  9
                     psR.setInt(1, cveId);
    +  428  9
                     rsR = psR.executeQuery();
    +  429  80
                     while (rsR.next()) {
    +  430  71
                         vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
     431  
                     }
    -  432  8
                     psS = getConnection().prepareStatement(statementBundle.getString("SELECT_SOFTWARE"));
    -  433  8
                     psS.setInt(1, cveId);
    -  434  8
                     rsS = psS.executeQuery();
    -  435  244
                     while (rsS.next()) {
    -  436  236
                         final String cpe = rsS.getString(1);
    -  437  236
                         final String prevVersion = rsS.getString(2);
    -  438  236
                         if (prevVersion == null) {
    -  439  228
                             vuln.addVulnerableSoftware(cpe);
    +  432  9
                     psS = getConnection().prepareStatement(statementBundle.getString("SELECT_SOFTWARE"));
    +  433  9
                     psS.setInt(1, cveId);
    +  434  9
                     rsS = psS.executeQuery();
    +  435  277
                     while (rsS.next()) {
    +  436  268
                         final String cpe = rsS.getString(1);
    +  437  268
                         final String prevVersion = rsS.getString(2);
    +  438  268
                         if (prevVersion == null) {
    +  439  259
                             vuln.addVulnerableSoftware(cpe);
     440  
                         } else {
    -  441  8
                             vuln.addVulnerableSoftware(cpe, prevVersion);
    +  441  9
                             vuln.addVulnerableSoftware(cpe, prevVersion);
     442  
                         }
    -  443  236
                     }
    +  443  268
                     }
     444  
                 }
     445  0
             } catch (SQLException ex) {
     446  0
                 throw new DatabaseException("Error retrieving " + cve, ex);
     447  
             } finally {
    -  448  8
                 DBUtils.closeResultSet(rsV);
    -  449  8
                 DBUtils.closeResultSet(rsR);
    -  450  8
                 DBUtils.closeResultSet(rsS);
    -  451  8
                 DBUtils.closeStatement(psV);
    -  452  8
                 DBUtils.closeStatement(psR);
    -  453  8
                 DBUtils.closeStatement(psS);
    -  454  8
             }
    -  455  8
             return vuln;
    +  448  9
                 DBUtils.closeResultSet(rsV);
    +  449  9
                 DBUtils.closeResultSet(rsR);
    +  450  9
                 DBUtils.closeResultSet(rsS);
    +  451  9
                 DBUtils.closeStatement(psV);
    +  452  9
                 DBUtils.closeStatement(psR);
    +  453  9
                 DBUtils.closeStatement(psS);
    +  454  9
             }
    +  455  9
             return vuln;
     456  
         }
     457   @@ -1065,48 +1065,48 @@
                 DependencyVersion identifiedVersion) {
     708  
     
    -  709  16
             final boolean isVersionTwoADifferentProduct = "apache".equals(vendor) && "struts".equals(product);
    +  709  17
             final boolean isVersionTwoADifferentProduct = "apache".equals(vendor) && "struts".equals(product);
     710  
     
    -  711  16
             final Set<String> majorVersionsAffectingAllPrevious = new HashSet<String>();
    -  712  16
             final boolean matchesAnyPrevious = identifiedVersion == null || "-".equals(identifiedVersion.toString());
    -  713  16
             String majorVersionMatch = null;
    -  714  16
             for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
    -  715  305
                 final DependencyVersion v = parseDependencyVersion(entry.getKey());
    -  716  305
                 if (v == null || "-".equals(v.toString())) { //all versions
    +  711  17
             final Set<String> majorVersionsAffectingAllPrevious = new HashSet<String>();
    +  712  17
             final boolean matchesAnyPrevious = identifiedVersion == null || "-".equals(identifiedVersion.toString());
    +  713  17
             String majorVersionMatch = null;
    +  714  17
             for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
    +  715  337
                 final DependencyVersion v = parseDependencyVersion(entry.getKey());
    +  716  337
                 if (v == null || "-".equals(v.toString())) { //all versions
     717  0
                     return entry;
     718  
                 }
    -  719  305
                 if (entry.getValue()) {
    -  720  8
                     if (matchesAnyPrevious) {
    +  719  337
                 if (entry.getValue()) {
    +  720  9
                     if (matchesAnyPrevious) {
     721  0
                         return entry;
     722  
                     }
    -  723  8
                     if (identifiedVersion != null && identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0))) {
    -  724  6
                         majorVersionMatch = v.getVersionParts().get(0);
    +  723  9
                     if (identifiedVersion != null && identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0))) {
    +  724  7
                         majorVersionMatch = v.getVersionParts().get(0);
     725  
                     }
    -  726  8
                     majorVersionsAffectingAllPrevious.add(v.getVersionParts().get(0));
    +  726  9
                     majorVersionsAffectingAllPrevious.add(v.getVersionParts().get(0));
     727  
                 }
    -  728  305
             }
    -  729  16
             if (matchesAnyPrevious) {
    +  728  337
             }
    +  729  17
             if (matchesAnyPrevious) {
     730  0
                 return null;
     731  
             }
     732  
     
    -  733  16
             final boolean canSkipVersions = majorVersionMatch != null && majorVersionsAffectingAllPrevious.size() > 1;
    +  733  17
             final boolean canSkipVersions = majorVersionMatch != null && majorVersionsAffectingAllPrevious.size() > 1;
     734  
             //yes, we are iterating over this twice. The first time we are skipping versions those that affect all versions
     735  
             //then later we process those that affect all versions. This could be done with sorting...
    -  736  16
             for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
    -  737  263
                 if (!entry.getValue()) {
    -  738  255
                     final DependencyVersion v = parseDependencyVersion(entry.getKey());
    +  736  17
             for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
    +  737  295
                 if (!entry.getValue()) {
    +  738  286
                     final DependencyVersion v = parseDependencyVersion(entry.getKey());
     739  
                     //this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
    -  740  255
                     if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
    +  740  286
                     if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
     741  8
                         continue;
     742  
                     }
    @@ -1114,19 +1114,19 @@
                     //this can't dereference a null 'identifiedVersion' because if it was null we would have exited
     744  
                     //in the above loop or just after loop (if matchesAnyPrevious return null).
    -  745  247
                     if (identifiedVersion.equals(v)) {
    +  745  278
                     if (identifiedVersion.equals(v)) {
     746  8
                         return entry;
     747  
                     }
     748  
                 }
    -  749  247
             }
    -  750  8
             for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
    -  751  82
                 if (entry.getValue()) {
    -  752  0
                     final DependencyVersion v = parseDependencyVersion(entry.getKey());
    +  749  279
             }
    +  750  9
             for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
    +  751  105
                 if (entry.getValue()) {
    +  752  1
                     final DependencyVersion v = parseDependencyVersion(entry.getKey());
     753  
                     //this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
    -  754  0
                     if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
    +  754  1
                     if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
     755  0
                         continue;
     756  
                     }
    @@ -1134,16 +1134,16 @@
                     //this can't dereference a null 'identifiedVersion' because if it was null we would have exited
     758  
                     //in the above loop or just after loop (if matchesAnyPrevious return null).
    -  759  0
                     if (entry.getValue() && identifiedVersion.compareTo(v) <= 0) {
    -  760  0
                         if (!(isVersionTwoADifferentProduct && !identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0)))) {
    -  761  0
                             return entry;
    +  759  1
                     if (entry.getValue() && identifiedVersion.compareTo(v) <= 0) {
    +  760  1
                         if (!(isVersionTwoADifferentProduct && !identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0)))) {
    +  761  1
                             return entry;
     762  
                         }
     763  
                     }
     764  
                 }
    -  765  82
             }
    +  765  104
             }
     766  8
             return null;
     767  
         }
    @@ -1165,16 +1165,16 @@
          */
     776  
         private DependencyVersion parseDependencyVersion(String cpeStr) {
    -  777  560
             final VulnerableSoftware cpe = new VulnerableSoftware();
    +  777  624
             final VulnerableSoftware cpe = new VulnerableSoftware();
     778  
             try {
    -  779  560
                 cpe.parseName(cpeStr);
    +  779  624
                 cpe.parseName(cpeStr);
     780  0
             } catch (UnsupportedEncodingException ex) {
     781  
                 //never going to happen.
     782  0
                 LOGGER.trace("", ex);
    -  783  560
             }
    -  784  560
             return parseDependencyVersion(cpe);
    +  783  624
             }
    +  784  624
             return parseDependencyVersion(cpe);
     785  
         }
     786   @@ -1197,22 +1197,22 @@
         private DependencyVersion parseDependencyVersion(VulnerableSoftware cpe) {
     795  
             final DependencyVersion cpeVersion;
    -  796  564
             if (cpe.getVersion() != null && !cpe.getVersion().isEmpty()) {
    +  796  628
             if (cpe.getVersion() != null && !cpe.getVersion().isEmpty()) {
     797  
                 final String versionText;
    -  798  564
                 if (cpe.getUpdate() != null && !cpe.getUpdate().isEmpty()) {
    +  798  628
                 if (cpe.getUpdate() != null && !cpe.getUpdate().isEmpty()) {
     799  113
                     versionText = String.format("%s.%s", cpe.getVersion(), cpe.getUpdate());
     800  
                 } else {
    -  801  451
                     versionText = cpe.getVersion();
    +  801  515
                     versionText = cpe.getVersion();
     802  
                 }
    -  803  564
                 cpeVersion = DependencyVersionUtil.parseVersion(versionText);
    -  804  564
             } else {
    +  803  628
                 cpeVersion = DependencyVersionUtil.parseVersion(versionText);
    +  804  628
             } else {
     805  0
                 cpeVersion = new DependencyVersion("-");
     806  
             }
    -  807  564
             return cpeVersion;
    +  807  628
             return cpeVersion;
     808  
         }
     809   @@ -1284,6 +1284,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseException.html index 7c07e2d31..7b02fcba8 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseException.html @@ -131,6 +131,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.html index 258405de5..5ff284c8a 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.html @@ -56,19 +56,19 @@  19  
     
     20   -
     import java.text.DateFormat;
    -  21   -
     import java.text.SimpleDateFormat;
    -  22   -
     import java.util.Date;
    -  23  
     import java.util.Map;
    -  24   +  21  
     import java.util.Map.Entry;
    -  25   +  22  
     import java.util.Properties;
    -  26   +  23  
     import java.util.TreeMap;
    +  24   +
     import org.joda.time.DateTime;
    +  25   +
     import org.joda.time.format.DateTimeFormat;
    +  26   +
     import org.joda.time.format.DateTimeFormatter;
     27  
     import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
     28   @@ -103,9 +103,9 @@  43  
         /**
     44   -
          * Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8 days of
    +
          * Modified key word, used as a key to store information about the modified
     45   -
          * updates)..
    +
          * file (i.e. the containing the last 8 days of updates)..
     46  
          */
     47   @@ -113,245 +113,261 @@  48  
         /**
     49   -
          * The properties file key for the last checked field - used to store the last check time of the Modified NVD CVE xml file.
    +
          * The properties file key for the last checked field - used to store the
     50   -
          */
    +
          * last check time of the Modified NVD CVE xml file.
     51   -
         public static final String LAST_CHECKED = "NVD CVE Checked";
    +
          */
     52   -
         /**
    +
         public static final String LAST_CHECKED = "NVD CVE Checked";
     53   -
          * The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE xml file.
    +
         /**
     54   -
          */
    +
          * The properties file key for the last updated field - used to store the
     55   -
         public static final String LAST_UPDATED = "NVD CVE Modified";
    +
          * last updated time of the Modified NVD CVE xml file.
     56   -
         /**
    +
          */
     57   -
          * Stores the last updated time for each of the NVD CVE files. These timestamps should be updated if we process the modified
    +
         public static final String LAST_UPDATED = "NVD CVE Modified";
     58   -
          * file within 7 days of the last update.
    +
         /**
     59   -
          */
    +
          * Stores the last updated time for each of the NVD CVE files. These
     60   -
         public static final String LAST_UPDATED_BASE = "NVD CVE ";
    +
          * timestamps should be updated if we process the modified file within 7
     61   -
         /**
    +
          * days of the last update.
     62   -
          * The key for the last time the CPE data was updated.
    +
          */
     63   -
          */
    +
         public static final String LAST_UPDATED_BASE = "NVD CVE ";
     64   -
         public static final String LAST_CPE_UPDATE = "LAST_CPE_UPDATE";
    +
         /**
     65   -
         /**
    +
          * The key for the last time the CPE data was updated.
     66   -
          * The key for the database schema version.
    +
          */
     67   -
          */
    +
         public static final String LAST_CPE_UPDATE = "LAST_CPE_UPDATE";
     68   -
         public static final String VERSION = "version";
    +
         /**
     69   -
     
    +
          * The key for the database schema version.
     70   -
         /**
    +
          */
     71   -
          * A collection of properties about the data.
    +
         public static final String VERSION = "version";
     72   -
          */
    +
     
     73   -
         private final Properties properties;
    +
         /**
     74   -
         /**
    +
          * A collection of properties about the data.
     75   -
          * A reference to the database.
    +
          */
     76   -
          */
    +
         private final Properties properties;
     77   -
         private final CveDB cveDB;
    +
         /**
     78   -
     
    +
          * A reference to the database.
     79   -
         /**
    +
          */
     80   -
          * Constructs a new data properties object.
    +
         private final CveDB cveDB;
     81   -
          *
    +
     
     82   -
          * @param cveDB the database object holding the properties
    +
         /**
     83   +
          * Constructs a new data properties object.
    +  84   +
          *
    +  85   +
          * @param cveDB the database object holding the properties
    +  86  
          */
    -  84  13
         DatabaseProperties(CveDB cveDB) {
    -  85  13
             this.cveDB = cveDB;
    -  86  13
             this.properties = cveDB.getProperties();
    -  87  13
         }
    -  88   -
     
    -  89   -
         /**
    -  90   -
          * Returns whether or not any properties are set.
    +  87  13
         DatabaseProperties(CveDB cveDB) {
    +  88  13
             this.cveDB = cveDB;
    +  89  13
             this.properties = cveDB.getProperties();
    +  90  13
         }
     91   -
          *
    +
     
     92   -
          * @return whether or not any properties are set
    +
         /**
     93   -
          */
    +
          * Returns whether or not any properties are set.
     94   -
         public boolean isEmpty() {
    -  95  0
             return properties == null || properties.isEmpty();
    +
          *
    +  95   +
          * @return whether or not any properties are set
     96   -
         }
    +
          */
     97   -
     
    -  98   -
         /**
    +
         public boolean isEmpty() {
    +  98  0
             return properties == null || properties.isEmpty();
     99   -
          * Saves the last updated information to the properties file.
    +
         }
     100   -
          *
    +
     
     101   -
          * @param updatedValue the updated NVD CVE entry
    +
         /**
     102   -
          * @throws UpdateException is thrown if there is an update exception
    +
          * Saves the last updated information to the properties file.
     103   -
          */
    +
          *
     104   -
         public void save(NvdCveInfo updatedValue) throws UpdateException {
    -  105  0
             if (updatedValue == null) {
    -  106  0
                 return;
    -  107   -
             }
    -  108  0
             save(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
    -  109  0
         }
    -  110   -
     
    -  111   -
         /**
    -  112   -
          * Saves the key value pair to the properties store.
    -  113   -
          *
    -  114   -
          * @param key the property key
    -  115   -
          * @param value the property value
    -  116   +
          * @param updatedValue the updated NVD CVE entry
    +  105  
          * @throws UpdateException is thrown if there is an update exception
    +  106   +
          */
    +  107   +
         public void save(NvdCveInfo updatedValue) throws UpdateException {
    +  108  0
             if (updatedValue == null) {
    +  109  0
                 return;
    +  110   +
             }
    +  111  0
             save(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
    +  112  0
         }
    +  113   +
     
    +  114   +
         /**
    +  115   +
          * Saves the key value pair to the properties store.
    +  116   +
          *
     117   -
          */
    +
          * @param key the property key
     118   +
          * @param value the property value
    +  119   +
          * @throws UpdateException is thrown if there is an update exception
    +  120   +
          */
    +  121  
         public void save(String key, String value) throws UpdateException {
    -  119  0
             properties.put(key, value);
    -  120  0
             cveDB.saveProperty(key, value);
    -  121  0
         }
    -  122   -
     
    -  123   -
         /**
    -  124   -
          * Returns the property value for the given key. If the key is not contained in the underlying properties null is returned.
    +  122  0
             properties.put(key, value);
    +  123  0
             cveDB.saveProperty(key, value);
    +  124  0
         }
     125   -
          *
    +
     
     126   -
          * @param key the property key
    +
         /**
     127   -
          * @return the value of the property
    +
          * Returns the property value for the given key. If the key is not contained
     128   -
          */
    +
          * in the underlying properties null is returned.
     129   -
         public String getProperty(String key) {
    -  130  0
             return properties.getProperty(key);
    -  131   -
         }
    -  132   -
     
    -  133   -
         /**
    -  134   -
          * Returns the property value for the given key. If the key is not contained in the underlying properties the default value is
    -  135   -
          * returned.
    -  136  
          *
    -  137   +  130  
          * @param key the property key
    -  138   -
          * @param defaultValue the default value
    -  139   +  131  
          * @return the value of the property
    +  132   +
          */
    +  133   +
         public String getProperty(String key) {
    +  134  0
             return properties.getProperty(key);
    +  135   +
         }
    +  136   +
     
    +  137   +
         /**
    +  138   +
          * Returns the property value for the given key. If the key is not contained
    +  139   +
          * in the underlying properties the default value is returned.
     140   -
          */
    +
          *
     141   -
         public String getProperty(String key, String defaultValue) {
    -  142  0
             return properties.getProperty(key, defaultValue);
    +
          * @param key the property key
    +  142   +
          * @param defaultValue the default value
     143   -
         }
    +
          * @return the value of the property
     144   -
     
    +
          */
     145   -
         /**
    -  146   -
          * Returns the collection of Database Properties as a properties collection.
    +
         public String getProperty(String key, String defaultValue) {
    +  146  0
             return properties.getProperty(key, defaultValue);
     147   -
          *
    +
         }
     148   -
          * @return the collection of Database Properties
    -  149   -
          */
    -  150   -
         public Properties getProperties() {
    -  151  1
             return properties;
    -  152   -
         }
    -  153  
     
    -  154   +  149  
         /**
    -  155   -
          * Returns a map of the meta data from the database properties. This primarily contains timestamps of when the NVD CVE
    -  156   -
          * information was last updated.
    -  157   +  150   +
          * Returns the collection of Database Properties as a properties collection.
    +  151  
          *
    -  158   -
          * @return a map of the database meta data
    -  159   +  152   +
          * @return the collection of Database Properties
    +  153  
          */
    -  160   -
         public Map<String, String> getMetaData() {
    -  161  0
             final Map<String, String> map = new TreeMap<String, String>();
    -  162  0
             for (Entry<Object, Object> entry : properties.entrySet()) {
    -  163  0
                 final String key = (String) entry.getKey();
    -  164  0
                 if (!"version".equals(key)) {
    -  165  0
                     if (key.startsWith("NVD CVE ")) {
    -  166   -
                         try {
    -  167  0
                             final long epoch = Long.parseLong((String) entry.getValue());
    -  168  0
                             final Date date = new Date(epoch);
    -  169  0
                             final DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    -  170  0
                             final String formatted = format.format(date);
    -  171  0
                             map.put(key, formatted);
    -  172  0
                         } catch (Throwable ex) { //deliberately being broad in this catch clause
    -  173  0
                             LOGGER.debug("Unable to parse timestamp from DB", ex);
    -  174  0
                             map.put(key, (String) entry.getValue());
    -  175  0
                         }
    -  176   -
                     } else {
    -  177  0
                         map.put(key, (String) entry.getValue());
    -  178   -
                     }
    -  179   -
                 }
    -  180  0
             }
    -  181  0
             return map;
    -  182   +  154   +
         public Properties getProperties() {
    +  155  1
             return properties;
    +  156  
         }
    -  183   +  157   +
     
    +  158   +
         /**
    +  159   +
          * Returns a map of the meta data from the database properties. This
    +  160   +
          * primarily contains timestamps of when the NVD CVE information was last
    +  161   +
          * updated.
    +  162   +
          *
    +  163   +
          * @return a map of the database meta data
    +  164   +
          */
    +  165   +
         public Map<String, String> getMetaData() {
    +  166  0
             final Map<String, String> map = new TreeMap<String, String>();
    +  167  0
             for (Entry<Object, Object> entry : properties.entrySet()) {
    +  168  0
                 final String key = (String) entry.getKey();
    +  169  0
                 if (!"version".equals(key)) {
    +  170  0
                     if (key.startsWith("NVD CVE ")) {
    +  171   +
                         try {
    +  172  0
                             final long epoch = Long.parseLong((String) entry.getValue());
    +  173  0
                             final DateTime date = new DateTime(epoch);
    +  174  0
                             final DateTimeFormatter format = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
    +  175  0
                             final String formatted = format.print(date);
    +  176   +
     //                        final Date date = new Date(epoch);
    +  177   +
     //                        final DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    +  178   +
     //                        final String formatted = format.format(date);
    +  179  0
                             map.put(key, formatted);
    +  180  0
                         } catch (Throwable ex) { //deliberately being broad in this catch clause
    +  181  0
                             LOGGER.debug("Unable to parse timestamp from DB", ex);
    +  182  0
                             map.put(key, (String) entry.getValue());
    +  183  0
                         }
    +  184   +
                     } else {
    +  185  0
                         map.put(key, (String) entry.getValue());
    +  186   +
                     }
    +  187   +
                 }
    +  188  0
             }
    +  189  0
             return map;
    +  190   +
         }
    +  191  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoadException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoadException.html index d777765f0..99572e51b 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoadException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoadException.html @@ -131,6 +131,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoader.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoader.html index d0f6df8f7..495f50352 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoader.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverLoader.html @@ -269,6 +269,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverShim.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverShim.html index 675a6606b..c9cc91452 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverShim.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.nvdcve.DriverShim.html @@ -244,156 +244,154 @@  117  
          */
     118   -
         @Override
    -  119  
         public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
    -  120   +  119  
             //return driver.getParentLogger();
    -  121  0
             Method m = null;
    -  122   +  120  0
             Method m = null;
    +  121  
             try {
    -  123  0
                 m = driver.getClass().getMethod("getParentLogger");
    -  124  0
             } catch (Throwable e) {
    -  125  0
                 throw new SQLFeatureNotSupportedException();
    -  126  0
             }
    -  127  0
             if (m != null) {
    -  128   +  122  0
                 m = driver.getClass().getMethod("getParentLogger");
    +  123  0
             } catch (Throwable e) {
    +  124  0
                 throw new SQLFeatureNotSupportedException();
    +  125  0
             }
    +  126  0
             if (m != null) {
    +  127  
                 try {
    -  129  0
                     return (java.util.logging.Logger) m.invoke(m);
    -  130  0
                 } catch (IllegalAccessException ex) {
    -  131  0
                     LOGGER.trace("", ex);
    -  132  0
                 } catch (IllegalArgumentException ex) {
    -  133  0
                     LOGGER.trace("", ex);
    -  134  0
                 } catch (InvocationTargetException ex) {
    -  135  0
                     LOGGER.trace("", ex);
    -  136  0
                 }
    -  137   +  128  0
                     return (java.util.logging.Logger) m.invoke(m);
    +  129  0
                 } catch (IllegalAccessException ex) {
    +  130  0
                     LOGGER.trace("", ex);
    +  131  0
                 } catch (IllegalArgumentException ex) {
    +  132  0
                     LOGGER.trace("", ex);
    +  133  0
                 } catch (InvocationTargetException ex) {
    +  134  0
                     LOGGER.trace("", ex);
    +  135  0
                 }
    +  136  
             }
    -  138  0
             throw new SQLFeatureNotSupportedException();
    +  137  0
             throw new SQLFeatureNotSupportedException();
    +  138   +
         }
     139   -
         }
    +
     
     140   -
     
    +
         /**
     141   -
         /**
    -  142  
          * Wraps the call to the underlying driver's getPropertyInfo method.
    +  142   +
          *
     143   -
          *
    -  144  
          * @param url the URL of the database
    -  145   +  144  
          * @param info a collection of string/value pairs
    -  146   +  145  
          * @return an array of DriverPropertyInfo objects
    -  147   +  146  
          * @throws SQLException thrown if there is an error accessing the database
    -  148   +  147  
          * @see java.sql.Driver#getPropertyInfo(java.lang.String, java.util.Properties)
    +  148   +
          */
     149   -
          */
    +
         @Override
     150   -
         @Override
    -  151  
         public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
    -  152  0
             return this.driver.getPropertyInfo(url, info);
    +  151  0
             return this.driver.getPropertyInfo(url, info);
    +  152   +
         }
     153   -
         }
    +
     
     154   -
     
    +
         /**
     155   -
         /**
    -  156  
          * Returns whether or not the wrapped driver is jdbcCompliant.
    +  156   +
          *
     157   -
          *
    -  158  
          * @return true if the wrapped driver is JDBC compliant; otherwise false
    -  159   +  158  
          * @see java.sql.Driver#jdbcCompliant()
    +  159   +
          */
     160   -
          */
    +
         @Override
     161   -
         @Override
    -  162  
         public boolean jdbcCompliant() {
    -  163  0
             return this.driver.jdbcCompliant();
    +  162  0
             return this.driver.jdbcCompliant();
    +  163   +
         }
     164   -
         }
    +
     
     165   -
     
    +
         /**
     166   -
         /**
    -  167  
          * Standard implementation of hashCode.
    +  167   +
          *
     168   -
          *
    -  169  
          * @return the hashCode of the object
    +  169   +
          */
     170   -
          */
    +
         @Override
     171   -
         @Override
    -  172  
         public int hashCode() {
    -  173  0
             int hash = 7;
    -  174  0
             hash = 97 * hash + (this.driver != null ? this.driver.hashCode() : 0);
    -  175  0
             return hash;
    +  172  0
             int hash = 7;
    +  173  0
             hash = 97 * hash + (this.driver != null ? this.driver.hashCode() : 0);
    +  174  0
             return hash;
    +  175   +
         }
     176   -
         }
    +
     
     177   -
     
    +
         /**
     178   -
         /**
    -  179  
          * Standard implementation of equals.
    +  179   +
          *
     180   -
          *
    -  181  
          * @param obj the object to compare
    -  182   +  181  
          * @return returns true if the objects are equal; otherwise false
    +  182   +
          */
     183   -
          */
    +
         @Override
     184   -
         @Override
    -  185  
         public boolean equals(Object obj) {
    -  186  0
             if (obj == null) {
    -  187  0
                 return false;
    -  188   +  185  0
             if (obj == null) {
    +  186  0
                 return false;
    +  187  
             }
    -  189  0
             if (getClass() != obj.getClass()) {
    -  190  0
                 return false;
    -  191   +  188  0
             if (getClass() != obj.getClass()) {
    +  189  0
                 return false;
    +  190  
             }
    -  192  0
             final DriverShim other = (DriverShim) obj;
    -  193  0
             return this.driver == other.driver || (this.driver != null && this.driver.equals(other.driver));
    +  191  0
             final DriverShim other = (DriverShim) obj;
    +  192  0
             return this.driver == other.driver || (this.driver != null && this.driver.equals(other.driver));
    +  193   +
         }
     194   -
         }
    -  195  
     
    -  196   +  195  
         /**
    -  197   +  196  
          * Standard implementation of toString().
    -  198   +  197  
          *
    -  199   +  198  
          * @return the String representation of the object
    -  200   +  199  
          */
    -  201   +  200  
         @Override
    -  202   +  201  
         public String toString() {
    -  203  9
             return "DriverShim{" + "driver=" + driver + '}';
    -  204   +  202  9
             return "DriverShim{" + "driver=" + driver + '}';
    +  203  
         }
    -  205   +  204  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.BaseUpdater.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.BaseUpdater.html index c708219a1..07dd50b4c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.BaseUpdater.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.BaseUpdater.html @@ -171,6 +171,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CachedWebDataSource.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CachedWebDataSource.html index 57b7a84e5..a92f1309c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CachedWebDataSource.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CachedWebDataSource.html @@ -93,6 +93,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CpeUpdater.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CpeUpdater.html index 4e113c816..14a8f4f70 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CpeUpdater.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.CpeUpdater.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    CpeUpdater
    0%
    0/78
    0%
    0/28
    6.8
    CpeUpdater
    0%
    0/47
    0%
    0/12
    5.5
     
    @@ -58,309 +58,244 @@  20  
     import java.io.File;
     21   -
     import java.io.FileInputStream;
    -  22   -
     import java.io.FileNotFoundException;
    -  23   -
     import java.io.FileOutputStream;
    -  24  
     import java.io.IOException;
    -  25   +  22  
     import java.net.MalformedURLException;
    -  26   +  23  
     import java.net.URL;
    -  27   +  24  
     import java.util.List;
    -  28   -
     import java.util.zip.GZIPInputStream;
    -  29   +  25  
     import javax.xml.parsers.ParserConfigurationException;
    -  30   +  26  
     import javax.xml.parsers.SAXParser;
    -  31   -
     import javax.xml.parsers.SAXParserFactory;
    -  32   -
     import org.apache.commons.io.FileUtils;
    -  33   +  27  
     import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.LAST_CPE_UPDATE;
    -  34   +  28  
     import org.owasp.dependencycheck.data.update.cpe.CPEHandler;
    -  35   +  29  
     import org.owasp.dependencycheck.data.update.cpe.Cpe;
    -  36   +  30  
     import org.owasp.dependencycheck.data.update.exception.UpdateException;
    -  37   +  31  
     import org.owasp.dependencycheck.utils.DateUtil;
    -  38   +  32  
     import org.owasp.dependencycheck.utils.DownloadFailedException;
    -  39   +  33  
     import org.owasp.dependencycheck.utils.Downloader;
    -  40   +  34   +
     import org.owasp.dependencycheck.utils.ExtractionUtil;
    +  35  
     import org.owasp.dependencycheck.utils.Settings;
    -  41   +  36   +
     import org.owasp.dependencycheck.utils.XmlUtils;
    +  37  
     import org.slf4j.Logger;
    -  42   +  38  
     import org.slf4j.LoggerFactory;
    -  43   +  39  
     import org.xml.sax.SAXException;
    -  44   +  40  
     
    -  45   +  41  
     /**
    -  46   +  42  
      *
    -  47   +  43  
      * This class is currently unused and if enabled will likely not work on MySQL
    -  48   +  44  
      * as the MERGE statement is used.
    -  49   +  45  
      *
    -  50   +  46  
      * The CpeUpdater is designed to download the CPE data file from NIST and import
    -  51   +  47  
      * the data into the database. However, as this currently adds no beneficial
    -  52   +  48  
      * data, compared to what is in the CPE data contained in the CVE data files,
    -  53   +  49  
      * this class is not currently used. The code is being kept as a future update
    -  54   +  50  
      * may utilize more data from the CPE XML files.
    -  55   +  51  
      *
    -  56   +  52   +
      * @deprecated the CPE updater is not currently used.
    +  53  
      * @author Jeremy Long
    -  57   +  54  
      */
    -  58  0
     public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
    +  55   +
     @Deprecated
    +  56  0
     public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
    +  57   +
     
    +  58   +
         /**
     59   -
     
    -  60   -
         /**
    -  61  
          * Static logger.
    +  60   +
          */
    +  61  0
         private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
     62   -
          */
    -  63  0
         private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
    -  64  
     
    -  65   +  63  
         @Override
    -  66   +  64  
         public void update() throws UpdateException {
    +  65   +
             /*
    +  66   +
             //the following could be used if this were ever used.
     67   -
             try {
    -  68  0
                 openDataStores();
    -  69  0
                 if (updateNeeded()) {
    -  70  0
                     LOGGER.info("Updating the Common Platform Enumeration (CPE)");
    -  71  0
                     final File xml = downloadCpe();
    -  72  0
                     final List<Cpe> cpes = processXML(xml);
    -  73  0
                     getCveDB().deleteUnusedCpe();
    -  74  0
                     for (Cpe cpe : cpes) {
    -  75  0
                         getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
    -  76  0
                     }
    -  77  0
                     final long now = System.currentTimeMillis();
    -  78  0
                     getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
    -  79  0
                     LOGGER.info("CPE update complete");
    -  80   -
                 }
    -  81   -
             } finally {
    -  82  0
                 closeDataStores();
    -  83  0
             }
    -  84  0
         }
    -  85   +
             try {
    +  68   +
                 if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
    +  69   +
                     return;
    +  70   +
                 }
    +  71   +
             } catch (InvalidSettingException ex) {
    +  72   +
                 LOGGER.trace("inavlid setting UPDATE_NVDCVE_ENABLED", ex);
    +  73   +
             }
    +  74   +
              */
    +  75  
     
    -  86   -
         /**
    -  87   -
          * Downloads the CPE XML file.
    -  88   -
          *
    +  76   +
             try {
    +  77  0
                 openDataStores();
    +  78  0
                 if (updateNeeded()) {
    +  79  0
                     LOGGER.info("Updating the Common Platform Enumeration (CPE)");
    +  80  0
                     final File xml = downloadCpe();
    +  81  0
                     final List<Cpe> cpes = processXML(xml);
    +  82  0
                     getCveDB().deleteUnusedCpe();
    +  83  0
                     for (Cpe cpe : cpes) {
    +  84  0
                         getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
    +  85  0
                     }
    +  86  0
                     final long now = System.currentTimeMillis();
    +  87  0
                     getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
    +  88  0
                     LOGGER.info("CPE update complete");
     89   -
          * @return the file reference to the CPE.xml file
    +
                 }
     90   -
          * @throws UpdateException thrown if there is an issue downloading the XML
    -  91   -
          * file
    -  92   -
          */
    -  93   -
         private File downloadCpe() throws UpdateException {
    -  94   -
             File xml;
    -  95   -
             final URL url;
    -  96   -
             try {
    -  97  0
                 url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
    -  98  0
                 xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
    -  99  0
                 Downloader.fetchFile(url, xml);
    -  100  0
                 if (url.toExternalForm().endsWith(".xml.gz")) {
    -  101  0
                     extractGzip(xml);
    -  102   -
                 }
    -  103   -
     
    -  104  0
             } catch (MalformedURLException ex) {
    -  105  0
                 throw new UpdateException("Invalid CPE URL", ex);
    -  106  0
             } catch (DownloadFailedException ex) {
    -  107  0
                 throw new UpdateException("Unable to download CPE XML file", ex);
    -  108  0
             } catch (IOException ex) {
    -  109  0
                 throw new UpdateException("Unable to create temporary file to download CPE", ex);
    -  110  0
             }
    -  111  0
             return xml;
    -  112   -
         }
    -  113   -
     
    -  114   -
         /**
    -  115   -
          * Parses the CPE XML file to return a list of CPE entries.
    -  116   -
          *
    -  117   -
          * @param xml the CPE data file
    -  118   -
          * @return the list of CPE entries
    -  119   -
          * @throws UpdateException thrown if there is an issue with parsing the XML
    -  120   -
          * file
    -  121   -
          */
    -  122   -
         private List<Cpe> processXML(final File xml) throws UpdateException {
    -  123   -
             try {
    -  124  0
                 final SAXParserFactory factory = SAXParserFactory.newInstance();
    -  125  0
                 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  126  0
                 final SAXParser saxParser = factory.newSAXParser();
    -  127  0
                 final CPEHandler handler = new CPEHandler();
    -  128  0
                 saxParser.parse(xml, handler);
    -  129  0
                 return handler.getData();
    -  130  0
             } catch (ParserConfigurationException ex) {
    -  131  0
                 throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
    -  132  0
             } catch (SAXException ex) {
    -  133  0
                 throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
    -  134  0
             } catch (IOException ex) {
    -  135  0
                 throw new UpdateException("Unable to parse CPE XML file due to IO Failure", ex);
    -  136   -
             }
    -  137   -
         }
    -  138   -
     
    -  139   -
         /**
    -  140   -
          * Checks to find the last time the CPE data was refreshed and if it needs
    -  141   -
          * to be updated.
    -  142   -
          *
    -  143   -
          * @return true if the CPE data should be refreshed
    -  144   -
          */
    -  145   -
         private boolean updateNeeded() {
    -  146  0
             final long now = System.currentTimeMillis();
    -  147  0
             final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
    -  148  0
             long timestamp = 0;
    -  149  0
             final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
    -  150  0
             if (ts != null && ts.matches("^[0-9]+$")) {
    -  151  0
                 timestamp = Long.parseLong(ts);
    -  152   -
             }
    -  153  0
             return !DateUtil.withinDateRange(timestamp, now, days);
    -  154   -
         }
    -  155   -
     
    -  156   -
         /**
    -  157   -
          * Extracts the file contained in a gzip archive. The extracted file is
    -  158   -
          * placed in the exact same path as the file specified.
    -  159   -
          *
    -  160   -
          * @param file the archive file
    -  161   -
          * @throws FileNotFoundException thrown if the file does not exist
    -  162   -
          * @throws IOException thrown if there is an error extracting the file.
    -  163   -
          */
    -  164   -
         private void extractGzip(File file) throws FileNotFoundException, IOException {
    -  165   -
             //TODO - move this to a util class as it is duplicative of (copy of) code in the DownloadTask
    -  166  0
             final String originalPath = file.getPath();
    -  167  0
             final File gzip = new File(originalPath + ".gz");
    -  168  0
             if (gzip.isFile() && !gzip.delete()) {
    -  169  0
                 LOGGER.debug("Failed to delete intial temporary file {}", gzip.toString());
    -  170  0
                 gzip.deleteOnExit();
    -  171   -
             }
    -  172  0
             if (!file.renameTo(gzip)) {
    -  173  0
                 throw new IOException("Unable to rename '" + file.getPath() + "'");
    -  174   -
             }
    -  175  0
             final File newfile = new File(originalPath);
    -  176   -
     
    -  177  0
             final byte[] buffer = new byte[4096];
    -  178   -
     
    -  179  0
             GZIPInputStream cin = null;
    -  180  0
             FileOutputStream out = null;
    -  181   -
             try {
    -  182  0
                 cin = new GZIPInputStream(new FileInputStream(gzip));
    -  183  0
                 out = new FileOutputStream(newfile);
    -  184   -
     
    -  185   -
                 int len;
    -  186  0
                 while ((len = cin.read(buffer)) > 0) {
    -  187  0
                     out.write(buffer, 0, len);
    -  188   -
                 }
    -  189  
             } finally {
    -  190  0
                 if (cin != null) {
    -  191   -
                     try {
    -  192  0
                         cin.close();
    -  193  0
                     } catch (IOException ex) {
    -  194  0
                         LOGGER.trace("ignore", ex);
    -  195  0
                     }
    -  196   +  91  0
                 closeDataStores();
    +  92  0
             }
    +  93  0
         }
    +  94   +
     
    +  95   +
         /**
    +  96   +
          * Downloads the CPE XML file.
    +  97   +
          *
    +  98   +
          * @return the file reference to the CPE.xml file
    +  99   +
          * @throws UpdateException thrown if there is an issue downloading the XML
    +  100   +
          * file
    +  101   +
          */
    +  102   +
         private File downloadCpe() throws UpdateException {
    +  103   +
             File xml;
    +  104   +
             final URL url;
    +  105   +
             try {
    +  106  0
                 url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
    +  107  0
                 xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
    +  108  0
                 Downloader.fetchFile(url, xml);
    +  109  0
                 if (url.toExternalForm().endsWith(".xml.gz")) {
    +  110  0
                     ExtractionUtil.extractGzip(xml);
    +  111  
                 }
    -  197  0
                 if (out != null) {
    -  198   -
                     try {
    -  199  0
                         out.close();
    -  200  0
                     } catch (IOException ex) {
    -  201  0
                         LOGGER.trace("ignore", ex);
    -  202  0
                     }
    -  203   -
                 }
    -  204  0
                 if (gzip.isFile() && !FileUtils.deleteQuietly(gzip)) {
    -  205  0
                     LOGGER.debug("Failed to delete temporary file {}", gzip.toString());
    -  206  0
                     gzip.deleteOnExit();
    -  207   -
                 }
    -  208   +  112   +
     
    +  113  0
             } catch (MalformedURLException ex) {
    +  114  0
                 throw new UpdateException("Invalid CPE URL", ex);
    +  115  0
             } catch (DownloadFailedException ex) {
    +  116  0
                 throw new UpdateException("Unable to download CPE XML file", ex);
    +  117  0
             } catch (IOException ex) {
    +  118  0
                 throw new UpdateException("Unable to create temporary file to download CPE", ex);
    +  119  0
             }
    +  120  0
             return xml;
    +  121   +
         }
    +  122   +
     
    +  123   +
         /**
    +  124   +
          * Parses the CPE XML file to return a list of CPE entries.
    +  125   +
          *
    +  126   +
          * @param xml the CPE data file
    +  127   +
          * @return the list of CPE entries
    +  128   +
          * @throws UpdateException thrown if there is an issue with parsing the XML
    +  129   +
          * file
    +  130   +
          */
    +  131   +
         private List<Cpe> processXML(final File xml) throws UpdateException {
    +  132   +
             try {
    +  133  0
                 final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
    +  134  0
                 final CPEHandler handler = new CPEHandler();
    +  135  0
                 saxParser.parse(xml, handler);
    +  136  0
                 return handler.getData();
    +  137  0
             } catch (ParserConfigurationException ex) {
    +  138  0
                 throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
    +  139  0
             } catch (SAXException ex) {
    +  140  0
                 throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
    +  141  0
             } catch (IOException ex) {
    +  142  0
                 throw new UpdateException("Unable to parse CPE XML file due to IO Failure", ex);
    +  143  
             }
    -  209  0
         }
    -  210   +  144   +
         }
    +  145   +
     
    +  146   +
         /**
    +  147   +
          * Checks to find the last time the CPE data was refreshed and if it needs
    +  148   +
          * to be updated.
    +  149   +
          *
    +  150   +
          * @return true if the CPE data should be refreshed
    +  151   +
          */
    +  152   +
         private boolean updateNeeded() {
    +  153  0
             final long now = System.currentTimeMillis();
    +  154  0
             final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
    +  155  0
             long timestamp = 0;
    +  156  0
             final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
    +  157  0
             if (ts != null && ts.matches("^[0-9]+$")) {
    +  158  0
                 timestamp = Long.parseLong(ts);
    +  159   +
             }
    +  160  0
             return !DateUtil.withinDateRange(timestamp, now, days);
    +  161   +
         }
    +  162  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.EngineVersionCheck.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.EngineVersionCheck.html index 7cc77689d..5dc9b1fa9 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.EngineVersionCheck.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.EngineVersionCheck.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    EngineVersionCheck
    43%
    35/81
    42%
    12/28
    4.714
    EngineVersionCheck
    41%
    35/85
    35%
    12/34
    5.143
     
    @@ -213,201 +213,215 @@
         public void update() throws UpdateException {
     101  
             try {
    -  102  0
                 if (Settings.getBoolean(Settings.KEYS.AUTO_UPDATE)) {
    -  103  0
                     openDatabase();
    -  104  0
                     LOGGER.debug("Begin Engine Version Check");
    -  105  0
                     final DatabaseProperties properties = cveDB.getDatabaseProperties();
    -  106  0
                     final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
    -  107  0
                     final long now = System.currentTimeMillis();
    -  108  0
                     updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
    -  109  0
                     final String currentVersion = Settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
    -  110  0
                     LOGGER.debug("Last checked: {}", lastChecked);
    -  111  0
                     LOGGER.debug("Now: {}", now);
    -  112  0
                     LOGGER.debug("Current version: {}", currentVersion);
    -  113  0
                     final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
    -  114  0
                     if (updateNeeded) {
    -  115  0
                         LOGGER.warn("A new version of dependency-check is available. Consider updating to version {}.",
    -  116   +  102  0
                 final boolean autoupdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
    +  103  0
                 final boolean enabled = Settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true);
    +  104  0
                 final String original = Settings.getString(Settings.KEYS.CVE_ORIGINAL_MODIFIED_20_URL);
    +  105  0
                 final String current = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
    +  106   +
                 /**
    +  107   +
                  * Only update if auto-update is enabled, the engine check is
    +  108   +
                  * enabled, and the NVD CVE URLs have not been modified (i.e. the
    +  109   +
                  * user has not configured them to point to an internal source).
    +  110   +
                  */
    +  111  0
                 if (enabled && autoupdate && original != null && original.equals(current)) {
    +  112  0
                     openDatabase();
    +  113  0
                     LOGGER.debug("Begin Engine Version Check");
    +  114  0
                     final DatabaseProperties properties = cveDB.getDatabaseProperties();
    +  115  0
                     final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
    +  116  0
                     final long now = System.currentTimeMillis();
    +  117  0
                     updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
    +  118  0
                     final String currentVersion = Settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
    +  119  0
                     LOGGER.debug("Last checked: {}", lastChecked);
    +  120  0
                     LOGGER.debug("Now: {}", now);
    +  121  0
                     LOGGER.debug("Current version: {}", currentVersion);
    +  122  0
                     final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
    +  123  0
                     if (updateNeeded) {
    +  124  0
                         LOGGER.warn("A new version of dependency-check is available. Consider updating to version {}.",
    +  125  
                                 updateToVersion);
    -  117   +  126  
                     }
    -  118   +  127  
                 }
    -  119  0
             } catch (DatabaseException ex) {
    -  120  0
                 LOGGER.debug("Database Exception opening databases to retrieve properties", ex);
    -  121  0
                 throw new UpdateException("Error occurred updating database properties.");
    -  122  0
             } catch (InvalidSettingException ex) {
    -  123  0
                 LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
    -  124   -
             } finally {
    -  125  0
                 closeDatabase();
    -  126  0
             }
    -  127  0
         }
    -  128   -
     
    -  129   -
         /**
    -  130   -
          * Determines if a new version of the dependency-check engine has been
    -  131   -
          * released.
    -  132   -
          *
    +  128  0
             } catch (DatabaseException ex) {
    +  129  0
                 LOGGER.debug("Database Exception opening databases to retrieve properties", ex);
    +  130  0
                 throw new UpdateException("Error occurred updating database properties.");
    +  131  0
             } catch (InvalidSettingException ex) {
    +  132  0
                 LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
     133   -
          * @param lastChecked the epoch time of the last version check
    -  134   -
          * @param now the current epoch time
    -  135   -
          * @param properties the database properties object
    -  136   -
          * @param currentVersion the current version of dependency-check
    -  137   -
          * @return <code>true</code> if a newer version of the database has been
    -  138   -
          * released; otherwise <code>false</code>
    -  139   -
          * @throws UpdateException thrown if there is an error connecting to the
    -  140   -
          * github documentation site or accessing the local database.
    -  141   -
          */
    -  142   -
         protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties,
    -  143   -
                 String currentVersion) throws UpdateException {
    -  144   -
             //check every 30 days if we know there is an update, otherwise check every 7 days
    -  145  7
             final int checkRange = 30;
    -  146  7
             if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) {
    -  147  2
                 LOGGER.debug("Checking web for new version.");
    -  148  2
                 final String currentRelease = getCurrentReleaseVersion();
    -  149  2
                 if (currentRelease != null) {
    -  150  2
                     final DependencyVersion v = new DependencyVersion(currentRelease);
    -  151  2
                     if (v.getVersionParts() != null && v.getVersionParts().size() >= 3) {
    -  152  2
                         updateToVersion = v.toString();
    -  153  2
                         if (!currentRelease.equals(updateToVersion)) {
    -  154  0
                             properties.save(CURRENT_ENGINE_RELEASE, updateToVersion);
    -  155   -
                         }
    -  156  2
                         properties.save(ENGINE_VERSION_CHECKED_ON, Long.toString(now));
    -  157   -
                     }
    -  158   -
                 }
    -  159  2
                 LOGGER.debug("Current Release: {}", updateToVersion);
    -  160   -
             }
    -  161  7
             if (updateToVersion == null) {
    -  162  0
                 LOGGER.debug("Unable to obtain current release");
    -  163  0
                 return false;
    -  164   -
             }
    -  165  7
             final DependencyVersion running = new DependencyVersion(currentVersion);
    -  166  7
             final DependencyVersion released = new DependencyVersion(updateToVersion);
    -  167  7
             if (running.compareTo(released) < 0) {
    -  168  3
                 LOGGER.debug("Upgrade recommended");
    -  169  3
                 return true;
    -  170   -
             }
    -  171  4
             LOGGER.debug("Upgrade not needed");
    -  172  4
             return false;
    -  173   -
         }
    -  174   -
     
    -  175   -
         /**
    -  176   -
          * Opens the CVE and CPE data stores.
    -  177   -
          *
    -  178   -
          * @throws DatabaseException thrown if a data store cannot be opened
    -  179   -
          */
    -  180   -
         protected final void openDatabase() throws DatabaseException {
    -  181  0
             if (cveDB != null) {
    -  182  0
                 return;
    -  183   -
             }
    -  184  0
             cveDB = new CveDB();
    -  185  0
             cveDB.open();
    -  186  0
         }
    -  187   -
     
    -  188   -
         /**
    -  189   -
          * Closes the CVE and CPE data stores.
    -  190   -
          */
    -  191   -
         protected void closeDatabase() {
    -  192  0
             if (cveDB != null) {
    -  193   -
                 try {
    -  194  0
                     cveDB.close();
    -  195  0
                     cveDB = null;
    -  196  0
                 } catch (Throwable ignore) {
    -  197  0
                     LOGGER.trace("Error closing the cveDB", ignore);
    -  198  0
                 }
    -  199   -
             }
    -  200  0
         }
    -  201   -
     
    -  202   -
         /**
    -  203   -
          * Retrieves the current released version number from the github
    -  204   -
          * documentation site.
    -  205   -
          *
    -  206   -
          * @return the current released version number
    -  207   -
          */
    -  208   -
         protected String getCurrentReleaseVersion() {
    -  209  3
             HttpURLConnection conn = null;
    -  210   -
             try {
    -  211  3
                 final String str = Settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt");
    -  212  3
                 final URL url = new URL(str);
    -  213  3
                 conn = URLConnectionFactory.createHttpURLConnection(url);
    -  214  3
                 conn.connect();
    -  215  3
                 if (conn.getResponseCode() != 200) {
    -  216  0
                     return null;
    -  217   -
                 }
    -  218  3
                 final String releaseVersion = IOUtils.toString(conn.getInputStream(), "UTF-8");
    -  219  3
                 if (releaseVersion != null) {
    -  220  6
                     return releaseVersion.trim();
    -  221   -
                 }
    -  222  0
             } catch (MalformedURLException ex) {
    -  223  0
                 LOGGER.debug("Unable to retrieve current release version of dependency-check - malformed url?");
    -  224  0
             } catch (URLConnectionFailureException ex) {
    -  225  0
                 LOGGER.debug("Unable to retrieve current release version of dependency-check - connection failed");
    -  226  0
             } catch (IOException ex) {
    -  227  0
                 LOGGER.debug("Unable to retrieve current release version of dependency-check - i/o exception");
    -  228  
             } finally {
    -  229  3
                 if (conn != null) {
    -  230  3
                     conn.disconnect();
    -  231   +  134  0
                 closeDatabase();
    +  135  0
             }
    +  136  0
         }
    +  137   +
     
    +  138   +
         /**
    +  139   +
          * Determines if a new version of the dependency-check engine has been
    +  140   +
          * released.
    +  141   +
          *
    +  142   +
          * @param lastChecked the epoch time of the last version check
    +  143   +
          * @param now the current epoch time
    +  144   +
          * @param properties the database properties object
    +  145   +
          * @param currentVersion the current version of dependency-check
    +  146   +
          * @return <code>true</code> if a newer version of the database has been
    +  147   +
          * released; otherwise <code>false</code>
    +  148   +
          * @throws UpdateException thrown if there is an error connecting to the
    +  149   +
          * github documentation site or accessing the local database.
    +  150   +
          */
    +  151   +
         protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties,
    +  152   +
                 String currentVersion) throws UpdateException {
    +  153   +
             //check every 30 days if we know there is an update, otherwise check every 7 days
    +  154  7
             final int checkRange = 30;
    +  155  7
             if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) {
    +  156  2
                 LOGGER.debug("Checking web for new version.");
    +  157  2
                 final String currentRelease = getCurrentReleaseVersion();
    +  158  2
                 if (currentRelease != null) {
    +  159  2
                     final DependencyVersion v = new DependencyVersion(currentRelease);
    +  160  2
                     if (v.getVersionParts() != null && v.getVersionParts().size() >= 3) {
    +  161  2
                         updateToVersion = v.toString();
    +  162  2
                         if (!currentRelease.equals(updateToVersion)) {
    +  163  0
                             properties.save(CURRENT_ENGINE_RELEASE, updateToVersion);
    +  164   +
                         }
    +  165  2
                         properties.save(ENGINE_VERSION_CHECKED_ON, Long.toString(now));
    +  166   +
                     }
    +  167  
                 }
    -  232   +  168  2
                 LOGGER.debug("Current Release: {}", updateToVersion);
    +  169  
             }
    -  233  0
             return null;
    -  234   +  170  7
             if (updateToVersion == null) {
    +  171  0
                 LOGGER.debug("Unable to obtain current release");
    +  172  0
                 return false;
    +  173   +
             }
    +  174  7
             final DependencyVersion running = new DependencyVersion(currentVersion);
    +  175  7
             final DependencyVersion released = new DependencyVersion(updateToVersion);
    +  176  7
             if (running.compareTo(released) < 0) {
    +  177  3
                 LOGGER.debug("Upgrade recommended");
    +  178  3
                 return true;
    +  179   +
             }
    +  180  4
             LOGGER.debug("Upgrade not needed");
    +  181  4
             return false;
    +  182  
         }
    -  235   +  183   +
     
    +  184   +
         /**
    +  185   +
          * Opens the CVE and CPE data stores.
    +  186   +
          *
    +  187   +
          * @throws DatabaseException thrown if a data store cannot be opened
    +  188   +
          */
    +  189   +
         protected final void openDatabase() throws DatabaseException {
    +  190  0
             if (cveDB != null) {
    +  191  0
                 return;
    +  192   +
             }
    +  193  0
             cveDB = new CveDB();
    +  194  0
             cveDB.open();
    +  195  0
         }
    +  196   +
     
    +  197   +
         /**
    +  198   +
          * Closes the CVE and CPE data stores.
    +  199   +
          */
    +  200   +
         protected void closeDatabase() {
    +  201  0
             if (cveDB != null) {
    +  202   +
                 try {
    +  203  0
                     cveDB.close();
    +  204  0
                     cveDB = null;
    +  205  0
                 } catch (Throwable ignore) {
    +  206  0
                     LOGGER.trace("Error closing the cveDB", ignore);
    +  207  0
                 }
    +  208   +
             }
    +  209  0
         }
    +  210   +
     
    +  211   +
         /**
    +  212   +
          * Retrieves the current released version number from the github
    +  213   +
          * documentation site.
    +  214   +
          *
    +  215   +
          * @return the current released version number
    +  216   +
          */
    +  217   +
         protected String getCurrentReleaseVersion() {
    +  218  3
             HttpURLConnection conn = null;
    +  219   +
             try {
    +  220  3
                 final String str = Settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt");
    +  221  3
                 final URL url = new URL(str);
    +  222  3
                 conn = URLConnectionFactory.createHttpURLConnection(url);
    +  223  3
                 conn.connect();
    +  224  3
                 if (conn.getResponseCode() != 200) {
    +  225  0
                     return null;
    +  226   +
                 }
    +  227  3
                 final String releaseVersion = IOUtils.toString(conn.getInputStream(), "UTF-8");
    +  228  3
                 if (releaseVersion != null) {
    +  229  6
                     return releaseVersion.trim();
    +  230   +
                 }
    +  231  0
             } catch (MalformedURLException ex) {
    +  232  0
                 LOGGER.debug("Unable to retrieve current release version of dependency-check - malformed url?");
    +  233  0
             } catch (URLConnectionFailureException ex) {
    +  234  0
                 LOGGER.debug("Unable to retrieve current release version of dependency-check - connection failed");
    +  235  0
             } catch (IOException ex) {
    +  236  0
                 LOGGER.debug("Unable to retrieve current release version of dependency-check - i/o exception");
    +  237   +
             } finally {
    +  238  3
                 if (conn != null) {
    +  239  3
                     conn.disconnect();
    +  240   +
                 }
    +  241   +
             }
    +  242  0
             return null;
    +  243   +
         }
    +  244  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.NvdCveUpdater.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.NvdCveUpdater.html index 403ee1df1..f98e68633 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.NvdCveUpdater.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.NvdCveUpdater.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    NvdCveUpdater
    0%
    0/159
    0%
    0/62
    10.333
    NvdCveUpdater
    0%
    0/171
    0%
    0/72
    11.5
     
    @@ -154,402 +154,426 @@
         public void update() throws UpdateException {
     70  
             try {
    -  71  0
                 openDataStores();
    -  72  0
                 boolean autoUpdate = true;
    +  71  0
                 if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
    +  72  0
                     return;
     73   -
                 try {
    -  74  0
                     autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
    -  75  0
                 } catch (InvalidSettingException ex) {
    -  76  0
                     LOGGER.debug("Invalid setting for auto-update; using true.");
    -  77  0
                 }
    -  78  0
                 if (autoUpdate && checkUpdate()) {
    -  79  0
                     final UpdateableNvdCve updateable = getUpdatesNeeded();
    -  80  0
                     if (updateable.isUpdateNeeded()) {
    -  81  0
                         performUpdate(updateable);
    -  82   -
                     }
    -  83  0
                     getProperties().save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis()));
    -  84  
                 }
    -  85  0
             } catch (MalformedURLException ex) {
    -  86  0
                 throw new UpdateException("NVD CVE properties files contain an invalid URL, unable to update the data to use the most current data.", ex);
    -  87  0
             } catch (DownloadFailedException ex) {
    -  88  0
                 LOGGER.warn(
    -  89   -
                         "Unable to download the NVD CVE data; the results may not include the most recent CPE/CVEs from the NVD.");
    -  90  0
                 if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
    -  91  0
                     LOGGER.info(
    -  92   -
                             "If you are behind a proxy you may need to configure dependency-check to use the proxy.");
    -  93   -
                 }
    -  94  0
                 throw new UpdateException("Unable to download the NVD CVE data.", ex);
    -  95   -
             } finally {
    -  96  0
                 closeDataStores();
    -  97  0
             }
    -  98  0
         }
    -  99   +  74  0
             } catch (InvalidSettingException ex) {
    +  75  0
                 LOGGER.trace("inavlid setting UPDATE_NVDCVE_ENABLED", ex);
    +  76  0
             }
    +  77  
     
    -  100   -
         /**
    -  101   -
          * Checks if the NVD CVE XML files were last checked recently. As an
    -  102   -
          * optimization, we can avoid repetitive checks against the NVD. Setting
    -  103   -
          * CVE_CHECK_VALID_FOR_HOURS determines the duration since last check before
    -  104   -
          * checking again. A database property stores the timestamp of the last
    -  105   -
          * check.
    -  106   -
          *
    -  107   -
          * @return true to proceed with the check, or false to skip
    -  108   -
          * @throws UpdateException thrown when there is an issue checking for
    -  109   -
          * updates
    -  110   -
          */
    -  111   -
         private boolean checkUpdate() throws UpdateException {
    -  112  0
             boolean proceed = true;
    -  113   -
             // If the valid setting has not been specified, then we proceed to check...
    -  114  0
             final int validForHours = Settings.getInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, 0);
    -  115  0
             if (dataExists() && 0 < validForHours) {
    -  116   -
                 // ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec
    -  117  0
                 final long msValid = validForHours * 60L * 60L * 1000L;
    -  118  0
                 final long lastChecked = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_CHECKED, "0"));
    -  119  0
                 final long now = System.currentTimeMillis();
    -  120  0
                 proceed = (now - lastChecked) > msValid;
    -  121  0
                 if (!proceed) {
    -  122  0
                     LOGGER.info("Skipping NVD check since last check was within {} hours.", validForHours);
    -  123  0
                     LOGGER.debug("Last NVD was at {}, and now {} is within {} ms.",
    -  124  0
                             lastChecked, now, msValid);
    -  125   -
                 }
    -  126   -
             }
    -  127  0
             return proceed;
    -  128   -
         }
    -  129   -
     
    -  130   -
         /**
    -  131   -
          * Checks the CVE Index to ensure data exists and analysis can continue.
    -  132   -
          *
    -  133   -
          * @return true if the database contains data
    -  134   -
          */
    -  135   -
         private boolean dataExists() {
    -  136  0
             CveDB cve = null;
    -  137   +  78  
             try {
    -  138  0
                 cve = new CveDB();
    -  139  0
                 cve.open();
    -  140  0
                 return cve.dataExists();
    -  141  0
             } catch (DatabaseException ex) {
    -  142  0
                 return false;
    -  143   -
             } finally {
    -  144  0
                 if (cve != null) {
    -  145  0
                     cve.close();
    -  146   -
                 }
    -  147   -
             }
    -  148   -
         }
    -  149   -
     
    -  150   -
         /**
    -  151   -
          * Downloads the latest NVD CVE XML file from the web and imports it into
    -  152   -
          * the current CVE Database.
    -  153   -
          *
    -  154   -
          * @param updateable a collection of NVD CVE data file references that need
    -  155   -
          * to be downloaded and processed to update the database
    -  156   -
          * @throws UpdateException is thrown if there is an error updating the
    -  157   -
          * database
    -  158   -
          */
    -  159   -
         private void performUpdate(UpdateableNvdCve updateable) throws UpdateException {
    -  160  0
             int maxUpdates = 0;
    -  161  0
             for (NvdCveInfo cve : updateable) {
    -  162  0
                 if (cve.getNeedsUpdate()) {
    -  163  0
                     maxUpdates += 1;
    -  164   -
                 }
    -  165  0
             }
    -  166  0
             if (maxUpdates <= 0) {
    -  167  0
                 return;
    -  168   -
             }
    -  169  0
             if (maxUpdates > 3) {
    -  170  0
                 LOGGER.info("NVD CVE requires several updates; this could take a couple of minutes.");
    -  171   -
             }
    -  172   -
     
    -  173  0
             final int poolSize = (MAX_THREAD_POOL_SIZE < maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates;
    -  174   -
     
    -  175  0
             final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize);
    -  176  0
             final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
    -  177  0
             final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
    -  178  0
             for (NvdCveInfo cve : updateable) {
    -  179  0
                 if (cve.getNeedsUpdate()) {
    -  180  0
                     final DownloadTask call = new DownloadTask(cve, processExecutor, getCveDB(), Settings.getInstance());
    -  181  0
                     downloadFutures.add(downloadExecutors.submit(call));
    -  182   -
                 }
    -  183  0
             }
    -  184  0
             downloadExecutors.shutdown();
    -  185   -
     
    -  186   -
             //next, move the future future processTasks to just future processTasks
    -  187  0
             final Set<Future<ProcessTask>> processFutures = new HashSet<Future<ProcessTask>>(maxUpdates);
    -  188  0
             for (Future<Future<ProcessTask>> future : downloadFutures) {
    -  189  0
                 Future<ProcessTask> task = null;
    -  190   +  79  0
                 openDataStores();
    +  80  0
                 boolean autoUpdate = true;
    +  81  
                 try {
    -  191  0
                     task = future.get();
    -  192  0
                 } catch (InterruptedException ex) {
    -  193  0
                     downloadExecutors.shutdownNow();
    -  194  0
                     processExecutor.shutdownNow();
    -  195   -
     
    -  196  0
                     LOGGER.debug("Thread was interrupted during download", ex);
    -  197  0
                     throw new UpdateException("The download was interrupted", ex);
    -  198  0
                 } catch (ExecutionException ex) {
    -  199  0
                     downloadExecutors.shutdownNow();
    -  200  0
                     processExecutor.shutdownNow();
    -  201   -
     
    -  202  0
                     LOGGER.debug("Thread was interrupted during download execution", ex);
    -  203  0
                     throw new UpdateException("The execution of the download was interrupted", ex);
    -  204  0
                 }
    -  205  0
                 if (task == null) {
    -  206  0
                     downloadExecutors.shutdownNow();
    -  207  0
                     processExecutor.shutdownNow();
    -  208  0
                     LOGGER.debug("Thread was interrupted during download");
    -  209  0
                     throw new UpdateException("The download was interrupted; unable to complete the update");
    -  210   -
                 } else {
    -  211  0
                     processFutures.add(task);
    -  212   -
                 }
    -  213  0
             }
    -  214   -
     
    -  215  0
             for (Future<ProcessTask> future : processFutures) {
    -  216   -
                 try {
    -  217  0
                     final ProcessTask task = future.get();
    -  218  0
                     if (task.getException() != null) {
    -  219  0
                         throw task.getException();
    -  220   +  82  0
                     autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
    +  83  0
                 } catch (InvalidSettingException ex) {
    +  84  0
                     LOGGER.debug("Invalid setting for auto-update; using true.");
    +  85  0
                 }
    +  86  0
                 if (autoUpdate && checkUpdate()) {
    +  87  0
                     final UpdateableNvdCve updateable = getUpdatesNeeded();
    +  88  0
                     if (updateable.isUpdateNeeded()) {
    +  89  0
                         performUpdate(updateable);
    +  90  
                     }
    -  221  0
                 } catch (InterruptedException ex) {
    -  222  0
                     processExecutor.shutdownNow();
    -  223  0
                     LOGGER.debug("Thread was interrupted during processing", ex);
    -  224  0
                     throw new UpdateException(ex);
    -  225  0
                 } catch (ExecutionException ex) {
    -  226  0
                     processExecutor.shutdownNow();
    -  227  0
                     LOGGER.debug("Execution Exception during process", ex);
    -  228  0
                     throw new UpdateException(ex);
    -  229   -
                 } finally {
    -  230  0
                     processExecutor.shutdown();
    -  231  0
                 }
    -  232  0
             }
    -  233   +  91  0
                     getProperties().save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis()));
    +  92   +
                 }
    +  93  0
             } catch (MalformedURLException ex) {
    +  94  0
                 throw new UpdateException("NVD CVE properties files contain an invalid URL, unable to update the data to use the most current data.", ex);
    +  95  0
             } catch (DownloadFailedException ex) {
    +  96  0
                 LOGGER.warn(
    +  97   +
                         "Unable to download the NVD CVE data; the results may not include the most recent CPE/CVEs from the NVD.");
    +  98  0
                 if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
    +  99  0
                     LOGGER.info(
    +  100   +
                             "If you are behind a proxy you may need to configure dependency-check to use the proxy.");
    +  101   +
                 }
    +  102  0
                 throw new UpdateException("Unable to download the NVD CVE data.", ex);
    +  103   +
             } finally {
    +  104  0
                 closeDataStores();
    +  105  0
             }
    +  106  0
         }
    +  107  
     
    -  234  0
             if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
    -  235  0
                 getProperties().save(updateable.get(MODIFIED));
    -  236  0
                 LOGGER.info("Begin database maintenance.");
    -  237  0
                 getCveDB().cleanupDatabase();
    -  238  0
                 LOGGER.info("End database maintenance.");
    -  239   +  108   +
         /**
    +  109   +
          * Checks if the NVD CVE XML files were last checked recently. As an
    +  110   +
          * optimization, we can avoid repetitive checks against the NVD. Setting
    +  111   +
          * CVE_CHECK_VALID_FOR_HOURS determines the duration since last check before
    +  112   +
          * checking again. A database property stores the timestamp of the last
    +  113   +
          * check.
    +  114   +
          *
    +  115   +
          * @return true to proceed with the check, or false to skip
    +  116   +
          * @throws UpdateException thrown when there is an issue checking for
    +  117   +
          * updates
    +  118   +
          */
    +  119   +
         private boolean checkUpdate() throws UpdateException {
    +  120  0
             boolean proceed = true;
    +  121   +
             // If the valid setting has not been specified, then we proceed to check...
    +  122  0
             final int validForHours = Settings.getInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, 0);
    +  123  0
             if (dataExists() && 0 < validForHours) {
    +  124   +
                 // ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec
    +  125  0
                 final long msValid = validForHours * 60L * 60L * 1000L;
    +  126  0
                 final long lastChecked = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_CHECKED, "0"));
    +  127  0
                 final long now = System.currentTimeMillis();
    +  128  0
                 proceed = (now - lastChecked) > msValid;
    +  129  0
                 if (!proceed) {
    +  130  0
                     LOGGER.info("Skipping NVD check since last check was within {} hours.", validForHours);
    +  131  0
                     LOGGER.debug("Last NVD was at {}, and now {} is within {} ms.",
    +  132  0
                             lastChecked, now, msValid);
    +  133   +
                 }
    +  134  
             }
    -  240  0
         }
    +  135  0
             return proceed;
    +  136   +
         }
    +  137   +
     
    +  138   +
         /**
    +  139   +
          * Checks the CVE Index to ensure data exists and analysis can continue.
    +  140   +
          *
    +  141   +
          * @return true if the database contains data
    +  142   +
          */
    +  143   +
         private boolean dataExists() {
    +  144  0
             CveDB cve = null;
    +  145   +
             try {
    +  146  0
                 cve = new CveDB();
    +  147  0
                 cve.open();
    +  148  0
                 return cve.dataExists();
    +  149  0
             } catch (DatabaseException ex) {
    +  150  0
                 return false;
    +  151   +
             } finally {
    +  152  0
                 if (cve != null) {
    +  153  0
                     cve.close();
    +  154   +
                 }
    +  155   +
             }
    +  156   +
         }
    +  157   +
     
    +  158   +
         /**
    +  159   +
          * Downloads the latest NVD CVE XML file from the web and imports it into
    +  160   +
          * the current CVE Database.
    +  161   +
          *
    +  162   +
          * @param updateable a collection of NVD CVE data file references that need
    +  163   +
          * to be downloaded and processed to update the database
    +  164   +
          * @throws UpdateException is thrown if there is an error updating the
    +  165   +
          * database
    +  166   +
          */
    +  167   +
         private void performUpdate(UpdateableNvdCve updateable) throws UpdateException {
    +  168  0
             int maxUpdates = 0;
    +  169  0
             for (NvdCveInfo cve : updateable) {
    +  170  0
                 if (cve.getNeedsUpdate()) {
    +  171  0
                     maxUpdates += 1;
    +  172   +
                 }
    +  173  0
             }
    +  174  0
             if (maxUpdates <= 0) {
    +  175  0
                 return;
    +  176   +
             }
    +  177  0
             if (maxUpdates > 3) {
    +  178  0
                 LOGGER.info("NVD CVE requires several updates; this could take a couple of minutes.");
    +  179   +
             }
    +  180   +
     
    +  181  0
             final int poolSize = (MAX_THREAD_POOL_SIZE < maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates;
    +  182   +
     
    +  183  0
             final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize);
    +  184  0
             final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
    +  185  0
             final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
    +  186  0
             for (NvdCveInfo cve : updateable) {
    +  187  0
                 if (cve.getNeedsUpdate()) {
    +  188  0
                     final DownloadTask call = new DownloadTask(cve, processExecutor, getCveDB(), Settings.getInstance());
    +  189  0
                     downloadFutures.add(downloadExecutors.submit(call));
    +  190   +
                 }
    +  191  0
             }
    +  192  0
             downloadExecutors.shutdown();
    +  193   +
     
    +  194   +
             //next, move the future future processTasks to just future processTasks
    +  195  0
             final Set<Future<ProcessTask>> processFutures = new HashSet<Future<ProcessTask>>(maxUpdates);
    +  196  0
             for (Future<Future<ProcessTask>> future : downloadFutures) {
    +  197  0
                 Future<ProcessTask> task = null;
    +  198   +
                 try {
    +  199  0
                     task = future.get();
    +  200  0
                 } catch (InterruptedException ex) {
    +  201  0
                     downloadExecutors.shutdownNow();
    +  202  0
                     processExecutor.shutdownNow();
    +  203   +
     
    +  204  0
                     LOGGER.debug("Thread was interrupted during download", ex);
    +  205  0
                     throw new UpdateException("The download was interrupted", ex);
    +  206  0
                 } catch (ExecutionException ex) {
    +  207  0
                     downloadExecutors.shutdownNow();
    +  208  0
                     processExecutor.shutdownNow();
    +  209   +
     
    +  210  0
                     LOGGER.debug("Thread was interrupted during download execution", ex);
    +  211  0
                     throw new UpdateException("The execution of the download was interrupted", ex);
    +  212  0
                 }
    +  213  0
                 if (task == null) {
    +  214  0
                     downloadExecutors.shutdownNow();
    +  215  0
                     processExecutor.shutdownNow();
    +  216  0
                     LOGGER.debug("Thread was interrupted during download");
    +  217  0
                     throw new UpdateException("The download was interrupted; unable to complete the update");
    +  218   +
                 } else {
    +  219  0
                     processFutures.add(task);
    +  220   +
                 }
    +  221  0
             }
    +  222   +
     
    +  223  0
             for (Future<ProcessTask> future : processFutures) {
    +  224   +
                 try {
    +  225  0
                     final ProcessTask task = future.get();
    +  226  0
                     if (task.getException() != null) {
    +  227  0
                         throw task.getException();
    +  228   +
                     }
    +  229  0
                 } catch (InterruptedException ex) {
    +  230  0
                     processExecutor.shutdownNow();
    +  231  0
                     LOGGER.debug("Thread was interrupted during processing", ex);
    +  232  0
                     throw new UpdateException(ex);
    +  233  0
                 } catch (ExecutionException ex) {
    +  234  0
                     processExecutor.shutdownNow();
    +  235  0
                     LOGGER.debug("Execution Exception during process", ex);
    +  236  0
                     throw new UpdateException(ex);
    +  237   +
                 } finally {
    +  238  0
                     processExecutor.shutdown();
    +  239  0
                 }
    +  240  0
             }
     241  
     
    -  242   -
         /**
    -  243   -
          * Determines if the index needs to be updated. This is done by fetching the
    -  244   -
          * NVD CVE meta data and checking the last update date. If the data needs to
    -  245   -
          * be refreshed this method will return the NvdCveUrl for the files that
    -  246   -
          * need to be updated.
    +  242  0
             if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
    +  243  0
                 getProperties().save(updateable.get(MODIFIED));
    +  244  0
                 LOGGER.info("Begin database maintenance.");
    +  245  0
                 getCveDB().cleanupDatabase();
    +  246  0
                 LOGGER.info("End database maintenance.");
     247   -
          *
    -  248   -
          * @return the collection of files that need to be updated
    -  249   -
          * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
    -  250   -
          * data is incorrect
    -  251   -
          * @throws DownloadFailedException is thrown if there is an error.
    -  252   -
          * downloading the NVD CVE download data file
    -  253   -
          * @throws UpdateException Is thrown if there is an issue with the last
    -  254   -
          * updated properties file
    -  255   -
          */
    -  256   -
         protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
    -  257  0
             UpdateableNvdCve updates = null;
    -  258   -
             try {
    -  259  0
                 updates = retrieveCurrentTimestampsFromWeb();
    -  260  0
             } catch (InvalidDataException ex) {
    -  261  0
                 final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
    -  262  0
                 LOGGER.debug(msg, ex);
    -  263  0
                 throw new DownloadFailedException(msg, ex);
    -  264  0
             } catch (InvalidSettingException ex) {
    -  265  0
                 LOGGER.debug("Invalid setting found when retrieving timestamps", ex);
    -  266  0
                 throw new DownloadFailedException("Invalid settings", ex);
    -  267  0
             }
    -  268   -
     
    -  269  0
             if (updates == null) {
    -  270  0
                 throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
    -  271  
             }
    -  272  0
             if (!getProperties().isEmpty()) {
    -  273   +  248  0
         }
    +  249   +
     
    +  250   +
         /**
    +  251   +
          * Determines if the index needs to be updated. This is done by fetching the
    +  252   +
          * NVD CVE meta data and checking the last update date. If the data needs to
    +  253   +
          * be refreshed this method will return the NvdCveUrl for the files that
    +  254   +
          * need to be updated.
    +  255   +
          *
    +  256   +
          * @return the collection of files that need to be updated
    +  257   +
          * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
    +  258   +
          * data is incorrect
    +  259   +
          * @throws DownloadFailedException is thrown if there is an error.
    +  260   +
          * downloading the NVD CVE download data file
    +  261   +
          * @throws UpdateException Is thrown if there is an issue with the last
    +  262   +
          * updated properties file
    +  263   +
          */
    +  264   +
         protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
    +  265  0
             UpdateableNvdCve updates = null;
    +  266   +
             try {
    +  267  0
                 updates = retrieveCurrentTimestampsFromWeb();
    +  268  0
             } catch (InvalidDataException ex) {
    +  269  0
                 final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
    +  270  0
                 LOGGER.debug(msg, ex);
    +  271  0
                 throw new DownloadFailedException(msg, ex);
    +  272  0
             } catch (InvalidSettingException ex) {
    +  273  0
                 LOGGER.debug("Invalid setting found when retrieving timestamps", ex);
    +  274  0
                 throw new DownloadFailedException("Invalid settings", ex);
    +  275  0
             }
    +  276   +
     
    +  277  0
             if (updates == null) {
    +  278  0
                 throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
    +  279   +
             }
    +  280  0
             if (!getProperties().isEmpty()) {
    +  281  
                 try {
    -  274  0
                     final long lastUpdated = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED, "0"));
    -  275  0
                     final long now = System.currentTimeMillis();
    -  276  0
                     final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
    -  277  0
                     if (lastUpdated == updates.getTimeStamp(MODIFIED)) {
    -  278  0
                         updates.clear(); //we don't need to update anything.
    -  279  0
                     } else if (DateUtil.withinDateRange(lastUpdated, now, days)) {
    -  280  0
                         for (NvdCveInfo entry : updates) {
    -  281  0
                             if (MODIFIED.equals(entry.getId())) {
    -  282  0
                                 entry.setNeedsUpdate(true);
    -  283   -
                             } else {
    -  284  0
                                 entry.setNeedsUpdate(false);
    -  285   -
                             }
    -  286  0
                         }
    -  287   -
                     } else { //we figure out which of the several XML files need to be downloaded.
    -  288  0
                         for (NvdCveInfo entry : updates) {
    -  289  0
                             if (MODIFIED.equals(entry.getId())) {
    -  290  0
                                 entry.setNeedsUpdate(true);
    +  282  0
                     final int startYear = Settings.getInt(Settings.KEYS.CVE_START_YEAR, 2002);
    +  283  0
                     final int endYear = Calendar.getInstance().get(Calendar.YEAR);
    +  284  0
                     boolean needsFullUpdate = false;
    +  285  0
                     for (int y = startYear; y <= endYear; y++) {
    +  286  0
                         final long val = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE + y, "0"));
    +  287  0
                         if (val == 0) {
    +  288  0
                             needsFullUpdate = true;
    +  289   +
                         }
    +  290   +
                     }
     291   +
     
    +  292  0
                     final long lastUpdated = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED, "0"));
    +  293  0
                     final long now = System.currentTimeMillis();
    +  294  0
                     final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
    +  295  0
                     if (!needsFullUpdate && lastUpdated == updates.getTimeStamp(MODIFIED)) {
    +  296  0
                         updates.clear(); //we don't need to update anything.
    +  297  0
                     } else if (!needsFullUpdate && DateUtil.withinDateRange(lastUpdated, now, days)) {
    +  298  0
                         for (NvdCveInfo entry : updates) {
    +  299  0
                             if (MODIFIED.equals(entry.getId())) {
    +  300  0
                                 entry.setNeedsUpdate(true);
    +  301  
                             } else {
    -  292  0
                                 long currentTimestamp = 0;
    -  293   -
                                 try {
    -  294  0
                                     currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE
    -  295  0
                                             + entry.getId(), "0"));
    -  296  0
                                 } catch (NumberFormatException ex) {
    -  297  0
                                     LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated",
    -  298  0
                                             DatabaseProperties.LAST_UPDATED_BASE, entry.getId(), ex);
    -  299  0
                                 }
    -  300  0
                                 if (currentTimestamp == entry.getTimestamp()) {
    -  301  0
                                     entry.setNeedsUpdate(false);
    -  302   -
                                 }
    +  302  0
                                 entry.setNeedsUpdate(false);
     303  
                             }
     304  0
                         }
     305   -
                     }
    -  306  0
                 } catch (NumberFormatException ex) {
    -  307  0
                     LOGGER.warn("An invalid schema version or timestamp exists in the data.properties file.");
    -  308  0
                     LOGGER.debug("", ex);
    -  309  0
                 }
    -  310   -
             }
    -  311  0
             return updates;
    -  312   -
         }
    -  313   -
     
    -  314   -
         /**
    -  315   -
          * Retrieves the timestamps from the NVD CVE meta data file.
    -  316   -
          *
    -  317   -
          * @return the timestamp from the currently published nvdcve downloads page
    -  318   -
          * @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
    -  319   -
          * is incorrect.
    +
                     } else { //we figure out which of the several XML files need to be downloaded.
    +  306  0
                         for (NvdCveInfo entry : updates) {
    +  307  0
                             if (MODIFIED.equals(entry.getId())) {
    +  308  0
                                 entry.setNeedsUpdate(true);
    +  309   +
                             } else {
    +  310  0
                                 long currentTimestamp = 0;
    +  311   +
                                 try {
    +  312  0
                                     currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE
    +  313  0
                                             + entry.getId(), "0"));
    +  314  0
                                 } catch (NumberFormatException ex) {
    +  315  0
                                     LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated",
    +  316  0
                                             DatabaseProperties.LAST_UPDATED_BASE, entry.getId(), ex);
    +  317  0
                                 }
    +  318  0
                                 if (currentTimestamp == entry.getTimestamp()) {
    +  319  0
                                     entry.setNeedsUpdate(false);
     320   -
          * @throws DownloadFailedException thrown if there is an error downloading
    +
                                 }
     321   -
          * the nvd cve meta data file
    -  322   -
          * @throws InvalidDataException thrown if there is an exception parsing the
    +
                             }
    +  322  0
                         }
     323   -
          * timestamps
    -  324   -
          * @throws InvalidSettingException thrown if the settings are invalid
    -  325   -
          */
    -  326   -
         private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
    -  327   -
                 throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
    +
                     }
    +  324  0
                 } catch (NumberFormatException ex) {
    +  325  0
                     LOGGER.warn("An invalid schema version or timestamp exists in the data.properties file.");
    +  326  0
                     LOGGER.debug("", ex);
    +  327  0
                 }
     328   -
     
    -  329  0
             final UpdateableNvdCve updates = new UpdateableNvdCve();
    -  330  0
             updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL),
    -  331  0
                     Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
    -  332   -
                     false);
    -  333   -
     
    -  334  0
             final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
    -  335  0
             final int end = Calendar.getInstance().get(Calendar.YEAR);
    -  336  0
             final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
    -  337  0
             final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
    -  338  0
             for (int i = start; i <= end; i++) {
    -  339  0
                 updates.add(Integer.toString(i), String.format(baseUrl20, i),
    -  340  0
                         String.format(baseUrl12, i),
    -  341   -
                         true);
    -  342  
             }
    -  343  0
             return updates;
    -  344   +  329  0
             return updates;
    +  330  
         }
    +  331   +
     
    +  332   +
         /**
    +  333   +
          * Retrieves the timestamps from the NVD CVE meta data file.
    +  334   +
          *
    +  335   +
          * @return the timestamp from the currently published nvdcve downloads page
    +  336   +
          * @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
    +  337   +
          * is incorrect.
    +  338   +
          * @throws DownloadFailedException thrown if there is an error downloading
    +  339   +
          * the nvd cve meta data file
    +  340   +
          * @throws InvalidDataException thrown if there is an exception parsing the
    +  341   +
          * timestamps
    +  342   +
          * @throws InvalidSettingException thrown if the settings are invalid
    +  343   +
          */
    +  344   +
         private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
     345   +
                 throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
    +  346   +
     
    +  347  0
             final UpdateableNvdCve updates = new UpdateableNvdCve();
    +  348  0
             updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL),
    +  349  0
                     Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
    +  350   +
                     false);
    +  351   +
     
    +  352  0
             final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
    +  353  0
             final int end = Calendar.getInstance().get(Calendar.YEAR);
    +  354  0
             final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
    +  355  0
             final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
    +  356  0
             for (int i = start; i <= end; i++) {
    +  357  0
                 updates.add(Integer.toString(i), String.format(baseUrl20, i),
    +  358  0
                         String.format(baseUrl12, i),
    +  359   +
                         true);
    +  360   +
             }
    +  361  0
             return updates;
    +  362   +
         }
    +  363  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.UpdateService.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.UpdateService.html index c2b458d1d..a6eb7201d 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.UpdateService.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.UpdateService.html @@ -121,6 +121,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.CPEHandler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.CPEHandler.html index d563767e9..f2cc4a7bf 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.CPEHandler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.CPEHandler.html @@ -722,6 +722,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.Cpe.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.Cpe.html index 594950513..d661dacfe 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.Cpe.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.cpe.Cpe.html @@ -251,6 +251,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.InvalidDataException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.InvalidDataException.html index 8ca9ac311..f49babc31 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.InvalidDataException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.InvalidDataException.html @@ -115,6 +115,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.UpdateException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.UpdateException.html index 00a18491b..07a3fa7bb 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.UpdateException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.exception.UpdateException.html @@ -143,6 +143,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.DownloadTask.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.DownloadTask.html index f5265838a..022c51198 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.DownloadTask.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.DownloadTask.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    DownloadTask
    55%
    60/108
    35%
    23/64
    5.364
    DownloadTask
    50%
    40/79
    31%
    15/48
    4.7
     
    @@ -62,479 +62,396 @@  22  
     import java.io.FileNotFoundException;
     23   -
     import java.io.FileOutputStream;
    -  24  
     import java.io.IOException;
    -  25   +  24  
     import java.io.InputStream;
    -  26   +  25  
     import java.net.URL;
    -  27   +  26  
     import java.util.concurrent.Callable;
    -  28   +  27  
     import java.util.concurrent.ExecutorService;
    -  29   +  28  
     import java.util.concurrent.Future;
    -  30   -
     import java.util.zip.GZIPInputStream;
    -  31   -
     import org.apache.commons.io.FileUtils;
    -  32   +  29  
     import org.owasp.dependencycheck.data.nvdcve.CveDB;
    -  33   +  30  
     import org.owasp.dependencycheck.data.update.exception.UpdateException;
    -  34   +  31  
     import org.owasp.dependencycheck.utils.DownloadFailedException;
    -  35   +  32  
     import org.owasp.dependencycheck.utils.Downloader;
    -  36   +  33   +
     import org.owasp.dependencycheck.utils.ExtractionUtil;
    +  34  
     import org.owasp.dependencycheck.utils.Settings;
    -  37   +  35  
     import org.slf4j.Logger;
    -  38   +  36  
     import org.slf4j.LoggerFactory;
    -  39   +  37  
     
    -  40   +  38  
     /**
    -  41   +  39  
      * A callable object to download two files.
    -  42   +  40  
      *
    -  43   +  41  
      * @author Jeremy Long
    -  44   +  42  
      */
    -  45  0
     public class DownloadTask implements Callable<Future<ProcessTask>> {
    +  43  0
     public class DownloadTask implements Callable<Future<ProcessTask>> {
    +  44   +
     
    +  45   +
         /**
     46   -
     
    -  47   -
         /**
    -  48  
          * The Logger.
    +  47   +
          */
    +  48  1
         private static final Logger LOGGER = LoggerFactory.getLogger(DownloadTask.class);
     49   -
          */
    -  50  1
         private static final Logger LOGGER = LoggerFactory.getLogger(DownloadTask.class);
    +
     
    +  50   +
         /**
     51   -
     
    -  52   -
         /**
    -  53  
          * Simple constructor for the callable download task.
    -  54   +  52  
          *
    -  55   +  53  
          * @param nvdCveInfo the NVD CVE info
    -  56   +  54  
          * @param processor the processor service to submit the downloaded files to
    -  57   +  55  
          * @param cveDB the CVE DB to use to store the vulnerability data
    -  58   +  56  
          * @param settings a reference to the global settings object; this is
    -  59   +  57  
          * necessary so that when the thread is started the dependencies have a
    -  60   +  58  
          * correct reference to the global settings.
    -  61   +  59  
          * @throws UpdateException thrown if temporary files could not be created
    -  62   +  60  
          */
    -  63  1
         public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
    -  64  1
             this.nvdCveInfo = nvdCveInfo;
    -  65  1
             this.processorService = processor;
    -  66  1
             this.cveDB = cveDB;
    -  67  1
             this.settings = settings;
    -  68   +  61  1
         public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
    +  62  1
             this.nvdCveInfo = nvdCveInfo;
    +  63  1
             this.processorService = processor;
    +  64  1
             this.cveDB = cveDB;
    +  65  1
             this.settings = settings;
    +  66  
     
    -  69   +  67  
             final File file1;
    -  70   +  68  
             final File file2;
    -  71   +  69  
     
    -  72   +  70  
             try {
    -  73  1
                 file1 = File.createTempFile("cve" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
    -  74  1
                 file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
    -  75  0
             } catch (IOException ex) {
    -  76  0
                 throw new UpdateException("Unable to create temporary files", ex);
    -  77  1
             }
    -  78  1
             this.first = file1;
    -  79  1
             this.second = file2;
    +  71  1
                 file1 = File.createTempFile("cve" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
    +  72  1
                 file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
    +  73  0
             } catch (IOException ex) {
    +  74  0
                 throw new UpdateException("Unable to create temporary files", ex);
    +  75  1
             }
    +  76  1
             this.first = file1;
    +  77  1
             this.second = file2;
    +  78   +
     
    +  79  1
         }
     80   -
     
    -  81  1
         }
    -  82  
         /**
    -  83   +  81  
          * The CVE DB to use when processing the files.
    -  84   +  82  
          */
    -  85   +  83  
         private final CveDB cveDB;
    -  86   +  84  
         /**
    -  87   +  85  
          * The processor service to pass the results of the download to.
    -  88   +  86  
          */
    -  89   +  87  
         private final ExecutorService processorService;
    -  90   +  88  
         /**
    -  91   +  89  
          * The NVD CVE Meta Data.
    -  92   +  90  
          */
    -  93   +  91  
         private NvdCveInfo nvdCveInfo;
    -  94   +  92  
         /**
    -  95   +  93  
          * A reference to the global settings object.
    -  96   +  94  
          */
    -  97   +  95  
         private final Settings settings;
    +  96   +
     
    +  97   +
         /**
     98   -
     
    -  99   -
         /**
    -  100  
          * Get the value of nvdCveInfo.
    -  101   +  99  
          *
    -  102   +  100  
          * @return the value of nvdCveInfo
    -  103   +  101  
          */
    -  104   +  102  
         public NvdCveInfo getNvdCveInfo() {
    -  105  0
             return nvdCveInfo;
    +  103  0
             return nvdCveInfo;
    +  104   +
         }
    +  105   +
     
     106   -
         }
    +
         /**
     107   -
     
    -  108   -
         /**
    -  109  
          * Set the value of nvdCveInfo.
    -  110   +  108  
          *
    -  111   +  109  
          * @param nvdCveInfo new value of nvdCveInfo
    -  112   +  110  
          */
    -  113   +  111  
         public void setNvdCveInfo(NvdCveInfo nvdCveInfo) {
    -  114  0
             this.nvdCveInfo = nvdCveInfo;
    -  115  0
         }
    +  112  0
             this.nvdCveInfo = nvdCveInfo;
    +  113  0
         }
    +  114   +
         /**
    +  115   +
          * a file.
     116   -
         /**
    +
          */
     117   -
          * a file.
    -  118   -
          */
    -  119  
         private File first;
    +  118   +
     
    +  119   +
         /**
     120   -
     
    -  121   -
         /**
    -  122  
          * Get the value of first.
    -  123   +  121  
          *
    -  124   +  122  
          * @return the value of first
    -  125   +  123  
          */
    -  126   +  124  
         public File getFirst() {
    -  127  0
             return first;
    +  125  0
             return first;
    +  126   +
         }
    +  127   +
     
     128   -
         }
    +
         /**
     129   -
     
    -  130   -
         /**
    -  131  
          * Set the value of first.
    -  132   +  130  
          *
    -  133   +  131  
          * @param first new value of first
    -  134   +  132  
          */
    -  135   +  133  
         public void setFirst(File first) {
    -  136  0
             this.first = first;
    -  137  0
         }
    -  138   +  134  0
             this.first = first;
    +  135  0
         }
    +  136  
         /**
    -  139   +  137  
          * a file.
    -  140   +  138  
          */
    -  141   +  139  
         private File second;
    +  140   +
     
    +  141   +
         /**
     142   -
     
    -  143   -
         /**
    -  144  
          * Get the value of second.
    -  145   +  143  
          *
    -  146   +  144  
          * @return the value of second
    -  147   +  145  
          */
    -  148   +  146  
         public File getSecond() {
    -  149  0
             return second;
    +  147  0
             return second;
    +  148   +
         }
    +  149   +
     
     150   -
         }
    +
         /**
     151   -
     
    -  152   -
         /**
    -  153  
          * Set the value of second.
    -  154   +  152  
          *
    -  155   +  153  
          * @param second new value of second
    -  156   +  154  
          */
    -  157   +  155  
         public void setSecond(File second) {
    -  158  0
             this.second = second;
    -  159  0
         }
    -  160   +  156  0
             this.second = second;
    +  157  0
         }
    +  158  
     
    -  161   +  159  
         @Override
    -  162   +  160  
         public Future<ProcessTask> call() throws Exception {
    -  163   +  161  
             try {
    -  164  1
                 Settings.setInstance(settings);
    -  165  1
                 final URL url1 = new URL(nvdCveInfo.getUrl());
    -  166  1
                 final URL url2 = new URL(nvdCveInfo.getOldSchemaVersionUrl());
    -  167  1
                 LOGGER.info("Download Started for NVD CVE - {}", nvdCveInfo.getId());
    -  168  1
                 final long startDownload = System.currentTimeMillis();
    -  169   +  162  1
                 Settings.setInstance(settings);
    +  163  1
                 final URL url1 = new URL(nvdCveInfo.getUrl());
    +  164  1
                 final URL url2 = new URL(nvdCveInfo.getOldSchemaVersionUrl());
    +  165  1
                 LOGGER.info("Download Started for NVD CVE - {}", nvdCveInfo.getId());
    +  166  1
                 final long startDownload = System.currentTimeMillis();
    +  167  
                 try {
    -  170  1
                     Downloader.fetchFile(url1, first);
    -  171  1
                     Downloader.fetchFile(url2, second);
    -  172  0
                 } catch (DownloadFailedException ex) {
    -  173  0
                     LOGGER.warn("Download Failed for NVD CVE - {}\nSome CVEs may not be reported.", nvdCveInfo.getId());
    -  174  0
                     if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
    -  175  0
                         LOGGER.info(
    -  176   +  168  1
                     Downloader.fetchFile(url1, first);
    +  169  1
                     Downloader.fetchFile(url2, second);
    +  170  0
                 } catch (DownloadFailedException ex) {
    +  171  0
                     LOGGER.warn("Download Failed for NVD CVE - {}\nSome CVEs may not be reported.", nvdCveInfo.getId());
    +  172  0
                     if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
    +  173  0
                         LOGGER.info(
    +  174  
                                 "If you are behind a proxy you may need to configure dependency-check to use the proxy.");
    -  177   +  175  
                     }
    -  178  0
                     LOGGER.debug("", ex);
    -  179  0
                     return null;
    -  180  1
                 }
    -  181  1
                 if (url1.toExternalForm().endsWith(".xml.gz") && !isXml(first)) {
    -  182  1
                     extractGzip(first);
    -  183   +  176  0
                     LOGGER.debug("", ex);
    +  177  0
                     return null;
    +  178  1
                 }
    +  179  1
                 if (url1.toExternalForm().endsWith(".xml.gz") && !isXml(first)) {
    +  180  1
                     ExtractionUtil.extractGzip(first);
    +  181  
                 }
    -  184  1
                 if (url2.toExternalForm().endsWith(".xml.gz") && !isXml(second)) {
    -  185  1
                     extractGzip(second);
    -  186   +  182  1
                 if (url2.toExternalForm().endsWith(".xml.gz") && !isXml(second)) {
    +  183  1
                     ExtractionUtil.extractGzip(second);
    +  184  
                 }
    -  187   +  185  
     
    -  188  2
                 LOGGER.info("Download Complete for NVD CVE - {}  ({} ms)", nvdCveInfo.getId(),
    -  189  1
                         System.currentTimeMillis() - startDownload);
    -  190  1
                 if (this.processorService == null) {
    -  191  2
                     return null;
    -  192   +  186  2
                 LOGGER.info("Download Complete for NVD CVE - {}  ({} ms)", nvdCveInfo.getId(),
    +  187  1
                         System.currentTimeMillis() - startDownload);
    +  188  1
                 if (this.processorService == null) {
    +  189  2
                     return null;
    +  190  
                 }
    -  193  0
                 final ProcessTask task = new ProcessTask(cveDB, this, settings);
    -  194  0
                 return this.processorService.submit(task);
    -  195   +  191  0
                 final ProcessTask task = new ProcessTask(cveDB, this, settings);
    +  192  0
                 return this.processorService.submit(task);
    +  193  
     
    -  196  0
             } catch (Throwable ex) {
    -  197  0
                 LOGGER.warn("An exception occurred downloading NVD CVE - {}\nSome CVEs may not be reported.", nvdCveInfo.getId());
    -  198  0
                 LOGGER.debug("Download Task Failed", ex);
    -  199   +  194  0
             } catch (Throwable ex) {
    +  195  0
                 LOGGER.warn("An exception occurred downloading NVD CVE - {}\nSome CVEs may not be reported.", nvdCveInfo.getId());
    +  196  0
                 LOGGER.debug("Download Task Failed", ex);
    +  197  
             } finally {
    -  200  1
                 Settings.cleanup(false);
    -  201  0
             }
    -  202  0
             return null;
    +  198  1
                 Settings.cleanup(false);
    +  199  0
             }
    +  200  0
             return null;
    +  201   +
         }
    +  202   +
     
     203   -
         }
    +
         /**
     204   -
     
    -  205   -
         /**
    -  206  
          * Attempts to delete the files that were downloaded.
    -  207   +  205  
          */
    -  208   +  206  
         public void cleanup() {
    -  209  0
             if (first != null && first.exists() && first.delete()) {
    -  210  0
                 LOGGER.debug("Failed to delete first temporary file {}", second.toString());
    -  211  0
                 first.deleteOnExit();
    -  212   +  207  0
             if (first != null && first.exists() && first.delete()) {
    +  208  0
                 LOGGER.debug("Failed to delete first temporary file {}", second.toString());
    +  209  0
                 first.deleteOnExit();
    +  210  
             }
    -  213  0
             if (second != null && second.exists() && !second.delete()) {
    -  214  0
                 LOGGER.debug("Failed to delete second temporary file {}", second.toString());
    -  215  0
                 second.deleteOnExit();
    +  211  0
             if (second != null && second.exists() && !second.delete()) {
    +  212  0
                 LOGGER.debug("Failed to delete second temporary file {}", second.toString());
    +  213  0
                 second.deleteOnExit();
    +  214   +
             }
    +  215  0
         }
     216   -
             }
    -  217  0
         }
    +
     
    +  217   +
         /**
     218   -
     
    -  219   -
         /**
    -  220  
          * Checks the file header to see if it is an XML file.
    -  221   +  219  
          *
    -  222   +  220  
          * @param file the file to check
    -  223   +  221  
          * @return true if the file is XML
    -  224   +  222  
          */
    -  225   +  223  
         public static boolean isXml(File file) {
    -  226  4
             if (file == null || !file.isFile()) {
    -  227  0
                 return false;
    +  224  4
             if (file == null || !file.isFile()) {
    +  225  0
                 return false;
    +  226   +
             }
    +  227  4
             InputStream is = null;
     228   -
             }
    -  229  4
             InputStream is = null;
    +
             try {
    +  229  4
                 is = new FileInputStream(file);
     230   -
             try {
    -  231  4
                 is = new FileInputStream(file);
    -  232  
     
    -  233  4
                 final byte[] buf = new byte[5];
    -  234  4
                 int read = 0;
    -  235   +  231  4
                 final byte[] buf = new byte[5];
    +  232  4
                 int read = 0;
    +  233  
                 try {
    -  236  4
                     read = is.read(buf);
    -  237  0
                 } catch (IOException ex) {
    -  238  0
                     return false;
    -  239  4
                 }
    -  240  8
                 return read == 5
    -  241   +  234  4
                     read = is.read(buf);
    +  235  0
                 } catch (IOException ex) {
    +  236  0
                     return false;
    +  237  4
                 }
    +  238  8
                 return read == 5
    +  239  
                         && buf[0] == '<'
    -  242   +  240  
                         && (buf[1] == '?')
    -  243   +  241  
                         && (buf[2] == 'x' || buf[2] == 'X')
    -  244   +  242  
                         && (buf[3] == 'm' || buf[3] == 'M')
    -  245   +  243  
                         && (buf[4] == 'l' || buf[4] == 'L');
    -  246  0
             } catch (FileNotFoundException ex) {
    -  247  0
                 return false;
    +  244  0
             } catch (FileNotFoundException ex) {
    +  245  0
                 return false;
    +  246   +
             } finally {
    +  247  4
                 if (is != null) {
     248   -
             } finally {
    -  249  4
                 if (is != null) {
    -  250  
                     try {
    -  251  4
                         is.close();
    -  252  0
                     } catch (IOException ex) {
    -  253  0
                         LOGGER.debug("Error closing stream", ex);
    -  254  4
                     }
    +  249  4
                         is.close();
    +  250  0
                     } catch (IOException ex) {
    +  251  0
                         LOGGER.debug("Error closing stream", ex);
    +  252  4
                     }
    +  253   +
                 }
    +  254   +
             }
     255   -
                 }
    -  256   -
             }
    -  257  
         }
    -  258   -
     
    -  259   -
         /**
    -  260   -
          * Extracts the file contained in a gzip archive. The extracted file is
    -  261   -
          * placed in the exact same path as the file specified.
    -  262   -
          *
    -  263   -
          * @param file the archive file
    -  264   -
          * @throws FileNotFoundException thrown if the file does not exist
    -  265   -
          * @throws IOException thrown if there is an error extracting the file.
    -  266   -
          */
    -  267   -
         private void extractGzip(File file) throws FileNotFoundException, IOException {
    -  268  2
             final String originalPath = file.getPath();
    -  269  2
             final File gzip = new File(originalPath + ".gz");
    -  270  2
             if (gzip.isFile() && !gzip.delete()) {
    -  271  0
                 LOGGER.debug("Failed to delete initial temporary file when extracting 'gz' {}", gzip.toString());
    -  272  0
                 gzip.deleteOnExit();
    -  273   -
             }
    -  274  2
             if (!file.renameTo(gzip)) {
    -  275  0
                 throw new IOException("Unable to rename '" + file.getPath() + "'");
    -  276   -
             }
    -  277  2
             final File newfile = new File(originalPath);
    -  278   -
     
    -  279  2
             final byte[] buffer = new byte[4096];
    -  280   -
     
    -  281  2
             GZIPInputStream cin = null;
    -  282  2
             FileOutputStream out = null;
    -  283   -
             try {
    -  284  2
                 cin = new GZIPInputStream(new FileInputStream(gzip));
    -  285  2
                 out = new FileOutputStream(newfile);
    -  286   -
     
    -  287   -
                 int len;
    -  288  801
                 while ((len = cin.read(buffer)) > 0) {
    -  289  799
                     out.write(buffer, 0, len);
    -  290   -
                 }
    -  291   -
             } finally {
    -  292  2
                 if (cin != null) {
    -  293   -
                     try {
    -  294  2
                         cin.close();
    -  295  0
                     } catch (IOException ex) {
    -  296  0
                         LOGGER.trace("ignore", ex);
    -  297  2
                     }
    -  298   -
                 }
    -  299  2
                 if (out != null) {
    -  300   -
                     try {
    -  301  2
                         out.close();
    -  302  0
                     } catch (IOException ex) {
    -  303  0
                         LOGGER.trace("ignore", ex);
    -  304  2
                     }
    -  305   -
                 }
    -  306  2
                 if (gzip.isFile() && !FileUtils.deleteQuietly(gzip)) {
    -  307  0
                     LOGGER.debug("Failed to delete temporary file when extracting 'gz' {}", gzip.toString());
    -  308  0
                     gzip.deleteOnExit();
    -  309   -
                 }
    -  310   -
             }
    -  311  2
         }
    -  312   +  256  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler.html index 0aabbd2f0..37f119043 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler.html @@ -451,6 +451,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler.html index b5ca71e7c..3b29165f5 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler.html @@ -866,6 +866,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCveInfo.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCveInfo.html index f0a9780a2..2e5c74438 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCveInfo.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.NvdCveInfo.html @@ -276,6 +276,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.ProcessTask.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.ProcessTask.html index 32258bea7..4ce243c4a 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.ProcessTask.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.ProcessTask.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    ProcessTask
    0%
    0/54
    N/A
    3.5
    ProcessTask
    0%
    0/52
    N/A
    3.5
     
    @@ -74,19 +74,19 @@  28  
     import javax.xml.parsers.SAXParser;
     29   -
     import javax.xml.parsers.SAXParserFactory;
    -  30  
     import org.owasp.dependencycheck.data.nvdcve.CveDB;
    -  31   +  30  
     import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
    -  32   +  31  
     import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
    -  33   +  32  
     import org.owasp.dependencycheck.data.update.exception.UpdateException;
    -  34   +  33  
     import org.owasp.dependencycheck.dependency.VulnerableSoftware;
    -  35   +  34  
     import org.owasp.dependencycheck.utils.Settings;
    +  35   +
     import org.owasp.dependencycheck.utils.XmlUtils;
     36  
     import org.slf4j.Logger;
     37   @@ -286,69 +286,67 @@
                 SAXException, IOException, SQLException, DatabaseException, ClassNotFoundException {
     144  
     
    -  145  0
             final SAXParserFactory factory = SAXParserFactory.newInstance();
    -  146  0
             factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  147  0
             final SAXParser saxParser = factory.newSAXParser();
    -  148   +  145  0
             final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
    +  146  
     
    -  149  0
             final NvdCve12Handler cve12Handler = new NvdCve12Handler();
    -  150  0
             saxParser.parse(oldVersion, cve12Handler);
    -  151  0
             final Map<String, List<VulnerableSoftware>> prevVersionVulnMap = cve12Handler.getVulnerabilities();
    -  152   +  147  0
             final NvdCve12Handler cve12Handler = new NvdCve12Handler();
    +  148  0
             saxParser.parse(oldVersion, cve12Handler);
    +  149  0
             final Map<String, List<VulnerableSoftware>> prevVersionVulnMap = cve12Handler.getVulnerabilities();
    +  150  
     
    -  153  0
             final NvdCve20Handler cve20Handler = new NvdCve20Handler();
    -  154  0
             cve20Handler.setCveDB(cveDB);
    -  155  0
             cve20Handler.setPrevVersionVulnMap(prevVersionVulnMap);
    -  156  0
             saxParser.parse(file, cve20Handler);
    -  157  0
         }
    -  158   +  151  0
             final NvdCve20Handler cve20Handler = new NvdCve20Handler();
    +  152  0
             cve20Handler.setCveDB(cveDB);
    +  153  0
             cve20Handler.setPrevVersionVulnMap(prevVersionVulnMap);
    +  154  0
             saxParser.parse(file, cve20Handler);
    +  155  0
         }
    +  156  
     
    -  159   +  157  
         /**
    -  160   +  158  
          * Processes the NVD CVE XML file and imports the data into the DB.
    -  161   +  159  
          *
    -  162   +  160  
          * @throws UpdateException thrown if there is an error loading the data into
    -  163   +  161  
          * the database
    -  164   +  162  
          */
    -  165   +  163  
         private void processFiles() throws UpdateException {
    -  166  0
             LOGGER.info("Processing Started for NVD CVE - {}", filePair.getNvdCveInfo().getId());
    -  167  0
             final long startProcessing = System.currentTimeMillis();
    -  168   +  164  0
             LOGGER.info("Processing Started for NVD CVE - {}", filePair.getNvdCveInfo().getId());
    +  165  0
             final long startProcessing = System.currentTimeMillis();
    +  166  
             try {
    -  169  0
                 importXML(filePair.getFirst(), filePair.getSecond());
    -  170  0
                 cveDB.commit();
    -  171  0
                 properties.save(filePair.getNvdCveInfo());
    -  172  0
             } catch (FileNotFoundException ex) {
    +  167  0
                 importXML(filePair.getFirst(), filePair.getSecond());
    +  168  0
                 cveDB.commit();
    +  169  0
                 properties.save(filePair.getNvdCveInfo());
    +  170  0
             } catch (FileNotFoundException ex) {
    +  171  0
                 throw new UpdateException(ex);
    +  172  0
             } catch (ParserConfigurationException ex) {
     173  0
                 throw new UpdateException(ex);
    -  174  0
             } catch (ParserConfigurationException ex) {
    +  174  0
             } catch (SAXException ex) {
     175  0
                 throw new UpdateException(ex);
    -  176  0
             } catch (SAXException ex) {
    +  176  0
             } catch (IOException ex) {
     177  0
                 throw new UpdateException(ex);
    -  178  0
             } catch (IOException ex) {
    +  178  0
             } catch (SQLException ex) {
     179  0
                 throw new UpdateException(ex);
    -  180  0
             } catch (SQLException ex) {
    +  180  0
             } catch (DatabaseException ex) {
     181  0
                 throw new UpdateException(ex);
    -  182  0
             } catch (DatabaseException ex) {
    +  182  0
             } catch (ClassNotFoundException ex) {
     183  0
                 throw new UpdateException(ex);
    -  184  0
             } catch (ClassNotFoundException ex) {
    -  185  0
                 throw new UpdateException(ex);
    -  186   +  184  
             } finally {
    -  187  0
                 filePair.cleanup();
    -  188  0
             }
    -  189  0
             LOGGER.info("Processing Complete for NVD CVE - {}  ({} ms)", filePair.getNvdCveInfo().getId(),
    -  190  0
                     System.currentTimeMillis() - startProcessing);
    -  191  0
         }
    -  192   +  185  0
                 filePair.cleanup();
    +  186  0
             }
    +  187  0
             LOGGER.info("Processing Complete for NVD CVE - {}  ({} ms)", filePair.getNvdCveInfo().getId(),
    +  188  0
                     System.currentTimeMillis() - startProcessing);
    +  189  0
         }
    +  190  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve.html index 152281de7..1dd17b0af 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve.html @@ -369,6 +369,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Confidence.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Confidence.html index 729e7b8d9..f5b3de2b0 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Confidence.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Confidence.html @@ -100,6 +100,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Dependency.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Dependency.html index 3299c4850..20b52b355 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Dependency.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Dependency.html @@ -266,15 +266,15 @@
          * Constructs a new Dependency object.
     127  
          */
    -  128  94
         public Dependency() {
    -  129  94
             vendorEvidence = new EvidenceCollection();
    -  130  94
             productEvidence = new EvidenceCollection();
    -  131  94
             versionEvidence = new EvidenceCollection();
    -  132  94
             identifiers = new TreeSet<Identifier>();
    -  133  94
             vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
    -  134  94
             suppressedIdentifiers = new TreeSet<Identifier>();
    -  135  94
             suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
    -  136  94
         }
    +  128  98
         public Dependency() {
    +  129  98
             vendorEvidence = new EvidenceCollection();
    +  130  98
             productEvidence = new EvidenceCollection();
    +  131  98
             versionEvidence = new EvidenceCollection();
    +  132  98
             identifiers = new TreeSet<Identifier>();
    +  133  98
             vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
    +  134  98
             suppressedIdentifiers = new TreeSet<Identifier>();
    +  135  98
             suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
    +  136  98
         }
     137  
     
     138   @@ -310,7 +310,7 @@
          */
     157  
         public String getFileName() {
    -  158  76
             return this.fileName;
    +  158  85
             return this.fileName;
     159  
         }
     160   @@ -387,7 +387,7 @@
          */
     200  
         public String getActualFilePath() {
    -  201  73
             return this.actualFilePath;
    +  201  79
             return this.actualFilePath;
     202  
         }
     203   @@ -404,7 +404,7 @@
          */
     209  
         public File getActualFile() {
    -  210  142
             return new File(this.actualFilePath);
    +  210  81
             return new File(this.actualFilePath);
     211  
         }
     212   @@ -435,7 +435,7 @@
          * The file name to display in reports.
     227  
          */
    -  228  94
         private String displayName = null;
    +  228  98
         private String displayName = null;
     229  
     
     230   @@ -499,7 +499,7 @@
          */
     262  
         public String getFilePath() {
    -  263  120
             return this.filePath;
    +  263  136
             return this.filePath;
     264  
         }
     265   @@ -582,7 +582,7 @@
          */
     307  
         public Set<Identifier> getIdentifiers() {
    -  308  491
             return this.identifiers;
    +  308  521
             return this.identifiers;
     309  
         }
     310   @@ -904,7 +904,7 @@
          */
     491  
         public EvidenceCollection getVendorEvidence() {
    -  492  175
             return this.vendorEvidence;
    +  492  174
             return this.vendorEvidence;
     493  
         }
     494   @@ -921,7 +921,7 @@
          */
     500  
         public EvidenceCollection getProductEvidence() {
    -  501  213
             return this.productEvidence;
    +  501  214
             return this.productEvidence;
     502  
         }
     503   @@ -938,7 +938,7 @@
          */
     509  
         public EvidenceCollection getVersionEvidence() {
    -  510  114
             return this.versionEvidence;
    +  510  151
             return this.versionEvidence;
     511  
         }
     512   @@ -1051,7 +1051,7 @@
          */
     569  
         public SortedSet<Vulnerability> getVulnerabilities() {
    -  570  15
             return vulnerabilities;
    +  570  23
             return vulnerabilities;
     571  
         }
     572   @@ -1124,7 +1124,7 @@
          * A collection of related dependencies.
     615  
          */
    -  616  94
         private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
    +  616  98
         private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
     617  
     
     618   @@ -1154,7 +1154,7 @@
          * A list of projects that reference this dependency.
     631  
          */
    -  632  94
         private Set<String> projectReferences = new HashSet<String>();
    +  632  98
         private Set<String> projectReferences = new HashSet<String>();
     633  
     
     634   @@ -1279,7 +1279,7 @@
          * A list of available versions.
     703  
          */
    -  704  94
         private List<String> availableVersions = new ArrayList<String>();
    +  704  98
         private List<String> availableVersions = new ArrayList<String>();
     705  
     
     706   @@ -1413,24 +1413,24 @@
         @Override
     784  
         public int hashCode() {
    -  785  12
             return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
    -  786  6
                     .append(actualFilePath)
    -  787  6
                     .append(filePath)
    -  788  6
                     .append(fileName)
    -  789  6
                     .append(md5sum)
    -  790  6
                     .append(sha1sum)
    -  791  6
                     .append(identifiers)
    -  792  6
                     .append(vendorEvidence)
    -  793  6
                     .append(productEvidence)
    -  794  6
                     .append(versionEvidence)
    -  795  6
                     .append(description)
    -  796  6
                     .append(license)
    -  797  6
                     .append(vulnerabilities)
    +  785  24
             return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
    +  786  12
                     .append(actualFilePath)
    +  787  12
                     .append(filePath)
    +  788  12
                     .append(fileName)
    +  789  12
                     .append(md5sum)
    +  790  12
                     .append(sha1sum)
    +  791  12
                     .append(identifiers)
    +  792  12
                     .append(vendorEvidence)
    +  793  12
                     .append(productEvidence)
    +  794  12
                     .append(versionEvidence)
    +  795  12
                     .append(description)
    +  796  12
                     .append(license)
    +  797  12
                     .append(vulnerabilities)
     798  
                     //.append(relatedDependencies)
    -  799  6
                     .append(projectReferences)
    -  800  6
                     .append(availableVersions)
    -  801  6
                     .toHashCode();
    +  799  12
                     .append(projectReferences)
    +  800  12
                     .append(availableVersions)
    +  801  12
                     .toHashCode();
     802  
         }
     803   @@ -1460,6 +1460,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Evidence.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Evidence.html index 0b2171e37..52bff3466 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Evidence.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Evidence.html @@ -77,7 +77,7 @@
      * @author Jeremy Long
     30  
      */
    -  31  691
     public class Evidence implements Serializable, Comparable<Evidence> {
    +  31  751
     public class Evidence implements Serializable, Comparable<Evidence> {
     32  
     
     33   @@ -134,12 +134,12 @@
          * @param confidence the confidence of the evidence.
     60  
          */
    -  61  437
         public Evidence(String source, String name, String value, Confidence confidence) {
    -  62  437
             this.source = source;
    -  63  437
             this.name = name;
    -  64  437
             this.value = value;
    -  65  437
             this.confidence = confidence;
    -  66  437
         }
    +  61  469
         public Evidence(String source, String name, String value, Confidence confidence) {
    +  62  468
             this.source = source;
    +  63  470
             this.name = name;
    +  64  470
             this.value = value;
    +  65  470
             this.confidence = confidence;
    +  66  469
         }
     67  
     
     68   @@ -164,7 +164,7 @@
          */
     78  
         public String getName() {
    -  79  25
             return name;
    +  79  152
             return name;
     80  
         }
     81   @@ -207,7 +207,7 @@
          */
     101  
         public String getSource() {
    -  102  14
             return source;
    +  102  522
             return source;
     103  
         }
     104   @@ -250,8 +250,8 @@
          */
     124  
         public String getValue() {
    -  125  451
             used = true;
    -  126  451
             return value;
    +  125  455
             used = true;
    +  126  455
             return value;
     127  
         }
     128   @@ -274,8 +274,8 @@
          */
     137  
         public String getValue(Boolean setUsed) {
    -  138  49
             used = used || setUsed;
    -  139  49
             return value;
    +  138  92
             used = used || setUsed;
    +  139  92
             return value;
     140  
         }
     141   @@ -318,7 +318,7 @@
          */
     161  
         public boolean isUsed() {
    -  162  390
             return used;
    +  162  400
             return used;
     163  
         }
     164   @@ -465,19 +465,19 @@
         @Override
     245  
         public int compareTo(Evidence o) {
    -  246  702
             if (o == null) {
    +  246  763
             if (o == null) {
     247  0
                 return 1;
     248  
             }
    -  249  702
             if (StringUtils.equalsIgnoreCase(source, o.source)) {
    -  250  451
                 if (StringUtils.equalsIgnoreCase(name, o.name)) {
    -  251  240
                     if (StringUtils.equalsIgnoreCase(value, o.value)) {
    +  249  763
             if (StringUtils.equalsIgnoreCase(source, o.source)) {
    +  250  456
                 if (StringUtils.equalsIgnoreCase(name, o.name)) {
    +  251  244
                     if (StringUtils.equalsIgnoreCase(value, o.value)) {
     252  
                         //TODO the call to ObjectUtils.equals needs to be replaced when we
     253  
                         //stop supporting Jenkins 1.6 requirement.
    -  254  215
                         if (ObjectUtils.equals(confidence, o.confidence)) {
    -  255  213
                             return 0; //they are equal
    +  254  219
                         if (ObjectUtils.equals(confidence, o.confidence)) {
    +  255  217
                             return 0; //they are equal
     256  
                         } else {
     257  2
                             return ObjectUtils.compare(confidence, o.confidence);
    @@ -490,12 +490,12 @@
                     }
     262  
                 } else {
    -  263  211
                     return compareToIgnoreCaseWithNullCheck(name, o.name);
    +  263  215
                     return compareToIgnoreCaseWithNullCheck(name, o.name);
     264  
                 }
     265  
             } else {
    -  266  251
                 return compareToIgnoreCaseWithNullCheck(source, o.source);
    +  266  304
                 return compareToIgnoreCaseWithNullCheck(source, o.source);
     267  
             }
     268   @@ -522,15 +522,15 @@
          */
     279  
         private int compareToIgnoreCaseWithNullCheck(String me, String other) {
    -  280  486
             if (me == null && other == null) {
    +  280  542
             if (me == null && other == null) {
     281  0
                 return 0;
    -  282  487
             } else if (me == null) {
    +  282  542
             } else if (me == null) {
     283  0
                 return -1; //the other string is greater then me
    -  284  487
             } else if (other == null) {
    +  284  544
             } else if (other == null) {
     285  0
                 return 1; //me is greater then the other string
     286  
             }
    -  287  486
             return me.compareToIgnoreCase(other);
    +  287  543
             return me.compareToIgnoreCase(other);
     288  
         }
     289   @@ -556,6 +556,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.EvidenceCollection.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.EvidenceCollection.html index fc98c1f92..e0ea72079 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.EvidenceCollection.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.EvidenceCollection.html @@ -189,12 +189,12 @@
          * Used to iterate over evidence that has was used (aka read) from the collection.
     88  
          */
    -  89  389
         private static final Filter<Evidence> EVIDENCE_USED = new Filter<Evidence>() {
    +  89  399
         private static final Filter<Evidence> EVIDENCE_USED = new Filter<Evidence>() {
     90  
             @Override
     91  
             public boolean passes(Evidence evidence) {
    -  92  388
                 return evidence.isUsed();
    +  92  398
                 return evidence.isUsed();
     93  
             }
     94   @@ -252,10 +252,10 @@
          * Creates a new EvidenceCollection.
     124  
          */
    -  125  294
         public EvidenceCollection() {
    -  126  294
             list = new TreeSet<Evidence>();
    -  127  294
             weightedStrings = new HashSet<String>();
    -  128  294
         }
    +  125  306
         public EvidenceCollection() {
    +  126  306
             list = new TreeSet<Evidence>();
    +  127  306
             weightedStrings = new HashSet<String>();
    +  128  306
         }
     129  
     
     130   @@ -270,8 +270,8 @@
          */
     135  
         public void addEvidence(Evidence e) {
    -  136  332
             list.add(e);
    -  137  332
         }
    +  136  364
             list.add(e);
    +  137  365
         }
     138  
     
     139   @@ -292,9 +292,9 @@
          */
     147  
         public void addEvidence(String source, String name, String value, Confidence confidence) {
    -  148  327
             final Evidence e = new Evidence(source, name, value, confidence);
    -  149  327
             addEvidence(e);
    -  150  327
         }
    +  148  359
             final Evidence e = new Evidence(source, name, value, confidence);
    +  149  359
             addEvidence(e);
    +  150  360
         }
     151  
     
     152   @@ -437,7 +437,7 @@
         @Override
     231  
         public Iterator<Evidence> iterator() {
    -  232  75
             return list.iterator();
    +  232  111
             return list.iterator();
     233  
         }
     234   @@ -456,23 +456,23 @@
          */
     241  
         public boolean containsUsedString(String text) {
    -  242  60
             if (text == null) {
    +  242  62
             if (text == null) {
     243  0
                 return false;
     244  
             }
    -  245  60
             final String textToTest = text.toLowerCase();
    +  245  62
             final String textToTest = text.toLowerCase();
     246  
     
    -  247  60
             for (Evidence e : EvidenceCollection.EVIDENCE_USED.filter(this)) {
    +  247  62
             for (Evidence e : EvidenceCollection.EVIDENCE_USED.filter(this)) {
     248  
                 //TODO consider changing the regex to only compare alpha-numeric (i.e. strip everything else)
    -  249  295
                 final String value = urlCorrection(e.getValue().toLowerCase()).replaceAll("[\\s_-]", "");
    -  250  295
                 if (value.contains(textToTest)) {
    -  251  31
                     return true;
    +  249  299
                 final String value = urlCorrection(e.getValue().toLowerCase()).replaceAll("[\\s_-]", "");
    +  250  299
                 if (value.contains(textToTest)) {
    +  251  32
                     return true;
     252  
                 }
    -  253  264
             }
    -  254  29
             return false;
    +  253  267
             }
    +  254  30
             return false;
     255  
         }
     256   @@ -655,7 +655,7 @@
          */
     364  
         public int size() {
    -  365  19
             return list.size();
    +  365  38
             return list.size();
     366  
         }
     367   @@ -698,8 +698,8 @@
          */
     386  
         private String urlCorrection(String value) {
    -  387  295
             if (value == null || !UrlStringUtils.containsUrl(value)) {
    -  388  273
                 return value;
    +  387  299
             if (value == null || !UrlStringUtils.containsUrl(value)) {
    +  388  277
                 return value;
     389  
             }
     390  22
             final StringBuilder sb = new StringBuilder(value.length());
    @@ -728,6 +728,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Identifier.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Identifier.html index c9186ca34..e7f9f0e2f 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Identifier.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Identifier.html @@ -287,7 +287,7 @@
          */
     145  
         public String getType() {
    -  146  543
             return type;
    +  146  575
             return type;
     147  
         }
     148   @@ -437,6 +437,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Reference.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Reference.html index b12dd4a29..08869be2f 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Reference.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Reference.html @@ -73,7 +73,7 @@
      * @author Jeremy Long
     28  
      */
    -  29  526
     public class Reference implements Serializable, Comparable<Reference> {
    +  29  533
     public class Reference implements Serializable, Comparable<Reference> {
     30  
     
     31   @@ -123,8 +123,8 @@
          */
     54  
         public void setName(String name) {
    -  55  163
             this.name = name;
    -  56  163
         }
    +  55  166
             this.name = name;
    +  56  166
         }
     57  
         /**
     58   @@ -164,8 +164,8 @@
          */
     76  
         public void setUrl(String url) {
    -  77  163
             this.url = url;
    -  78  163
         }
    +  77  166
             this.url = url;
    +  78  166
         }
     79  
         /**
     80   @@ -205,8 +205,8 @@
          */
     98  
         public void setSource(String source) {
    -  99  163
             this.source = source;
    -  100  163
         }
    +  99  166
             this.source = source;
    +  100  166
         }
     101  
     
     102   @@ -277,17 +277,17 @@
         @Override
     144  
         public int compareTo(Reference o) {
    -  145  726
             return new CompareToBuilder()
    -  146  363
                     .append(source, o.source)
    -  147  363
                     .append(name, o.name)
    -  148  363
                     .append(url, o.url)
    -  149  363
                     .toComparison();
    +  145  734
             return new CompareToBuilder()
    +  146  367
                     .append(source, o.source)
    +  147  367
                     .append(name, o.name)
    +  148  367
                     .append(url, o.url)
    +  149  367
                     .toComparison();
     150  
         }
     151  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Vulnerability.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Vulnerability.html index 62357de80..cb50f4718 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Vulnerability.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.Vulnerability.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    Vulnerability
    51%
    47/91
    18%
    4/22
    1.324
    Vulnerability
    54%
    50/91
    22%
    5/22
    1.324
     
    @@ -77,7 +77,7 @@
      * @author Jeremy Long
     30  
      */
    -  31  40
     public class Vulnerability implements Serializable, Comparable<Vulnerability> {
    +  31  41
     public class Vulnerability implements Serializable, Comparable<Vulnerability> {
     32  
     
     33   @@ -112,7 +112,7 @@
          */
     48  
         public String getName() {
    -  49  73
             return name;
    +  49  90
             return name;
     50  
         }
     51   @@ -129,8 +129,8 @@
          */
     57  
         public void setName(String name) {
    -  58  37
             this.name = name;
    -  59  37
         }
    +  58  38
             this.name = name;
    +  59  38
         }
     60  
         /**
     61   @@ -170,15 +170,15 @@
          */
     79  
         public void setDescription(String description) {
    -  80  36
             this.description = description;
    -  81  36
         }
    +  80  37
             this.description = description;
    +  81  37
         }
     82  
         /**
     83  
          * References for this vulnerability.
     84  
          */
    -  85  40
         private SortedSet<Reference> references = new TreeSet<Reference>();
    +  85  41
         private SortedSet<Reference> references = new TreeSet<Reference>();
     86  
     
     87   @@ -246,19 +246,19 @@
          */
     121  
         public void addReference(String referenceSource, String referenceName, String referenceUrl) {
    -  122  68
             final Reference ref = new Reference();
    -  123  68
             ref.setSource(referenceSource);
    -  124  68
             ref.setName(referenceName);
    -  125  68
             ref.setUrl(referenceUrl);
    -  126  68
             this.references.add(ref);
    -  127  68
         }
    +  122  71
             final Reference ref = new Reference();
    +  123  71
             ref.setSource(referenceSource);
    +  124  71
             ref.setName(referenceName);
    +  125  71
             ref.setUrl(referenceUrl);
    +  126  71
             this.references.add(ref);
    +  127  71
         }
     128  
         /**
     129  
          * A set of vulnerable software.
     130  
          */
    -  131  40
         private SortedSet<VulnerableSoftware> vulnerableSoftware = new TreeSet<VulnerableSoftware>();
    +  131  41
         private SortedSet<VulnerableSoftware> vulnerableSoftware = new TreeSet<VulnerableSoftware>();
     132  
     
     133   @@ -308,7 +308,7 @@
          */
     157  
         public boolean addVulnerableSoftware(String cpe) {
    -  158  876
             return addVulnerableSoftware(cpe, null);
    +  158  907
             return addVulnerableSoftware(cpe, null);
     159  
         }
     160   @@ -331,13 +331,13 @@
          */
     169  
         public boolean addVulnerableSoftware(String cpe, String previousVersion) {
    -  170  947
             final VulnerableSoftware vs = new VulnerableSoftware();
    -  171  947
             vs.setCpe(cpe);
    -  172  947
             if (previousVersion != null) {
    -  173  9
                 vs.setPreviousVersion(previousVersion);
    +  170  979
             final VulnerableSoftware vs = new VulnerableSoftware();
    +  171  979
             vs.setCpe(cpe);
    +  172  979
             if (previousVersion != null) {
    +  173  10
                 vs.setPreviousVersion(previousVersion);
     174  
             }
    -  175  947
             return updateVulnerableSoftware(vs);
    +  175  979
             return updateVulnerableSoftware(vs);
     176  
         }
     177   @@ -356,11 +356,11 @@
          */
     184  
         public boolean updateVulnerableSoftware(VulnerableSoftware vulnSoftware) {
    -  185  948
             if (vulnerableSoftware.contains(vulnSoftware)) {
    +  185  980
             if (vulnerableSoftware.contains(vulnSoftware)) {
     186  3
                 vulnerableSoftware.remove(vulnSoftware);
     187  
             }
    -  188  948
             return vulnerableSoftware.add(vulnSoftware);
    +  188  980
             return vulnerableSoftware.add(vulnSoftware);
     189  
         }
     190   @@ -402,8 +402,8 @@
          */
     209  
         public void setCwe(String cwe) {
    -  210  29
             this.cwe = cwe;
    -  211  29
         }
    +  210  30
             this.cwe = cwe;
    +  211  30
         }
     212  
         /**
     213   @@ -443,8 +443,8 @@
          */
     231  
         public void setCvssScore(float cvssScore) {
    -  232  36
             this.cvssScore = cvssScore;
    -  233  36
         }
    +  232  37
             this.cvssScore = cvssScore;
    +  233  37
         }
     234  
         /**
     235   @@ -484,8 +484,8 @@
          */
     253  
         public void setCvssAccessVector(String cvssAccessVector) {
    -  254  35
             this.cvssAccessVector = cvssAccessVector;
    -  255  35
         }
    +  254  36
             this.cvssAccessVector = cvssAccessVector;
    +  255  36
         }
     256  
         /**
     257   @@ -525,8 +525,8 @@
          */
     275  
         public void setCvssAccessComplexity(String cvssAccessComplexity) {
    -  276  35
             this.cvssAccessComplexity = cvssAccessComplexity;
    -  277  35
         }
    +  276  36
             this.cvssAccessComplexity = cvssAccessComplexity;
    +  277  36
         }
     278  
         /**
     279   @@ -566,8 +566,8 @@
          */
     297  
         public void setCvssAuthentication(String cvssAuthentication) {
    -  298  35
             this.cvssAuthentication = cvssAuthentication;
    -  299  35
         }
    +  298  36
             this.cvssAuthentication = cvssAuthentication;
    +  299  36
         }
     300  
         /**
     301   @@ -607,8 +607,8 @@
          */
     319  
         public void setCvssConfidentialityImpact(String cvssConfidentialityImpact) {
    -  320  35
             this.cvssConfidentialityImpact = cvssConfidentialityImpact;
    -  321  35
         }
    +  320  36
             this.cvssConfidentialityImpact = cvssConfidentialityImpact;
    +  321  36
         }
     322  
         /**
     323   @@ -648,8 +648,8 @@
          */
     341  
         public void setCvssIntegrityImpact(String cvssIntegrityImpact) {
    -  342  35
             this.cvssIntegrityImpact = cvssIntegrityImpact;
    -  343  35
         }
    +  342  36
             this.cvssIntegrityImpact = cvssIntegrityImpact;
    +  343  36
         }
     344  
         /**
     345   @@ -689,8 +689,8 @@
          */
     363  
         public void setCvssAvailabilityImpact(String cvssAvailabilityImpact) {
    -  364  35
             this.cvssAvailabilityImpact = cvssAvailabilityImpact;
    -  365  35
         }
    +  364  36
             this.cvssAvailabilityImpact = cvssAvailabilityImpact;
    +  365  36
         }
     366  
     
     367   @@ -719,9 +719,9 @@
         @Override
     383  
         public int hashCode() {
    -  384  0
             int hash = 5;
    -  385  0
             hash = 41 * hash + (this.name != null ? this.name.hashCode() : 0);
    -  386  0
             return hash;
    +  384  9
             int hash = 5;
    +  385  9
             hash = 41 * hash + (this.name != null ? this.name.hashCode() : 0);
    +  386  9
             return hash;
     387  
         }
     388   @@ -810,9 +810,9 @@
          */
     439  
         public void setMatchedCPE(String cpeId, String previous) {
    -  440  8
             matchedCPE = cpeId;
    -  441  8
             matchedAllPreviousCPE = previous;
    -  442  8
         }
    +  440  9
             matchedCPE = cpeId;
    +  441  9
             matchedAllPreviousCPE = previous;
    +  442  9
         }
     443  
     
     444   @@ -868,6 +868,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerabilityComparator.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerabilityComparator.html index 815b77595..a6c4af5b5 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerabilityComparator.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerabilityComparator.html @@ -71,7 +71,7 @@
      * @author Jeremy Long
     27  
      */
    -  28  213
     public class VulnerabilityComparator implements Comparator<Vulnerability>, Serializable {
    +  28  225
     public class VulnerabilityComparator implements Comparator<Vulnerability>, Serializable {
     29  
     
     30   @@ -102,13 +102,13 @@
         @Override
     43  
         public int compare(Vulnerability o1, Vulnerability o2) {
    -  44  25
             return o2.getName().compareTo(o1.getName());
    +  44  29
             return o2.getName().compareTo(o1.getName());
     45  
         }
     46  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerableSoftware.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerableSoftware.html index 6138e46b6..005800997 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerableSoftware.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.dependency.VulnerableSoftware.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    VulnerableSoftware
    70%
    70/99
    79%
    57/72
    3.15
    VulnerableSoftware
    71%
    72/101
    80%
    61/76
    3.3
     
    @@ -79,7 +79,7 @@
      * @author Jeremy Long
     31  
      */
    -  32  12396
     public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> {
    +  32  12845
     public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> {
     33  
     
     34   @@ -113,13 +113,13 @@
         public void setCpe(String cpe) {
     49  
             try {
    -  50  1103
                 parseName(cpe);
    +  50  1159
                 parseName(cpe);
     51  0
             } catch (UnsupportedEncodingException ex) {
     52  0
                 LOGGER.warn("Character encoding is unsupported for CPE '{}'.", cpe);
     53  0
                 LOGGER.debug("", ex);
     54  0
                 setName(cpe);
    -  55  1103
             }
    -  56  1103
         }
    +  55  1159
             }
    +  56  1159
         }
     57  
     
     58   @@ -154,32 +154,32 @@
         @Override
     73  
         public void parseName(String cpeName) throws UnsupportedEncodingException {
    -  74  1677
             this.name = cpeName;
    -  75  1677
             if (cpeName != null && cpeName.length() > 7) {
    -  76  1672
                 final String[] data = cpeName.substring(7).split(":");
    -  77  1672
                 if (data.length >= 1) {
    -  78  1672
                     this.setVendor(urlDecode(data[0]));
    +  74  1797
             this.name = cpeName;
    +  75  1797
             if (cpeName != null && cpeName.length() > 7) {
    +  76  1788
                 final String[] data = cpeName.substring(7).split(":");
    +  77  1788
                 if (data.length >= 1) {
    +  78  1788
                     this.setVendor(urlDecode(data[0]));
     79  
                 }
    -  80  1672
                 if (data.length >= 2) {
    -  81  1671
                     this.setProduct(urlDecode(data[1]));
    +  80  1788
                 if (data.length >= 2) {
    +  81  1787
                     this.setProduct(urlDecode(data[1]));
     82  
                 }
    -  83  1672
                 if (data.length >= 3) {
    -  84  1671
                     version = urlDecode(data[2]);
    +  83  1788
                 if (data.length >= 3) {
    +  84  1787
                     version = urlDecode(data[2]);
     85  
                 }
    -  86  1672
                 if (data.length >= 4) {
    +  86  1788
                 if (data.length >= 4) {
     87  232
                     update = urlDecode(data[3]);
     88  
                 }
    -  89  1672
                 if (data.length >= 5) {
    +  89  1788
                 if (data.length >= 5) {
     90  0
                     edition = urlDecode(data[4]);
     91  
                 }
     92  
             }
    -  93  1677
         }
    +  93  1797
         }
     94  
         /**
     95   @@ -236,8 +236,8 @@
          */
     122  
         public void setPreviousVersion(String previousVersion) {
    -  123  14
             this.previousVersion = previousVersion;
    -  124  14
         }
    +  123  15
             this.previousVersion = previousVersion;
    +  124  15
         }
     125  
     
     126   @@ -288,9 +288,9 @@
         @Override
     153  
         public int hashCode() {
    -  154  131
             int hash = 7;
    -  155  131
             hash = 83 * hash + (this.name != null ? this.name.hashCode() : 0);
    -  156  131
             return hash;
    +  154  149
             int hash = 7;
    +  155  149
             hash = 83 * hash + (this.name != null ? this.name.hashCode() : 0);
    +  156  149
             return hash;
     157  
         }
     158   @@ -330,21 +330,21 @@
         @Override
     176  
         public int compareTo(VulnerableSoftware vs) {
    -  177  10736
             int result = 0;
    -  178  10736
             final String[] left = this.name.split(":");
    -  179  10736
             final String[] right = vs.getName().split(":");
    -  180  10736
             final int max = (left.length <= right.length) ? left.length : right.length;
    -  181  10736
             if (max > 0) {
    -  182  64619
                 for (int i = 0; result == 0 && i < max; i++) {
    -  183  53883
                     final String[] subLeft = left[i].split("(\\.|-)");
    -  184  53883
                     final String[] subRight = right[i].split("(\\.|-)");
    -  185  53883
                     final int subMax = (subLeft.length <= subRight.length) ? subLeft.length : subRight.length;
    -  186  53883
                     if (subMax > 0) {
    -  187  123319
                         for (int x = 0; result == 0 && x < subMax; x++) {
    -  188  69445
                             if (isPositiveInteger(subLeft[x]) && isPositiveInteger(subRight[x])) {
    +  177  11074
             int result = 0;
    +  178  11074
             final String[] left = this.name.split(":");
    +  179  11074
             final String[] right = vs.getName().split(":");
    +  180  11074
             final int max = (left.length <= right.length) ? left.length : right.length;
    +  181  11074
             if (max > 0) {
    +  182  66639
                 for (int i = 0; result == 0 && i < max; i++) {
    +  183  55565
                     final String[] subLeft = left[i].split("(\\.|-)");
    +  184  55565
                     final String[] subRight = right[i].split("(\\.|-)");
    +  185  55565
                     final int subMax = (subLeft.length <= subRight.length) ? subLeft.length : subRight.length;
    +  186  55565
                     if (subMax > 0) {
    +  187  127140
                         for (int x = 0; result == 0 && x < subMax; x++) {
    +  188  71584
                             if (isPositiveInteger(subLeft[x]) && isPositiveInteger(subRight[x])) {
     189  
                                 try {
    -  190  25569
                                     result = Long.valueOf(subLeft[x]).compareTo(Long.valueOf(subRight[x]));
    +  190  25239
                                     result = Long.valueOf(subLeft[x]).compareTo(Long.valueOf(subRight[x]));
     191  0
                                 } catch (NumberFormatException ex) {
     192  
                                     //ignore the exception - they obviously aren't numbers
    @@ -352,20 +352,20 @@  194  0
                                         result = subLeft[x].compareToIgnoreCase(subRight[x]);
     195  
                                     }
    -  196  25569
                                 }
    +  196  25239
                                 }
     197  
                             } else {
    -  198  43876
                                 result = subLeft[x].compareToIgnoreCase(subRight[x]);
    +  198  46345
                                 result = subLeft[x].compareToIgnoreCase(subRight[x]);
     199  
                             }
     200  
                         }
    -  201  53874
                         if (result == 0) {
    -  202  43469
                             if (subLeft.length > subRight.length) {
    +  201  55556
                         if (result == 0) {
    +  202  44814
                             if (subLeft.length > subRight.length) {
     203  156
                                 result = 2;
     204  
                             }
    -  205  43469
                             if (subRight.length > subLeft.length) {
    +  205  44814
                             if (subRight.length > subLeft.length) {
     206  53
                                 result = -2;
     207  
                             }
    @@ -378,12 +378,12 @@
                     }
     212  
                 }
    -  213  10736
                 if (result == 0) {
    -  214  116
                     if (left.length > right.length) {
    +  213  11074
                 if (result == 0) {
    +  214  117
                     if (left.length > right.length) {
     215  68
                         result = 2;
     216  
                     }
    -  217  116
                     if (right.length > left.length) {
    +  217  117
                     if (right.length > left.length) {
     218  10
                         result = -2;
     219  
                     }
    @@ -394,7 +394,7 @@  222  0
                 result = this.getName().compareToIgnoreCase(vs.getName());
     223  
             }
    -  224  10736
             return result;
    +  224  11074
             return result;
     225  
         }
     226   @@ -404,252 +404,270 @@  228  
          * Determines if the string passed in is a positive integer.
     229   -
          *
    +
          * To be counted as a positive integer, the string must only contain 0-9
     230   -
          * @param str the string to test
    +
          * and must not have any leading zeros (though "0" is a valid positive
     231   -
          * @return true if the string only contains 0-9, otherwise false.
    +
          * integer).
     232   -
          */
    +
          *
     233   -
         private static boolean isPositiveInteger(final String str) {
    -  234  95100
             if (str == null || str.isEmpty()) {
    -  235  14
                 return false;
    +
          * @param str the string to test
    +  234   +
          * @return true if the string only contains 0-9, otherwise false.
    +  235   +
          */
     236   +
         static boolean isPositiveInteger(final String str) {
    +  237  97150
             if (str == null || str.isEmpty()) {
    +  238  14
                 return false;
    +  239  
             }
    -  237  154859
             for (int i = 0; i < str.length(); i++) {
    -  238  103635
                 final char c = str.charAt(i);
    -  239  103635
                 if (c < '0' || c > '9') {
    -  240  43862
                     return false;
    +  240   +
     
     241   -
                 }
    +
             // numbers with leading zeros should not be treated as numbers
     242   -
             }
    -  243  51224
             return true;
    -  244   -
         }
    +
             // (e.g. when comparing "01" <-> "1")
    +  243  97136
             if (str.charAt(0) == '0' && str.length() > 1) {
    +  244  1153
                 return false;
     245   -
         /**
    +
             }
     246   -
          * The name of the cpe.
    -  247   -
          */
    -  248   -
         private String name;
    -  249  
     
    -  250   -
         /**
    +  247  153422
             for (int i = 0; i < str.length(); i++) {
    +  248  102622
                 final char c = str.charAt(i);
    +  249  102622
                 if (c < '0' || c > '9') {
    +  250  45183
                     return false;
     251   -
          * Get the value of name.
    +
                 }
     252   -
          *
    -  253   -
          * @return the value of name
    +
             }
    +  253  50800
             return true;
     254   -
          */
    +
         }
     255   -
         public String getName() {
    -  256  10783
             return name;
    +
         /**
    +  256   +
          * The name of the cpe.
     257   -
         }
    +
          */
     258   -
     
    +
         private String name;
     259   -
         /**
    +
     
     260   -
          * Set the value of name.
    +
         /**
     261   -
          *
    +
          * Get the value of name.
     262   -
          * @param name new value of name
    +
          *
     263   -
          */
    +
          * @return the value of name
     264   -
         public void setName(String name) {
    -  265  0
             this.name = name;
    -  266  0
         }
    +
          */
    +  265   +
         public String getName() {
    +  266  11121
             return name;
     267   -
         /**
    +
         }
     268   -
          * The product version number.
    +
     
     269   -
          */
    +
         /**
     270   -
         private String version;
    +
          * Set the value of name.
     271   -
     
    +
          *
     272   -
         /**
    +
          * @param name new value of name
     273   -
          * Get the value of version.
    +
          */
     274   -
          *
    -  275   -
          * @return the value of version
    -  276   -
          */
    +
         public void setName(String name) {
    +  275  0
             this.name = name;
    +  276  0
         }
     277   -
         public String getVersion() {
    -  278  2083
             return version;
    +
         /**
    +  278   +
          * The product version number.
     279   -
         }
    +
          */
     280   -
     
    +
         private String version;
     281   -
         /**
    +
     
     282   -
          * Set the value of version.
    +
         /**
     283   -
          *
    +
          * Get the value of version.
     284   -
          * @param version new value of version
    +
          *
     285   -
          */
    +
          * @return the value of version
     286   -
         public void setVersion(String version) {
    -  287  0
             this.version = version;
    -  288  0
         }
    +
          */
    +  287   +
         public String getVersion() {
    +  288  2329
             return version;
     289   -
         /**
    +
         }
     290   -
          * The product update version.
    +
     
     291   -
          */
    +
         /**
     292   -
         private String update;
    +
          * Set the value of version.
     293   -
     
    +
          *
     294   -
         /**
    +
          * @param version new value of version
     295   -
          * Get the value of update.
    +
          */
     296   -
          *
    -  297   -
          * @return the value of update
    -  298   -
          */
    +
         public void setVersion(String version) {
    +  297  0
             this.version = version;
    +  298  0
         }
     299   -
         public String getUpdate() {
    -  300  1372
             return update;
    +
         /**
    +  300   +
          * The product update version.
     301   -
         }
    +
          */
     302   -
     
    +
         private String update;
     303   -
         /**
    +
     
     304   -
          * Set the value of update.
    +
         /**
     305   -
          *
    +
          * Get the value of update.
     306   -
          * @param update new value of update
    +
          *
     307   -
          */
    +
          * @return the value of update
     308   -
         public void setUpdate(String update) {
    -  309  0
             this.update = update;
    -  310  0
         }
    +
          */
    +  309   +
         public String getUpdate() {
    +  310  1490
             return update;
     311   -
         /**
    -  312   -
          * The product edition.
    -  313   -
          */
    -  314   -
         private String edition;
    -  315   -
     
    -  316   -
         /**
    -  317   -
          * Get the value of edition.
    -  318   -
          *
    -  319   -
          * @return the value of edition
    -  320   -
          */
    -  321   -
         public String getEdition() {
    -  322  0
             return edition;
    -  323  
         }
    -  324   +  312  
     
    -  325   +  313  
         /**
    -  326   -
          * Set the value of edition.
    -  327   +  314   +
          * Set the value of update.
    +  315  
          *
    -  328   -
          * @param edition new value of edition
    -  329   +  316   +
          * @param update new value of update
    +  317  
          */
    -  330   -
         public void setEdition(String edition) {
    -  331  0
             this.edition = edition;
    -  332  0
         }
    -  333   -
     
    -  334   +  318   +
         public void setUpdate(String update) {
    +  319  0
             this.update = update;
    +  320  0
         }
    +  321  
         /**
    -  335   -
          * Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default.
    -  336   +  322   +
          * The product edition.
    +  323   +
          */
    +  324   +
         private String edition;
    +  325   +
     
    +  326   +
         /**
    +  327   +
          * Get the value of edition.
    +  328  
          *
    +  329   +
          * @return the value of edition
    +  330   +
          */
    +  331   +
         public String getEdition() {
    +  332  0
             return edition;
    +  333   +
         }
    +  334   +
     
    +  335   +
         /**
    +  336   +
          * Set the value of edition.
     337   -
          * @param string the string to URL Decode
    +
          *
     338   -
          * @return the URL Decoded string
    +
          * @param edition new value of edition
     339  
          */
     340   -
         private String urlDecode(String string) {
    -  341  5246
             final String text = string.replace("+", "%2B");
    -  342   -
             String result;
    +
         public void setEdition(String edition) {
    +  341  0
             this.edition = edition;
    +  342  0
         }
     343   -
             try {
    -  344  5246
                 result = URLDecoder.decode(text, "UTF-8");
    -  345  0
             } catch (UnsupportedEncodingException ex) {
    -  346   -
                 try {
    -  347  0
                     result = URLDecoder.decode(text, "ASCII");
    -  348  0
                 } catch (UnsupportedEncodingException ex1) {
    -  349  0
                     result = defaultUrlDecode(text);
    -  350  0
                 }
    -  351  5246
             }
    -  352  5246
             return result;
    -  353   -
         }
    -  354  
     
    -  355   +  344  
         /**
    -  356   -
          * Call {@link java.net.URLDecoder#decode(String)} to URL decode using the default encoding.
    -  357   +  345   +
          * Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default.
    +  346  
          *
    -  358   -
          * @param text www-form-encoded URL to decode
    -  359   -
          * @return the newly decoded String
    -  360   +  347   +
          * @param string the string to URL Decode
    +  348   +
          * @return the URL Decoded string
    +  349  
          */
    -  361   -
         @SuppressWarnings("deprecation")
    -  362   -
         private String defaultUrlDecode(final String text) {
    -  363  0
             return URLDecoder.decode(text);
    -  364   +  350   +
         private String urlDecode(String string) {
    +  351  5594
             final String text = string.replace("+", "%2B");
    +  352   +
             String result;
    +  353   +
             try {
    +  354  5594
                 result = URLDecoder.decode(text, "UTF-8");
    +  355  0
             } catch (UnsupportedEncodingException ex) {
    +  356   +
                 try {
    +  357  0
                     result = URLDecoder.decode(text, "ASCII");
    +  358  0
                 } catch (UnsupportedEncodingException ex1) {
    +  359  0
                     result = defaultUrlDecode(text);
    +  360  0
                 }
    +  361  5594
             }
    +  362  5594
             return result;
    +  363  
         }
    +  364   +
     
     365   +
         /**
    +  366   +
          * Call {@link java.net.URLDecoder#decode(String)} to URL decode using the default encoding.
    +  367   +
          *
    +  368   +
          * @param text www-form-encoded URL to decode
    +  369   +
          * @return the newly decoded String
    +  370   +
          */
    +  371   +
         @SuppressWarnings("deprecation")
    +  372   +
         private String defaultUrlDecode(final String text) {
    +  373  0
             return URLDecoder.decode(text);
    +  374   +
         }
    +  375  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ExceptionCollection.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ExceptionCollection.html index 80ae4be63..ce53a3f46 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ExceptionCollection.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ExceptionCollection.html @@ -413,6 +413,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.InitializationException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.InitializationException.html index dedb620fb..bc69af5ec 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.InitializationException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.InitializationException.html @@ -143,6 +143,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.NoDataException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.NoDataException.html index e58a3f11c..1ba66e9a9 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.NoDataException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.NoDataException.html @@ -147,6 +147,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ReportException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ReportException.html index 91956e01f..c9d8d690f 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ReportException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ReportException.html @@ -143,6 +143,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ScanAgentException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ScanAgentException.html index 0a6ca0c6d..a65599ad0 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ScanAgentException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.exception.ScanAgentException.html @@ -147,6 +147,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.EscapeTool.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.EscapeTool.html index 8f6ef2f37..553fcc954 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.EscapeTool.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.EscapeTool.html @@ -170,6 +170,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.ReportGenerator.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.ReportGenerator.html index 545c99573..c1b1d2e46 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.ReportGenerator.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.ReportGenerator.html @@ -77,21 +77,21 @@  29  
     import java.io.UnsupportedEncodingException;
     30   -
     import java.text.DateFormat;
    -  31   -
     import java.text.SimpleDateFormat;
    -  32   -
     import java.util.Date;
    -  33  
     import java.util.List;
    -  34   +  31  
     import org.apache.velocity.VelocityContext;
    -  35   +  32  
     import org.apache.velocity.app.VelocityEngine;
    -  36   +  33  
     import org.apache.velocity.context.Context;
    -  37   +  34  
     import org.apache.velocity.runtime.RuntimeConstants;
    +  35   +
     import org.joda.time.DateTime;
    +  36   +
     import org.joda.time.format.DateTimeFormat;
    +  37   +
     import org.joda.time.format.DateTimeFormatter;
     38  
     import org.owasp.dependencycheck.analyzer.Analyzer;
     39   @@ -218,349 +218,359 @@  104  
     
     105  0
             velocityEngine.init();
    -  106   +  106  0
             final EscapeTool enc = new EscapeTool();
    +  107  
     
    -  107  0
             final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z");
    -  108  0
             final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    -  109  0
             final Date d = new Date();
    -  110  0
             final String scanDate = dateFormat.format(d);
    -  111  0
             final String scanDateXML = dateFormatXML.format(d);
    -  112  0
             final EscapeTool enc = new EscapeTool();
    +  108  0
             final DateTime dt = new DateTime();
    +  109  0
             final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("MMM d, yyyy 'at' HH:mm:ss z");
    +  110  0
             final DateTimeFormatter dateFormatXML = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    +  111   +
     
    +  112   +
     //        final Date d = new Date();
     113   +
     //        final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z");
    +  114   +
     //        final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    +  115  0
             final String scanDate = dateFormat.print(dt);
    +  116  0
             final String scanDateXML = dateFormatXML.print(dt);
    +  117  
     
    -  114  0
             context.put("applicationName", applicationName);
    -  115  0
             context.put("dependencies", dependencies);
    -  116  0
             context.put("analyzers", analyzers);
    -  117  0
             context.put("properties", properties);
    -  118  0
             context.put("scanDate", scanDate);
    -  119  0
             context.put("scanDateXML", scanDateXML);
    -  120  0
             context.put("enc", enc);
    -  121  0
             context.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
    -  122  0
         }
    -  123   -
     
    -  124   -
         /**
    -  125   -
          * Creates a new Velocity Engine.
    -  126   -
          *
    +  118  0
             context.put("applicationName", applicationName);
    +  119  0
             context.put("dependencies", dependencies);
    +  120  0
             context.put("analyzers", analyzers);
    +  121  0
             context.put("properties", properties);
    +  122  0
             context.put("scanDate", scanDate);
    +  123  0
             context.put("scanDateXML", scanDateXML);
    +  124  0
             context.put("enc", enc);
    +  125  0
             context.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
    +  126  0
         }
     127   -
          * @return a velocity engine
    +
     
     128   -
          */
    +
         /**
     129   -
         private VelocityEngine createVelocityEngine() {
    -  130  0
             final VelocityEngine velocity = new VelocityEngine();
    +
          * Creates a new Velocity Engine.
    +  130   +
          *
     131   -
             // Logging redirection for Velocity - Required by Jenkins and other server applications
    -  132  0
             velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
    -  133  0
             return velocity;
    -  134   -
         }
    +
          * @return a velocity engine
    +  132   +
          */
    +  133   +
         private VelocityEngine createVelocityEngine() {
    +  134  0
             final VelocityEngine velocity = new VelocityEngine();
     135   -
     
    -  136   -
         /**
    -  137   -
          * Creates a new Velocity Context.
    +
             // Logging redirection for Velocity - Required by Jenkins and other server applications
    +  136  0
             velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
    +  137  0
             return velocity;
     138   -
          *
    -  139   -
          * @return a Velocity Context
    -  140   -
          */
    -  141   -
         private Context createContext() {
    -  142  0
             return new VelocityContext();
    -  143  
         }
    +  139   +
     
    +  140   +
         /**
    +  141   +
          * Creates a new Velocity Context.
    +  142   +
          *
    +  143   +
          * @return a Velocity Context
     144   -
     
    +
          */
     145   -
         /**
    -  146   -
          * Generates the Dependency Reports for the identified dependencies.
    +
         private Context createContext() {
    +  146  0
             return new VelocityContext();
     147   -
          *
    +
         }
     148   -
          * @param outputStream the OutputStream to send the generated report to
    +
     
     149   -
          * @param format the format the report should be written in
    +
         /**
     150   -
          * @throws IOException is thrown when the template file does not exist
    +
          * Generates the Dependency Reports for the identified dependencies.
     151   -
          * @throws Exception is thrown if there is an error writing out the reports
    +
          *
     152   -
          */
    +
          * @param outputStream the OutputStream to send the generated report to
     153   -
         public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
    -  154  0
             if (format == Format.XML || format == Format.ALL) {
    -  155  0
                 generateReport("XmlReport", outputStream);
    -  156   -
             }
    -  157  0
             if (format == Format.HTML || format == Format.ALL) {
    -  158  0
                 generateReport("HtmlReport", outputStream);
    -  159   -
             }
    -  160  0
             if (format == Format.VULN || format == Format.ALL) {
    -  161  0
                 generateReport("VulnerabilityReport", outputStream);
    -  162   -
             }
    -  163  0
         }
    -  164   -
     
    -  165   -
         /**
    -  166   -
          * Generates the Dependency Reports for the identified dependencies.
    -  167   -
          *
    -  168   -
          * @param outputDir the path where the reports should be written
    -  169  
          * @param format the format the report should be written in
    +  154   +
          * @throws IOException is thrown when the template file does not exist
    +  155   +
          * @throws Exception is thrown if there is an error writing out the reports
    +  156   +
          */
    +  157   +
         public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
    +  158  0
             if (format == Format.XML || format == Format.ALL) {
    +  159  0
                 generateReport("XmlReport", outputStream);
    +  160   +
             }
    +  161  0
             if (format == Format.HTML || format == Format.ALL) {
    +  162  0
                 generateReport("HtmlReport", outputStream);
    +  163   +
             }
    +  164  0
             if (format == Format.VULN || format == Format.ALL) {
    +  165  0
                 generateReport("VulnerabilityReport", outputStream);
    +  166   +
             }
    +  167  0
         }
    +  168   +
     
    +  169   +
         /**
     170   -
          * @throws ReportException is thrown if there is an error writing out the reports
    -  171   -
          */
    -  172   -
         public void generateReports(String outputDir, Format format) throws ReportException {
    -  173  0
             if (format == Format.XML || format == Format.ALL) {
    -  174  0
                 generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
    -  175   -
             }
    -  176  0
             if (format == Format.HTML || format == Format.ALL) {
    -  177  0
                 generateReport("HtmlReport", outputDir + File.separator + "dependency-check-report.html");
    -  178   -
             }
    -  179  0
             if (format == Format.VULN || format == Format.ALL) {
    -  180  0
                 generateReport("VulnerabilityReport", outputDir + File.separator + "dependency-check-vulnerability.html");
    -  181   -
             }
    -  182  0
         }
    -  183   -
     
    -  184   -
         /**
    -  185  
          * Generates the Dependency Reports for the identified dependencies.
    -  186   +  171  
          *
    -  187   +  172  
          * @param outputDir the path where the reports should be written
    -  188   -
          * @param outputFormat the format the report should be written in (XML,
    -  189   -
          * HTML, ALL)
    -  190   -
          * @throws ReportException is thrown if there is an error creating out the
    -  191   +  173   +
          * @param format the format the report should be written in
    +  174   +
          * @throws ReportException is thrown if there is an error writing out the
    +  175  
          * reports
    +  176   +
          */
    +  177   +
         public void generateReports(String outputDir, Format format) throws ReportException {
    +  178  0
             if (format == Format.XML || format == Format.ALL) {
    +  179  0
                 generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
    +  180   +
             }
    +  181  0
             if (format == Format.HTML || format == Format.ALL) {
    +  182  0
                 generateReport("HtmlReport", outputDir + File.separator + "dependency-check-report.html");
    +  183   +
             }
    +  184  0
             if (format == Format.VULN || format == Format.ALL) {
    +  185  0
                 generateReport("VulnerabilityReport", outputDir + File.separator + "dependency-check-vulnerability.html");
    +  186   +
             }
    +  187  0
         }
    +  188   +
     
    +  189   +
         /**
    +  190   +
          * Generates the Dependency Reports for the identified dependencies.
    +  191   +
          *
     192   -
          */
    +
          * @param outputDir the path where the reports should be written
     193   +
          * @param outputFormat the format the report should be written in (XML,
    +  194   +
          * HTML, ALL)
    +  195   +
          * @throws ReportException is thrown if there is an error creating out the
    +  196   +
          * reports
    +  197   +
          */
    +  198  
         public void generateReports(String outputDir, String outputFormat) throws ReportException {
    -  194  0
             final String format = outputFormat.toUpperCase();
    -  195  0
             final String pathToCheck = outputDir.toLowerCase();
    -  196  0
             if (format.matches("^(XML|HTML|VULN|ALL)$")) {
    -  197  0
                 if ("XML".equalsIgnoreCase(format)) {
    -  198  0
                     if (pathToCheck.endsWith(".xml")) {
    -  199  0
                         generateReport("XmlReport", outputDir);
    -  200   +  199  0
             final String format = outputFormat.toUpperCase();
    +  200  0
             final String pathToCheck = outputDir.toLowerCase();
    +  201  0
             if (format.matches("^(XML|HTML|VULN|ALL)$")) {
    +  202  0
                 if ("XML".equalsIgnoreCase(format)) {
    +  203  0
                     if (pathToCheck.endsWith(".xml")) {
    +  204  0
                         generateReport("XmlReport", outputDir);
    +  205  
                     } else {
    -  201  0
                         generateReports(outputDir, Format.XML);
    -  202   -
                     }
    -  203   -
                 }
    -  204  0
                 if ("HTML".equalsIgnoreCase(format)) {
    -  205  0
                     if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
    -  206  0
                         generateReport("HtmlReport", outputDir);
    +  206  0
                         generateReports(outputDir, Format.XML);
     207   -
                     } else {
    -  208  0
                         generateReports(outputDir, Format.HTML);
    -  209  
                     }
    -  210   +  208  
                 }
    -  211  0
                 if ("VULN".equalsIgnoreCase(format)) {
    -  212  0
                     if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
    -  213  0
                         generateReport("VulnReport", outputDir);
    +  209  0
                 if ("HTML".equalsIgnoreCase(format)) {
    +  210  0
                     if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
    +  211  0
                         generateReport("HtmlReport", outputDir);
    +  212   +
                     } else {
    +  213  0
                         generateReports(outputDir, Format.HTML);
     214   -
                     } else {
    -  215  0
                         generateReports(outputDir, Format.VULN);
    -  216  
                     }
    -  217   -
                 }
    -  218  0
                 if ("ALL".equalsIgnoreCase(format)) {
    -  219  0
                     generateReports(outputDir, Format.ALL);
    -  220   +  215  
                 }
    +  216  0
                 if ("VULN".equalsIgnoreCase(format)) {
    +  217  0
                     if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
    +  218  0
                         generateReport("VulnReport", outputDir);
    +  219   +
                     } else {
    +  220  0
                         generateReports(outputDir, Format.VULN);
     221   -
             }
    -  222  0
         }
    -  223   -
     
    -  224   -
         /**
    +
                     }
    +  222   +
                 }
    +  223  0
                 if ("ALL".equalsIgnoreCase(format)) {
    +  224  0
                     generateReports(outputDir, Format.ALL);
     225   -
          * Generates a report from a given Velocity Template. The template name
    +
                 }
     226   -
          * provided can be the name of a template contained in the jar file, such as
    -  227   -
          * 'XmlReport' or 'HtmlReport', or the template name can be the path to a
    +
             }
    +  227  0
         }
     228   -
          * template file.
    +
     
     229   -
          *
    -  230   -
          * @param templateName the name of the template to load
    -  231   -
          * @param outputStream the OutputStream to write the report to
    -  232   -
          * @throws ReportException is thrown when an exception occurs
    -  233   -
          */
    -  234   -
         protected void generateReport(String templateName, OutputStream outputStream) throws ReportException {
    -  235  0
             InputStream input = null;
    -  236  0
             String templatePath = null;
    -  237  0
             final File f = new File(templateName);
    -  238  0
             if (f.exists() && f.isFile()) {
    -  239   -
                 try {
    -  240  0
                     templatePath = templateName;
    -  241  0
                     input = new FileInputStream(f);
    -  242  0
                 } catch (FileNotFoundException ex) {
    -  243  0
                     throw new ReportException("Unable to locate template file: " + templateName, ex);
    -  244  0
                 }
    -  245   -
             } else {
    -  246  0
                 templatePath = "templates/" + templateName + ".vsl";
    -  247  0
                 input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
    -  248   -
             }
    -  249  0
             if (input == null) {
    -  250  0
                 throw new ReportException("Template file doesn't exist: " + templatePath);
    -  251   -
             }
    -  252   -
     
    -  253  0
             InputStreamReader reader = null;
    -  254  0
             OutputStreamWriter writer = null;
    -  255   -
     
    -  256   -
             try {
    -  257  0
                 reader = new InputStreamReader(input, "UTF-8");
    -  258  0
                 writer = new OutputStreamWriter(outputStream, "UTF-8");
    -  259  0
                 if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
    -  260  0
                     throw new ReportException("Failed to convert the template into html.");
    -  261   -
                 }
    -  262  0
                 writer.flush();
    -  263  0
             } catch (UnsupportedEncodingException ex) {
    -  264  0
                 throw new ReportException("Unable to generate the report using UTF-8", ex);
    -  265  0
             } catch (IOException ex) {
    -  266  0
                 throw new ReportException("Unable to write the report", ex);
    -  267   -
             } finally {
    -  268  0
                 if (writer != null) {
    -  269   -
                     try {
    -  270  0
                         writer.close();
    -  271  0
                     } catch (IOException ex) {
    -  272  0
                         LOGGER.trace("", ex);
    -  273  0
                     }
    -  274   -
                 }
    -  275  0
                 if (outputStream != null) {
    -  276   -
                     try {
    -  277  0
                         outputStream.close();
    -  278  0
                     } catch (IOException ex) {
    -  279  0
                         LOGGER.trace("", ex);
    -  280  0
                     }
    -  281   -
                 }
    -  282  0
                 if (reader != null) {
    -  283   -
                     try {
    -  284  0
                         reader.close();
    -  285  0
                     } catch (IOException ex) {
    -  286  0
                         LOGGER.trace("", ex);
    -  287  0
                     }
    -  288   -
                 }
    -  289   -
             }
    -  290  0
         }
    -  291   -
     
    -  292  
         /**
    -  293   +  230  
          * Generates a report from a given Velocity Template. The template name
    -  294   +  231  
          * provided can be the name of a template contained in the jar file, such as
    -  295   +  232  
          * 'XmlReport' or 'HtmlReport', or the template name can be the path to a
    -  296   +  233  
          * template file.
    -  297   +  234  
          *
    -  298   +  235  
          * @param templateName the name of the template to load
    -  299   -
          * @param outFileName the filename and path to write the report to
    -  300   -
          * @throws ReportException is thrown when the report cannot be generated
    -  301   +  236   +
          * @param outputStream the OutputStream to write the report to
    +  237   +
          * @throws ReportException is thrown when an exception occurs
    +  238  
          */
    -  302   -
         protected void generateReport(String templateName, String outFileName) throws ReportException {
    -  303  0
             File outFile = new File(outFileName);
    -  304  0
             if (outFile.getParentFile() == null) {
    -  305  0
                 outFile = new File(".", outFileName);
    -  306   +  239   +
         protected void generateReport(String templateName, OutputStream outputStream) throws ReportException {
    +  240  0
             InputStream input = null;
    +  241  0
             String templatePath = null;
    +  242  0
             final File f = new File(templateName);
    +  243  0
             if (f.exists() && f.isFile()) {
    +  244   +
                 try {
    +  245  0
                     templatePath = templateName;
    +  246  0
                     input = new FileInputStream(f);
    +  247  0
                 } catch (FileNotFoundException ex) {
    +  248  0
                     throw new ReportException("Unable to locate template file: " + templateName, ex);
    +  249  0
                 }
    +  250   +
             } else {
    +  251  0
                 templatePath = "templates/" + templateName + ".vsl";
    +  252  0
                 input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
    +  253  
             }
    -  307  0
             if (!outFile.getParentFile().exists()) {
    -  308  0
                 final boolean created = outFile.getParentFile().mkdirs();
    -  309  0
                 if (!created) {
    -  310  0
                     throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
    -  311   -
                 }
    -  312   +  254  0
             if (input == null) {
    +  255  0
                 throw new ReportException("Template file doesn't exist: " + templatePath);
    +  256  
             }
    -  313   +  257  
     
    -  314  0
             OutputStream outputSteam = null;
    -  315   +  258  0
             InputStreamReader reader = null;
    +  259  0
             OutputStreamWriter writer = null;
    +  260   +
     
    +  261  
             try {
    -  316  0
                 outputSteam = new FileOutputStream(outFile);
    -  317  0
                 generateReport(templateName, outputSteam);
    -  318  0
             } catch (FileNotFoundException ex) {
    -  319  0
                 throw new ReportException("Unable to write to file: " + outFile, ex);
    -  320   -
             } finally {
    -  321  0
                 if (outputSteam != null) {
    -  322   -
                     try {
    -  323  0
                         outputSteam.close();
    -  324  0
                     } catch (IOException ex) {
    -  325  0
                         LOGGER.trace("ignore", ex);
    -  326  0
                     }
    -  327   +  262  0
                 reader = new InputStreamReader(input, "UTF-8");
    +  263  0
                 writer = new OutputStreamWriter(outputStream, "UTF-8");
    +  264  0
                 if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
    +  265  0
                     throw new ReportException("Failed to convert the template into html.");
    +  266  
                 }
    -  328   +  267  0
                 writer.flush();
    +  268  0
             } catch (UnsupportedEncodingException ex) {
    +  269  0
                 throw new ReportException("Unable to generate the report using UTF-8", ex);
    +  270  0
             } catch (IOException ex) {
    +  271  0
                 throw new ReportException("Unable to write the report", ex);
    +  272   +
             } finally {
    +  273  0
                 if (writer != null) {
    +  274   +
                     try {
    +  275  0
                         writer.close();
    +  276  0
                     } catch (IOException ex) {
    +  277  0
                         LOGGER.trace("", ex);
    +  278  0
                     }
    +  279   +
                 }
    +  280  0
                 if (outputStream != null) {
    +  281   +
                     try {
    +  282  0
                         outputStream.close();
    +  283  0
                     } catch (IOException ex) {
    +  284  0
                         LOGGER.trace("", ex);
    +  285  0
                     }
    +  286   +
                 }
    +  287  0
                 if (reader != null) {
    +  288   +
                     try {
    +  289  0
                         reader.close();
    +  290  0
                     } catch (IOException ex) {
    +  291  0
                         LOGGER.trace("", ex);
    +  292  0
                     }
    +  293   +
                 }
    +  294  
             }
    -  329  0
         }
    -  330   +  295  0
         }
    +  296   +
     
    +  297   +
         /**
    +  298   +
          * Generates a report from a given Velocity Template. The template name
    +  299   +
          * provided can be the name of a template contained in the jar file, such as
    +  300   +
          * 'XmlReport' or 'HtmlReport', or the template name can be the path to a
    +  301   +
          * template file.
    +  302   +
          *
    +  303   +
          * @param templateName the name of the template to load
    +  304   +
          * @param outFileName the filename and path to write the report to
    +  305   +
          * @throws ReportException is thrown when the report cannot be generated
    +  306   +
          */
    +  307   +
         protected void generateReport(String templateName, String outFileName) throws ReportException {
    +  308  0
             File outFile = new File(outFileName);
    +  309  0
             if (outFile.getParentFile() == null) {
    +  310  0
                 outFile = new File(".", outFileName);
    +  311   +
             }
    +  312  0
             if (!outFile.getParentFile().exists()) {
    +  313  0
                 final boolean created = outFile.getParentFile().mkdirs();
    +  314  0
                 if (!created) {
    +  315  0
                     throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
    +  316   +
                 }
    +  317   +
             }
    +  318   +
     
    +  319  0
             OutputStream outputSteam = null;
    +  320   +
             try {
    +  321  0
                 outputSteam = new FileOutputStream(outFile);
    +  322  0
                 generateReport(templateName, outputSteam);
    +  323  0
             } catch (FileNotFoundException ex) {
    +  324  0
                 throw new ReportException("Unable to write to file: " + outFile, ex);
    +  325   +
             } finally {
    +  326  0
                 if (outputSteam != null) {
    +  327   +
                     try {
    +  328  0
                         outputSteam.close();
    +  329  0
                     } catch (IOException ex) {
    +  330  0
                         LOGGER.trace("ignore", ex);
    +  331  0
                     }
    +  332   +
                 }
    +  333   +
             }
    +  334  0
         }
    +  335  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.VelocityLoggerRedirect.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.VelocityLoggerRedirect.html index b6ef24305..93524cf92 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.VelocityLoggerRedirect.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.reporting.VelocityLoggerRedirect.html @@ -235,6 +235,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DBUtils.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DBUtils.html index 9b1d2c2f5..877d441ef 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DBUtils.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DBUtils.html @@ -151,16 +151,16 @@
          */
     74  
         public static void closeStatement(Statement statement) {
    -  75  51
             if (statement != null) {
    +  75  54
             if (statement != null) {
     76  
                 try {
    -  77  51
                     statement.close();
    +  77  54
                     statement.close();
     78  0
                 } catch (SQLException ex) {
     79  0
                     LOGGER.trace(statement.toString(), ex);
    -  80  51
                 }
    +  80  54
                 }
     81  
             }
    -  82  51
         }
    +  82  54
         }
     83  
     
     84   @@ -175,20 +175,20 @@
          */
     89  
         public static void closeResultSet(ResultSet rs) {
    -  90  51
             if (rs != null) {
    +  90  54
             if (rs != null) {
     91  
                 try {
    -  92  51
                     rs.close();
    +  92  54
                     rs.close();
     93  0
                 } catch (SQLException ex) {
     94  0
                     LOGGER.trace(rs.toString(), ex);
    -  95  51
                 }
    +  95  54
                 }
     96  
             }
    -  97  51
         }
    +  97  54
         }
     98  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DateUtil.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DateUtil.html index 31db3625f..c79cc9b6d 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DateUtil.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DateUtil.html @@ -109,6 +109,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersion.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersion.html index fbf59b61d..5ba756e47 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersion.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersion.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    DependencyVersion
    93%
    88/94
    84%
    59/70
    5.636
    DependencyVersion
    94%
    89/94
    87%
    61/70
    5.636
     
    @@ -126,9 +126,9 @@
          * @param version the well formatted version number to parse
     56  
          */
    -  57  1054
         public DependencyVersion(String version) {
    -  58  1054
             parseVersion(version);
    -  59  1054
         }
    +  57  1208
         public DependencyVersion(String version) {
    +  58  1208
             parseVersion(version);
    +  59  1208
         }
     60  
     
     61   @@ -147,21 +147,21 @@
          */
     68  
         public final void parseVersion(String version) {
    -  69  1056
             versionParts = new ArrayList<String>();
    -  70  1056
             if (version != null) {
    -  71  1056
                 final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
    -  72  1056
                 final Matcher matcher = rx.matcher(version.toLowerCase());
    -  73  4362
                 while (matcher.find()) {
    -  74  3306
                     versionParts.add(matcher.group());
    +  69  1210
             versionParts = new ArrayList<String>();
    +  70  1210
             if (version != null) {
    +  71  1201
                 final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
    +  72  1200
                 final Matcher matcher = rx.matcher(version.toLowerCase());
    +  73  4941
                 while (matcher.find()) {
    +  74  3741
                     versionParts.add(matcher.group());
     75  
                 }
    -  76  1056
                 if (versionParts.isEmpty()) {
    +  76  1201
                 if (versionParts.isEmpty()) {
     77  7
                     versionParts.add(version);
     78  
                 }
     79  
             }
    -  80  1056
         }
    +  80  1210
         }
     81  
         /**
     82   @@ -184,7 +184,7 @@
          */
     91  
         public List<String> getVersionParts() {
    -  92  1635
             return versionParts;
    +  92  1814
             return versionParts;
     93  
         }
     94   @@ -238,7 +238,7 @@
         @Override
     120  
         public String toString() {
    -  121  348
             return StringUtils.join(versionParts, '.');
    +  121  380
             return StringUtils.join(versionParts, '.');
     122  
         }
     123   @@ -259,22 +259,22 @@
         @Override
     131  
         public boolean equals(Object obj) {
    -  132  648
             if (obj == null) {
    +  132  785
             if (obj == null) {
     133  0
                 return false;
     134  
             }
    -  135  648
             if (getClass() != obj.getClass()) {
    +  135  785
             if (getClass() != obj.getClass()) {
     136  0
                 return false;
     137  
             }
    -  138  648
             final DependencyVersion other = (DependencyVersion) obj;
    -  139  648
             final int minVersionMatchLength = (this.versionParts.size() < other.versionParts.size())
    -  140  105
                     ? this.versionParts.size() : other.versionParts.size();
    -  141  648
             final int maxVersionMatchLength = (this.versionParts.size() > other.versionParts.size())
    -  142  10
                     ? this.versionParts.size() : other.versionParts.size();
    +  138  785
             final DependencyVersion other = (DependencyVersion) obj;
    +  139  785
             final int minVersionMatchLength = (this.versionParts.size() < other.versionParts.size())
    +  140  124
                     ? this.versionParts.size() : other.versionParts.size();
    +  141  785
             final int maxVersionMatchLength = (this.versionParts.size() > other.versionParts.size())
    +  142  18
                     ? this.versionParts.size() : other.versionParts.size();
     143  
     
    -  144  648
             if (minVersionMatchLength == 1 && maxVersionMatchLength >= 3) {
    +  144  785
             if (minVersionMatchLength == 1 && maxVersionMatchLength >= 3) {
     145  1
                 return false;
     146  
             }
    @@ -282,19 +282,19 @@
     
     148  
             //TODO steal better version of code from compareTo
    -  149  1373
             for (int i = 0; i < minVersionMatchLength; i++) {
    -  150  1273
                 final String thisPart = this.versionParts.get(i);
    -  151  1273
                 final String otherPart = other.versionParts.get(i);
    -  152  1273
                 if (!thisPart.equals(otherPart)) {
    -  153  547
                     return false;
    +  149  1620
             for (int i = 0; i < minVersionMatchLength; i++) {
    +  150  1468
                 final String thisPart = this.versionParts.get(i);
    +  151  1468
                 final String otherPart = other.versionParts.get(i);
    +  152  1468
                 if (!thisPart.equals(otherPart)) {
    +  153  632
                     return false;
     154  
                 }
     155  
             }
    -  156  100
             if (this.versionParts.size() > minVersionMatchLength) {
    -  157  2
                 for (int i = minVersionMatchLength; i < this.versionParts.size(); i++) {
    -  158  1
                     if (!"0".equals(this.versionParts.get(i))) {
    -  159  0
                         return false;
    +  156  152
             if (this.versionParts.size() > minVersionMatchLength) {
    +  157  10
                 for (int i = minVersionMatchLength; i < this.versionParts.size(); i++) {
    +  158  9
                     if (!"0".equals(this.versionParts.get(i))) {
    +  159  8
                         return false;
     160  
                     }
     161   @@ -303,10 +303,10 @@
             }
     163  
     
    -  164  100
             if (other.versionParts.size() > minVersionMatchLength) {
    -  165  77
                 for (int i = minVersionMatchLength; i < other.versionParts.size(); i++) {
    -  166  77
                     if (!"0".equals(other.versionParts.get(i))) {
    -  167  77
                         return false;
    +  164  144
             if (other.versionParts.size() > minVersionMatchLength) {
    +  165  96
                 for (int i = minVersionMatchLength; i < other.versionParts.size(); i++) {
    +  166  96
                     if (!"0".equals(other.versionParts.get(i))) {
    +  167  96
                         return false;
     168  
                     }
     169   @@ -325,7 +325,7 @@
              *  }
     176  
              */
    -  177  23
             return true;
    +  177  48
             return true;
     178  
         }
     179   @@ -369,40 +369,40 @@
          */
     200  
         public boolean matchesAtLeastThreeLevels(DependencyVersion version) {
    -  201  382
             if (version == null) {
    +  201  436
             if (version == null) {
     202  0
                 return false;
     203  
             }
    -  204  382
             if (Math.abs(this.versionParts.size() - version.versionParts.size()) >= 3) {
    +  204  436
             if (Math.abs(this.versionParts.size() - version.versionParts.size()) >= 3) {
     205  1
                 return false;
     206  
             }
     207  
     
    -  208  381
             final int max = (this.versionParts.size() < version.versionParts.size())
    +  208  435
             final int max = (this.versionParts.size() < version.versionParts.size())
     209  66
                     ? this.versionParts.size() : version.versionParts.size();
     210  
     
    -  211  381
             boolean ret = true;
    -  212  762
             for (int i = 0; i < max; i++) {
    -  213  712
                 final String thisVersion = this.versionParts.get(i);
    -  214  712
                 final String otherVersion = version.getVersionParts().get(i);
    -  215  712
                 if (i >= 3) {
    +  211  435
             boolean ret = true;
    +  212  828
             for (int i = 0; i < max; i++) {
    +  213  778
                 final String thisVersion = this.versionParts.get(i);
    +  214  778
                 final String otherVersion = version.getVersionParts().get(i);
    +  215  778
                 if (i >= 3) {
     216  2
                     if (thisVersion.compareToIgnoreCase(otherVersion) >= 0) {
     217  1
                         ret = false;
     218  1
                         break;
     219  
                     }
    -  220  710
                 } else if (!thisVersion.equals(otherVersion)) {
    -  221  330
                     ret = false;
    -  222  330
                     break;
    +  220  776
                 } else if (!thisVersion.equals(otherVersion)) {
    +  221  384
                     ret = false;
    +  222  384
                     break;
     223  
                 }
     224  
             }
     225  
     
    -  226  381
             return ret;
    +  226  435
             return ret;
     227  
         }
     228   @@ -411,28 +411,28 @@
         @Override
     230  
         public int compareTo(DependencyVersion version) {
    -  231  32
             if (version == null) {
    +  231  33
             if (version == null) {
     232  0
                 return 1;
     233  
             }
    -  234  32
             final List<String> left = this.getVersionParts();
    -  235  32
             final List<String> right = version.getVersionParts();
    -  236  32
             final int max = left.size() < right.size() ? left.size() : right.size();
    +  234  33
             final List<String> left = this.getVersionParts();
    +  235  33
             final List<String> right = version.getVersionParts();
    +  236  33
             final int max = left.size() < right.size() ? left.size() : right.size();
     237  
     
    -  238  82
             for (int i = 0; i < max; i++) {
    -  239  70
                 final String lStr = left.get(i);
    -  240  70
                 final String rStr = right.get(i);
    -  241  70
                 if (lStr.equals(rStr)) {
    -  242  50
                     continue;
    +  238  84
             for (int i = 0; i < max; i++) {
    +  239  72
                 final String lStr = left.get(i);
    +  240  72
                 final String rStr = right.get(i);
    +  241  72
                 if (lStr.equals(rStr)) {
    +  242  51
                     continue;
     243  
                 }
     244  
                 try {
    -  245  20
                     final int l = Integer.parseInt(lStr);
    -  246  13
                     final int r = Integer.parseInt(rStr);
    -  247  12
                     if (l < r) {
    -  248  9
                         return -1;
    +  245  21
                     final int l = Integer.parseInt(lStr);
    +  246  14
                     final int r = Integer.parseInt(rStr);
    +  247  13
                     if (l < r) {
    +  248  10
                         return -1;
     249  3
                     } else if (l > r) {
     250  3
                         return 1;
     251   @@ -463,6 +463,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersionUtil.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersionUtil.html index 204370408..5eec87c46 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersionUtil.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.DependencyVersionUtil.html @@ -152,13 +152,13 @@
          */
     70  
         public static DependencyVersion parseVersion(String text) {
    -  71  1006
             if (text == null) {
    +  71  1123
             if (text == null) {
     72  0
                 return null;
     73  
             }
     74  
             //'-' is a special case used within the CVE entries, just include it as the version.
    -  75  1006
             if ("-".equals(text)) {
    +  75  1123
             if ("-".equals(text)) {
     76  1
                 final DependencyVersion dv = new DependencyVersion();
     77  1
                 final List<String> list = new ArrayList<String>();
     78  1
                 list.add(text);
    @@ -166,19 +166,19 @@  80  1
                 return dv;
     81  
             }
    -  82  1005
             String version = null;
    -  83  1005
             Matcher matcher = RX_VERSION.matcher(text);
    -  84  1005
             if (matcher.find()) {
    -  85  995
                 version = matcher.group();
    +  82  1122
             String version = null;
    +  83  1122
             Matcher matcher = RX_VERSION.matcher(text);
    +  84  1123
             if (matcher.find()) {
    +  85  1113
                 version = matcher.group();
     86  
             }
     87  
             //throw away the results if there are two things that look like version numbers
    -  88  1005
             if (matcher.find()) {
    +  88  1123
             if (matcher.find()) {
     89  2
                 return null;
     90  
             }
    -  91  1003
             if (version == null) {
    +  91  1121
             if (version == null) {
     92  10
                 matcher = RX_SINGLE_VERSION.matcher(text);
     93  10
                 if (matcher.find()) {
     94  2
                     version = matcher.group();
    @@ -195,11 +195,11 @@
                 }
     102  
             }
    -  103  994
             if (version != null && version.endsWith("-py2") && version.length() > 4) {
    +  103  1112
             if (version != null && version.endsWith("-py2") && version.length() > 4) {
     104  1
                 version = version.substring(0, version.length() - 4);
     105  
             }
    -  106  994
             return new DependencyVersion(version);
    +  106  1112
             return new DependencyVersion(version);
     107  
         }
     108   @@ -252,6 +252,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.ExtractionUtil.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.ExtractionUtil.html index d5571fffe..3c1441310 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.ExtractionUtil.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.ExtractionUtil.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    ExtractionUtil
    28%
    33/114
    27%
    10/36
    6.5
    ExtractionUtil
    35%
    49/137
    34%
    17/50
    7.625
     
    @@ -58,19 +58,19 @@  20  
     import java.io.BufferedInputStream;
     21   -
     import java.io.Closeable;
    -  22  
     import java.io.File;
    -  23   +  22  
     import java.io.FileInputStream;
    -  24   +  23  
     import java.io.FileNotFoundException;
    -  25   +  24  
     import java.io.FileOutputStream;
    -  26   +  25  
     import java.io.FilenameFilter;
    -  27   +  26  
     import java.io.IOException;
    +  27   +
     import java.util.zip.GZIPInputStream;
     28  
     import java.util.zip.ZipEntry;
     29   @@ -141,314 +141,387 @@  63  
          * @param extractTo a directory to extract the contents to
     64   -
          * @throws ExtractionException thrown if an exception occurs while extracting the files
    +
          * @throws ExtractionException thrown if an exception occurs while
     65   -
          */
    +
          * extracting the files
     66   +
          */
    +  67  
         public static void extractFiles(File archive, File extractTo) throws ExtractionException {
    -  67  0
             extractFiles(archive, extractTo, null);
    -  68  0
         }
    -  69   -
     
    +  68  0
             extractFiles(archive, extractTo, null);
    +  69  0
         }
     70   -
         /**
    +
     
     71   -
          * Extracts the contents of an archive into the specified directory. The files are only extracted if they are supported by the
    +
         /**
     72   -
          * analyzers loaded into the specified engine. If the engine is specified as null then all files are extracted.
    +
          * Extracts the contents of an archive into the specified directory. The
     73   -
          *
    +
          * files are only extracted if they are supported by the analyzers loaded
     74   -
          * @param archive an archive file such as a WAR or EAR
    +
          * into the specified engine. If the engine is specified as null then all
     75   -
          * @param extractTo a directory to extract the contents to
    +
          * files are extracted.
     76   -
          * @param engine the scanning engine
    +
          *
     77   -
          * @throws ExtractionException thrown if there is an error extracting the files
    -  78   -
          */
    -  79   -
         public static void extractFiles(File archive, File extractTo, Engine engine) throws ExtractionException {
    -  80  0
             if (archive == null || extractTo == null) {
    -  81  0
                 return;
    -  82   -
             }
    -  83   -
     
    -  84  0
             FileInputStream fis = null;
    -  85  0
             ZipInputStream zis = null;
    -  86   -
     
    -  87   -
             try {
    -  88  0
                 fis = new FileInputStream(archive);
    -  89  0
             } catch (FileNotFoundException ex) {
    -  90  0
                 LOGGER.debug("", ex);
    -  91  0
                 throw new ExtractionException("Archive file was not found.", ex);
    -  92  0
             }
    -  93  0
             zis = new ZipInputStream(new BufferedInputStream(fis));
    -  94   -
             ZipEntry entry;
    -  95   -
             try {
    -  96  0
                 while ((entry = zis.getNextEntry()) != null) {
    -  97  0
                     if (entry.isDirectory()) {
    -  98  0
                         final File d = new File(extractTo, entry.getName());
    -  99  0
                         if (!d.exists() && !d.mkdirs()) {
    -  100  0
                             final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
    -  101  0
                             throw new ExtractionException(msg);
    -  102   -
                         }
    -  103  0
                     } else {
    -  104  0
                         final File file = new File(extractTo, entry.getName());
    -  105  0
                         if (engine == null || engine.accept(file)) {
    -  106  0
                             FileOutputStream fos = null;
    -  107   -
                             try {
    -  108  0
                                 fos = new FileOutputStream(file);
    -  109  0
                                 IOUtils.copy(zis, fos);
    -  110  0
                             } catch (FileNotFoundException ex) {
    -  111  0
                                 LOGGER.debug("", ex);
    -  112  0
                                 final String msg = String.format("Unable to find file '%s'.", file.getName());
    -  113  0
                                 throw new ExtractionException(msg, ex);
    -  114  0
                             } catch (IOException ex) {
    -  115  0
                                 LOGGER.debug("", ex);
    -  116  0
                                 final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
    -  117  0
                                 throw new ExtractionException(msg, ex);
    -  118   -
                             } finally {
    -  119  0
                                 closeStream(fos);
    -  120  0
                             }
    -  121   -
                         }
    -  122  0
                     }
    -  123   -
                 }
    -  124  0
             } catch (IOException ex) {
    -  125  0
                 final String msg = String.format("Exception reading archive '%s'.", archive.getName());
    -  126  0
                 LOGGER.debug("", ex);
    -  127  0
                 throw new ExtractionException(msg, ex);
    -  128   -
             } finally {
    -  129  0
                 closeStream(zis);
    -  130  0
             }
    -  131  0
         }
    -  132   -
     
    -  133   -
         /**
    -  134   -
          * Extracts the contents of an archive into the specified directory.
    -  135   -
          *
    -  136  
          * @param archive an archive file such as a WAR or EAR
    -  137   -
          * @param destination a directory to extract the contents to
    -  138   -
          * @param filter determines which files get extracted
    -  139   -
          * @throws ExtractionException thrown if the archive is not found
    -  140   +  78   +
          * @param extractTo a directory to extract the contents to
    +  79   +
          * @param engine the scanning engine
    +  80   +
          * @throws ExtractionException thrown if there is an error extracting the
    +  81   +
          * files
    +  82  
          */
    -  141   -
         public static void extractFilesUsingFilter(File archive, File destination,
    -  142   -
                 FilenameFilter filter) throws ExtractionException {
    -  143  3
             if (archive == null || destination == null) {
    -  144  0
                 return;
    -  145   +  83   +
         public static void extractFiles(File archive, File extractTo, Engine engine) throws ExtractionException {
    +  84  0
             if (archive == null || extractTo == null) {
    +  85  0
                 return;
    +  86  
             }
    -  146   +  87  
     
    -  147  3
             FileInputStream fis = null;
    -  148   -
             try {
    -  149  3
                 fis = new FileInputStream(archive);
    -  150  0
             } catch (FileNotFoundException ex) {
    -  151  0
                 LOGGER.debug("", ex);
    -  152  0
                 throw new ExtractionException("Archive file was not found.", ex);
    -  153  3
             }
    -  154   -
             try {
    -  155  3
                 extractArchive(new ZipArchiveInputStream(new BufferedInputStream(
    -  156   -
                         fis)), destination, filter);
    -  157  0
             } catch (ArchiveExtractionException ex) {
    -  158  0
                 LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
    -  159  0
                 LOGGER.debug("", ex);
    -  160   -
             } finally {
    -  161  0
                 try {
    -  162  3
                     fis.close();
    -  163  0
                 } catch (IOException ex) {
    -  164  0
                     LOGGER.debug("", ex);
    -  165  3
                 }
    -  166  0
             }
    -  167  3
         }
    -  168   +  88  0
             FileInputStream fis = null;
    +  89  0
             ZipInputStream zis = null;
    +  90  
     
    -  169   -
         /**
    -  170   -
          * Extracts files from an archive.
    -  171   -
          *
    -  172   -
          * @param input the archive to extract files from
    -  173   -
          * @param destination the location to write the files too
    -  174   -
          * @param filter determines which files get extracted
    -  175   -
          * @throws ArchiveExtractionException thrown if there is an exception extracting files from the archive
    -  176   -
          */
    -  177   -
         private static void extractArchive(ArchiveInputStream input,
    -  178   -
                 File destination, FilenameFilter filter)
    -  179   -
                 throws ArchiveExtractionException {
    -  180   -
             ArchiveEntry entry;
    -  181   +  91  
             try {
    -  182  36
                 while ((entry = input.getNextEntry()) != null) {
    -  183  33
                     if (entry.isDirectory()) {
    -  184  0
                         final File dir = new File(destination, entry.getName());
    -  185  0
                         if (!dir.exists() && !dir.mkdirs()) {
    -  186  0
                             final String msg = String.format(
    -  187   -
                                     "Unable to create directory '%s'.",
    -  188  0
                                     dir.getAbsolutePath());
    -  189  0
                             throw new AnalysisException(msg);
    -  190   +  92  0
                 fis = new FileInputStream(archive);
    +  93  0
             } catch (FileNotFoundException ex) {
    +  94  0
                 LOGGER.debug("", ex);
    +  95  0
                 throw new ExtractionException("Archive file was not found.", ex);
    +  96  0
             }
    +  97  0
             zis = new ZipInputStream(new BufferedInputStream(fis));
    +  98   +
             ZipEntry entry;
    +  99   +
             try {
    +  100  0
                 while ((entry = zis.getNextEntry()) != null) {
    +  101  0
                     if (entry.isDirectory()) {
    +  102  0
                         final File d = new File(extractTo, entry.getName());
    +  103  0
                         if (!d.exists() && !d.mkdirs()) {
    +  104  0
                             final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
    +  105  0
                             throw new ExtractionException(msg);
    +  106  
                         }
    -  191  0
                     } else {
    -  192  33
                         extractFile(input, destination, filter, entry);
    -  193   -
                     }
    -  194   +  107  0
                     } else {
    +  108  0
                         final File file = new File(extractTo, entry.getName());
    +  109  0
                         if (engine == null || engine.accept(file)) {
    +  110  0
                             FileOutputStream fos = null;
    +  111   +
                             try {
    +  112  0
                                 fos = new FileOutputStream(file);
    +  113  0
                                 IOUtils.copy(zis, fos);
    +  114  0
                             } catch (FileNotFoundException ex) {
    +  115  0
                                 LOGGER.debug("", ex);
    +  116  0
                                 final String msg = String.format("Unable to find file '%s'.", file.getName());
    +  117  0
                                 throw new ExtractionException(msg, ex);
    +  118  0
                             } catch (IOException ex) {
    +  119  0
                                 LOGGER.debug("", ex);
    +  120  0
                                 final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
    +  121  0
                                 throw new ExtractionException(msg, ex);
    +  122   +
                             } finally {
    +  123  0
                                 FileUtils.close(fos);
    +  124  0
                             }
    +  125   +
                         }
    +  126  0
                     }
    +  127  
                 }
    -  195  0
             } catch (IOException ex) {
    -  196  0
                 throw new ArchiveExtractionException(ex);
    -  197  0
             } catch (Throwable ex) {
    -  198  0
                 throw new ArchiveExtractionException(ex);
    -  199   +  128  0
             } catch (IOException ex) {
    +  129  0
                 final String msg = String.format("Exception reading archive '%s'.", archive.getName());
    +  130  0
                 LOGGER.debug("", ex);
    +  131  0
                 throw new ExtractionException(msg, ex);
    +  132  
             } finally {
    -  200  3
                 closeStream(input);
    -  201  3
             }
    -  202  3
         }
    -  203   +  133  0
                 FileUtils.close(zis);
    +  134  0
             }
    +  135  0
         }
    +  136  
     
    +  137   +
         /**
    +  138   +
          * Extracts the contents of an archive into the specified directory.
    +  139   +
          *
    +  140   +
          * @param archive an archive file such as a WAR or EAR
    +  141   +
          * @param destination a directory to extract the contents to
    +  142   +
          * @param filter determines which files get extracted
    +  143   +
          * @throws ExtractionException thrown if the archive is not found
    +  144   +
          */
    +  145   +
         public static void extractFilesUsingFilter(File archive, File destination,
    +  146   +
                 FilenameFilter filter) throws ExtractionException {
    +  147  3
             if (archive == null || destination == null) {
    +  148  0
                 return;
    +  149   +
             }
    +  150   +
     
    +  151  3
             FileInputStream fis = null;
    +  152   +
             try {
    +  153  3
                 fis = new FileInputStream(archive);
    +  154  0
             } catch (FileNotFoundException ex) {
    +  155  0
                 LOGGER.debug("", ex);
    +  156  0
                 throw new ExtractionException("Archive file was not found.", ex);
    +  157  3
             }
    +  158   +
             try {
    +  159  3
                 extractArchive(new ZipArchiveInputStream(new BufferedInputStream(
    +  160   +
                         fis)), destination, filter);
    +  161  0
             } catch (ArchiveExtractionException ex) {
    +  162  0
                 LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
    +  163  0
                 LOGGER.debug("", ex);
    +  164   +
             } finally {
    +  165  0
                 try {
    +  166  3
                     fis.close();
    +  167  0
                 } catch (IOException ex) {
    +  168  0
                     LOGGER.debug("", ex);
    +  169  3
                 }
    +  170  0
             }
    +  171  3
         }
    +  172   +
     
    +  173   +
         /**
    +  174   +
          * Extracts files from an archive.
    +  175   +
          *
    +  176   +
          * @param input the archive to extract files from
    +  177   +
          * @param destination the location to write the files too
    +  178   +
          * @param filter determines which files get extracted
    +  179   +
          * @throws ArchiveExtractionException thrown if there is an exception
    +  180   +
          * extracting files from the archive
    +  181   +
          */
    +  182   +
         private static void extractArchive(ArchiveInputStream input,
    +  183   +
                 File destination, FilenameFilter filter)
    +  184   +
                 throws ArchiveExtractionException {
    +  185   +
             ArchiveEntry entry;
    +  186   +
             try {
    +  187  36
                 while ((entry = input.getNextEntry()) != null) {
    +  188  33
                     if (entry.isDirectory()) {
    +  189  0
                         final File dir = new File(destination, entry.getName());
    +  190  0
                         if (!dir.exists() && !dir.mkdirs()) {
    +  191  0
                             final String msg = String.format(
    +  192   +
                                     "Unable to create directory '%s'.",
    +  193  0
                                     dir.getAbsolutePath());
    +  194  0
                             throw new AnalysisException(msg);
    +  195   +
                         }
    +  196  0
                     } else {
    +  197  33
                         extractFile(input, destination, filter, entry);
    +  198   +
                     }
    +  199   +
                 }
    +  200  0
             } catch (IOException ex) {
    +  201  0
                 throw new ArchiveExtractionException(ex);
    +  202  0
             } catch (Throwable ex) {
    +  203  0
                 throw new ArchiveExtractionException(ex);
     204   -
         /**
    -  205   -
          * Extracts a file from an archive (input stream) and correctly builds the directory structure.
    -  206   -
          *
    -  207   -
          * @param input the archive input stream
    +
             } finally {
    +  205  3
                 FileUtils.close(input);
    +  206  3
             }
    +  207  3
         }
     208   -
          * @param destination where to write the file
    +
     
     209   -
          * @param filter the file filter to apply to the files being extracted
    +
         /**
     210   -
          * @param entry the entry from the archive to extract
    +
          * Extracts a file from an archive (input stream) and correctly builds the
     211   -
          * @throws ExtractionException thrown if there is an error reading from the archive stream
    +
          * directory structure.
     212   -
          */
    +
          *
     213   -
         private static void extractFile(ArchiveInputStream input, File destination,
    +
          * @param input the archive input stream
     214   -
                 FilenameFilter filter, ArchiveEntry entry) throws ExtractionException {
    -  215  33
             final File file = new File(destination, entry.getName());
    -  216  33
             if (filter.accept(file.getParentFile(), file.getName())) {
    -  217  6
                 LOGGER.debug("Extracting '{}'",
    -  218  3
                         file.getPath());
    -  219  3
                 FileOutputStream fos = null;
    +
          * @param destination where to write the file
    +  215   +
          * @param filter the file filter to apply to the files being extracted
    +  216   +
          * @param entry the entry from the archive to extract
    +  217   +
          * @throws ExtractionException thrown if there is an error reading from the
    +  218   +
          * archive stream
    +  219   +
          */
     220   +
         private static void extractFile(ArchiveInputStream input, File destination,
    +  221   +
                 FilenameFilter filter, ArchiveEntry entry) throws ExtractionException {
    +  222  33
             final File file = new File(destination, entry.getName());
    +  223  33
             if (filter.accept(file.getParentFile(), file.getName())) {
    +  224  6
                 LOGGER.debug("Extracting '{}'",
    +  225  3
                         file.getPath());
    +  226  3
                 FileOutputStream fos = null;
    +  227  
                 try {
    -  221  3
                     createParentFile(file);
    -  222  3
                     fos = new FileOutputStream(file);
    -  223  3
                     IOUtils.copy(input, fos);
    -  224  0
                 } catch (FileNotFoundException ex) {
    -  225  0
                     LOGGER.debug("", ex);
    -  226  0
                     final String msg = String.format("Unable to find file '%s'.",
    -  227  0
                             file.getName());
    -  228  0
                     throw new ExtractionException(msg, ex);
    -  229  0
                 } catch (IOException ex) {
    -  230  0
                     LOGGER.debug("", ex);
    -  231  0
                     final String msg = String
    -  232  0
                             .format("IO Exception while parsing file '%s'.",
    -  233  0
                                     file.getName());
    -  234  0
                     throw new ExtractionException(msg, ex);
    -  235   -
                 } finally {
    -  236  3
                     closeStream(fos);
    -  237  3
                 }
    -  238   -
             }
    -  239  33
         }
    -  240   -
     
    -  241   -
         /**
    +  228  3
                     createParentFile(file);
    +  229  3
                     fos = new FileOutputStream(file);
    +  230  3
                     IOUtils.copy(input, fos);
    +  231  0
                 } catch (FileNotFoundException ex) {
    +  232  0
                     LOGGER.debug("", ex);
    +  233  0
                     final String msg = String.format("Unable to find file '%s'.",
    +  234  0
                             file.getName());
    +  235  0
                     throw new ExtractionException(msg, ex);
    +  236  0
                 } catch (IOException ex) {
    +  237  0
                     LOGGER.debug("", ex);
    +  238  0
                     final String msg = String
    +  239  0
                             .format("IO Exception while parsing file '%s'.",
    +  240  0
                                     file.getName());
    +  241  0
                     throw new ExtractionException(msg, ex);
     242   -
          * Closes the stream.
    -  243   -
          *
    -  244   -
          * @param stream the stream to close
    +
                 } finally {
    +  243  3
                     FileUtils.close(fos);
    +  244  3
                 }
     245   -
          */
    -  246   -
         private static void closeStream(Closeable stream) {
    -  247  6
             if (stream != null) {
    -  248   -
                 try {
    -  249  6
                     stream.close();
    -  250  0
                 } catch (IOException ex) {
    -  251  0
                     LOGGER.trace("", ex);
    -  252  6
                 }
    -  253  
             }
    -  254  6
         }
    -  255   +  246  33
         }
    +  247  
     
    -  256   +  248  
         /**
    -  257   -
          * Ensures the parent path is correctly created on disk so that the file can be extracted to the correct location.
    -  258   +  249   +
          * Ensures the parent path is correctly created on disk so that the file can
    +  250   +
          * be extracted to the correct location.
    +  251  
          *
    -  259   +  252  
          * @param file the file path
    -  260   -
          * @throws ExtractionException thrown if the parent paths could not be created
    -  261   +  253   +
          * @throws ExtractionException thrown if the parent paths could not be
    +  254   +
          * created
    +  255  
          */
    -  262   +  256  
         private static void createParentFile(final File file)
    -  263   +  257  
                 throws ExtractionException {
    -  264  3
             final File parent = file.getParentFile();
    -  265  3
             if (!parent.isDirectory() && !parent.mkdirs()) {
    -  266  0
                 final String msg = String.format(
    -  267   +  258  3
             final File parent = file.getParentFile();
    +  259  3
             if (!parent.isDirectory() && !parent.mkdirs()) {
    +  260  0
                 final String msg = String.format(
    +  261  
                         "Unable to build directory '%s'.",
    -  268  0
                         parent.getAbsolutePath());
    -  269  0
                 throw new ExtractionException(msg);
    -  270   +  262  0
                         parent.getAbsolutePath());
    +  263  0
                 throw new ExtractionException(msg);
    +  264  
             }
    -  271  3
         }
    +  265  3
         }
    +  266   +
     
    +  267   +
         /**
    +  268   +
          * Extracts the file contained in a gzip archive. The extracted file is
    +  269   +
          * placed in the exact same path as the file specified.
    +  270   +
          *
    +  271   +
          * @param file the archive file
     272   +
          * @throws FileNotFoundException thrown if the file does not exist
    +  273   +
          * @throws IOException thrown if there is an error extracting the file.
    +  274   +
          */
    +  275   +
         public static void extractGzip(File file) throws FileNotFoundException, IOException {
    +  276  2
             final String originalPath = file.getPath();
    +  277  2
             final File gzip = new File(originalPath + ".gz");
    +  278  2
             if (gzip.isFile() && !gzip.delete()) {
    +  279  0
                 LOGGER.debug("Failed to delete initial temporary file when extracting 'gz' {}", gzip.toString());
    +  280  0
                 gzip.deleteOnExit();
    +  281   +
             }
    +  282  2
             if (!file.renameTo(gzip)) {
    +  283  0
                 throw new IOException("Unable to rename '" + file.getPath() + "'");
    +  284   +
             }
    +  285  2
             final File newfile = new File(originalPath);
    +  286   +
     
    +  287  2
             final byte[] buffer = new byte[4096];
    +  288   +
     
    +  289  2
             GZIPInputStream cin = null;
    +  290  2
             FileOutputStream out = null;
    +  291   +
             try {
    +  292  2
                 cin = new GZIPInputStream(new FileInputStream(gzip));
    +  293  2
                 out = new FileOutputStream(newfile);
    +  294   +
     
    +  295   +
                 int len;
    +  296  1136
                 while ((len = cin.read(buffer)) > 0) {
    +  297  1134
                     out.write(buffer, 0, len);
    +  298   +
                 }
    +  299   +
             } finally {
    +  300  2
                 if (cin != null) {
    +  301   +
                     try {
    +  302  2
                         cin.close();
    +  303  0
                     } catch (IOException ex) {
    +  304  0
                         LOGGER.trace("ignore", ex);
    +  305  2
                     }
    +  306   +
                 }
    +  307  2
                 if (out != null) {
    +  308   +
                     try {
    +  309  2
                         out.close();
    +  310  0
                     } catch (IOException ex) {
    +  311  0
                         LOGGER.trace("ignore", ex);
    +  312  2
                     }
    +  313   +
                 }
    +  314  2
                 if (gzip.isFile() && !org.apache.commons.io.FileUtils.deleteQuietly(gzip)) {
    +  315  0
                     LOGGER.debug("Failed to delete temporary file when extracting 'gz' {}", gzip.toString());
    +  316  0
                     gzip.deleteOnExit();
    +  317   +
                 }
    +  318   +
             }
    +  319  2
         }
    +  320  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.FileFilterBuilder.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.FileFilterBuilder.html index 710adc64d..a1e6ec077 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.FileFilterBuilder.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.FileFilterBuilder.html @@ -270,6 +270,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Filter.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Filter.html index f21c1204d..5ddd93e40 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Filter.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Filter.html @@ -56,21 +56,21 @@
     
     19  
         public Iterator<T> filter(Iterator<T> iterator) {
    -  20  95
             return new FilterIterator(iterator);
    +  20  97
             return new FilterIterator(iterator);
     21  
         }
     22  
     
     23  
         public Iterable<T> filter(final Iterable<T> iterable) {
    -  24  95
             return new Iterable<T>() {
    +  24  97
             return new Iterable<T>() {
     25  
     
     26  
                 @Override
     27  
                 public Iterator<T> iterator() {
    -  28  95
                     return filter(iterable.iterator());
    +  28  97
                     return filter(iterable.iterator());
     29  
                 }
     30   @@ -79,7 +79,7 @@
         }
     32  
     
    -  33  95
         private class FilterIterator implements Iterator<T> {
    +  33  97
         private class FilterIterator implements Iterator<T> {
     34  
     
     35   @@ -88,17 +88,17 @@
             private T next;
     37  
     
    -  38  95
             private FilterIterator(Iterator<T> iterator) {
    -  39  95
                 this.iterator = iterator;
    -  40  95
                 toNext();
    -  41  95
             }
    +  38  97
             private FilterIterator(Iterator<T> iterator) {
    +  39  97
                 this.iterator = iterator;
    +  40  97
                 toNext();
    +  41  97
             }
     42  
     
     43  
             @Override
     44  
             public boolean hasNext() {
    -  45  414
                 return next != null;
    +  45  419
                 return next != null;
     46  
             }
     47   @@ -107,13 +107,13 @@
             @Override
     49  
             public T next() {
    -  50  350
                 if (next == null) {
    +  50  354
                 if (next == null) {
     51  0
                     throw new NoSuchElementException();
     52  
                 }
    -  53  350
                 final T returnValue = next;
    -  54  350
                 toNext();
    -  55  350
                 return returnValue;
    +  53  354
                 final T returnValue = next;
    +  54  354
                 toNext();
    +  55  354
                 return returnValue;
     56  
             }
     57   @@ -129,22 +129,22 @@
     
     63  
             private void toNext() {
    -  64  445
                 next = null;
    -  65  629
                 while (iterator.hasNext()) {
    -  66  563
                     final T item = iterator.next();
    -  67  563
                     if (item != null && passes(item)) {
    -  68  379
                         next = item;
    -  69  379
                         break;
    +  64  451
                 next = null;
    +  65  640
                 while (iterator.hasNext()) {
    +  66  573
                     final T item = iterator.next();
    +  67  573
                     if (item != null && passes(item)) {
    +  68  384
                         next = item;
    +  69  384
                         break;
     70  
                     }
    -  71  184
                 }
    -  72  445
             }
    +  71  189
                 }
    +  72  451
             }
     73  
         }
     74  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Pair.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Pair.html index 810677be9..9354e750f 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Pair.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.Pair.html @@ -97,17 +97,17 @@
          * @param right the value for the right pair
     41  
          */
    -  42  52774
         public Pair(L left, R right) {
    -  43  52774
             this.left = left;
    -  44  52774
             this.right = right;
    -  45  52774
         }
    +  42  53114
         public Pair(L left, R right) {
    +  43  53114
             this.left = left;
    +  44  53114
             this.right = right;
    +  45  53114
         }
     46  
         /**
     47  
          * The left element of the pair.
     48  
          */
    -  49  52774
         private L left = null;
    +  49  53114
         private L left = null;
     50  
     
     51   @@ -122,7 +122,7 @@
          */
     56  
         public L getLeft() {
    -  57  105546
             return left;
    +  57  106226
             return left;
     58  
         }
     59   @@ -147,7 +147,7 @@
          * The right element of the pair.
     70  
          */
    -  71  52774
         private R right = null;
    +  71  53114
         private R right = null;
     72  
     
     73   @@ -162,7 +162,7 @@
          */
     78  
         public R getRight() {
    -  79  105546
             return right;
    +  79  106226
             return right;
     80  
         }
     81   @@ -197,10 +197,10 @@
         @Override
     97  
         public int hashCode() {
    -  98  52774
             int hash = 3;
    -  99  52774
             hash = 53 * hash + (this.left != null ? this.left.hashCode() : 0);
    -  100  52774
             hash = 53 * hash + (this.right != null ? this.right.hashCode() : 0);
    -  101  52774
             return hash;
    +  98  53114
             int hash = 3;
    +  99  53114
             hash = 53 * hash + (this.left != null ? this.left.hashCode() : 0);
    +  100  53114
             hash = 53 * hash + (this.right != null ? this.right.hashCode() : 0);
    +  101  53114
             return hash;
     102  
         }
     103   @@ -245,6 +245,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.UrlStringUtils.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.UrlStringUtils.html index 17682714a..a7f6f3976 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.UrlStringUtils.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.utils.UrlStringUtils.html @@ -125,7 +125,7 @@
          */
     56  
         public static boolean containsUrl(String text) {
    -  57  208244
             return CONTAINS_URL_TEST.matcher(text).matches();
    +  57  218814
             return CONTAINS_URL_TEST.matcher(text).matches();
     58  
         }
     59   @@ -221,6 +221,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintErrorHandler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintErrorHandler.html index 0a40d6bb8..966eb9680 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintErrorHandler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintErrorHandler.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    HintErrorHandler
    11%
    2/17
    0%
    0/8
    2.5
    HintErrorHandler
    33%
    2/6
    N/A
    1.667
     
    @@ -56,146 +56,105 @@  19  
     
     20   -
     import org.slf4j.Logger;
    +
     import org.owasp.dependencycheck.utils.XmlUtils;
     21   -
     import org.slf4j.LoggerFactory;
    +
     import org.slf4j.Logger;
     22   -
     import org.xml.sax.ErrorHandler;
    +
     import org.slf4j.LoggerFactory;
     23   -
     import org.xml.sax.SAXException;
    +
     import org.xml.sax.ErrorHandler;
     24   -
     import org.xml.sax.SAXParseException;
    +
     import org.xml.sax.SAXException;
     25   -
     
    +
     import org.xml.sax.SAXParseException;
     26   -
     /**
    +
     
     27   -
      * An XML parsing error handler.
    +
     /**
     28   -
      *
    +
      * An XML parsing error handler.
     29   -
      * @author Jeremy Long
    +
      *
     30   +
      * @author Jeremy Long
    +  31  
      */
    -  31  5
     public class HintErrorHandler implements ErrorHandler {
    -  32   -
     
    +  32  5
     public class HintErrorHandler implements ErrorHandler {
     33   -
         /**
    +
     
     34   -
          * The logger.
    +
         /**
     35   +
          * The logger.
    +  36  
          */
    -  36  1
         private static final Logger LOGGER = LoggerFactory.getLogger(HintErrorHandler.class);
    -  37   -
     
    +  37  1
         private static final Logger LOGGER = LoggerFactory.getLogger(HintErrorHandler.class);
     38   -
         /**
    +
     
     39   -
          * Builds a prettier exception message.
    +
         /**
     40   -
          *
    -  41   -
          * @param ex the SAXParseException
    -  42   -
          * @return an easier to read exception message
    -  43   -
          */
    -  44   -
         private String getPrettyParseExceptionInfo(SAXParseException ex) {
    -  45   -
     
    -  46  0
             final StringBuilder sb = new StringBuilder();
    -  47   -
     
    -  48  0
             if (ex.getSystemId() != null) {
    -  49  0
                 sb.append("systemId=").append(ex.getSystemId()).append(", ");
    -  50   -
             }
    -  51  0
             if (ex.getPublicId() != null) {
    -  52  0
                 sb.append("publicId=").append(ex.getPublicId()).append(", ");
    -  53   -
             }
    -  54  0
             if (ex.getLineNumber() > 0) {
    -  55  0
                 sb.append("Line=").append(ex.getLineNumber());
    -  56   -
             }
    -  57  0
             if (ex.getColumnNumber() > 0) {
    -  58  0
                 sb.append(", Column=").append(ex.getColumnNumber());
    -  59   -
             }
    -  60  0
             sb.append(": ").append(ex.getMessage());
    -  61   -
     
    -  62  0
             return sb.toString();
    -  63   -
         }
    -  64   -
     
    -  65   -
         /**
    -  66  
          * Logs warnings.
    -  67   +  41  
          *
    -  68   +  42  
          * @param ex the warning to log
    -  69   +  43  
          * @throws SAXException is never thrown
    -  70   +  44  
          */
    -  71   +  45  
         @Override
    -  72   +  46  
         public void warning(SAXParseException ex) throws SAXException {
    -  73  0
             LOGGER.debug("", ex);
    -  74  0
         }
    -  75   +  47  0
             LOGGER.debug("", ex);
    +  48  0
         }
    +  49  
     
    -  76   +  50  
         /**
    -  77   +  51  
          * Handles errors.
    -  78   +  52  
          *
    -  79   +  53  
          * @param ex the error to handle
    -  80   +  54  
          * @throws SAXException is always thrown
    -  81   +  55  
          */
    -  82   +  56  
         @Override
    -  83   +  57  
         public void error(SAXParseException ex) throws SAXException {
    -  84  0
             throw new SAXException(getPrettyParseExceptionInfo(ex));
    -  85   +  58  0
             throw new SAXException(XmlUtils.getPrettyParseExceptionInfo(ex));
    +  59  
         }
    -  86   +  60  
     
    -  87   +  61  
         /**
    -  88   +  62  
          * Handles fatal exceptions.
    -  89   +  63  
          *
    -  90   +  64  
          * @param ex a fatal exception
    -  91   +  65  
          * @throws SAXException is always
    -  92   +  66  
          */
    -  93   +  67  
         @Override
    -  94   +  68  
         public void fatalError(SAXParseException ex) throws SAXException {
    -  95  0
             throw new SAXException(getPrettyParseExceptionInfo(ex));
    -  96   +  69  0
             throw new SAXException(XmlUtils.getPrettyParseExceptionInfo(ex));
    +  70  
         }
    -  97   +  71  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintHandler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintHandler.html index 76be69db8..27917e3db 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintHandler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintHandler.html @@ -429,6 +429,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParseException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParseException.html index e2a54d422..dc670e40e 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParseException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParseException.html @@ -147,6 +147,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParser.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParser.html index d359949a2..a40e2ec70 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParser.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintParser.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    HintParser
    57%
    31/54
    33%
    2/6
    11
    HintParser
    52%
    25/48
    33%
    2/6
    11
     
    @@ -74,7 +74,7 @@  28  
     import javax.xml.parsers.SAXParser;
     29   -
     import javax.xml.parsers.SAXParserFactory;
    +
     import org.owasp.dependencycheck.utils.XmlUtils;
     30  
     
     31   @@ -219,64 +219,58 @@
             try {
     109  4
                 schemaStream = this.getClass().getClassLoader().getResourceAsStream(HINT_SCHEMA);
     110  4
                 final HintHandler handler = new HintHandler();
    -  111  4
                 final SAXParserFactory factory = SAXParserFactory.newInstance();
    -  112  4
                 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  113  4
                 factory.setNamespaceAware(true);
    -  114  4
                 factory.setValidating(true);
    -  115  4
                 final SAXParser saxParser = factory.newSAXParser();
    -  116  4
                 saxParser.setProperty(HintParser.JAXP_SCHEMA_LANGUAGE, HintParser.W3C_XML_SCHEMA);
    -  117  4
                 saxParser.setProperty(HintParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
    -  118  4
                 final XMLReader xmlReader = saxParser.getXMLReader();
    -  119  4
                 xmlReader.setErrorHandler(new HintErrorHandler());
    -  120  4
                 xmlReader.setContentHandler(handler);
    -  121   +  111  4
                 final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream);
    +  112  4
                 final XMLReader xmlReader = saxParser.getXMLReader();
    +  113  4
                 xmlReader.setErrorHandler(new HintErrorHandler());
    +  114  4
                 xmlReader.setContentHandler(handler);
    +  115  
     
    -  122  4
                 final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    -  123  4
                 final InputSource in = new InputSource(reader);
    -  124   +  116  4
                 final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    +  117  4
                 final InputSource in = new InputSource(reader);
    +  118  
     
    -  125  4
                 xmlReader.parse(in);
    -  126  4
                 final Hints hints = new Hints();
    -  127  4
                 hints.setHintRules(handler.getHintRules());
    -  128  4
                 hints.setVendorDuplicatingHintRules(handler.getVendorDuplicatingHintRules());
    -  129  8
                 return hints;
    -  130  0
             } catch (ParserConfigurationException ex) {
    -  131  0
                 LOGGER.debug("", ex);
    -  132  0
                 throw new HintParseException(ex);
    -  133  0
             } catch (SAXException ex) {
    -  134  0
                 if (ex.getMessage().contains("Cannot find the declaration of element 'hints'.")) {
    -  135  0
                     throw ex;
    -  136   +  119  4
                 xmlReader.parse(in);
    +  120  4
                 final Hints hints = new Hints();
    +  121  4
                 hints.setHintRules(handler.getHintRules());
    +  122  4
                 hints.setVendorDuplicatingHintRules(handler.getVendorDuplicatingHintRules());
    +  123  8
                 return hints;
    +  124  0
             } catch (ParserConfigurationException ex) {
    +  125  0
                 LOGGER.debug("", ex);
    +  126  0
                 throw new HintParseException(ex);
    +  127  0
             } catch (SAXException ex) {
    +  128  0
                 if (ex.getMessage().contains("Cannot find the declaration of element 'hints'.")) {
    +  129  0
                     throw ex;
    +  130  
                 } else {
    -  137  0
                     LOGGER.debug("", ex);
    -  138  0
                     throw new HintParseException(ex);
    -  139   +  131  0
                     LOGGER.debug("", ex);
    +  132  0
                     throw new HintParseException(ex);
    +  133  
                 }
    -  140  0
             } catch (FileNotFoundException ex) {
    -  141  0
                 LOGGER.debug("", ex);
    -  142  0
                 throw new HintParseException(ex);
    -  143  0
             } catch (IOException ex) {
    -  144  0
                 LOGGER.debug("", ex);
    -  145  0
                 throw new HintParseException(ex);
    -  146   +  134  0
             } catch (FileNotFoundException ex) {
    +  135  0
                 LOGGER.debug("", ex);
    +  136  0
                 throw new HintParseException(ex);
    +  137  0
             } catch (IOException ex) {
    +  138  0
                 LOGGER.debug("", ex);
    +  139  0
                 throw new HintParseException(ex);
    +  140  
             } finally {
    -  147  4
                 if (schemaStream != null) {
    -  148   +  141  4
                 if (schemaStream != null) {
    +  142  
                     try {
    -  149  4
                         schemaStream.close();
    -  150  0
                     } catch (IOException ex) {
    -  151  0
                         LOGGER.debug("Error closing hint file stream", ex);
    -  152  4
                     }
    -  153   +  143  4
                         schemaStream.close();
    +  144  0
                     } catch (IOException ex) {
    +  145  0
                         LOGGER.debug("Error closing hint file stream", ex);
    +  146  4
                     }
    +  147  
                 }
    -  154   +  148  
             }
    -  155   +  149  
         }
    -  156   +  150  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintRule.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintRule.html index 358dff5a4..56ed88534 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintRule.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.HintRule.html @@ -167,7 +167,7 @@
          */
     79  
         public List<Evidence> getGivenProduct() {
    -  80  48
             return givenProduct;
    +  80  49
             return givenProduct;
     81  
         }
     82   @@ -364,6 +364,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.Hints.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.Hints.html index 292fc8b83..b186ec593 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.Hints.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.Hints.html @@ -160,6 +160,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule.html index ac87f4af6..f28c14ecc 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule.html @@ -179,6 +179,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.License.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.License.html index c6cfc821a..8e1536ab6 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.License.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.License.html @@ -266,6 +266,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.Model.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.Model.html index 8c21b6d76..77ce8537a 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.Model.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.Model.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    Model
    94%
    51/54
    83%
    5/6
    1.154
    Model
    94%
    51/54
    66%
    4/6
    1.154
    Model$PropertyLookup
    100%
    4/4
    N/A
    1.154
    @@ -491,7 +491,7 @@
          */
     251  
         public List<License> getLicenses() {
    -  252  8
             return licenses;
    +  252  6
             return licenses;
     253  
         }
     254   @@ -567,21 +567,21 @@
          */
     292  
         public void processProperties(Properties properties) {
    -  293  3
             this.groupId = interpolateString(this.groupId, properties);
    -  294  3
             this.artifactId = interpolateString(this.artifactId, properties);
    -  295  3
             this.version = interpolateString(this.version, properties);
    -  296  3
             this.description = interpolateString(this.description, properties);
    -  297  3
             for (License l : this.getLicenses()) {
    +  293  1
             this.groupId = interpolateString(this.groupId, properties);
    +  294  1
             this.artifactId = interpolateString(this.artifactId, properties);
    +  295  1
             this.version = interpolateString(this.version, properties);
    +  296  1
             this.description = interpolateString(this.description, properties);
    +  297  1
             for (License l : this.getLicenses()) {
     298  0
                 l.setName(interpolateString(l.getName(), properties));
     299  0
                 l.setUrl(interpolateString(l.getUrl(), properties));
     300  0
             }
    -  301  3
             this.name = interpolateString(this.name, properties);
    -  302  3
             this.projectURL = interpolateString(this.projectURL, properties);
    -  303  3
             this.organization = interpolateString(this.organization, properties);
    -  304  3
             this.parentGroupId = interpolateString(this.parentGroupId, properties);
    -  305  3
             this.parentArtifactId = interpolateString(this.parentArtifactId, properties);
    -  306  3
             this.parentVersion = interpolateString(this.parentVersion, properties);
    -  307  3
         }
    +  301  1
             this.name = interpolateString(this.name, properties);
    +  302  1
             this.projectURL = interpolateString(this.projectURL, properties);
    +  303  1
             this.organization = interpolateString(this.organization, properties);
    +  304  1
             this.parentGroupId = interpolateString(this.parentGroupId, properties);
    +  305  1
             this.parentArtifactId = interpolateString(this.parentArtifactId, properties);
    +  306  1
             this.parentVersion = interpolateString(this.parentVersion, properties);
    +  307  1
         }
     308  
     
     309   @@ -646,8 +646,8 @@
          */
     339  
         public static String interpolateString(String text, Properties properties) {
    -  340  31
             if (null == text || null == properties) {
    -  341  29
                 return text;
    +  340  11
             if (null == text || null == properties) {
    +  341  9
                 return text;
     342  
             }
     343  2
             final StrSubstitutor substitutor = new StrSubstitutor(new PropertyLookup(properties));
    @@ -718,6 +718,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomHandler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomHandler.html index 038eb6ce2..c46cb5e24 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomHandler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomHandler.html @@ -356,6 +356,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParseException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParseException.html index 115503d3c..437d101fa 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParseException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParseException.html @@ -147,6 +147,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParser.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParser.html index 03e317094..4671d6c6b 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParser.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomParser.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    PomParser
    51%
    18/35
    50%
    1/2
    8
    PomParser
    48%
    16/33
    50%
    1/2
    8
     
    @@ -74,7 +74,7 @@  28  
     import javax.xml.parsers.SAXParser;
     29   -
     import javax.xml.parsers.SAXParserFactory;
    +
     import org.owasp.dependencycheck.utils.XmlUtils;
     30  
     
     31   @@ -131,23 +131,23 @@
          */
     58  
         public Model parse(File file) throws PomParseException {
    -  59  1
             FileInputStream fis = null;
    +  59  3
             FileInputStream fis = null;
     60  
             try {
    -  61  1
                 fis = new FileInputStream(file);
    -  62  2
                 return parse(fis);
    +  61  3
                 fis = new FileInputStream(file);
    +  62  6
                 return parse(fis);
     63  0
             } catch (IOException ex) {
     64  0
                 LOGGER.debug("", ex);
     65  0
                 throw new PomParseException(ex);
     66  
             } finally {
    -  67  1
                 if (fis != null) {
    +  67  3
                 if (fis != null) {
     68  
                     try {
    -  69  1
                         fis.close();
    +  69  3
                         fis.close();
     70  0
                     } catch (IOException ex) {
     71  0
                         LOGGER.debug("Unable to close stream", ex);
    -  72  1
                     }
    +  72  3
                     }
     73  
                 }
     74   @@ -177,47 +177,33 @@  86  
             try {
     87  3
                 final PomHandler handler = new PomHandler();
    -  88  3
                 final SAXParserFactory factory = SAXParserFactory.newInstance();
    -  89   -
     //            factory.setNamespaceAware(true);
    -  90   -
     //            factory.setValidating(true);
    -  91  3
                 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  92  3
                 final SAXParser saxParser = factory.newSAXParser();
    -  93  3
                 final XMLReader xmlReader = saxParser.getXMLReader();
    -  94  3
                 xmlReader.setContentHandler(handler);
    -  95   -
     
    -  96  3
                 final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    -  97  3
                 final InputSource in = new InputSource(reader);
    -  98   -
                 //in.setEncoding("UTF-8");
    -  99   -
     
    -  100  3
                 xmlReader.parse(in);
    -  101   -
     
    -  102  3
                 return handler.getModel();
    -  103  0
             } catch (ParserConfigurationException ex) {
    -  104  0
                 LOGGER.debug("", ex);
    -  105  0
                 throw new PomParseException(ex);
    -  106  0
             } catch (SAXException ex) {
    -  107  0
                 LOGGER.debug("", ex);
    -  108  0
                 throw new PomParseException(ex);
    -  109  0
             } catch (FileNotFoundException ex) {
    -  110  0
                 LOGGER.debug("", ex);
    -  111  0
                 throw new PomParseException(ex);
    -  112  0
             } catch (IOException ex) {
    -  113  0
                 LOGGER.debug("", ex);
    -  114  0
                 throw new PomParseException(ex);
    -  115   +  88  3
                 final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
    +  89  3
                 final XMLReader xmlReader = saxParser.getXMLReader();
    +  90  3
                 xmlReader.setContentHandler(handler);
    +  91  3
                 final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    +  92  3
                 final InputSource in = new InputSource(reader);
    +  93  3
                 xmlReader.parse(in);
    +  94  3
                 return handler.getModel();
    +  95  0
             } catch (ParserConfigurationException ex) {
    +  96  0
                 LOGGER.debug("", ex);
    +  97  0
                 throw new PomParseException(ex);
    +  98  0
             } catch (SAXException ex) {
    +  99  0
                 LOGGER.debug("", ex);
    +  100  0
                 throw new PomParseException(ex);
    +  101  0
             } catch (FileNotFoundException ex) {
    +  102  0
                 LOGGER.debug("", ex);
    +  103  0
                 throw new PomParseException(ex);
    +  104  0
             } catch (IOException ex) {
    +  105  0
                 LOGGER.debug("", ex);
    +  106  0
                 throw new PomParseException(ex);
    +  107  
             }
    -  116   +  108  
         }
    -  117   +  109  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomUtils.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomUtils.html index 340c3a9f8..7cbfa7a40 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomUtils.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.pom.PomUtils.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    PomUtils
    29%
    13/44
    50%
    3/6
    5.5
    PomUtils
    11%
    5/44
    16%
    1/6
    5.5
     
    @@ -124,13 +124,13 @@
         public static Model readPom(File file) throws AnalysisException {
     55  
             try {
    -  56  1
                 final PomParser parser = new PomParser();
    -  57  1
                 final Model model = parser.parse(file);
    -  58  1
                 if (model == null) {
    +  56  3
                 final PomParser parser = new PomParser();
    +  57  3
                 final Model model = parser.parse(file);
    +  58  3
                 if (model == null) {
     59  0
                     throw new AnalysisException(String.format("Unable to parse pom '%s'", file.getPath()));
     60  
                 }
    -  61  1
                 return model;
    +  61  3
                 return model;
     62  0
             } catch (PomParseException ex) {
     63  0
                 LOGGER.warn("Unable to parse pom '{}'", file.getPath());
     64  0
                 LOGGER.debug("", ex);
    @@ -169,14 +169,14 @@
          */
     86  
         public static Model readPom(String path, JarFile jar) throws AnalysisException {
    -  87  2
             final ZipEntry entry = jar.getEntry(path);
    -  88  2
             Model model = null;
    -  89  2
             if (entry != null) { //should never be null
    +  87  0
             final ZipEntry entry = jar.getEntry(path);
    +  88  0
             Model model = null;
    +  89  0
             if (entry != null) { //should never be null
     90  
                 try {
    -  91  2
                     final PomParser parser = new PomParser();
    -  92  2
                     model = parser.parse(jar.getInputStream(entry));
    -  93  2
                     if (model == null) {
    +  91  0
                     final PomParser parser = new PomParser();
    +  92  0
                     model = parser.parse(jar.getInputStream(entry));
    +  93  0
                     if (model == null) {
     94  0
                         throw new AnalysisException(String.format("Unable to parse pom '%s/%s'", jar.getName(), path));
     95  
                     }
    @@ -192,10 +192,10 @@  105  0
                     LOGGER.warn("Unexpected error during parsing of the pom '{}' in jar '{}'", path, jar.getName());
     106  0
                     LOGGER.debug("", ex);
     107  0
                     throw new AnalysisException(ex);
    -  108  2
                 }
    +  108  0
                 }
     109  
             }
    -  110  2
             return model;
    +  110  0
             return model;
     111  
         }
     112   @@ -227,6 +227,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.PropertyType.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.PropertyType.html index 1f3920a66..e99e0d3b5 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.PropertyType.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.PropertyType.html @@ -71,7 +71,7 @@
      * @author Jeremy Long
     27  
      */
    -  28  1111
     public class PropertyType {
    +  28  1209
     public class PropertyType {
     29  
     
     30   @@ -117,15 +117,15 @@
          */
     51  
         public void setValue(String value) {
    -  52  1120
             this.value = value;
    -  53  1120
         }
    +  52  1218
             this.value = value;
    +  53  1218
         }
     54  
         /**
     55  
          * Whether or not the expression is a regex.
     56  
          */
    -  57  1111
         private boolean regex = false;
    +  57  1209
         private boolean regex = false;
     58  
     
     59   @@ -161,15 +161,15 @@
          */
     75  
         public void setRegex(boolean value) {
    -  76  1104
             this.regex = value;
    -  77  1104
         }
    +  76  1202
             this.regex = value;
    +  77  1202
         }
     78  
         /**
     79  
          * Indicates case sensitivity.
     80  
          */
    -  81  1111
         private boolean caseSensitive = false;
    +  81  1209
         private boolean caseSensitive = false;
     82  
     
     83   @@ -205,8 +205,8 @@
          */
     99  
         public void setCaseSensitive(boolean value) {
    -  100  1105
             this.caseSensitive = value;
    -  101  1105
         }
    +  100  1203
             this.caseSensitive = value;
    +  101  1203
         }
     102  
         //</editor-fold>
     103   @@ -225,21 +225,21 @@
          */
     110  
         public boolean matches(String text) {
    -  111  198
             if (text == null) {
    +  111  214
             if (text == null) {
     112  0
                 return false;
     113  
             }
    -  114  198
             if (this.regex) {
    +  114  214
             if (this.regex) {
     115  
                 Pattern rx;
    -  116  100
                 if (this.caseSensitive) {
    +  116  116
                 if (this.caseSensitive) {
     117  2
                     rx = Pattern.compile(this.value);
     118  
                 } else {
    -  119  98
                     rx = Pattern.compile(this.value, Pattern.CASE_INSENSITIVE);
    +  119  114
                     rx = Pattern.compile(this.value, Pattern.CASE_INSENSITIVE);
     120  
                 }
    -  121  100
                 return rx.matcher(text).matches();
    +  121  116
                 return rx.matcher(text).matches();
     122  
             } else {
     123  98
                 if (this.caseSensitive) {
    @@ -345,6 +345,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionErrorHandler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionErrorHandler.html index 06713fafe..1bf54026e 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionErrorHandler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionErrorHandler.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    SuppressionErrorHandler
    80%
    12/15
    50%
    4/8
    2.5
    SuppressionErrorHandler
    75%
    3/4
    N/A
    1.667
     
    @@ -56,144 +56,103 @@  19  
     
     20   -
     import org.xml.sax.ErrorHandler;
    +
     import org.owasp.dependencycheck.utils.XmlUtils;
     21   -
     import org.xml.sax.SAXException;
    +
     import org.xml.sax.ErrorHandler;
     22   -
     import org.xml.sax.SAXParseException;
    +
     import org.xml.sax.SAXException;
     23   -
     
    +
     import org.xml.sax.SAXParseException;
     24   -
     /**
    +
     
     25   -
      * An XML parsing error handler.
    +
     /**
     26   -
      *
    +
      * An XML parsing error handler.
     27   -
      * @author Jeremy Long
    +
      *
     28   +
      * @author Jeremy Long
    +  29  
      */
    -  29  14
     public class SuppressionErrorHandler implements ErrorHandler {
    -  30   -
     
    +  30  14
     public class SuppressionErrorHandler implements ErrorHandler {
     31   -
         /**
    +
     
     32   -
          * The logger.
    +
         /**
     33   -
          */
    +
          * The logger.
     34   -
         //private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionErrorHandler.class);
    +
          */
     35   -
     
    +
         //private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionErrorHandler.class);
     36   -
         /**
    +
     
     37   -
          * Builds a prettier exception message.
    +
         /**
     38   -
          *
    -  39   -
          * @param ex the SAXParseException
    -  40   -
          * @return an easier to read exception message
    -  41   -
          */
    -  42   -
         private String getPrettyParseExceptionInfo(SAXParseException ex) {
    -  43   -
     
    -  44  3
             final StringBuilder sb = new StringBuilder();
    -  45   -
     
    -  46  3
             if (ex.getSystemId() != null) {
    -  47  0
                 sb.append("systemId=").append(ex.getSystemId()).append(", ");
    -  48   -
             }
    -  49  3
             if (ex.getPublicId() != null) {
    -  50  0
                 sb.append("publicId=").append(ex.getPublicId()).append(", ");
    -  51   -
             }
    -  52  3
             if (ex.getLineNumber() > 0) {
    -  53  3
                 sb.append("Line=").append(ex.getLineNumber());
    -  54   -
             }
    -  55  3
             if (ex.getColumnNumber() > 0) {
    -  56  3
                 sb.append(", Column=").append(ex.getColumnNumber());
    -  57   -
             }
    -  58  3
             sb.append(": ").append(ex.getMessage());
    -  59   -
     
    -  60  3
             return sb.toString();
    -  61   -
         }
    -  62   -
     
    -  63   -
         /**
    -  64  
          * Logs warnings.
    -  65   +  39  
          *
    -  66   +  40  
          * @param ex the warning to log
    -  67   +  41  
          * @throws SAXException is never thrown
    -  68   +  42  
          */
    -  69   +  43  
         @Override
    -  70   +  44  
         public void warning(SAXParseException ex) throws SAXException {
    -  71   +  45  
             //LOGGER.debug("", ex);
    -  72  3
         }
    -  73   +  46  3
         }
    +  47  
     
    -  74   +  48  
         /**
    -  75   +  49  
          * Handles errors.
    -  76   +  50  
          *
    -  77   +  51  
          * @param ex the error to handle
    -  78   +  52  
          * @throws SAXException is always thrown
    -  79   +  53  
          */
    -  80   +  54  
         @Override
    -  81   +  55  
         public void error(SAXParseException ex) throws SAXException {
    -  82  3
             throw new SAXException(getPrettyParseExceptionInfo(ex));
    -  83   +  56  3
             throw new SAXException(XmlUtils.getPrettyParseExceptionInfo(ex));
    +  57  
         }
    -  84   +  58  
     
    -  85   +  59  
         /**
    -  86   +  60  
          * Handles fatal exceptions.
    -  87   +  61  
          *
    -  88   +  62  
          * @param ex a fatal exception
    -  89   +  63  
          * @throws SAXException is always
    -  90   +  64  
          */
    -  91   +  65  
         @Override
    -  92   +  66  
         public void fatalError(SAXParseException ex) throws SAXException {
    -  93  0
             throw new SAXException(getPrettyParseExceptionInfo(ex));
    -  94   +  67  0
             throw new SAXException(XmlUtils.getPrettyParseExceptionInfo(ex));
    +  68  
         }
    -  95   +  69  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionHandler.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionHandler.html index 753bb2ea7..6e4aeed3d 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionHandler.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionHandler.html @@ -216,13 +216,13 @@
         @Override
     101  
         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    -  102  1984
             currentAttributes = attributes;
    -  103  1984
             currentText = new StringBuilder();
    -  104  1984
             if (SUPPRESS.equals(qName)) {
    -  105  440
                 rule = new SuppressionRule();
    -  106  440
                 final String base = currentAttributes.getValue("base");
    -  107  440
                 if (base != null) {
    -  108  440
                     rule.setBase(Boolean.parseBoolean(base));
    +  102  2187
             currentAttributes = attributes;
    +  103  2187
             currentText = new StringBuilder();
    +  104  2187
             if (SUPPRESS.equals(qName)) {
    +  105  482
                 rule = new SuppressionRule();
    +  106  482
                 final String base = currentAttributes.getValue("base");
    +  107  482
                 if (base != null) {
    +  108  482
                     rule.setBase(Boolean.parseBoolean(base));
     109  
                 } else {
     110  0
                     rule.setBase(false);
    @@ -230,7 +230,7 @@
                 }
     112  
             }
    -  113  1984
         }
    +  113  2187
         }
     114  
     
     115   @@ -253,30 +253,30 @@
         @Override
     124  
         public void endElement(String uri, String localName, String qName) throws SAXException {
    -  125  1984
             if (SUPPRESS.equals(qName)) {
    -  126  440
                 suppressionRules.add(rule);
    -  127  440
                 rule = null;
    -  128  1544
             } else if (FILE_PATH.equals(qName)) {
    -  129  75
                 final PropertyType pt = processPropertyType();
    -  130  75
                 rule.setFilePath(pt);
    -  131  75
             } else if (SHA1.equals(qName)) {
    +  125  2187
             if (SUPPRESS.equals(qName)) {
    +  126  482
                 suppressionRules.add(rule);
    +  127  482
                 rule = null;
    +  128  1705
             } else if (FILE_PATH.equals(qName)) {
    +  129  89
                 final PropertyType pt = processPropertyType();
    +  130  89
                 rule.setFilePath(pt);
    +  131  89
             } else if (SHA1.equals(qName)) {
     132  4
                 rule.setSha1(currentText.toString());
    -  133  1465
             } else if (GAV.equals(qName)) {
    -  134  357
                 final PropertyType pt = processPropertyType();
    -  135  357
                 rule.setGav(pt);
    -  136  357
             } else if (CPE.equals(qName)) {
    -  137  645
                 final PropertyType pt = processPropertyType();
    -  138  645
                 rule.addCpe(pt);
    -  139  645
             } else if (CWE.equals(qName)) {
    +  133  1612
             } else if (GAV.equals(qName)) {
    +  134  385
                 final PropertyType pt = processPropertyType();
    +  135  385
                 rule.setGav(pt);
    +  136  385
             } else if (CPE.equals(qName)) {
    +  137  701
                 final PropertyType pt = processPropertyType();
    +  138  701
                 rule.addCpe(pt);
    +  139  701
             } else if (CWE.equals(qName)) {
     140  0
                 rule.addCwe(currentText.toString());
    -  141  463
             } else if (CVE.equals(qName)) {
    -  142  8
                 rule.addCve(currentText.toString());
    -  143  455
             } else if (CVSS_BELOW.equals(qName)) {
    +  141  526
             } else if (CVE.equals(qName)) {
    +  142  29
                 rule.addCve(currentText.toString());
    +  143  497
             } else if (CVSS_BELOW.equals(qName)) {
     144  4
                 final float cvss = Float.parseFloat(currentText.toString());
     145  4
                 rule.addCvssBelow(cvss);
     146  
             }
    -  147  1984
         }
    +  147  2187
         }
     148  
     
     149   @@ -299,8 +299,8 @@
         @Override
     158  
         public void characters(char[] ch, int start, int length) throws SAXException {
    -  159  4460
             currentText.append(ch, start, length);
    -  160  4460
         }
    +  159  4922
             currentText.append(ch, start, length);
    +  160  4922
         }
     161  
     
     162   @@ -317,28 +317,28 @@
          */
     168  
         private PropertyType processPropertyType() {
    -  169  1077
             final PropertyType pt = new PropertyType();
    -  170  1077
             pt.setValue(currentText.toString());
    -  171  1077
             if (currentAttributes != null && currentAttributes.getLength() > 0) {
    -  172  1077
                 final String regex = currentAttributes.getValue("regex");
    -  173  1077
                 if (regex != null) {
    -  174  1077
                     pt.setRegex(Boolean.parseBoolean(regex));
    +  169  1175
             final PropertyType pt = new PropertyType();
    +  170  1175
             pt.setValue(currentText.toString());
    +  171  1175
             if (currentAttributes != null && currentAttributes.getLength() > 0) {
    +  172  1175
                 final String regex = currentAttributes.getValue("regex");
    +  173  1175
                 if (regex != null) {
    +  174  1175
                     pt.setRegex(Boolean.parseBoolean(regex));
     175  
                 }
    -  176  1077
                 final String caseSensitive = currentAttributes.getValue("caseSensitive");
    -  177  1077
                 if (caseSensitive != null) {
    -  178  1077
                     pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
    +  176  1175
                 final String caseSensitive = currentAttributes.getValue("caseSensitive");
    +  177  1175
                 if (caseSensitive != null) {
    +  178  1175
                     pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
     179  
                 }
     180  
             }
    -  181  1077
             return pt;
    +  181  1175
             return pt;
     182  
         }
     183  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParseException.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParseException.html index 07c94057a..7c960dba7 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParseException.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParseException.html @@ -147,6 +147,6 @@
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParser.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParser.html index 322ac2901..bc5539f68 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParser.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionParser.html @@ -12,7 +12,7 @@
     
    - +
    Classes in this File Line Coverage Branch Coverage Complexity
    SuppressionParser
    61%
    57/93
    50%
    5/10
    12.667
    SuppressionParser
    57%
    33/57
    50%
    4/8
    9.667
     
    @@ -76,7 +76,7 @@  29  
     import javax.xml.parsers.SAXParser;
     30   -
     import javax.xml.parsers.SAXParserFactory;
    +
     import org.owasp.dependencycheck.utils.XmlUtils;
     31  
     
     32   @@ -114,266 +114,184 @@  49  
         /**
     50   -
          * JAXP Schema Language. Source:
    -  51   -
          * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
    -  52   -
          */
    -  53   -
         public static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    -  54   -
         /**
    -  55   -
          * W3C XML Schema. Source:
    -  56   -
          * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
    -  57   -
          */
    -  58   -
         public static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
    -  59   -
         /**
    -  60   -
          * JAXP Schema Source. Source:
    -  61   -
          * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
    -  62   -
          */
    -  63   -
         public static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
    -  64   -
         /**
    -  65  
          * The suppression schema file location.
    -  66   +  51  
          */
    -  67   -
         private static final String SUPPRESSION_SCHEMA = "schema/dependency-suppression.1.1.xsd";
    -  68   +  52   +
         public static final String SUPPRESSION_SCHEMA = "schema/dependency-suppression.1.1.xsd";
    +  53  
         /**
    -  69   +  54  
          * The old suppression schema file location.
    -  70   +  55  
          */
    -  71   +  56  
         private static final String OLD_SUPPRESSION_SCHEMA = "schema/suppression.xsd";
    -  72   +  57  
     
    -  73   +  58  
         /**
    -  74   +  59  
          * Parses the given XML file and returns a list of the suppression rules
    -  75   +  60  
          * contained.
    -  76   +  61  
          *
    -  77   +  62  
          * @param file an XML file containing suppression rules
    -  78   +  63  
          * @return a list of suppression rules
    -  79   +  64  
          * @throws SuppressionParseException thrown if the XML file cannot be parsed
    -  80   +  65  
          */
    -  81   +  66  
         public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
    -  82  3
             FileInputStream fis = null;
    -  83   +  67  3
             FileInputStream fis = null;
    +  68  
             try {
    -  84  3
                 fis = new FileInputStream(file);
    -  85  3
                 return parseSuppressionRules(fis);
    -  86  0
             } catch (IOException ex) {
    -  87  0
                 LOGGER.debug("", ex);
    -  88  0
                 throw new SuppressionParseException(ex);
    -  89  3
             } catch (SAXException ex) {
    -  90   +  69  3
                 fis = new FileInputStream(file);
    +  70  3
                 return parseSuppressionRules(fis);
    +  71  0
             } catch (IOException ex) {
    +  72  0
                 LOGGER.debug("", ex);
    +  73  0
                 throw new SuppressionParseException(ex);
    +  74  3
             } catch (SAXException ex) {
    +  75  
                 try {
    -  91  3
                     if (fis != null) {
    -  92   +  76  3
                     if (fis != null) {
    +  77  
                         try {
    -  93  3
                             fis.close();
    -  94  0
                         } catch (IOException ex1) {
    -  95  0
                             LOGGER.debug("Unable to close stream", ex1);
    -  96  3
                         }
    -  97   +  78  3
                             fis.close();
    +  79  0
                         } catch (IOException ex1) {
    +  80  0
                             LOGGER.debug("Unable to close stream", ex1);
    +  81  3
                         }
    +  82  
                     }
    -  98  3
                     fis = new FileInputStream(file);
    -  99  0
                 } catch (FileNotFoundException ex1) {
    -  100  0
                     throw new SuppressionParseException(ex);
    -  101  3
                 }
    -  102  6
                 return parseOldSuppressionRules(fis);
    +  83  3
                     fis = new FileInputStream(file);
    +  84  0
                 } catch (FileNotFoundException ex1) {
    +  85  0
                     throw new SuppressionParseException(ex);
    +  86  3
                 }
    +  87   +
                 try {
    +  88  6
                     return parseSuppressionRules(fis, OLD_SUPPRESSION_SCHEMA);
    +  89  0
                 } catch (SAXException ex1) {
    +  90  0
                     throw new SuppressionParseException(ex);
    +  91   +
                 }
    +  92   +
             } finally {
    +  93  3
                 if (fis != null) {
    +  94   +
                     try {
    +  95  3
                         fis.close();
    +  96  0
                     } catch (IOException ex) {
    +  97  0
                         LOGGER.debug("Unable to close stream", ex);
    +  98  3
                     }
    +  99   +
                 }
    +  100   +
             }
    +  101   +
         }
    +  102   +
     
     103   -
             } finally {
    -  104  3
                 if (fis != null) {
    +
         /**
    +  104   +
          * Parses the given XML stream and returns a list of the suppression rules
     105   -
                     try {
    -  106  3
                         fis.close();
    -  107  0
                     } catch (IOException ex) {
    -  108  0
                         LOGGER.debug("Unable to close stream", ex);
    -  109  3
                     }
    -  110   -
                 }
    -  111   -
             }
    -  112   -
         }
    -  113   -
     
    -  114   -
         /**
    -  115   -
          * Parses the given XML stream and returns a list of the suppression rules
    -  116  
          * contained.
    -  117   +  106  
          *
    -  118   +  107  
          * @param inputStream an InputStream containing suppression rules
    -  119   +  108  
          * @return a list of suppression rules
    -  120   +  109  
          * @throws SuppressionParseException thrown if the XML cannot be parsed
    -  121   +  110  
          * @throws SAXException thrown if the XML cannot be parsed
    -  122   +  111  
          */
    -  123   +  112  
         public List<SuppressionRule> parseSuppressionRules(InputStream inputStream) throws SuppressionParseException, SAXException {
    -  124  10
             InputStream schemaStream = null;
    -  125   -
             try {
    -  126  10
                 schemaStream = this.getClass().getClassLoader().getResourceAsStream(SUPPRESSION_SCHEMA);
    -  127  10
                 final SuppressionHandler handler = new SuppressionHandler();
    -  128  10
                 final SAXParserFactory factory = SAXParserFactory.newInstance();
    -  129  10
                 factory.setNamespaceAware(true);
    -  130  10
                 factory.setValidating(true);
    -  131  10
                 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -  132  10
                 final SAXParser saxParser = factory.newSAXParser();
    -  133  10
                 saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
    -  134  10
                 saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
    -  135  10
                 final XMLReader xmlReader = saxParser.getXMLReader();
    -  136  10
                 xmlReader.setErrorHandler(new SuppressionErrorHandler());
    -  137  10
                 xmlReader.setContentHandler(handler);
    -  138   -
     
    -  139  10
                 final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    -  140  10
                 final InputSource in = new InputSource(reader);
    -  141   -
                 //in.setEncoding("UTF-8");
    -  142   -
     
    -  143  10
                 xmlReader.parse(in);
    -  144   -
     
    -  145  14
                 return handler.getSuppressionRules();
    -  146  0
             } catch (ParserConfigurationException ex) {
    -  147  0
                 LOGGER.debug("", ex);
    -  148  0
                 throw new SuppressionParseException(ex);
    -  149  3
             } catch (SAXException ex) {
    -  150  3
                 if (ex.getMessage().contains("Cannot find the declaration of element 'suppressions'.")) {
    -  151  3
                     throw ex;
    -  152   -
                 } else {
    -  153  0
                     LOGGER.debug("", ex);
    -  154  0
                     throw new SuppressionParseException(ex);
    -  155   -
                 }
    -  156  0
             } catch (FileNotFoundException ex) {
    -  157  0
                 LOGGER.debug("", ex);
    -  158  0
                 throw new SuppressionParseException(ex);
    -  159  0
             } catch (IOException ex) {
    -  160  0
                 LOGGER.debug("", ex);
    -  161  0
                 throw new SuppressionParseException(ex);
    -  162   -
             } finally {
    -  163  10
                 if (schemaStream != null) {
    -  164   -
                     try {
    -  165  10
                         schemaStream.close();
    -  166  0
                     } catch (IOException ex) {
    -  167  0
                         LOGGER.debug("Error closing suppression file stream", ex);
    -  168  13
                     }
    -  169   -
                 }
    -  170   -
             }
    -  171   +  113  10
             return parseSuppressionRules(inputStream, SUPPRESSION_SCHEMA);
    +  114  
         }
    -  172   +  115  
     
    -  173   +  116  
         /**
    -  174   +  117  
          * Parses the given XML stream and returns a list of the suppression rules
    -  175   +  118  
          * contained.
    -  176   +  119  
          *
    -  177   -
          * @param inputStream an InputStream containing suppression rues
    -  178   +  120   +
          * @param inputStream an InputStream containing suppression rules
    +  121   +
          * @param schema the schema used to validate the XML stream
    +  122  
          * @return a list of suppression rules
    -  179   -
          * @throws SuppressionParseException if the XML cannot be parsed
    -  180   +  123   +
          * @throws SuppressionParseException thrown if the XML cannot be parsed
    +  124   +
          * @throws SAXException thrown if the XML cannot be parsed
    +  125  
          */
    -  181   -
         private List<SuppressionRule> parseOldSuppressionRules(InputStream inputStream) throws SuppressionParseException {
    -  182  3
             InputStream schemaStream = null;
    -  183   +  126   +
         private List<SuppressionRule> parseSuppressionRules(InputStream inputStream, String schema) throws SuppressionParseException, SAXException {
    +  127  13
             InputStream schemaStream = null;
    +  128  
             try {
    -  184  3
                 schemaStream = this.getClass().getClassLoader().getResourceAsStream(OLD_SUPPRESSION_SCHEMA);
    -  185  3
                 final SuppressionHandler handler = new SuppressionHandler();
    -  186  3
                 final SAXParserFactory factory = SAXParserFactory.newInstance();
    -  187  3
                 factory.setNamespaceAware(true);
    -  188  3
                 factory.setValidating(true);
    -  189  3
                 final SAXParser saxParser = factory.newSAXParser();
    -  190  3
                 saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
    -  191  3
                 saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
    -  192  3
                 final XMLReader xmlReader = saxParser.getXMLReader();
    -  193  3
                 xmlReader.setErrorHandler(new SuppressionErrorHandler());
    -  194  3
                 xmlReader.setContentHandler(handler);
    -  195   -
     
    -  196  3
                 final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    -  197  3
                 final InputSource in = new InputSource(reader);
    -  198   -
     
    -  199  3
                 xmlReader.parse(in);
    -  200   -
     
    -  201  6
                 return handler.getSuppressionRules();
    -  202  0
             } catch (ParserConfigurationException ex) {
    -  203  0
                 LOGGER.debug("", ex);
    -  204  0
                 throw new SuppressionParseException(ex);
    -  205  0
             } catch (SAXException ex) {
    -  206  0
                 LOGGER.debug("", ex);
    -  207  0
                 throw new SuppressionParseException(ex);
    -  208  0
             } catch (FileNotFoundException ex) {
    -  209  0
                 LOGGER.debug("", ex);
    -  210  0
                 throw new SuppressionParseException(ex);
    -  211  0
             } catch (IOException ex) {
    -  212  0
                 LOGGER.debug("", ex);
    -  213  0
                 throw new SuppressionParseException(ex);
    -  214   -
             } finally {
    -  215  3
                 if (schemaStream != null) {
    -  216   -
                     try {
    -  217  3
                         schemaStream.close();
    -  218  0
                     } catch (IOException ex) {
    -  219  0
                         LOGGER.debug("Error closing old suppression file stream", ex);
    -  220  3
                     }
    -  221   +  129  13
                 schemaStream = this.getClass().getClassLoader().getResourceAsStream(schema);
    +  130  13
                 final SuppressionHandler handler = new SuppressionHandler();
    +  131  13
                 final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream);
    +  132  13
                 final XMLReader xmlReader = saxParser.getXMLReader();
    +  133  13
                 xmlReader.setErrorHandler(new SuppressionErrorHandler());
    +  134  13
                 xmlReader.setContentHandler(handler);
    +  135  13
                 final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    +  136  13
                 final InputSource in = new InputSource(reader);
    +  137  13
                 xmlReader.parse(in);
    +  138  20
                 return handler.getSuppressionRules();
    +  139  0
             } catch (ParserConfigurationException ex) {
    +  140  0
                 LOGGER.debug("", ex);
    +  141  0
                 throw new SuppressionParseException(ex);
    +  142  3
             } catch (SAXException ex) {
    +  143  3
                 if (ex.getMessage().contains("Cannot find the declaration of element 'suppressions'.")) {
    +  144  3
                     throw ex;
    +  145   +
                 } else {
    +  146  0
                     LOGGER.debug("", ex);
    +  147  0
                     throw new SuppressionParseException(ex);
    +  148  
                 }
    -  222   +  149  0
             } catch (FileNotFoundException ex) {
    +  150  0
                 LOGGER.debug("", ex);
    +  151  0
                 throw new SuppressionParseException(ex);
    +  152  0
             } catch (IOException ex) {
    +  153  0
                 LOGGER.debug("", ex);
    +  154  0
                 throw new SuppressionParseException(ex);
    +  155   +
             } finally {
    +  156  13
                 if (schemaStream != null) {
    +  157   +
                     try {
    +  158  13
                         schemaStream.close();
    +  159  0
                     } catch (IOException ex) {
    +  160  0
                         LOGGER.debug("Error closing suppression file stream", ex);
    +  161  16
                     }
    +  162   +
                 }
    +  163  
             }
    -  223   +  164  
         }
    -  224   +  165  
     }
    - + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionRule.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionRule.html index 7fce52a86..73c23d11c 100644 --- a/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionRule.html +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.xml.suppression.SuppressionRule.html @@ -77,7 +77,7 @@
      * @author Jeremy Long
     30  
      */
    -  31  455
     public class SuppressionRule {
    +  31  497
     public class SuppressionRule {
     32  
     
     33   @@ -119,8 +119,8 @@
          */
     52  
         public void setFilePath(PropertyType filePath) {
    -  53  77
             this.filePath = filePath;
    -  54  77
         }
    +  53  91
             this.filePath = filePath;
    +  54  91
         }
     55  
         /**
     56   @@ -168,7 +168,7 @@
          * A list of CPEs to suppression
     79  
          */
    -  80  455
         private List<PropertyType> cpe = new ArrayList<PropertyType>();
    +  80  497
         private List<PropertyType> cpe = new ArrayList<PropertyType>();
     81  
     
     82   @@ -216,8 +216,8 @@
          */
     105  
         public void addCpe(PropertyType cpe) {
    -  106  652
             this.cpe.add(cpe);
    -  107  652
         }
    +  106  708
             this.cpe.add(cpe);
    +  107  708
         }
     108  
     
     109   @@ -232,7 +232,7 @@
          */
     114  
         public boolean hasCpe() {
    -  115  35
             return !cpe.isEmpty();
    +  115  43
             return !cpe.isEmpty();
     116  
         }
     117   @@ -241,7 +241,7 @@
          * The list of cvssBelow scores.
     119  
          */
    -  120  455
         private List<Float> cvssBelow = new ArrayList<Float>();
    +  120  497
         private List<Float> cvssBelow = new ArrayList<Float>();
     121  
     
     122   @@ -314,7 +314,7 @@
          * The list of cwe entries to suppress.
     159  
          */
    -  160  455
         private List<String> cwe = new ArrayList<String>();
    +  160  497
         private List<String> cwe = new ArrayList<String>();
     161  
     
     162   @@ -387,7 +387,7 @@
          * The list of cve entries to suppress.
     199  
          */
    -  200  455
         private List<String> cve = new ArrayList<String>();
    +  200  497
         private List<String> cve = new ArrayList<String>();
     201  
     
     202   @@ -435,8 +435,8 @@
          */
     225  
         public void addCve(String cve) {
    -  226  11
             this.cve.add(cve);
    -  227  11
         }
    +  226  32
             this.cve.add(cve);
    +  227  32
         }
     228  
     
     229   @@ -451,7 +451,7 @@
          */
     234  
         public boolean hasCve() {
    -  235  35
             return !cve.isEmpty();
    +  235  43
             return !cve.isEmpty();
     236  
         }
     237   @@ -460,7 +460,7 @@
          * A Maven GAV to suppression.
     239  
          */
    -  240  455
         private PropertyType gav = null;
    +  240  497
         private PropertyType gav = null;
     241  
     
     242   @@ -492,8 +492,8 @@
          */
     256  
         public void setGav(PropertyType gav) {
    -  257  358
             this.gav = gav;
    -  258  358
         }
    +  257  386
             this.gav = gav;
    +  258  386
         }
     259  
     
     260   @@ -554,8 +554,8 @@
          */
     289  
         public void setBase(boolean base) {
    -  290  442
             this.base = base;
    -  291  442
         }
    +  290  484
             this.base = base;
    +  291  484
         }
     292  
     
     293   @@ -572,34 +572,34 @@
          */
     299  
         public void process(Dependency dependency) {
    -  300  490
             if (filePath != null && !filePath.matches(dependency.getFilePath())) {
    -  301  48
                 return;
    +  300  538
             if (filePath != null && !filePath.matches(dependency.getFilePath())) {
    +  301  56
                 return;
     302  
             }
    -  303  442
             if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
    +  303  482
             if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
     304  1
                 return;
     305  
             }
    -  306  441
             if (gav != null) {
    -  307  409
                 final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
    -  308  409
                 boolean gavFound = false;
    -  309  821
                 while (itr.hasNext()) {
    -  310  413
                     final Identifier i = itr.next();
    -  311  413
                     if (identifierMatches("maven", this.gav, i)) {
    +  306  481
             if (gav != null) {
    +  307  441
                 final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
    +  308  441
                 boolean gavFound = false;
    +  309  885
                 while (itr.hasNext()) {
    +  310  445
                     final Identifier i = itr.next();
    +  311  445
                     if (identifierMatches("maven", this.gav, i)) {
     312  1
                         gavFound = true;
     313  1
                         break;
     314  
                     }
    -  315  412
                 }
    -  316  409
                 if (!gavFound) {
    -  317  408
                     return;
    +  315  444
                 }
    +  316  441
                 if (!gavFound) {
    +  317  440
                     return;
     318  
                 }
     319  
             }
     320  
     
    -  321  33
             if (this.hasCpe()) {
    +  321  41
             if (this.hasCpe()) {
     322  28
                 final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
     323  86
                 while (itr.hasNext()) {
     324  58
                     final Identifier i = itr.next();
    @@ -617,20 +617,20 @@  334  58
                 }
     335  
             }
    -  336  33
             if (hasCve() || hasCwe() || hasCvssBelow()) {
    -  337  5
                 final Iterator<Vulnerability> itr = dependency.getVulnerabilities().iterator();
    -  338  10
                 while (itr.hasNext()) {
    -  339  5
                     boolean remove = false;
    -  340  5
                     final Vulnerability v = itr.next();
    -  341  5
                     for (String entry : this.cve) {
    -  342  3
                         if (entry.equalsIgnoreCase(v.getName())) {
    +  336  41
             if (hasCve() || hasCwe() || hasCvssBelow()) {
    +  337  13
                 final Iterator<Vulnerability> itr = dependency.getVulnerabilities().iterator();
    +  338  27
                 while (itr.hasNext()) {
    +  339  14
                     boolean remove = false;
    +  340  14
                     final Vulnerability v = itr.next();
    +  341  14
                     for (String entry : this.cve) {
    +  342  12
                         if (entry.equalsIgnoreCase(v.getName())) {
     343  1
                             remove = true;
     344  1
                             break;
     345  
                         }
    -  346  2
                     }
    -  347  5
                     if (!remove) {
    -  348  4
                         for (String entry : this.cwe) {
    +  346  11
                     }
    +  347  14
                     if (!remove) {
    +  348  13
                         for (String entry : this.cwe) {
     349  1
                             if (v.getCwe() != null) {
     350  1
                                 final String toMatch = String.format("CWE-%s ", entry);
     351  1
                                 final String toTest = v.getCwe().substring(0, toMatch.length()).toUpperCase();
    @@ -644,8 +644,8 @@  357  0
                         }
     358  
                     }
    -  359  5
                     if (!remove) {
    -  360  3
                         for (float cvss : this.cvssBelow) {
    +  359  14
                     if (!remove) {
    +  360  12
                         for (float cvss : this.cvssBelow) {
     361  3
                             if (v.getCvssScore() < cvss) {
     362  1
                                 remove = true;
     363  1
                                 break;
    @@ -654,7 +654,7 @@  365  2
                         }
     366  
                     }
    -  367  5
                     if (remove) {
    +  367  14
                     if (remove) {
     368  3
                         if (!isBase()) {
     369  3
                             dependency.addSuppressedVulnerability(v);
     370   @@ -662,10 +662,10 @@  371  3
                         itr.remove();
     372  
                     }
    -  373  5
                 }
    +  373  14
                 }
     374  
             }
    -  375  33
         }
    +  375  41
         }
     376  
     
     377   @@ -733,7 +733,7 @@
          */
     412  
         boolean identifierMatches(String identifierType, PropertyType suppressionEntry, Identifier identifier) {
    -  413  512
             if (identifierType.equals(identifier.getType())) {
    +  413  544
             if (identifierType.equals(identifier.getType())) {
     414  97
                 if (suppressionEntry.matches(identifier.getValue())) {
     415  5
                     return true;
     416  92
                 } else if ("cpe".equals(identifierType) && cpeHasNoVersion(suppressionEntry)) {
    @@ -750,7 +750,7 @@
                 }
     425  
             }
    -  426  422
             return false;
    +  426  454
             return false;
     427  
         }
     428   @@ -823,6 +823,6 @@
     }
    - + diff --git a/dependency-check-core/cpd.html b/dependency-check-core/cpd.html index 344244625..70c4fda74 100644 --- a/dependency-check-core/cpd.html +++ b/dependency-check-core/cpd.html @@ -1,13 +1,13 @@ - + dependency-check-core – CPD Results @@ -52,7 +52,7 @@ @@ -246,98 +246,8 @@ File Line -org\owasp\dependencycheck\data\update\CpeUpdater.java -169 - -org\owasp\dependencycheck\data\update\nvd\DownloadTask.java -271 - -
    -
                LOGGER.debug("Failed to delete intial temporary file {}", gzip.toString());
    -            gzip.deleteOnExit();
    -        }
    -        if (!file.renameTo(gzip)) {
    -            throw new IOException("Unable to rename '" + file.getPath() + "'");
    -        }
    -        final File newfile = new File(originalPath);
    -
    -        final byte[] buffer = new byte[4096];
    -
    -        GZIPInputStream cin = null;
    -        FileOutputStream out = null;
    -        try {
    -            cin = new GZIPInputStream(new FileInputStream(gzip));
    -            out = new FileOutputStream(newfile);
    -
    -            int len;
    -            while ((len = cin.read(buffer)) > 0) {
    -                out.write(buffer, 0, len);
    -            }
    -        } finally {
    -            if (cin != null) {
    -                try {
    -                    cin.close();
    -                } catch (IOException ex) {
    -                    LOGGER.trace("ignore", ex);
    -                }
    -            }
    -            if (out != null) {
    -                try {
    -                    out.close();
    -                } catch (IOException ex) {
    -                    LOGGER.trace("ignore", ex);
    -                }
    -            }
    -            if (gzip.isFile() && !FileUtils.deleteQuietly(gzip)) {
    -                LOGGER.debug("Failed to delete temporary file {}", gzip.toString());
    - - - - - - - - - - -
    FileLine
    org\owasp\dependencycheck\xml\hints\HintErrorHandler.java44
    org\owasp\dependencycheck\xml\suppression\SuppressionErrorHandler.java42
    -
    -
        private String getPrettyParseExceptionInfo(SAXParseException ex) {
    -
    -        final StringBuilder sb = new StringBuilder();
    -
    -        if (ex.getSystemId() != null) {
    -            sb.append("systemId=").append(ex.getSystemId()).append(", ");
    -        }
    -        if (ex.getPublicId() != null) {
    -            sb.append("publicId=").append(ex.getPublicId()).append(", ");
    -        }
    -        if (ex.getLineNumber() > 0) {
    -            sb.append("Line=").append(ex.getLineNumber());
    -        }
    -        if (ex.getColumnNumber() > 0) {
    -            sb.append(", Column=").append(ex.getColumnNumber());
    -        }
    -        sb.append(": ").append(ex.getMessage());
    -
    -        return sb.toString();
    -    }
    -
    -    /**
    -     * Logs warnings.
    -     *
    -     * @param ex the warning to log
    -     * @throws SAXException is never thrown
    -     */
    -    @Override
    -    public void warning(SAXParseException ex) throws SAXException {
    - - - - - - + @@ -371,45 +281,51 @@ * files */ @Override - public void close() throws Exception {
    FileLine
    org\owasp\dependencycheck\analyzer\ArchiveAnalyzer.java180
    179
    org\owasp\dependencycheck\analyzer\PythonDistributionAnalyzer.java 248
    + public void closeAnalyzer() throws Exception { - - + + - - + +
    File Line
    org\owasp\dependencycheck\xml\suppression\SuppressionParser.java131
    org\owasp\dependencycheck\analyzer\DependencyBundlingAnalyzer.java132
    org\owasp\dependencycheck\xml\suppression\SuppressionParser.java188
    org\owasp\dependencycheck\analyzer\DependencyMergingAnalyzer.java114
    -
                factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    -            final SAXParser saxParser = factory.newSAXParser();
    -            saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
    -            saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
    -            final XMLReader xmlReader = saxParser.getXMLReader();
    -            xmlReader.setErrorHandler(new SuppressionErrorHandler());
    -            xmlReader.setContentHandler(handler);
    +
        }
     
    -            final Reader reader = new InputStreamReader(inputStream, "UTF-8");
    -            final InputSource in = new InputSource(reader);
    -            //in.setEncoding("UTF-8");
    -
    -            xmlReader.parse(in);
    -
    -            return handler.getSuppressionRules();
    -        } catch (ParserConfigurationException ex) {
    -            LOGGER.debug("", ex);
    -            throw new SuppressionParseException(ex);
    -        } catch (SAXException ex) {
    + /** + * Analyzes a set of dependencies. If they have been found to have the same + * base path and the same set of identifiers they are likely related. The + * related dependencies are bundled into a single reportable item. + * + * @param ignore this analyzer ignores the dependency being analyzed + * @param engine the engine that is scanning the dependencies + * @throws AnalysisException is thrown if there is an error reading the JAR + * file. + */ + @Override + protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException { + if (!analyzed) { + analyzed = true; + final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>(); + final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator(); + //for (Dependency nextDependency : engine.getDependencies()) { + while (mainIterator.hasNext()) { + final Dependency dependency = mainIterator.next(); + if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) { + final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex()); + while (subIterator.hasNext()) { + final Dependency nextDependency = subIterator.next(); - + @@ -428,7 +344,7 @@ * Deletes any files extracted from the JAR during analysis. */ @Override - public void close() { + public void closeAnalyzer() { if (tempFileLocation != null && tempFileLocation.exists()) { LOGGER.debug("Attempting to delete temporary files"); final boolean success = FileUtils.delete(tempFileLocation); @@ -460,7 +376,7 @@ + + + + + + + + @@ -257,23 +265,23 @@ - + - + + + + + + + + + - - - - - - - - @@ -281,23 +289,23 @@ - + - + - + - + - + @@ -305,7 +313,7 @@ - + @@ -313,7 +321,7 @@ - + @@ -321,7 +329,7 @@ - + @@ -329,7 +337,7 @@ - + @@ -337,7 +345,7 @@ - + @@ -345,7 +353,7 @@ - + @@ -353,15 +361,15 @@ - + - + - + @@ -369,7 +377,7 @@ - + @@ -377,7 +385,7 @@ - + @@ -388,7 +396,7 @@

    Used but undeclared dependencies

    File Line
    org\owasp\dependencycheck\analyzer\JarAnalyzer.java917
    902
    org\owasp\dependencycheck\analyzer\PythonDistributionAnalyzer.java 263
    Type Optional
    joda-timejoda-time1.6compilejarfalse
    com.google.code.findbugs annotations 3.0.1u2 jar
    org.slf4j slf4j-api1.7.211.7.22compilejarfalse
    org.owaspdependency-check-utils1.4.5 compile jar false
    org.owaspdependency-check-utils1.4.4compilejarfalse
    org.apache.lucene lucene-test-framework 4.7.2 jar false
    org.jmockit jmockit1.241.25 test jar false
    org.apache.commons commons-compress1.121.13 compile jar false
    commons-io commons-io 2.5 jar false
    org.apache.commons commons-lang3 3.3.2 jar false
    org.apache.lucene lucene-core 4.7.2 jar false
    org.apache.lucene lucene-analyzers-common 4.7.2 jar false
    org.apache.lucene lucene-queryparser 4.7.2 jar false
    org.apache.velocity velocity 1.7 jar false
    org.glassfish javax.json 1.0.4 jar false
    org.jsoup jsoup1.9.21.10.1 compile jar false
    com.sun.mail mailapi 1.5.6 jar false
    junit junit 4.12 jar false
    org.hamcrest hamcrest-core 1.3
    - + @@ -396,7 +404,7 @@ - + @@ -407,7 +415,7 @@

    Unused but declared dependencies

    GroupId ArtifactId VersionClassifier Type Optional
    xerces xmlParserAPIs 2.6.0
    - + @@ -415,15 +423,15 @@ - + - + - + @@ -431,7 +439,7 @@ - + @@ -439,7 +447,7 @@ - + @@ -447,7 +455,7 @@ - + @@ -455,7 +463,7 @@ - + @@ -463,7 +471,7 @@ - + @@ -471,7 +479,7 @@ - + @@ -479,7 +487,7 @@ - + @@ -487,7 +495,7 @@ - + @@ -495,7 +503,7 @@ - + @@ -503,7 +511,7 @@ - + @@ -511,7 +519,7 @@ - + @@ -519,7 +527,7 @@ - + @@ -527,7 +535,7 @@ - + @@ -535,7 +543,7 @@ - + @@ -543,7 +551,7 @@ - + @@ -551,7 +559,7 @@ - + @@ -559,7 +567,7 @@ - + @@ -567,7 +575,7 @@ - + @@ -584,7 +592,7 @@ - + @@ -251,11 +251,11 @@ - + - + @@ -276,27 +276,27 @@ - + - + - + - + - + - + @@ -372,6 +372,18 @@ + + + + + + + + + + + + @@ -383,35 +395,35 @@ - - + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + - + @@ -419,7 +431,7 @@ - + @@ -431,7 +443,7 @@ - + @@ -443,7 +455,7 @@ - + @@ -455,7 +467,7 @@ - + @@ -467,7 +479,7 @@ - + @@ -479,7 +491,7 @@ - + @@ -491,7 +503,7 @@ - + @@ -503,7 +515,7 @@ - + @@ -515,7 +527,7 @@ - + @@ -527,7 +539,7 @@ - + @@ -539,7 +551,7 @@ - + @@ -551,7 +563,7 @@ - + @@ -563,7 +575,7 @@ - + @@ -575,7 +587,7 @@ - + @@ -587,7 +599,7 @@ - + @@ -599,35 +611,47 @@ - + - + - + - + - + + + + + + + + + + + + + - + - - + + @@ -637,18 +661,6 @@ - - - - - - - - - - - - @@ -659,7 +671,7 @@ - + @@ -674,7 +686,7 @@

    Dependencies

    GroupId ArtifactId VersionClassifier Type Optional
    ch.qos.logback logback-classic1.1.71.1.8 test jar false
    com.h2database h2 1.3.176 jar false
    org.apache.maven.scm maven-scm-provider-cvsexe 1.8.1 jar
    org.springframework spring-webmvc 2.5.5 jar
    org.springframework.security spring-security-web 3.0.0.RELEASE jar
    com.hazelcast hazelcast 2.5 jar
    net.sf.ehcache ehcache-core 2.2.0 jar
    org.apache.struts struts2-core 2.1.2 jar
    org.mortbay.jetty jetty 6.1.0 jar
    org.apache.axis2 axis2-spring 1.4.1 jar
    org.apache.axis2 axis2-adb 1.4.1 jar
    org.apache.geronimo.daytrader daytrader-ear 2.1.7 ear
    org.glassfish.main.admingui war 4.0 war
    org.dojotoolkit dojo-war 1.3.0 war
    org.apache.openjpa openjpa 2.0.1 jar
    com.google.inject guice 3.0 jar
    org.springframework.retry spring-retry 1.1.0.RELEASE jar
    uk.ltd.getahead dwr 1.1.1 jar
    xalan xalan 2.7.0 jar
    com.thoughtworks.xstream xstream 1.4.8
    # of dependencies using the latest version available25
    21
    # of dependencies where the next version available is smaller than an incremental version update
    # of dependencies where the next version available is an incremental version update7
    11
    # of dependencies where the next version available is a minor version update16
    17
    # of dependencies where the next version available is a major version updateNext Minor Next Major
    ch.qos.logback logback-classic1.1.71.1.8 jar 1.1.9
    ch.qos.logback logback-core1.1.71.1.8 jar 1.1.9
    joda-timejoda-time1.6jar1.6.12.0
    junit junit
    org.apache.ant ant1.9.71.9.8 jar
    org.apache.antant-testutil1.9.7jar1.10.0
    org.apache.antant-testutil1.9.8jar1.10.0
    org.apache.commons commons-compress1.121.13 jar
    org.apache.commons commons-lang3 3.4
    org.apache.lucene lucene-analyzers-common 4.8.0 5.0.0
    org.apache.lucene lucene-core 4.8.0 5.0.0
    org.apache.lucene lucene-queryparser 4.8.0 5.0.0
    org.apache.lucene lucene-test-framework 4.8.0 5.0.0
    org.apache.maven maven-core
    org.apache.maven maven-plugin-api
    org.apache.maven maven-settings
    org.apache.maven.plugin-testing maven-plugin-testing-harness
    org.apache.maven.plugin-tools maven-plugin-annotations
    org.apache.maven.reporting maven-reporting-api
    org.apache.maven.shared maven-dependency-tree 3.0
    org.apache.velocity velocity
    org.glassfish javax.json
    org.hamcrest hamcrest-core
    org.jmockit jmockit1.241.25 test jar 1.251.26
    org.jsoup jsoup1.9.21.10.1jar1.10.2
    org.slf4jslf4j-api1.7.22 jar 1.10.1
    org.slf4jslf4j-api1.7.21slf4j-simple1.7.22 jar
    org.slf4jslf4j-simple1.7.21jar
    org.sonatype.plexus plexus-sec-dispatcher 1.4
    Status Group Id Artifact Id
    - + @@ -686,7 +698,7 @@ - + @@ -698,7 +710,7 @@ - + @@ -710,7 +722,7 @@ - + @@ -722,7 +734,7 @@ - + @@ -734,7 +746,7 @@ - + @@ -746,7 +758,7 @@ - + @@ -758,7 +770,7 @@ - + @@ -770,7 +782,7 @@ - + @@ -782,7 +794,7 @@ - + @@ -794,7 +806,7 @@ - + @@ -806,7 +818,7 @@ - + @@ -818,7 +830,7 @@ - + @@ -830,7 +842,7 @@ - + @@ -842,11 +854,11 @@ - + - + @@ -854,7 +866,7 @@ - + @@ -866,7 +878,7 @@ - + @@ -876,9 +888,9 @@ - + - + @@ -890,7 +902,7 @@ - + @@ -902,7 +914,7 @@ - + @@ -914,7 +926,7 @@ - + @@ -932,33 +944,36 @@

    ch.qos.logback:logback-classic

    Status Group Id Artifact IdNext Incremental Next Minor Next Major
    com.google.inject guice 4.0-beta
    com.hazelcast hazelcast2.5.1 2.6 3.0
    com.thoughtworks.xstream xstream1.4.9
    net.sf.ehcache ehcache-core 2.3.0
    org.apache.axis2 axis2-adb 1.5
    org.apache.axis2 axis2-spring 1.5
    org.apache.geronimo.daytrader daytrader-ear
    org.apache.maven.scm maven-scm-provider-cvsexe 1.9
    org.apache.openjpa openjpa 2.1.0
    org.apache.struts struts2-core2.1.6 2.2.1
    org.dojotoolkit dojo-war 1.11.1
    org.glassfish.main.admingui war 4.1
    org.mortbay.jetty jetty6.1.17
    org.owasp dependency-check-utils1.4.41.4.5 compile jar
    org.springframework spring-webmvc2.5.6 3.0.0.RELEASE
    org.springframework.retry spring-retryjar 1.1.1.RELEASE1.2.0.RELEASE
    org.springframework.security spring-security-web3.0.1.RELEASE 3.1.0.RELEASE 4.0.0.RELEASE
    uk.ltd.getahead dwr
    xalan xalan2.7.2
    Status Group Id Artifact Id
    - - - + + + - + - - - + + + - + - + -
    Status No newer versions available.
    Status There is at least one newer incremental version available. Incremental updates are typically passive.
    Group Id ch.qos.logback
    Artifact Id logback-classic
    Current Version1.1.7
    Current Version1.1.8
    Scope
    Classifier
    Typejar
    +jar + +Newer versions +1.1.9 Next Incremental

    ch.qos.logback:logback-core

    - + @@ -967,7 +982,7 @@ - + @@ -976,7 +991,10 @@ -
    Status No newer versions available.
     There is at least one newer incremental version available. Incremental updates are typically passive.
    Group Id ch.qos.logback
    logback-core
    Current Version1.1.7
    1.1.8
    Scope
    Typejar
    +jar + +Newer versions +1.1.9 Next Incremental

    com.google.code.findbugs:annotations

    @@ -1081,7 +1099,7 @@ -
    jar
    Newer versions2.5.1 Next Incremental
    2.6 Next Minor
    2.6.1
    2.6.2
    2.6.3
    2.6.4
    2.6.5
    2.6.6
    2.6.7
    2.6.8
    2.6.9
    3.0-RC1
    3.0-RC2 Latest Minor
    3.0 Next Major
    3.0.1
    3.0.2
    3.0.3
    3.1
    3.1.1
    3.1.2
    3.1.3
    3.1.4
    3.1.5
    3.1.6
    3.1.7
    3.1.8
    3.2-RC1
    3.2-RC2
    3.2
    3.2.1
    3.2.2
    3.2.3
    3.2.4
    3.2.5
    3.2.6
    3.3-RC1
    3.3-RC2
    3.3-RC3
    3.3
    3.3-EA
    3.3-EA2
    3.3.1
    3.3.2
    3.3.3
    3.3.4
    3.3.5
    3.4
    3.4-EA
    3.4.1
    3.4.2
    3.4.5
    3.4.6
    3.4.7
    3.4.8
    3.5-EA
    3.5.1
    3.5.2
    3.5.3
    3.5.4
    3.5.5
    3.6-RC1
    3.6
    3.6-EA
    3.6-EA2
    3.6-EA3
    3.6.1
    3.6.2
    3.6.3
    3.6.4
    3.6.5
    3.6.6
    3.7
    3.7-EA
    3.7.1
    3.7.2 Latest Major
    +2.5.1 Next Incremental
    2.6 Next Minor
    2.6.1
    2.6.2
    2.6.3
    2.6.4
    2.6.5
    2.6.6
    2.6.7
    2.6.8
    2.6.9
    3.0-RC1
    3.0-RC2 Latest Minor
    3.0 Next Major
    3.0.1
    3.0.2
    3.0.3
    3.1
    3.1.1
    3.1.2
    3.1.3
    3.1.4
    3.1.5
    3.1.6
    3.1.7
    3.1.8
    3.2-RC1
    3.2-RC2
    3.2
    3.2.1
    3.2.2
    3.2.3
    3.2.4
    3.2.5
    3.2.6
    3.3-RC1
    3.3-RC2
    3.3-RC3
    3.3
    3.3-EA
    3.3-EA2
    3.3.1
    3.3.2
    3.3.3
    3.3.4
    3.3.5
    3.4
    3.4-EA
    3.4.1
    3.4.2
    3.4.5
    3.4.6
    3.4.7
    3.4.8
    3.5-EA
    3.5.1
    3.5.2
    3.5.3
    3.5.4
    3.5.5
    3.6-RC1
    3.6
    3.6-EA
    3.6-EA2
    3.6-EA3
    3.6.1
    3.6.2
    3.6.3
    3.6.4
    3.6.5
    3.6.6
    3.6.7
    3.7
    3.7-EA
    3.7.1
    3.7.2
    3.7.3
    3.7.4
    3.8-EA Latest Major

    com.sun.mail:mailapi

    @@ -1209,6 +1227,33 @@
    Type jar
    +

    joda-time:joda-time

    + + + + + + + + + + + + + + + + + + + + + + + + +
    Status There is at least one newer incremental version available. Incremental updates are typically passive.
    Group Idjoda-time
    Artifact Idjoda-time
    Current Version1.6
    Scope
    Classifier
    Typejar
    Newer versions1.6.1 Next Incremental
    1.6.2 Latest Incremental
    2.0 Next Major
    2.1
    2.2
    2.3
    2.4
    2.5
    2.6
    2.7
    2.8
    2.8.2
    2.9
    2.9.1
    2.9.2
    2.9.3
    2.9.4
    2.9.5
    2.9.6
    2.9.7 Latest Major
    +

    junit:junit

    @@ -1264,7 +1309,7 @@
    - + @@ -1273,7 +1318,7 @@ - + @@ -1282,13 +1327,16 @@ -
    Status No newer versions available.
     There is at least one newer minor version available. Minor updates are sometimes passive.
    Group Id org.apache.ant
    ant
    Current Version1.9.7
    1.9.8
    Scope
    Typejar
    +jar + +Newer versions +1.10.0 Next Minor

    org.apache.ant:ant-testutil

    - + @@ -1297,7 +1345,7 @@ - + @@ -1306,7 +1354,10 @@ -
    Status No newer versions available.
     There is at least one newer minor version available. Minor updates are sometimes passive.
    Group Id org.apache.ant
    ant-testutil
    Current Version1.9.7
    1.9.8
    Scope
    Typejar
    +jar + +Newer versions +1.10.0 Next Minor

    org.apache.axis2:axis2-adb

    @@ -1375,7 +1426,7 @@ - + @@ -1462,7 +1513,7 @@ -
    commons-compress
    Current Version1.12
    1.13
    Scope
    jar
    Newer versions4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1 Latest Major
    +4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1
    6.3.0
    6.4.0 Latest Major

    org.apache.lucene:lucene-core

    @@ -1489,7 +1540,7 @@ -
    jar
    Newer versions4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1 Latest Major
    +4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1
    6.3.0
    6.4.0 Latest Major

    org.apache.lucene:lucene-queryparser

    @@ -1516,7 +1567,7 @@ -
    jar
    Newer versions4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1 Latest Major
    +4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1
    6.3.0
    6.4.0 Latest Major

    org.apache.lucene:lucene-test-framework

    @@ -1543,7 +1594,7 @@ -
    jar
    Newer versions4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1 Latest Major
    +4.8.0 Next Minor
    4.8.1
    4.9.0
    4.9.1
    4.10.0
    4.10.1
    4.10.2
    4.10.3
    4.10.4 Latest Minor
    5.0.0 Next Major
    5.1.0
    5.2.0
    5.2.1
    5.3.0
    5.3.1
    5.3.2
    5.4.0
    5.4.1
    5.5.0
    5.5.1
    5.5.2
    5.5.3
    6.0.0
    6.0.1
    6.1.0
    6.2.0
    6.2.1
    6.3.0
    6.4.0 Latest Major

    org.apache.maven:maven-core

    @@ -1768,7 +1819,7 @@ -
    jar
    Newer versions2.1.0 Next Minor
    2.1.1
    2.2.0
    2.2.1
    2.2.2
    2.3.0
    2.4.0
    2.4.1 Latest Minor
    +2.1.0 Next Minor
    2.1.1
    2.2.0
    2.2.1
    2.2.2
    2.3.0
    2.4.0
    2.4.1
    2.4.2 Latest Minor

    org.apache.struts:struts2-core

    @@ -1795,7 +1846,7 @@ -
    jar
    Newer versions2.1.6 Next Incremental
    2.1.8
    2.1.8.1 Latest Incremental
    2.2.1 Next Minor
    2.2.1.1
    2.2.3
    2.2.3.1
    2.3.1
    2.3.1.1
    2.3.1.2
    2.3.3
    2.3.4
    2.3.4.1
    2.3.7
    2.3.8
    2.3.12
    2.3.14
    2.3.14.1
    2.3.14.2
    2.3.14.3
    2.3.15
    2.3.15.1
    2.3.15.2
    2.3.15.3
    2.3.16
    2.3.16.1
    2.3.16.2
    2.3.16.3
    2.3.20
    2.3.20.1
    2.3.20.3
    2.3.24
    2.3.24.1
    2.3.24.3
    2.3.28
    2.3.28.1
    2.3.29
    2.3.30
    2.3.31
    2.5-BETA1
    2.5-BETA2
    2.5-BETA3
    2.5
    2.5.1
    2.5.2
    2.5.5 Latest Minor
    +2.1.6 Next Incremental
    2.1.8
    2.1.8.1 Latest Incremental
    2.2.1 Next Minor
    2.2.1.1
    2.2.3
    2.2.3.1
    2.3.1
    2.3.1.1
    2.3.1.2
    2.3.3
    2.3.4
    2.3.4.1
    2.3.7
    2.3.8
    2.3.12
    2.3.14
    2.3.14.1
    2.3.14.2
    2.3.14.3
    2.3.15
    2.3.15.1
    2.3.15.2
    2.3.15.3
    2.3.16
    2.3.16.1
    2.3.16.2
    2.3.16.3
    2.3.20
    2.3.20.1
    2.3.20.3
    2.3.24
    2.3.24.1
    2.3.24.3
    2.3.28
    2.3.28.1
    2.3.29
    2.3.30
    2.3.31
    2.5-BETA1
    2.5-BETA2
    2.5-BETA3
    2.5
    2.5.1
    2.5.2
    2.5.5
    2.5.8 Latest Minor

    org.apache.velocity:velocity

    @@ -1846,7 +1897,7 @@ -
    war
    Newer versions1.11.1 Next Minor
    1.11.2 Latest Minor
    +1.11.1 Next Minor
    1.11.2
    1.11.3 Latest Minor

    org.glassfish:javax.json

    @@ -1936,7 +1987,7 @@ - + @@ -1948,13 +1999,13 @@ -
    jmockit
    Current Version1.24
    1.25
    Scope test
    jar
    Newer versions1.25 Next Minor
    1.26
    1.27
    1.28
    1.29 Latest Minor
    +1.26 Next Minor
    1.27
    1.28
    1.29
    1.30 Latest Minor

    org.jsoup:jsoup

    - + @@ -1963,7 +2014,7 @@ - + @@ -1975,7 +2026,7 @@ -
    Status There is at least one newer minor version available. Minor updates are sometimes passive.
     There is at least one newer incremental version available. Incremental updates are typically passive.
    Group Id org.jsoup
    jsoup
    Current Version1.9.2
    1.10.1
    Scope
    jar
    Newer versions1.10.1 Next Minor
    +1.10.2 Next Incremental

    org.mortbay.jetty:jetty

    @@ -2017,7 +2068,7 @@ - + @@ -2041,7 +2092,7 @@ - + @@ -2065,7 +2116,7 @@ - + @@ -2125,7 +2176,7 @@ -
    dependency-check-utils
    Current Version1.4.4
    1.4.5
    Scope compile
    slf4j-api
    Current Version1.7.21
    1.7.22
    Scope
    slf4j-simple
    Current Version1.7.21
    1.7.22
    Scope
    jar
    Newer versions2.5.6 Next Incremental
    2.5.6.SEC01
    2.5.6.SEC02
    2.5.6.SEC03 Latest Incremental
    3.0.0.RELEASE Next Major
    3.0.1.RELEASE
    3.0.2.RELEASE
    3.0.3.RELEASE
    3.0.4.RELEASE
    3.0.5.RELEASE
    3.0.6.RELEASE
    3.0.7.RELEASE
    3.1.0.RELEASE
    3.1.1.RELEASE
    3.1.2.RELEASE
    3.2.0.RELEASE
    3.2.1.RELEASE
    3.2.2.RELEASE
    3.2.3.RELEASE
    3.2.4.RELEASE
    3.2.5.RELEASE
    3.2.6.RELEASE
    3.2.7.RELEASE
    3.2.8.RELEASE
    3.2.9.RELEASE
    3.2.10.RELEASE
    3.2.11.RELEASE
    3.2.12.RELEASE
    3.2.13.RELEASE
    3.2.14.RELEASE
    3.2.15.RELEASE
    3.2.16.RELEASE
    3.2.17.RELEASE
    4.0.0.RELEASE
    4.0.1.RELEASE
    4.0.2.RELEASE
    4.0.3.RELEASE
    4.0.4.RELEASE
    4.0.5.RELEASE
    4.0.6.RELEASE
    4.0.7.RELEASE
    4.0.8.RELEASE
    4.0.9.RELEASE
    4.1.0.RELEASE
    4.1.1.RELEASE
    4.1.2.RELEASE
    4.1.3.RELEASE
    4.1.4.RELEASE
    4.1.5.RELEASE
    4.1.6.RELEASE
    4.1.7.RELEASE
    4.1.8.RELEASE
    4.1.9.RELEASE
    4.2.0.RELEASE
    4.2.1.RELEASE
    4.2.2.RELEASE
    4.2.3.RELEASE
    4.2.4.RELEASE
    4.2.5.RELEASE
    4.2.6.RELEASE
    4.2.7.RELEASE
    4.2.8.RELEASE
    4.3.0.RELEASE
    4.3.1.RELEASE
    4.3.2.RELEASE
    4.3.3.RELEASE Latest Major
    +2.5.6 Next Incremental
    2.5.6.SEC01
    2.5.6.SEC02
    2.5.6.SEC03 Latest Incremental
    3.0.0.RELEASE Next Major
    3.0.1.RELEASE
    3.0.2.RELEASE
    3.0.3.RELEASE
    3.0.4.RELEASE
    3.0.5.RELEASE
    3.0.6.RELEASE
    3.0.7.RELEASE
    3.1.0.RELEASE
    3.1.1.RELEASE
    3.1.2.RELEASE
    3.1.3.RELEASE
    3.1.4.RELEASE
    3.2.0.RELEASE
    3.2.1.RELEASE
    3.2.2.RELEASE
    3.2.3.RELEASE
    3.2.4.RELEASE
    3.2.5.RELEASE
    3.2.6.RELEASE
    3.2.7.RELEASE
    3.2.8.RELEASE
    3.2.9.RELEASE
    3.2.10.RELEASE
    3.2.11.RELEASE
    3.2.12.RELEASE
    3.2.13.RELEASE
    3.2.14.RELEASE
    3.2.15.RELEASE
    3.2.16.RELEASE
    3.2.17.RELEASE
    3.2.18.RELEASE
    4.0.0.RELEASE
    4.0.1.RELEASE
    4.0.2.RELEASE
    4.0.3.RELEASE
    4.0.4.RELEASE
    4.0.5.RELEASE
    4.0.6.RELEASE
    4.0.7.RELEASE
    4.0.8.RELEASE
    4.0.9.RELEASE
    4.1.0.RELEASE
    4.1.1.RELEASE
    4.1.2.RELEASE
    4.1.3.RELEASE
    4.1.4.RELEASE
    4.1.5.RELEASE
    4.1.6.RELEASE
    4.1.7.RELEASE
    4.1.8.RELEASE
    4.1.9.RELEASE
    4.2.0.RELEASE
    4.2.1.RELEASE
    4.2.2.RELEASE
    4.2.3.RELEASE
    4.2.4.RELEASE
    4.2.5.RELEASE
    4.2.6.RELEASE
    4.2.7.RELEASE
    4.2.8.RELEASE
    4.2.9.RELEASE
    4.3.0.RELEASE
    4.3.1.RELEASE
    4.3.2.RELEASE
    4.3.3.RELEASE
    4.3.4.RELEASE
    4.3.5.RELEASE Latest Major

    org.springframework.retry:spring-retry

    @@ -2152,7 +2203,7 @@ -
    jar
    Newer versions1.1.1.RELEASE Next Incremental
    1.1.2.RELEASE
    1.1.3.RELEASE
    1.1.4.RELEASE Latest Incremental
    +1.1.1.RELEASE Next Incremental
    1.1.2.RELEASE
    1.1.3.RELEASE
    1.1.4.RELEASE
    1.1.5.RELEASE Latest Incremental
    1.2.0.RELEASE Next Minor

    org.springframework.security:spring-security-web

    @@ -2179,7 +2230,7 @@ -
    jar
    Newer versions3.0.1.RELEASE Next Incremental
    3.0.2.RELEASE
    3.0.3.RELEASE
    3.0.4.RELEASE
    3.0.5.RELEASE
    3.0.6.RELEASE
    3.0.7.RELEASE
    3.0.8.RELEASE Latest Incremental
    3.1.0.RELEASE Next Minor
    3.1.1.RELEASE
    3.1.2.RELEASE
    3.1.3.RELEASE
    3.1.4.RELEASE
    3.1.5.RELEASE
    3.1.6.RELEASE
    3.1.7.RELEASE
    3.2.0.RELEASE
    3.2.1.RELEASE
    3.2.2.RELEASE
    3.2.3.RELEASE
    3.2.4.RELEASE
    3.2.5.RELEASE
    3.2.6.RELEASE
    3.2.7.RELEASE
    3.2.8.RELEASE
    3.2.9.RELEASE Latest Minor
    4.0.0.RELEASE Next Major
    4.0.1.RELEASE
    4.0.2.RELEASE
    4.0.3.RELEASE
    4.0.4.RELEASE
    4.1.0.RELEASE
    4.1.1.RELEASE
    4.1.2.RELEASE
    4.1.3.RELEASE Latest Major
    +3.0.1.RELEASE Next Incremental
    3.0.2.RELEASE
    3.0.3.RELEASE
    3.0.4.RELEASE
    3.0.5.RELEASE
    3.0.6.RELEASE
    3.0.7.RELEASE
    3.0.8.RELEASE Latest Incremental
    3.1.0.RELEASE Next Minor
    3.1.1.RELEASE
    3.1.2.RELEASE
    3.1.3.RELEASE
    3.1.4.RELEASE
    3.1.5.RELEASE
    3.1.6.RELEASE
    3.1.7.RELEASE
    3.2.0.RELEASE
    3.2.1.RELEASE
    3.2.2.RELEASE
    3.2.3.RELEASE
    3.2.4.RELEASE
    3.2.5.RELEASE
    3.2.6.RELEASE
    3.2.7.RELEASE
    3.2.8.RELEASE
    3.2.9.RELEASE
    3.2.10.RELEASE Latest Minor
    4.0.0.RELEASE Next Major
    4.0.1.RELEASE
    4.0.2.RELEASE
    4.0.3.RELEASE
    4.0.4.RELEASE
    4.1.0.RELEASE
    4.1.1.RELEASE
    4.1.2.RELEASE
    4.1.3.RELEASE
    4.1.4.RELEASE
    4.2.0.RELEASE
    4.2.1.RELEASE Latest Major

    uk.ltd.getahead:dwr

    @@ -2240,7 +2291,7 @@ -
    0 0 100%181.425

    +133.468

    Note: failures are anticipated and checked for with assertions while errors are unanticipated.


    Package List

    @@ -293,7 +293,7 @@ function toggleDisplay(elementId) { 0 0 100% -3.375 +3.981 org.owasp.dependencycheck.reporting 2 @@ -301,7 +301,7 @@ function toggleDisplay(elementId) { 0 0 100% -9.681 +7.465 org.owasp.dependencycheck.data.nvdcve 10 @@ -309,7 +309,7 @@ function toggleDisplay(elementId) { 0 0 100% -6.494 +6.669 org.owasp.dependencycheck 1 @@ -317,7 +317,7 @@ function toggleDisplay(elementId) { 0 0 100% -42.813 +38.299 org.owasp.dependencycheck.analyzer 22 @@ -325,7 +325,7 @@ function toggleDisplay(elementId) { 0 0 100% -119.062
    +77.054

    Note: package statistics are not computed recursively, they only sum up all of its testsuites numbers.

    org.owasp.dependencycheck.data.update

    @@ -347,7 +347,7 @@ function toggleDisplay(elementId) { 0 0 100% -0.004 +0 NvdCveUpdaterIntegrationTest @@ -356,7 +356,7 @@ function toggleDisplay(elementId) { 0 0 100% -3.371
    +3.981

    org.owasp.dependencycheck.reporting

    @@ -377,7 +377,7 @@ function toggleDisplay(elementId) { -
    0 0 100%9.681
    +7.465

    org.owasp.dependencycheck.data.nvdcve

    @@ -398,7 +398,7 @@ function toggleDisplay(elementId) { - + @@ -407,7 +407,7 @@ function toggleDisplay(elementId) { -
    0 0 100%3.282
    3.454
    DatabasePropertiesIntegrationTest0 0 100%3.212
    +3.215

    org.owasp.dependencycheck

    @@ -428,7 +428,7 @@ function toggleDisplay(elementId) { -
    0 0 100%42.813
    +38.299

    org.owasp.dependencycheck.analyzer

    @@ -449,7 +449,7 @@ function toggleDisplay(elementId) { - + @@ -458,7 +458,7 @@ function toggleDisplay(elementId) { - + @@ -467,7 +467,7 @@ function toggleDisplay(elementId) { - + @@ -476,7 +476,7 @@ function toggleDisplay(elementId) { -
    0 0 100%26.302
    29.327
    CPEAnalyzerIntegrationTest0 0 100%89.138
    44.644
    DependencyBundlingAnalyzerIntegrationTest0 0 100%0.002
    0
    VulnerabilitySuppressionAnalyzerIntegrationTest0 0 100%3.62

    +3.083

    Test Cases

    [Summary] [Package List] [Test Cases]

    @@ -486,35 +486,35 @@ function toggleDisplay(elementId) { testAnalyzeExecutableJar -1.981 +1.723 testAnalyzeTar -2.049 +6.916 testAnalyzeTgz -5.776 +5.525 testAnalyzeTarBz2 -4.424 +3.786 testAnalyze -1.059 +3.516 testGetAnalysisPhase -0.001 +0 testGetName -0.001 +0 testAnalyze_badZip -0.527 +0.554 testInitialize @@ -522,11 +522,11 @@ function toggleDisplay(elementId) { testAnalyzeTbz2 -3.658 +3.361 testAnalyzeTarGz -5.724 +3.403 testSupportsExtension @@ -534,26 +534,26 @@ function toggleDisplay(elementId) { testSupportsExtensions -0.002
    +0

    CPEAnalyzerIntegrationTest

    - + - + - + - + @@ -571,7 +571,7 @@ function toggleDisplay(elementId) { - + @@ -586,46 +586,46 @@ function toggleDisplay(elementId) { - + - + - + - + -
    testSearchCPE2.132
    1.802
    testDetermineCPE2.447
    1.198
    testDetermineIdentifiers1.287
    1.04
    testDetermineCPE_full83.263
    40.604
    testBuildSearch
    testAnalyze3.617
    3.067
    testGetAnalysisPhase
    testOpen0.966
    1.05
    testGetCPEs0.507
    0.518
    testGetVulnerabilities0.789
    0.669
    testGetMatchingSoftware0.505
    0.544
    testgetVulnerability0.514
    +0.673

    DatabasePropertiesIntegrationTest

    - + - + - + - + -
    testSave1.188
    1.067
    testGetProperty_String_String0.504
    0.524
    testGetProperties0.505
    0.548
    testGetProperty_String0.507
    0.536
    testIsEmpty0.506
    +0.54

    CpeUpdaterIntegrationTest

    @@ -639,29 +639,29 @@ function toggleDisplay(elementId) { - + -
    testUpdatesNeeded1.009
    1.114
    testUpdate2.359
    +2.867

    EngineIntegrationTest

    -
    testEngine42.791
    +38.298

    ReportGeneratorIntegrationTest

    - + -
    testGenerateXMLReport9.661
    7.463
    testGenerateReport0.007

    +0
    @@ -671,7 +671,7 @@ function toggleDisplay(elementId) {