mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
185 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92bd305b00 | ||
|
|
f71eb09f74 | ||
|
|
83d4a7bc18 | ||
|
|
29595324c4 | ||
|
|
f9064e526f | ||
|
|
93ec2e8639 | ||
|
|
0e2a31709a | ||
|
|
c785b39eda | ||
|
|
8fab2f58da | ||
|
|
e44ee3bfe1 | ||
|
|
62065c9d28 | ||
|
|
c76275275f | ||
|
|
257f78879d | ||
|
|
894263809c | ||
|
|
c503935d6a | ||
|
|
d4756c9eb8 | ||
|
|
0004767775 | ||
|
|
74908642c7 | ||
|
|
aadfb71c98 | ||
|
|
1244af649d | ||
|
|
7bd48cc811 | ||
|
|
8f3ce38418 | ||
|
|
1b2d9b4245 | ||
|
|
c6b2b34fde | ||
|
|
e58fc13fdb | ||
|
|
922d53d2e4 | ||
|
|
fec53b3951 | ||
|
|
e72e2c6a02 | ||
|
|
08d001ee05 | ||
|
|
99d8a07f4a | ||
|
|
eef565134b | ||
|
|
9d78293437 | ||
|
|
fc0a556e5f | ||
|
|
b6b070584f | ||
|
|
e13225eee6 | ||
|
|
da20fb2922 | ||
|
|
459c2beb12 | ||
|
|
f1cc44dead | ||
|
|
d24cfdc382 | ||
|
|
ae4cc543f6 | ||
|
|
abdb3d17f9 | ||
|
|
4095c5da38 | ||
|
|
78fab728e4 | ||
|
|
52097a6867 | ||
|
|
cb990b55b5 | ||
|
|
5070fe303a | ||
|
|
b4405ebf3e | ||
|
|
d9e6bf5068 | ||
|
|
6822188f52 | ||
|
|
15858d03ff | ||
|
|
814a733258 | ||
|
|
3ce85d8ca9 | ||
|
|
d3bff2f39d | ||
|
|
f2272730ac | ||
|
|
fe19c97d86 | ||
|
|
56b447493e | ||
|
|
e45b68eda7 | ||
|
|
8df1ef5986 | ||
|
|
dac34cda82 | ||
|
|
9925e30c8b | ||
|
|
dc5566b5ae | ||
|
|
8132ee651a | ||
|
|
f49a134a3d | ||
|
|
bd955cda06 | ||
|
|
c6dbc01912 | ||
|
|
fabe1aa940 | ||
|
|
ba5dbb94b8 | ||
|
|
6ccc053d7e | ||
|
|
cf21dfaa3a | ||
|
|
54ceb630de | ||
|
|
0a0c302cb2 | ||
|
|
f6eef54566 | ||
|
|
a69804f84d | ||
|
|
0b06b194b0 | ||
|
|
73f6ce304c | ||
|
|
195818a432 | ||
|
|
47c817de1c | ||
|
|
8b3894f213 | ||
|
|
a411252f07 | ||
|
|
d7626aeb3f | ||
|
|
3565098650 | ||
|
|
803fcf146b | ||
|
|
d9d646c5fb | ||
|
|
034a274b07 | ||
|
|
718d7af8bc | ||
|
|
860d3d9c8b | ||
|
|
f28b566992 | ||
|
|
1c261c7463 | ||
|
|
226b2482b1 | ||
|
|
ff346dc429 | ||
|
|
2dcef25175 | ||
|
|
46702bbb5c | ||
|
|
5600c9bc69 | ||
|
|
d7e46b1693 | ||
|
|
fe8c60ade1 | ||
|
|
288892441f | ||
|
|
e1179a8e22 | ||
|
|
4b06d0fd87 | ||
|
|
464d91f45a | ||
|
|
5cc7aa25cc | ||
|
|
20ec224070 | ||
|
|
9cbcc29ddb | ||
|
|
0badbfc4a0 | ||
|
|
e042148c62 | ||
|
|
d8ba04ae7f | ||
|
|
314d5fdad2 | ||
|
|
5c874cafd1 | ||
|
|
8cafc14d09 | ||
|
|
25ac5033fc | ||
|
|
848be0db6c | ||
|
|
0f9da0731e | ||
|
|
8bc2364cce | ||
|
|
b64916ce3f | ||
|
|
452955667c | ||
|
|
f38bbf4cc7 | ||
|
|
25eaa11a52 | ||
|
|
4b4da8d467 | ||
|
|
13116c5381 | ||
|
|
d2cd406a62 | ||
|
|
acbce05fbf | ||
|
|
bee4d3a338 | ||
|
|
bce226002b | ||
|
|
a417db7c7a | ||
|
|
0ffef12a8b | ||
|
|
4539b040e0 | ||
|
|
f85014a86d | ||
|
|
d90d07c68b | ||
|
|
ce292b84fa | ||
|
|
01690860db | ||
|
|
89fb2d4915 | ||
|
|
5cc3a42832 | ||
|
|
60b0145e04 | ||
|
|
ce48823d38 | ||
|
|
d43fee5585 | ||
|
|
5dc9e51dd4 | ||
|
|
235fcccbd7 | ||
|
|
91c971b8fd | ||
|
|
e43003cadc | ||
|
|
9a96165655 | ||
|
|
994aef411c | ||
|
|
094a180935 | ||
|
|
74e9de6370 | ||
|
|
c7f31b3d79 | ||
|
|
98d0239d03 | ||
|
|
ffeab147ce | ||
|
|
90bdbd6b84 | ||
|
|
e29dd3cd33 | ||
|
|
23b95178ff | ||
|
|
9bde80357f | ||
|
|
1485733715 | ||
|
|
d125a7f09d | ||
|
|
77486dffd4 | ||
|
|
c84bcb433f | ||
|
|
f1e5221257 | ||
|
|
b8bf01acc3 | ||
|
|
65aa7bd1de | ||
|
|
6f511444a7 | ||
|
|
ef5174d89f | ||
|
|
e2a97e75d8 | ||
|
|
9fc6e265eb | ||
|
|
f81c42b1fd | ||
|
|
8594e146eb | ||
|
|
cda0dfdafe | ||
|
|
363568b02c | ||
|
|
443ab02788 | ||
|
|
65784d6dc4 | ||
|
|
da805d037f | ||
|
|
d383776245 | ||
|
|
51eba8da73 | ||
|
|
14b4d64244 | ||
|
|
7cb7f68cda | ||
|
|
83300d028b | ||
|
|
e891ce39c0 | ||
|
|
e58b7782ac | ||
|
|
1ddb468a08 | ||
|
|
95e3f0e0d9 | ||
|
|
0edf017ddc | ||
|
|
ad601fd1ee | ||
|
|
e7eaccb5e0 | ||
|
|
6b201da3ff | ||
|
|
a85a47bc20 | ||
|
|
69b8f51319 | ||
|
|
0d943ba805 | ||
|
|
56fe3b5892 | ||
|
|
c177f12e1d |
@@ -40,7 +40,6 @@ The plugin can be configured using the following:
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -59,7 +58,7 @@ The plugin can be configured using the following:
|
||||
|
||||
### Ant Task
|
||||
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-maven/installation.html).
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/installation.html).
|
||||
|
||||
Development Usage
|
||||
-------------
|
||||
@@ -106,4 +105,4 @@ Dependency-Check makes use of several other open source libraries. Please see th
|
||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||
[post]: mailto:dependency-check@googlegroups.com
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
|
||||
@@ -15,20 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Ant Task</name>
|
||||
<description>Dependency-check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-ant is an Ant Task that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The task will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -324,6 +323,9 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -439,6 +441,11 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
|
||||
@@ -285,26 +285,50 @@ public class DependencyCheckTask extends Task {
|
||||
this.reportFormat = reportFormat.getValue();
|
||||
}
|
||||
/**
|
||||
* The Proxy URL.
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyUrl;
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUrl.
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyUrl
|
||||
* @return the value of proxyServer
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return proxyUrl;
|
||||
public String getProxyServer() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyUrl.
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyUrl
|
||||
* @param server new value of proxyServer
|
||||
*/
|
||||
public void setProxyServer(String server) {
|
||||
this.proxyServer = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#getProxyServer()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProxyUrl() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#setProxyServer(java.lang.String)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
LOGGER.warning("A deprecated configuration option 'proxyUrl' was detected; use 'proxyServer' instead.");
|
||||
this.proxyServer = proxyUrl;
|
||||
}
|
||||
/**
|
||||
* The Proxy Port.
|
||||
@@ -866,7 +890,7 @@ public class DependencyCheckTask extends Task {
|
||||
|
||||
Engine engine = null;
|
||||
try {
|
||||
engine = new Engine();
|
||||
engine = new Engine(DependencyCheckTask.class.getClassLoader());
|
||||
|
||||
for (Resource resource : path) {
|
||||
final FileProvider provider = resource.as(FileProvider.class);
|
||||
@@ -912,7 +936,7 @@ public class DependencyCheckTask extends Task {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
@@ -935,7 +959,7 @@ public class DependencyCheckTask extends Task {
|
||||
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
||||
* properties required to change the proxy url, port, and connection timeout.
|
||||
* properties required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
@@ -967,8 +991,8 @@ public class DependencyCheckTask extends Task {
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
|
||||
@@ -32,7 +32,7 @@ failBuildOnCVSS | Specifies if the build should be failed if a CVSS score a
|
||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
logFile | The file path to write verbose logging information. |
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |
|
||||
proxyUrl | The Proxy URL. |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
|
||||
@@ -3,7 +3,20 @@ Installation
|
||||
Download dependency-check-ant from [bintray here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-ant-${project.version}.jar).
|
||||
To install dependency-check-ant place the dependency-check-ant-${project.version}.jar into
|
||||
the lib directory of your Ant instalation directory. Once installed you can add
|
||||
the taskdef to you build.xml and add the task to a new or existing target.
|
||||
the taskdef to you build.xml and add the task to a new or existing target:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
If you do not want to install dependency-check-ant into your ant's lib directory when you define the task def you
|
||||
must add the classpath to the taskdef:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
It is important to understand that the first time this task is executed it may
|
||||
take 20 minutes or more as it downloads and processes the data from the National
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
Usage
|
||||
====================
|
||||
First, add the dependency-check-ant taskdef to your build.xml:
|
||||
First, add the dependency-check-ant taskdef to your build.xml (see the [installation guide](installation.html):
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
Next, add the task to a target of your choosing:
|
||||
|
||||
```xml
|
||||
@@ -45,7 +45,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
public void tearDown() {
|
||||
//no cleanup...
|
||||
//executeTarget("cleanup");
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,20 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Command Line</name>
|
||||
<description>Dependency-Check-Maven is a Maven Plugin that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-cli is an command line tool that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the scanned project dependencies. The tool will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -174,6 +173,9 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -341,5 +343,10 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -57,8 +57,13 @@ public class App {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final App app = new App();
|
||||
app.run(args);
|
||||
try {
|
||||
Settings.initialize();
|
||||
final App app = new App();
|
||||
app.run(args);
|
||||
} finally {
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,8 +72,8 @@ public class App {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public void run(String[] args) {
|
||||
|
||||
final CliParser cli = new CliParser();
|
||||
|
||||
try {
|
||||
cli.parse(args);
|
||||
} catch (FileNotFoundException ex) {
|
||||
@@ -140,7 +145,6 @@ public class App {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
if (scanner != null) {
|
||||
scanner.cleanup();
|
||||
}
|
||||
@@ -155,11 +159,9 @@ public class App {
|
||||
*/
|
||||
private void populateSettings(CliParser cli) {
|
||||
|
||||
Settings.initialize();
|
||||
|
||||
final boolean autoUpdate = cli.isAutoUpdate();
|
||||
final String connectionTimeout = cli.getConnectionTimeout();
|
||||
final String proxyUrl = cli.getProxyUrl();
|
||||
final String proxyServer = cli.getProxyServer();
|
||||
final String proxyPort = cli.getProxyPort();
|
||||
final String proxyUser = cli.getProxyUsername();
|
||||
final String proxyPass = cli.getProxyPassword();
|
||||
@@ -210,8 +212,8 @@ public class App {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.cli;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
@@ -39,6 +40,10 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public final class CliParser {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CliParser.class.getName());
|
||||
/**
|
||||
* The command line.
|
||||
*/
|
||||
@@ -85,16 +90,16 @@ public final class CliParser {
|
||||
*/
|
||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
||||
if (isRunScan()) {
|
||||
validatePathExists(getScanFiles(), ArgumentName.SCAN);
|
||||
validatePathExists(getReportDirectory(), ArgumentName.OUT);
|
||||
validatePathExists(getScanFiles(), ARGUMENT.SCAN);
|
||||
validatePathExists(getReportDirectory(), ARGUMENT.OUT);
|
||||
if (getPathToMono() != null) {
|
||||
validatePathExists(getPathToMono(), ArgumentName.PATH_TO_MONO);
|
||||
validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
if (!line.hasOption(ArgumentName.APP_NAME)) {
|
||||
if (!line.hasOption(ARGUMENT.APP_NAME)) {
|
||||
throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
|
||||
}
|
||||
if (line.hasOption(ArgumentName.OUTPUT_FORMAT)) {
|
||||
final String format = line.getOptionValue(ArgumentName.OUTPUT_FORMAT);
|
||||
if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
|
||||
final String format = line.getOptionValue(ARGUMENT.OUTPUT_FORMAT);
|
||||
try {
|
||||
Format.valueOf(format);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
@@ -150,7 +155,7 @@ public final class CliParser {
|
||||
final Options options = new Options();
|
||||
addStandardOptions(options);
|
||||
addAdvancedOptions(options);
|
||||
|
||||
addDeprecatedOptions(options);
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -162,44 +167,44 @@ public final class CliParser {
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private void addStandardOptions(final Options options) throws IllegalArgumentException {
|
||||
final Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
|
||||
final Option help = new Option(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, false,
|
||||
"Print this message.");
|
||||
|
||||
final Option advancedHelp = OptionBuilder.withLongOpt(ArgumentName.ADVANCED_HELP)
|
||||
final Option advancedHelp = OptionBuilder.withLongOpt(ARGUMENT.ADVANCED_HELP)
|
||||
.withDescription("Print the advanced help message.").create();
|
||||
|
||||
final Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
|
||||
final Option version = new Option(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION,
|
||||
false, "Print the version information.");
|
||||
|
||||
final Option noUpdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
|
||||
final Option noUpdate = new Option(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE,
|
||||
false, "Disables the automatic updating of the CPE data.");
|
||||
|
||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APP_NAME)
|
||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ARGUMENT.APP_NAME)
|
||||
.withDescription("The name of the application being scanned. This is a required argument.")
|
||||
.create(ArgumentName.APP_NAME_SHORT);
|
||||
.create(ARGUMENT.APP_NAME_SHORT);
|
||||
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
||||
.withDescription("The path to scan - this option can be specified multiple times. To limit the scan"
|
||||
+ " to specific file types *.[ext] can be added to the end of the path.")
|
||||
.create(ArgumentName.SCAN_SHORT);
|
||||
.create(ARGUMENT.SCAN_SHORT);
|
||||
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
|
||||
.withDescription("A property file to load.")
|
||||
.create(ArgumentName.PROP_SHORT);
|
||||
.create(ARGUMENT.PROP_SHORT);
|
||||
|
||||
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
|
||||
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ARGUMENT.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory.")
|
||||
.create(ArgumentName.OUT_SHORT);
|
||||
.create(ARGUMENT.OUT_SHORT);
|
||||
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||
.withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
|
||||
.create(ArgumentName.OUTPUT_FORMAT_SHORT);
|
||||
.create(ARGUMENT.OUTPUT_FORMAT_SHORT);
|
||||
|
||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.VERBOSE_LOG)
|
||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.VERBOSE_LOG)
|
||||
.withDescription("The file path to write verbose logging information.")
|
||||
.create(ArgumentName.VERBOSE_LOG_SHORT);
|
||||
.create(ARGUMENT.VERBOSE_LOG_SHORT);
|
||||
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.SUPPRESSION_FILE)
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
||||
.withDescription("The file path to the suppression XML file.")
|
||||
.create();
|
||||
|
||||
@@ -230,87 +235,87 @@ public final class CliParser {
|
||||
@SuppressWarnings("static-access")
|
||||
private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DATA_DIRECTORY)
|
||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DATA_DIRECTORY)
|
||||
.withDescription("The location of the H2 Database file. This option should generally not be set.")
|
||||
.create(ArgumentName.DATA_DIRECTORY_SHORT);
|
||||
.create(ARGUMENT.DATA_DIRECTORY_SHORT);
|
||||
|
||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ArgumentName.CONNECTION_TIMEOUT)
|
||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
|
||||
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
|
||||
.create(ArgumentName.CONNECTION_TIMEOUT_SHORT);
|
||||
.create(ARGUMENT.CONNECTION_TIMEOUT_SHORT);
|
||||
|
||||
final Option proxyUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.PROXY_URL)
|
||||
.withDescription("The proxy url to use when downloading resources.")
|
||||
.create(ArgumentName.PROXY_URL_SHORT);
|
||||
final Option proxyServer = OptionBuilder.withArgName("server").hasArg().withLongOpt(ARGUMENT.PROXY_SERVER)
|
||||
.withDescription("The proxy server to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ArgumentName.PROXY_PORT)
|
||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ARGUMENT.PROXY_PORT)
|
||||
.withDescription("The proxy port to use when downloading resources.")
|
||||
.create(ArgumentName.PROXY_PORT_SHORT);
|
||||
.create();
|
||||
|
||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.PROXY_USERNAME)
|
||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.PROXY_USERNAME)
|
||||
.withDescription("The proxy username to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ArgumentName.PROXY_PASSWORD)
|
||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ARGUMENT.PROXY_PASSWORD)
|
||||
.withDescription("The proxy password to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ArgumentName.CONNECTION_STRING)
|
||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ARGUMENT.CONNECTION_STRING)
|
||||
.withDescription("The connection string to the database.")
|
||||
.create();
|
||||
|
||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.DB_NAME)
|
||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.DB_NAME)
|
||||
.withDescription("The username used to connect to the database.")
|
||||
.create();
|
||||
|
||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ArgumentName.DB_PASSWORD)
|
||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ARGUMENT.DB_PASSWORD)
|
||||
.withDescription("The password for connecting to the database.")
|
||||
.create();
|
||||
|
||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ArgumentName.DB_DRIVER)
|
||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ARGUMENT.DB_DRIVER)
|
||||
.withDescription("The database driver name.")
|
||||
.create();
|
||||
|
||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DB_DRIVER_PATH)
|
||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DB_DRIVER_PATH)
|
||||
.withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
|
||||
.create();
|
||||
|
||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_JAR)
|
||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
|
||||
.withDescription("Disable the Jar Analyzer.")
|
||||
.create();
|
||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ARCHIVE)
|
||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
|
||||
.withDescription("Disable the Archive Analyzer.")
|
||||
.create();
|
||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NUSPEC)
|
||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
|
||||
.withDescription("Disable the Nuspec Analyzer.")
|
||||
.create();
|
||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ASSEMBLY)
|
||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
||||
.withDescription("Disable the .NET Assembly Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NEXUS)
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
|
||||
.withDescription("Disable the Nexus Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.NEXUS_URL)
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
||||
.withDescription("The url to the Nexus Server.")
|
||||
.create();
|
||||
|
||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ArgumentName.NEXUS_USES_PROXY)
|
||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.NEXUS_USES_PROXY)
|
||||
.withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
|
||||
.create();
|
||||
|
||||
final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
|
||||
.withLongOpt(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
|
||||
+ "(ZIP, EAR, WAR are already treated as zip files)")
|
||||
.create();
|
||||
|
||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.PATH_TO_MONO)
|
||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.PATH_TO_MONO)
|
||||
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
||||
.create();
|
||||
|
||||
options.addOption(proxyPort)
|
||||
.addOption(proxyUrl)
|
||||
.addOption(proxyServer)
|
||||
.addOption(proxyUsername)
|
||||
.addOption(proxyPassword)
|
||||
.addOption(connectionTimeout)
|
||||
@@ -331,13 +336,30 @@ public final class CliParser {
|
||||
.addOption(pathToMono);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the deprecated command line options to the given options collection. These are split out for purposes of not
|
||||
* including them in the help message. We need to add the deprecated options so as not to break existing scripts.
|
||||
*
|
||||
* @param options a collection of command line arguments
|
||||
* @throws IllegalArgumentException thrown if there is an exception
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
|
||||
.withDescription("The proxy url argument is deprecated, use proxyserver instead.")
|
||||
.create();
|
||||
|
||||
options.addOption(proxyServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the 'version' command line argument was passed in.
|
||||
*
|
||||
* @return whether or not the 'version' command line argument was passed in
|
||||
*/
|
||||
public boolean isGetVersion() {
|
||||
return (line != null) && line.hasOption(ArgumentName.VERSION);
|
||||
return (line != null) && line.hasOption(ARGUMENT.VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,7 +368,7 @@ public final class CliParser {
|
||||
* @return whether or not the 'help' command line argument was passed in
|
||||
*/
|
||||
public boolean isGetHelp() {
|
||||
return (line != null) && line.hasOption(ArgumentName.HELP);
|
||||
return (line != null) && line.hasOption(ARGUMENT.HELP);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,7 +377,7 @@ public final class CliParser {
|
||||
* @return whether or not the 'scan' command line argument was passed in
|
||||
*/
|
||||
public boolean isRunScan() {
|
||||
return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
|
||||
return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,7 +386,7 @@ public final class CliParser {
|
||||
* @return true if the disableJar command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isJarDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_JAR);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,7 +395,7 @@ public final class CliParser {
|
||||
* @return true if the disableArchive command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isArchiveDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_ARCHIVE);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,7 +404,7 @@ public final class CliParser {
|
||||
* @return true if the disableNuspec command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNuspecDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_NUSPEC);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,7 +413,7 @@ public final class CliParser {
|
||||
* @return true if the disableAssembly command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isAssemblyDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_ASSEMBLY);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +422,7 @@ public final class CliParser {
|
||||
* @return true if the disableNexus command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNexusDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_NEXUS);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,10 +431,10 @@ public final class CliParser {
|
||||
* @return the url to the nexus server; if none was specified this will return null;
|
||||
*/
|
||||
public String getNexusUrl() {
|
||||
if (line == null || !line.hasOption(ArgumentName.NEXUS_URL)) {
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_URL)) {
|
||||
return null;
|
||||
} else {
|
||||
return line.getOptionValue(ArgumentName.NEXUS_URL);
|
||||
return line.getOptionValue(ARGUMENT.NEXUS_URL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,14 +447,14 @@ public final class CliParser {
|
||||
public boolean isNexusUsesProxy() {
|
||||
// If they didn't specify whether Nexus needs to use the proxy, we should
|
||||
// still honor the property if it's set.
|
||||
if (line == null || !line.hasOption(ArgumentName.NEXUS_USES_PROXY)) {
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
|
||||
try {
|
||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
|
||||
} catch (InvalidSettingException ise) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return Boolean.parseBoolean(line.getOptionValue(ArgumentName.NEXUS_USES_PROXY));
|
||||
return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +465,7 @@ public final class CliParser {
|
||||
final HelpFormatter formatter = new HelpFormatter();
|
||||
final Options options = new Options();
|
||||
addStandardOptions(options);
|
||||
if (line != null && line.hasOption(ArgumentName.ADVANCED_HELP)) {
|
||||
if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) {
|
||||
addAdvancedOptions(options);
|
||||
}
|
||||
final String helpMsg = String.format("%n%s"
|
||||
@@ -466,7 +488,7 @@ public final class CliParser {
|
||||
* @return the file paths specified on the command line for scan
|
||||
*/
|
||||
public String[] getScanFiles() {
|
||||
return line.getOptionValues(ArgumentName.SCAN);
|
||||
return line.getOptionValues(ARGUMENT.SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,7 +497,7 @@ public final class CliParser {
|
||||
* @return the path to the reports directory.
|
||||
*/
|
||||
public String getReportDirectory() {
|
||||
return line.getOptionValue(ArgumentName.OUT, ".");
|
||||
return line.getOptionValue(ARGUMENT.OUT, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -484,7 +506,7 @@ public final class CliParser {
|
||||
* @return the path to Mono
|
||||
*/
|
||||
public String getPathToMono() {
|
||||
return line.getOptionValue(ArgumentName.PATH_TO_MONO);
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,7 +515,7 @@ public final class CliParser {
|
||||
* @return the output format name.
|
||||
*/
|
||||
public String getReportFormat() {
|
||||
return line.getOptionValue(ArgumentName.OUTPUT_FORMAT, "HTML");
|
||||
return line.getOptionValue(ARGUMENT.OUTPUT_FORMAT, "HTML");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,7 +524,7 @@ public final class CliParser {
|
||||
* @return the application name.
|
||||
*/
|
||||
public String getApplicationName() {
|
||||
return line.getOptionValue(ArgumentName.APP_NAME);
|
||||
return line.getOptionValue(ARGUMENT.APP_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -511,16 +533,24 @@ public final class CliParser {
|
||||
* @return the connection timeout
|
||||
*/
|
||||
public String getConnectionTimeout() {
|
||||
return line.getOptionValue(ArgumentName.CONNECTION_TIMEOUT);
|
||||
return line.getOptionValue(ARGUMENT.CONNECTION_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proxy url.
|
||||
* Returns the proxy server.
|
||||
*
|
||||
* @return the proxy url
|
||||
* @return the proxy server
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_URL);
|
||||
public String getProxyServer() {
|
||||
|
||||
String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
|
||||
if (server == null) {
|
||||
server = line.getOptionValue(ARGUMENT.PROXY_URL);
|
||||
if (server != null) {
|
||||
LOGGER.warning("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
||||
}
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,7 +559,7 @@ public final class CliParser {
|
||||
* @return the proxy port
|
||||
*/
|
||||
public String getProxyPort() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PORT);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,7 +568,7 @@ public final class CliParser {
|
||||
* @return the proxy username
|
||||
*/
|
||||
public String getProxyUsername() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_USERNAME);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,7 +577,7 @@ public final class CliParser {
|
||||
* @return the proxy password
|
||||
*/
|
||||
public String getProxyPassword() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,7 +586,7 @@ public final class CliParser {
|
||||
* @return the value of dataDirectory
|
||||
*/
|
||||
public String getDataDirectory() {
|
||||
return line.getOptionValue(ArgumentName.DATA_DIRECTORY);
|
||||
return line.getOptionValue(ARGUMENT.DATA_DIRECTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,7 +595,7 @@ public final class CliParser {
|
||||
* @return the properties file specified on the command line
|
||||
*/
|
||||
public File getPropertiesFile() {
|
||||
final String path = line.getOptionValue(ArgumentName.PROP);
|
||||
final String path = line.getOptionValue(ARGUMENT.PROP);
|
||||
if (path != null) {
|
||||
return new File(path);
|
||||
}
|
||||
@@ -578,7 +608,7 @@ public final class CliParser {
|
||||
* @return the path to the verbose log file
|
||||
*/
|
||||
public String getVerboseLog() {
|
||||
return line.getOptionValue(ArgumentName.VERBOSE_LOG);
|
||||
return line.getOptionValue(ARGUMENT.VERBOSE_LOG);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,7 +617,7 @@ public final class CliParser {
|
||||
* @return the path to the suppression file
|
||||
*/
|
||||
public String getSuppressionFile() {
|
||||
return line.getOptionValue(ArgumentName.SUPPRESSION_FILE);
|
||||
return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -610,7 +640,7 @@ public final class CliParser {
|
||||
* @return if auto-update is allowed.
|
||||
*/
|
||||
public boolean isAutoUpdate() {
|
||||
return (line == null) || !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE);
|
||||
return (line == null) || !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -619,7 +649,7 @@ public final class CliParser {
|
||||
* @return the database driver name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseDriverName() {
|
||||
return line.getOptionValue(ArgumentName.DB_DRIVER);
|
||||
return line.getOptionValue(ARGUMENT.DB_DRIVER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -628,7 +658,7 @@ public final class CliParser {
|
||||
* @return the database driver name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseDriverPath() {
|
||||
return line.getOptionValue(ArgumentName.DB_DRIVER_PATH);
|
||||
return line.getOptionValue(ARGUMENT.DB_DRIVER_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,7 +667,7 @@ public final class CliParser {
|
||||
* @return the database connection string if specified; otherwise null is returned
|
||||
*/
|
||||
public String getConnectionString() {
|
||||
return line.getOptionValue(ArgumentName.CONNECTION_STRING);
|
||||
return line.getOptionValue(ARGUMENT.CONNECTION_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -646,7 +676,7 @@ public final class CliParser {
|
||||
* @return the database database user name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseUser() {
|
||||
return line.getOptionValue(ArgumentName.DB_NAME);
|
||||
return line.getOptionValue(ARGUMENT.DB_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,7 +685,7 @@ public final class CliParser {
|
||||
* @return the database database password if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabasePassword() {
|
||||
return line.getOptionValue(ArgumentName.DB_PASSWORD);
|
||||
return line.getOptionValue(ARGUMENT.DB_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -664,13 +694,13 @@ public final class CliParser {
|
||||
* @return the additional Extensions; otherwise null is returned
|
||||
*/
|
||||
public String getAdditionalZipExtensions() {
|
||||
return line.getOptionValue(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of static final strings that represent the possible command line arguments.
|
||||
*/
|
||||
public static class ArgumentName {
|
||||
public static class ARGUMENT {
|
||||
|
||||
/**
|
||||
* The long CLI argument name specifying the directory/file to scan.
|
||||
@@ -732,21 +762,20 @@ public final class CliParser {
|
||||
* The short CLI argument name asking for the version.
|
||||
*/
|
||||
public static final String VERSION = "version";
|
||||
/**
|
||||
* The short CLI argument name indicating the proxy port.
|
||||
*/
|
||||
public static final String PROXY_PORT_SHORT = "p";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy port.
|
||||
*/
|
||||
public static final String PROXY_PORT = "proxyport";
|
||||
/**
|
||||
* The short CLI argument name indicating the proxy url.
|
||||
* The CLI argument name indicating the proxy server.
|
||||
*/
|
||||
public static final String PROXY_URL_SHORT = "u";
|
||||
public static final String PROXY_SERVER = "proxyserver";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy url.
|
||||
*
|
||||
* @deprecated use {@link org.owasp.dependencycheck.cli.CliParser.ArgumentName#PROXY_SERVER} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String PROXY_URL = "proxyurl";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy username.
|
||||
|
||||
@@ -3,7 +3,7 @@ Command Line Arguments
|
||||
|
||||
The following table lists the command line arguments:
|
||||
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
-------|-----------------------|-----------------|-------------|------------
|
||||
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. | Required
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify specific file types that should be scanned by supplying a scan path of '[path]/[to]/[scan]/*.zip'. The wild card can only be used to denote any file-name with a specific extension. | Required
|
||||
@@ -18,7 +18,7 @@ Short | Argument Name | Parameter | Description | Requirement
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-------------|---------------
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
@@ -30,7 +30,7 @@ Short | Argument Name | Parameter | Description | Default Value
|
||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-proxyurl | \<url\> | The proxy url to use when downloading resources. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
|
||||
@@ -44,7 +44,7 @@ public class CliParserTest {
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
|
||||
@Before
|
||||
|
||||
@@ -15,19 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Core</name>
|
||||
<description>dependency-check-core is the engine and reporting tool used to identify and report if there are any known, publicly disclosed vulnerabilities in the scanned project's dependencies. The engine extracts meta-data from the dependencies and uses this to do fuzzy key-word matching against the Common Platfrom Enumeration (CPE), if any CPE identifiers are found the associated Common Vulnerability and Exposure (CVE) entries are added to the generated report.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -220,6 +220,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/data</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*IntegrationTest.java</include>
|
||||
@@ -267,6 +272,9 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -399,6 +407,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-test-framework</artifactId>
|
||||
@@ -419,7 +432,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.8</version>
|
||||
<version>1.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
@@ -521,6 +534,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hazelcast</groupId>
|
||||
<artifactId>hazelcast</artifactId>
|
||||
@@ -601,6 +621,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<version>1.1.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
@@ -662,11 +689,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
Additionally, these are only added when using "allTests" to
|
||||
make the build slightly faster in most cases. -->
|
||||
<id>False Positive Tests</id>
|
||||
<!--activation>
|
||||
<activation>
|
||||
<property>
|
||||
<name>allTests</name>
|
||||
</property>
|
||||
</activation-->
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
@@ -689,6 +716,41 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ganyo</groupId>
|
||||
<artifactId>gcm-server</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.python</groupId>
|
||||
<artifactId>jython-standalone</artifactId>
|
||||
<version>2.7-b1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby-complete</artifactId>
|
||||
<version>1.7.4</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby</artifactId>
|
||||
<version>1.6.3</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>2.12</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
@@ -52,7 +53,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Engine {
|
||||
public class Engine implements Serializable {
|
||||
|
||||
/**
|
||||
* The list of dependencies.
|
||||
@@ -61,19 +62,19 @@ public class Engine {
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
|
||||
private transient final EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final Set<FileTypeAnalyzer> fileTypeAnalyzers;
|
||||
private transient final Set<FileTypeAnalyzer> fileTypeAnalyzers;
|
||||
/**
|
||||
* The ClassLoader to use when dynamically loading Analyzer and Update services.
|
||||
*/
|
||||
private ClassLoader serviceClassLoader;
|
||||
private transient ClassLoader serviceClassLoader;
|
||||
/**
|
||||
* The Logger for use throughout the class.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
private transient static final Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a new Engine.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
* Copyright (c) 2014 Steve Springett. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.agent;
|
||||
|
||||
@@ -234,26 +234,49 @@ public class DependencyCheckScanAgent {
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy URL.
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyUrl;
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUrl.
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyUrl
|
||||
* @return the value of proxyServer
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return proxyUrl;
|
||||
public String getProxyServer() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyUrl.
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyUrl
|
||||
* @param proxyServer new value of proxyServer
|
||||
*/
|
||||
public void setProxyServer(String proxyServer) {
|
||||
this.proxyServer = proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProxyUrl() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#setProxyServer(java.lang.String)
|
||||
* } instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
this.proxyServer = proxyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -792,7 +815,7 @@ public class DependencyCheckScanAgent {
|
||||
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
||||
* properties required to change the proxy url, port, and connection timeout.
|
||||
* properties required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
@@ -808,8 +831,8 @@ public class DependencyCheckScanAgent {
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
@@ -888,7 +911,7 @@ public class DependencyCheckScanAgent {
|
||||
"Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
|
||||
@@ -98,11 +98,17 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
* @throws SuppressionParseException thrown if the XML cannot be parsed.
|
||||
*/
|
||||
private void loadSuppressionData() throws SuppressionParseException {
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
File file = null;
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
||||
} catch (SuppressionParseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to parse the base suppression data file", ex);
|
||||
}
|
||||
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
||||
if (suppressionFilePath == null) {
|
||||
return;
|
||||
}
|
||||
File file = null;
|
||||
boolean deleteTempFile = false;
|
||||
try {
|
||||
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
|
||||
@@ -132,9 +138,9 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(file);
|
||||
//rules = parser.parseSuppressionRules(file);
|
||||
rules.addAll(parser.parseSuppressionRules(file));
|
||||
LOGGER.log(Level.FINE, rules.size() + " suppression rules were loaded.");
|
||||
} catch (SuppressionParseException ex) {
|
||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -35,7 +36,9 @@ import java.util.logging.Logger;
|
||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.apache.commons.compress.compressors.CompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipUtils;
|
||||
@@ -99,6 +102,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
|
||||
|
||||
/**
|
||||
* The set of file extensions to remove from the engine's collection of dependencies.
|
||||
*/
|
||||
private static final Set<String> REMOVE_FROM_ANALYSIS = newHashSet("zip", "tar", "gz", "tgz"); //TODO add nupkg, apk, sar?
|
||||
|
||||
static {
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
@@ -178,7 +186,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success) {
|
||||
if (!success && tempFileLocation != null & tempFileLocation.exists()) {
|
||||
LOGGER.log(Level.WARNING, "Failed to delete some temporary files, see the log for more details");
|
||||
}
|
||||
}
|
||||
@@ -199,9 +207,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
extractFiles(f, tmpDir, engine);
|
||||
|
||||
//make a copy
|
||||
final List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpDir);
|
||||
final List<Dependency> newDependencies = engine.getDependencies();
|
||||
List<Dependency> newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
@@ -229,6 +237,40 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
|
||||
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
|
||||
final File tdir = getNextTempDirectory();
|
||||
final String fileName = dependency.getFileName();
|
||||
|
||||
LOGGER.info(String.format("The zip file '%s' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName));
|
||||
|
||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
|
||||
dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpLoc);
|
||||
newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(newDependencies);
|
||||
dependencySet.removeAll(dependencies);
|
||||
if (dependencySet.size() != 1) {
|
||||
LOGGER.info("Deep copy of ZIP to JAR file resulted in more then one dependency?");
|
||||
}
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
d.setFilePath(dependency.getFilePath());
|
||||
d.setDisplayFileName(dependency.getFileName());
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
}
|
||||
}
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
Collections.sort(engine.getDependencies());
|
||||
}
|
||||
|
||||
@@ -411,4 +453,38 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to determine if a zip file is actually a JAR file.
|
||||
*
|
||||
* @param dependency the dependency to check
|
||||
* @return true if the dependency appears to be a JAR file; otherwise false
|
||||
*/
|
||||
private boolean isZipFileActuallyJarFile(Dependency dependency) {
|
||||
boolean isJar = false;
|
||||
ZipFile zip = null;
|
||||
try {
|
||||
zip = new ZipFile(dependency.getActualFilePath());
|
||||
if (zip.getEntry("META-INF/MANIFEST.MF") != null
|
||||
|| zip.getEntry("META-INF/maven") != null) {
|
||||
final Enumeration<ZipArchiveEntry> entries = zip.getEntries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final ZipArchiveEntry entry = entries.nextElement();
|
||||
if (!entry.isDirectory()) {
|
||||
final String name = entry.getName().toLowerCase();
|
||||
if (name.endsWith(".class")) {
|
||||
isJar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, String.format("Unable to unzip zip file '%s'", dependency.getFilePath()), ex);
|
||||
} finally {
|
||||
ZipFile.closeQuietly(zip);
|
||||
}
|
||||
|
||||
return isJar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName(), "dependencycheck-resources");
|
||||
|
||||
/**
|
||||
* Builds the beginnings of a List for ProcessBuilder
|
||||
@@ -106,7 +106,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
public void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
if (grokAssemblyExe == null) {
|
||||
LOGGER.warning("GrokAssembly didn't get deployed");
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.notdeployed");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -114,16 +114,30 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
args.add(dependency.getActualFilePath());
|
||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||
BufferedReader rdr = null;
|
||||
Document doc = null;
|
||||
try {
|
||||
final Process proc = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
||||
String line = null;
|
||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
||||
LOGGER.log(Level.WARNING, "Error from GrokAssembly: {0}", line);
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
|
||||
}
|
||||
int rc = 0;
|
||||
final Document doc = builder.parse(proc.getInputStream());
|
||||
doc = builder.parse(proc.getInputStream());
|
||||
|
||||
try {
|
||||
rc = proc.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
return;
|
||||
}
|
||||
if (rc == 3) {
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.notassembly", dependency.getActualFilePath());
|
||||
return;
|
||||
} else if (rc != 0) {
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.rc", rc);
|
||||
}
|
||||
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
|
||||
// First, see if there was an error
|
||||
@@ -150,18 +164,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
product, Confidence.HIGH));
|
||||
}
|
||||
|
||||
try {
|
||||
rc = proc.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
return;
|
||||
}
|
||||
if (rc == 3) {
|
||||
LOGGER.log(Level.INFO, "{0} is not a valid assembly", dependency.getActualFilePath());
|
||||
return;
|
||||
} else if (rc != 0) {
|
||||
LOGGER.log(Level.WARNING, "Return code {0} from GrokAssembly", rc);
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
throw new AnalysisException(ioe);
|
||||
} catch (SAXException saxe) {
|
||||
@@ -201,9 +203,10 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
grokAssemblyExe = tempFile;
|
||||
// Set the temp file to get deleted when we're done
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
LOGGER.log(Level.FINE, "Extracted GrokAssembly.exe to {0}", grokAssemblyExe.getPath());
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.deployed", grokAssemblyExe.getPath());
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.log(Level.WARNING, "Could not extract GrokAssembly.exe: {0}", ioe.getMessage());
|
||||
this.setEnabled(false);
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.notdeployed", ioe.getMessage());
|
||||
throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
@@ -240,15 +243,16 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.warning("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
||||
LOGGER.fine("GrokAssembly.exe is not working properly");
|
||||
grokAssemblyExe = null;
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof AnalysisException) {
|
||||
throw (AnalysisException) e;
|
||||
} else {
|
||||
LOGGER.warning("An error occured with the .NET AssemblyAnalyzer; "
|
||||
+ "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.");
|
||||
LOGGER.log(Level.FINE, "Could not execute GrokAssembly {0}", e.getMessage());
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.grokassembly.initialization.failed");
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.initialization.message", e.getMessage());
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
} finally {
|
||||
@@ -260,7 +264,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
}
|
||||
|
||||
@@ -272,7 +275,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
}
|
||||
} catch (SecurityException se) {
|
||||
LOGGER.fine("Can't delete temporary GrokAssembly.exe");
|
||||
LOGGER.fine("analyzer.AssemblyAnalyzer.grokassembly.notdeleted");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CPEAnalyzer implements Analyzer {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
@@ -90,6 +91,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
*/
|
||||
private CveDB cve;
|
||||
|
||||
/**
|
||||
* The URL to perform a search of the NVD CVE data at NIST.
|
||||
*/
|
||||
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
|
||||
|
||||
/**
|
||||
* Returns the name of this analyzer.
|
||||
*
|
||||
@@ -164,29 +170,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||
*/
|
||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
||||
Confidence confidence = Confidence.HIGHEST;
|
||||
|
||||
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), confidence);
|
||||
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), confidence);
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
|
||||
int ctr = 0;
|
||||
do {
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
|
||||
for (IndexEntry e : entries) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
determineIdentifiers(dependency, vendor, product);
|
||||
}
|
||||
}
|
||||
}
|
||||
confidence = reduceConfidence(confidence);
|
||||
//TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||
String vendors = "";
|
||||
String products = "";
|
||||
for (Confidence confidence : Confidence.values()) {
|
||||
if (dependency.getVendorEvidence().contains(confidence)) {
|
||||
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
||||
}
|
||||
@@ -195,10 +182,26 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
if (dependency.getVersionEvidence().contains(confidence)) {
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
// if (dependency.getVersionEvidence().contains(confidence)) {
|
||||
// addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
// }
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
|
||||
boolean identifierAdded = false;
|
||||
for (IndexEntry e : entries) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||
}
|
||||
}
|
||||
if (identifierAdded) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((++ctr) < 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,22 +236,6 @@ public class CPEAnalyzer implements Analyzer {
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the given confidence by one level. This returns LOW if the confidence passed in is not HIGH.
|
||||
*
|
||||
* @param c the confidence to reduce.
|
||||
* @return One less then the confidence passed in.
|
||||
*/
|
||||
private Confidence reduceConfidence(final Confidence c) {
|
||||
if (c == Confidence.HIGHEST) {
|
||||
return Confidence.HIGH;
|
||||
} else if (c == Confidence.HIGH) {
|
||||
return Confidence.MEDIUM;
|
||||
} else {
|
||||
return Confidence.LOW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
||||
@@ -502,14 +489,19 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @param dependency the Dependency being analyzed
|
||||
* @param vendor the vendor for the CPE being analyzed
|
||||
* @param product the product for the CPE being analyzed
|
||||
* @return <code>true</code> if an identifier was added to the dependency; otherwise <code>false</code>
|
||||
* @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
|
||||
*/
|
||||
private void determineIdentifiers(Dependency dependency, String vendor, String product) throws UnsupportedEncodingException {
|
||||
private boolean determineIdentifiers(Dependency dependency, String vendor, String product, Confidence currentConfidence) throws UnsupportedEncodingException {
|
||||
final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
|
||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||
Confidence bestGuessConf = null;
|
||||
boolean hasBroadMatch = false;
|
||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
||||
for (Confidence conf : Confidence.values()) {
|
||||
// if (conf.compareTo(currentConfidence) > 0) {
|
||||
// break;
|
||||
// }
|
||||
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
||||
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
||||
if (evVer == null) {
|
||||
@@ -522,9 +514,13 @@ public class CPEAnalyzer implements Analyzer {
|
||||
} else {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||
}
|
||||
if (dbVer == null //special case, no version specified - everything is vulnerable
|
||||
|| evVer.equals(dbVer)) { //yeah! exact match
|
||||
final String url = String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
if (dbVer == null) { //special case, no version specified - everything is vulnerable
|
||||
hasBroadMatch = true;
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else if (evVer.equals(dbVer)) { //yeah! exact match
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else {
|
||||
@@ -549,7 +545,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
}
|
||||
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
|
||||
final String url = null; //String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(cpeName, "UTF-8"));
|
||||
String url = null;
|
||||
if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess.
|
||||
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
||||
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
||||
}
|
||||
if (bestGuessConf == null) {
|
||||
bestGuessConf = Confidence.LOW;
|
||||
}
|
||||
@@ -559,6 +559,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
Collections.sort(collected);
|
||||
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
||||
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
||||
boolean identifierAdded = false;
|
||||
for (IdentifierMatch m : collected) {
|
||||
if (bestIdentifierQuality.equals(m.getConfidence())
|
||||
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
||||
@@ -569,8 +570,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
i.setConfidence(bestEvidenceQuality);
|
||||
}
|
||||
dependency.addIdentifier(i);
|
||||
identifierAdded = true;
|
||||
}
|
||||
}
|
||||
return identifierAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -585,7 +588,12 @@ public class CPEAnalyzer implements Analyzer {
|
||||
/**
|
||||
* A best guess for the CPE.
|
||||
*/
|
||||
BEST_GUESS
|
||||
BEST_GUESS,
|
||||
/**
|
||||
* The entire vendor/product group must be added (without a guess at version) because there is a CVE with a VS
|
||||
* that only specifies vendor/product.
|
||||
*/
|
||||
BROAD_MATCH
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,11 +86,42 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
removeJreEntries(dependency);
|
||||
removeBadMatches(dependency);
|
||||
removeBadSpringMatches(dependency);
|
||||
removeWrongVersionMatches(dependency);
|
||||
removeSpuriousCPE(dependency);
|
||||
removeDuplicativeEntriesFromJar(dependency, engine);
|
||||
addFalseNegativeCPEs(dependency);
|
||||
}
|
||||
|
||||
private void removeBadSpringMatches(Dependency dependency) {
|
||||
String mustContain = null;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".contains(i.getType())) {
|
||||
if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||
int endPoint = i.getValue().indexOf(":", 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mustContain != null) {
|
||||
Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
Identifier i = itr.next();
|
||||
if ("cpe".contains(i.getType())
|
||||
&& i.getValue() != null
|
||||
&& i.getValue().startsWith("cpe:/a:springsource:")
|
||||
&& !i.getValue().toLowerCase().contains(mustContain)) {
|
||||
itr.remove();
|
||||
//dependency.getIdentifiers().remove(i);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
||||
@@ -160,11 +191,20 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
|
||||
+ "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
||||
+ "jdk|jre|jsf|jsse)($|:.*)");
|
||||
+ "jdk|jre|jsse)($|:.*)");
|
||||
|
||||
/**
|
||||
* Regex to identify core jsf libraries.
|
||||
*/
|
||||
public static final Pattern CORE_JAVA_JSF = Pattern.compile("^cpe:/a:(sun|oracle|ibm):jsf($|:.*)");
|
||||
/**
|
||||
* Regex to identify core java library files. This is currently incomplete.
|
||||
*/
|
||||
public static final Pattern CORE_FILES = Pattern.compile("^((alt[-])?rt|jsf[-].*|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||
public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||
/**
|
||||
* Regex to identify core jsf java library files. This is currently incomplete.
|
||||
*/
|
||||
public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
|
||||
|
||||
/**
|
||||
* Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
|
||||
@@ -181,27 +221,11 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
if (coreCPE.matches() && !coreFiles.matches()) {
|
||||
itr.remove();
|
||||
}
|
||||
|
||||
//replaced with the regex above.
|
||||
// if (("cpe:/a:sun:java".equals(i.getValue())
|
||||
// || "cpe:/a:oracle:java".equals(i.getValue())
|
||||
// || "cpe:/a:ibm:java".equals(i.getValue())
|
||||
// || "cpe:/a:sun:j2se".equals(i.getValue())
|
||||
// || "cpe:/a:oracle:j2se".equals(i.getValue())
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:j2se:")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:jre")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:jdk")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java_se")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:java_se")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:java:")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:j2se:")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:jre")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:jdk")
|
||||
// || i.getValue().startsWith("cpe:/a:ibm:java:"))
|
||||
// && !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
|
||||
// itr.remove();
|
||||
// }
|
||||
final Matcher coreJsfCPE = CORE_JAVA_JSF.matcher(i.getValue());
|
||||
final Matcher coreJsfFiles = CORE_JSF_FILES.matcher(dependency.getFileName());
|
||||
if (coreJsfCPE.matches() && !coreJsfFiles.matches()) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,14 +272,33 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
//TODO move this startsWith expression to a configuration file?
|
||||
if ("cpe".equals(i.getType())) {
|
||||
if ((i.getValue().matches(".*c\\+\\+.*")
|
||||
|| i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||
|| i.getValue().startsWith("cpe:/a:yahoo:yui")
|
||||
|| i.getValue().startsWith("cpe:/a:file:file")
|
||||
|| i.getValue().startsWith("cpe:/a:mozilla:mozilla")
|
||||
|| i.getValue().startsWith("cpe:/a:cvs:cvs")
|
||||
|| i.getValue().startsWith("cpe:/a:ftp:ftp")
|
||||
|| i.getValue().startsWith("cpe:/a:ssh:ssh"))
|
||||
|| i.getValue().startsWith("cpe:/a:tcp:tcp")
|
||||
|| i.getValue().startsWith("cpe:/a:ssh:ssh")
|
||||
|| i.getValue().startsWith("cpe:/a:lookup:lookup"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".nupkg"))) {
|
||||
itr.remove();
|
||||
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||
|| i.getValue().startsWith("cpe:/a:yahoo:yui"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".exe"))) {
|
||||
itr.remove();
|
||||
} else if ((i.getValue().startsWith("cpe:/a:microsoft:excel")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:office"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
||||
itr.remove();
|
||||
@@ -266,7 +309,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
&& !dependency.getEvidenceUsed().containsUsedString("m-core")) {
|
||||
itr.remove();
|
||||
} else if (i.getValue().startsWith("cpe:/a:jboss:jboss")
|
||||
&& !dependency.getFileName().toLowerCase().matches("jboss-[\\d\\.]+(GA)?\\.jar")) {
|
||||
&& !dependency.getFileName().toLowerCase().matches("jboss-?[\\d\\.-]+(GA)?\\.jar")) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
@@ -314,6 +357,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
* @param dependency the dependency being analyzed
|
||||
*/
|
||||
private void addFalseNegativeCPEs(Dependency dependency) {
|
||||
//TODO move this to the hint analyzer
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
@@ -329,20 +373,92 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe2,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe2, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe2, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe3,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe3, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe3, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe4,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe4, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM
|
||||
* entries or other types of files (such as DLLs and EXEs) being contained within the JAR.
|
||||
*
|
||||
* @param dependency the dependency that might be a duplicate
|
||||
* @param engine the engine used to scan all dependencies
|
||||
*/
|
||||
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| "dll".equals(dependency.getFileExtension())
|
||||
|| "exe".equals(dependency.getFileExtension())) {
|
||||
String parentPath = dependency.getFilePath().toLowerCase();
|
||||
if (parentPath.contains(".jar")) {
|
||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||
final Dependency parent = findDependency(parentPath, engine.getDependencies());
|
||||
if (parent != null) {
|
||||
boolean remove = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(i.getType())) {
|
||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||
for (Identifier parentId : parent.getIdentifiers()) {
|
||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||
remove |= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!remove) { //we can escape early
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a given dependency, based on a given path, from a list of dependencies.
|
||||
*
|
||||
* @param dependencyPath the path of the dependency to return
|
||||
* @param dependencies the collection of dependencies to search
|
||||
* @return the dependency object for the given path, otherwise null
|
||||
*/
|
||||
private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) {
|
||||
for (Dependency d : dependencies) {
|
||||
if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a full CPE and returns the CPE trimmed to include only vendor and product.
|
||||
*
|
||||
* @param value the CPE value to trim
|
||||
* @return a CPE value that only includes the vendor and product
|
||||
*/
|
||||
private String trimCpeToVendor(String value) {
|
||||
//cpe:/a:jruby:jruby:1.0.8
|
||||
final int pos1 = value.indexOf(":", 7); //right of vendor
|
||||
final int pos2 = value.indexOf(":", pos1 + 1); //right of product
|
||||
if (pos2 < 0) {
|
||||
return value;
|
||||
} else {
|
||||
return value.substring(0, pos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ import org.owasp.dependencycheck.jaxb.pom.MavenNamespaceFilter;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.License;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Model;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Organization;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Parent;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.NonClosingStream;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -74,7 +73,6 @@ import org.xml.sax.XMLFilter;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to load a JAR file and collect information that can be used to determine the associated CPE.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
@@ -138,7 +136,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
"include-resource",
|
||||
"embed-dependency",
|
||||
"ipojo-components",
|
||||
"ipojo-extension");
|
||||
"ipojo-extension",
|
||||
"eclipse-sourcereferences");
|
||||
/**
|
||||
* item in some manifest, should be considered medium confidence.
|
||||
*/
|
||||
@@ -170,7 +169,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
public JarAnalyzer() {
|
||||
try {
|
||||
final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
|
||||
//final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
|
||||
final JAXBContext jaxbContext = JAXBContext.newInstance(Model.class);
|
||||
pomUnmarshaller = jaxbContext.createUnmarshaller();
|
||||
} catch (JAXBException ex) { //guess we will just have a null pointer exception later...
|
||||
LOGGER.log(Level.SEVERE, "Unable to load parser. See the log for more details.");
|
||||
@@ -321,7 +321,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
newDependency.setFileName(displayName);
|
||||
newDependency.setFilePath(displayPath);
|
||||
addPomEvidence(newDependency, pom, pomProperties);
|
||||
setPomEvidence(newDependency, pom, pomProperties, null);
|
||||
engine.getDependencies().add(newDependency);
|
||||
Collections.sort(engine.getDependencies());
|
||||
} else {
|
||||
@@ -345,16 +345,25 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @return a Properties object or null if no pom.properties was found
|
||||
* @throws IOException thrown if there is an exception reading the pom.properties
|
||||
*/
|
||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "OS_OPEN_STREAM",
|
||||
justification = "The reader is closed by closing the zipEntry")
|
||||
private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
|
||||
Properties pomProperties = null;
|
||||
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
||||
final ZipEntry propEntry = jar.getEntry(propPath);
|
||||
if (propEntry != null) {
|
||||
final Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||
pomProperties = new Properties();
|
||||
pomProperties.load(reader);
|
||||
Reader reader = null;
|
||||
try {
|
||||
reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||
pomProperties = new Properties();
|
||||
pomProperties.load(reader);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "close error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pomProperties;
|
||||
}
|
||||
@@ -558,37 +567,93 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private boolean setPomEvidence(Dependency dependency, Model pom, Properties pomProperties, ArrayList<ClassNameInformation> classes) {
|
||||
boolean foundSomething = false;
|
||||
boolean addAsIdentifier = true;
|
||||
if (pom == null) {
|
||||
return foundSomething;
|
||||
}
|
||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||
String parentGroupId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentGroupId = interpolateString(pom.getParent().getGroupId(), pomProperties);
|
||||
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
groupid = parentGroupId;
|
||||
}
|
||||
}
|
||||
final String originalGroupID = groupid;
|
||||
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||
groupid = groupid.substring(4);
|
||||
}
|
||||
foundSomething = true;
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGHEST);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
addMatchingValues(classes, groupid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, groupid, dependency.getProductEvidence());
|
||||
if (parentGroupId != null && !parentGroupId.isEmpty() && !parentGroupId.equals(groupid)) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.MEDIUM);
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.LOW);
|
||||
addMatchingValues(classes, parentGroupId, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, parentGroupId, dependency.getProductEvidence());
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
|
||||
String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||
String parentArtifactId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentArtifactId = interpolateString(pom.getParent().getArtifactId(), pomProperties);
|
||||
if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
artifactid = parentArtifactId;
|
||||
}
|
||||
}
|
||||
final String originalArtifactID = artifactid;
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
foundSomething = true;
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, artifactid, dependency.getProductEvidence());
|
||||
if (parentArtifactId != null && !parentArtifactId.isEmpty() && !parentArtifactId.equals(artifactid)) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.MEDIUM);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.LOW);
|
||||
addMatchingValues(classes, parentArtifactId, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, parentArtifactId, dependency.getProductEvidence());
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
//version
|
||||
final String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
String parentVersion = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentVersion = interpolateString(pom.getParent().getVersion(), pomProperties);
|
||||
if ((version == null || version.isEmpty()) && parentVersion != null && !parentVersion.isEmpty()) {
|
||||
version = parentVersion;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != null && !version.isEmpty()) {
|
||||
foundSomething = true;
|
||||
dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
|
||||
if (parentVersion != null && !parentVersion.isEmpty() && !parentVersion.equals(version)) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent-version", version, Confidence.LOW);
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
|
||||
if (addAsIdentifier) {
|
||||
dependency.addIdentifier("maven", String.format("%s:%s:%s", originalGroupID, originalArtifactID, version), null, Confidence.LOW);
|
||||
}
|
||||
|
||||
// org name
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null && org.getName() != null) {
|
||||
@@ -647,7 +712,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
//TODO remove weighting
|
||||
vendor.addWeighting(entry.getKey());
|
||||
if (addPackagesAsEvidence && entry.getKey().length() > 1) {
|
||||
vendor.addEvidence("jar", "package", entry.getKey(), Confidence.LOW);
|
||||
vendor.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,7 +721,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (ratio > 0.5) {
|
||||
product.addWeighting(entry.getKey());
|
||||
if (addPackagesAsEvidence && entry.getKey().length() > 1) {
|
||||
product.addEvidence("jar", "package", entry.getKey(), Confidence.LOW);
|
||||
product.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -690,7 +755,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
|
||||
LOGGER.log(Level.INFO,
|
||||
LOGGER.log(Level.FINE,
|
||||
String.format("Jar file '%s' does not contain a manifest.",
|
||||
dependency.getFileName()));
|
||||
}
|
||||
@@ -764,6 +829,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
&& !key.endsWith("class-path")
|
||||
&& !key.endsWith("-scm") //todo change this to a regex?
|
||||
&& !key.startsWith("scm-")
|
||||
&& !value.trim().startsWith("scm:")
|
||||
&& !isImportPackage(key, value)
|
||||
&& !isPackage(key, value)) {
|
||||
|
||||
@@ -1111,7 +1177,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param evidence the evidence collection to add new entries too
|
||||
*/
|
||||
private void addMatchingValues(ArrayList<ClassNameInformation> classes, String value, EvidenceCollection evidence) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
if (value == null || value.isEmpty() || classes == null || classes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final String text = value.toLowerCase();
|
||||
@@ -1138,93 +1204,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds evidence from the POM to the dependency. This includes the GAV and in some situations the parent GAV if
|
||||
* specified.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @param pom the POM data
|
||||
* @param pomProperties the properties file associated with the pom
|
||||
*/
|
||||
private void addPomEvidence(Dependency dependency, Model pom, Properties pomProperties) {
|
||||
if (pom == null) {
|
||||
return;
|
||||
}
|
||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||
groupid = groupid.substring(4);
|
||||
}
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
}
|
||||
String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
}
|
||||
final String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
if (version != null && !version.isEmpty()) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
final Parent parent = pom.getParent(); //grab parent GAV
|
||||
if (parent != null) {
|
||||
final String parentGroupId = interpolateString(parent.getGroupId(), pomProperties);
|
||||
if (parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
if (groupid == null || groupid.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.MEDIUM);
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.LOW);
|
||||
}
|
||||
final String parentArtifactId = interpolateString(parent.getArtifactId(), pomProperties);
|
||||
if (parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
if (artifactid == null || artifactid.isEmpty()) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.MEDIUM);
|
||||
}
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.LOW);
|
||||
}
|
||||
final String parentVersion = interpolateString(parent.getVersion(), pomProperties);
|
||||
if (parentVersion != null && !parentVersion.isEmpty()) {
|
||||
if (version == null || version.isEmpty()) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent.version", parentVersion, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent.version", parentVersion, Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
// org name
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null && org.getName() != null) {
|
||||
final String orgName = interpolateString(org.getName(), pomProperties);
|
||||
if (orgName != null && !orgName.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Confidence.HIGH);
|
||||
}
|
||||
}
|
||||
//pom name
|
||||
final String pomName = interpolateString(pom.getName(), pomProperties);
|
||||
if (pomName != null && !pomName.isEmpty()) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
}
|
||||
|
||||
//Description
|
||||
if (pom.getDescription() != null) {
|
||||
final String description = interpolateString(pom.getDescription(), pomProperties);
|
||||
if (description != null && !description.isEmpty()) {
|
||||
addDescription(dependency, description, "pom", "description");
|
||||
}
|
||||
}
|
||||
extractLicense(pom, pomProperties, dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the license information from the pom and adds it to the dependency.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -161,7 +162,18 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
|
||||
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
|
||||
boolean found = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".equals(i.getType()) && i.getValue().equals(ma.toString())) {
|
||||
found = true;
|
||||
i.setConfidence(Confidence.HIGHEST);
|
||||
i.setUrl(ma.getArtifactUrl());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
|
||||
|
||||
@@ -22,7 +22,7 @@ package org.owasp.dependencycheck.data.cpe;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class Fields {
|
||||
public final class Fields {
|
||||
|
||||
/**
|
||||
* The key for the name document id.
|
||||
@@ -36,7 +36,10 @@ public abstract class Fields {
|
||||
* The key for the product field.
|
||||
*/
|
||||
public static final String PRODUCT = "product";
|
||||
|
||||
/**
|
||||
* The key for the version field.
|
||||
* Private constructor as this is more of an enumeration rather then a full class.
|
||||
*/
|
||||
private Fields() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class NexusSearch {
|
||||
public NexusSearch(URL rootURL) {
|
||||
this.rootURL = rootURL;
|
||||
try {
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_URL)
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class ConnectionFactory {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
@@ -49,7 +50,7 @@ public final class ConnectionFactory {
|
||||
/**
|
||||
* The version of the current DB Schema.
|
||||
*/
|
||||
public static final String DB_SCHEMA_VERSION = "2.9";
|
||||
public static final String DB_SCHEMA_VERSION = Settings.getString(Settings.KEYS.DB_VERSION);
|
||||
/**
|
||||
* Resource location for SQL file used to create the database schema.
|
||||
*/
|
||||
@@ -111,7 +112,10 @@ public final class ConnectionFactory {
|
||||
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
||||
password = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
||||
try {
|
||||
connectionString = getConnectionString();
|
||||
connectionString = Settings.getConnectionString(
|
||||
Settings.KEYS.DB_CONNECTION_STRING,
|
||||
Settings.KEYS.DB_FILE_NAME,
|
||||
Settings.KEYS.DB_VERSION);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE,
|
||||
"Unable to retrieve the database connection string", ex);
|
||||
@@ -120,7 +124,7 @@ public final class ConnectionFactory {
|
||||
boolean shouldCreateSchema = false;
|
||||
try {
|
||||
if (connectionString.startsWith("jdbc:h2:file:")) { //H2
|
||||
shouldCreateSchema = !dbSchemaExists();
|
||||
shouldCreateSchema = !h2DataFileExists();
|
||||
LOGGER.log(Level.FINE, "Need to create DB Structure: {0}", shouldCreateSchema);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
@@ -217,51 +221,17 @@ public final class ConnectionFactory {
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured connection string. If using the embedded H2 database this function will also ensure the
|
||||
* data directory exists and if not create it.
|
||||
*
|
||||
* @return the connection string
|
||||
* @throws IOException thrown the data directory cannot be created
|
||||
*/
|
||||
private static String getConnectionString() throws IOException {
|
||||
final String connStr = Settings.getString(Settings.KEYS.DB_CONNECTION_STRING, "jdbc:h2:file:%s;AUTO_SERVER=TRUE");
|
||||
if (connStr.contains("%s")) {
|
||||
final String directory = getDataDirectory().getCanonicalPath();
|
||||
final File dataFile = new File(directory, "cve." + DB_SCHEMA_VERSION);
|
||||
LOGGER.log(Level.FINE, String.format("File path for H2 file: '%s'", dataFile.toString()));
|
||||
return String.format(connStr, dataFile.getAbsolutePath());
|
||||
}
|
||||
return connStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the directory that the JAR file exists in so that we can ensure we always use a common data directory
|
||||
* for the embedded H2 database. This is public solely for some unit tests; otherwise this should be private.
|
||||
*
|
||||
* @return the data directory to store data files
|
||||
* @throws IOException is thrown if an IOException occurs of course...
|
||||
*/
|
||||
public static File getDataDirectory() throws IOException {
|
||||
final File path = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
|
||||
if (!path.exists()) {
|
||||
if (!path.mkdirs()) {
|
||||
throw new IOException("Unable to create NVD CVE Data directory");
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the H2 database file exists. If it does not exist then the data structure will need to be created.
|
||||
*
|
||||
* @return true if the H2 database file does not exist; otherwise false
|
||||
* @throws IOException thrown if the data directory does not exist and cannot be created
|
||||
*/
|
||||
private static boolean dbSchemaExists() throws IOException {
|
||||
final File dir = getDataDirectory();
|
||||
final String name = String.format("cve.%s.h2.db", DB_SCHEMA_VERSION);
|
||||
final File file = new File(dir, name);
|
||||
private static boolean h2DataFileExists() throws IOException {
|
||||
final File dir = Settings.getDataDirectory();
|
||||
final String name = Settings.getString(Settings.KEYS.DB_FILE_NAME);
|
||||
final String fileName = String.format(name, DB_SCHEMA_VERSION);
|
||||
final File file = new File(dir, fileName);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.owasp.dependencycheck.utils.Pair;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CveDB {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -247,6 +248,7 @@ public class CveDB {
|
||||
/**
|
||||
* SQL Statement to retrieve a property from the database.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static final String SELECT_PROPERTY = "SELECT id, value FROM properties WHERE id = ?";
|
||||
/**
|
||||
* SQL Statement to insert a new property.
|
||||
@@ -259,6 +261,7 @@ public class CveDB {
|
||||
/**
|
||||
* SQL Statement to delete a property.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static final String DELETE_PROPERTY = "DELETE FROM properties WHERE id = ?";
|
||||
|
||||
//</editor-fold>
|
||||
@@ -733,8 +736,10 @@ public class CveDB {
|
||||
final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
|
||||
final DependencyVersion v = parseDependencyVersion(cpeId);
|
||||
final boolean prevAffected = previous != null && !previous.isEmpty();
|
||||
if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
|
||||
if (v == null || "-".equals(v.toString())) {
|
||||
if (v == null || "-".equals(v.toString())) { //all versions
|
||||
affected = true;
|
||||
} else if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
|
||||
if (prevAffected) {
|
||||
affected = true;
|
||||
}
|
||||
} else if (identifiedVersion.equals(v) || (prevAffected && identifiedVersion.compareTo(v) < 0)) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Class responsible for updating the NVD CVE and CPE data stores.
|
||||
@@ -54,7 +55,11 @@ public class NvdCveUpdater implements CachedWebDataSource {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (DownloadFailedException ex) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to download the NVD CVE data, unable to update the data to use the most current data.");
|
||||
"Unable to download the NVD CVE data; the results may not include the most recent CPE/CVEs from the NVD.");
|
||||
if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
|
||||
}
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED;
|
||||
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.data.update.task.CallableDownloadTask;
|
||||
import org.owasp.dependencycheck.data.update.task.DownloadTask;
|
||||
import org.owasp.dependencycheck.data.update.task.ProcessTask;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
@@ -122,7 +122,7 @@ public class StandardUpdate {
|
||||
final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
|
||||
for (NvdCveInfo cve : updateable) {
|
||||
if (cve.getNeedsUpdate()) {
|
||||
final CallableDownloadTask call = new CallableDownloadTask(cve, processExecutor, cveDB, Settings.getInstance());
|
||||
final DownloadTask call = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());
|
||||
downloadFutures.add(downloadExecutors.submit(call));
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,9 @@ public class StandardUpdate {
|
||||
|
||||
if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
|
||||
properties.save(updateable.get(MODIFIED));
|
||||
LOGGER.log(Level.INFO, "Begin database maintenance.");
|
||||
cveDB.cleanupDatabase();
|
||||
LOGGER.log(Level.INFO, "End database maintenance.");
|
||||
}
|
||||
} finally {
|
||||
closeDataStores();
|
||||
|
||||
@@ -37,12 +37,12 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CallableDownloadTask.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(DownloadTask.class.getName());
|
||||
|
||||
/**
|
||||
* Simple constructor for the callable download task.
|
||||
@@ -54,7 +54,7 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
* the dependencies have a correct reference to the global settings.
|
||||
* @throws UpdateException thrown if temporary files could not be created
|
||||
*/
|
||||
public CallableDownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
|
||||
public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
|
||||
this.nvdCveInfo = nvdCveInfo;
|
||||
this.processorService = processor;
|
||||
this.cveDB = cveDB;
|
||||
@@ -188,6 +188,10 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
} catch (DownloadFailedException ex) {
|
||||
msg = String.format("Download Failed for NVD CVE - %s%nSome CVEs may not be reported.", nvdCveInfo.getId());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
|
||||
}
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
return null;
|
||||
}
|
||||
@@ -203,7 +207,7 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "Download Task Failed", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
/**
|
||||
* A reference to the callable download task.
|
||||
*/
|
||||
private final CallableDownloadTask filePair;
|
||||
private final DownloadTask filePair;
|
||||
/**
|
||||
* A reference to the properties.
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
* @param settings a reference to the global settings object; this is necessary so that when the thread is started
|
||||
* the dependencies have a correct reference to the global settings.
|
||||
*/
|
||||
public ProcessTask(final CveDB cveDB, final CallableDownloadTask filePair, Settings settings) {
|
||||
public ProcessTask(final CveDB cveDB, final DownloadTask filePair, Settings settings) {
|
||||
this.cveDB = cveDB;
|
||||
this.filePair = filePair;
|
||||
this.properties = cveDB.getDatabaseProperties();
|
||||
@@ -119,7 +119,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
} catch (UpdateException ex) {
|
||||
this.exception = ex;
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(false);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
@@ -35,7 +36,7 @@ import org.owasp.dependencycheck.utils.FileUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Dependency implements Comparable<Dependency> {
|
||||
public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
@@ -177,6 +178,33 @@ public class Dependency implements Comparable<Dependency> {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file name to display in reports.
|
||||
*/
|
||||
private String displayName = null;
|
||||
|
||||
/**
|
||||
* Sets the file name to display in reports.
|
||||
*
|
||||
* @param displayName the name to display
|
||||
*/
|
||||
public void setDisplayFileName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name to display in reports; if no display file name has been set it will default to the actual
|
||||
* file name.
|
||||
*
|
||||
* @return the file name to display
|
||||
*/
|
||||
public String getDisplayFileName() {
|
||||
if (displayName == null) {
|
||||
return this.fileName;
|
||||
}
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the file path of the dependency.</p>
|
||||
@@ -369,6 +397,15 @@ public class Dependency implements Comparable<Dependency> {
|
||||
return EvidenceCollection.merge(this.productEvidence, this.vendorEvidence, this.versionEvidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evidence used to identify this dependency.
|
||||
*
|
||||
* @return an EvidenceCollection.
|
||||
*/
|
||||
public Set<Evidence> getEvidenceForDisplay() {
|
||||
return EvidenceCollection.mergeForDisplay(this.productEvidence, this.vendorEvidence, this.versionEvidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evidence used to identify this dependency.
|
||||
*
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Evidence is a piece of information about a Dependency.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Evidence implements Comparable<Evidence> {
|
||||
public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
|
||||
/**
|
||||
* Creates a new Evidence object.
|
||||
@@ -220,22 +222,95 @@ public class Evidence implements Comparable<Evidence> {
|
||||
* @return an integer indicating the ordering of the two objects
|
||||
*/
|
||||
public int compareTo(Evidence o) {
|
||||
if (source.equals(o.source)) {
|
||||
if (name.equals(o.name)) {
|
||||
if (value.equals(o.value)) {
|
||||
if (confidence.equals(o.confidence)) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
if (equalsWithNullCheck(source, o.source)) {
|
||||
if (equalsWithNullCheck(name, o.name)) {
|
||||
if (equalsWithNullCheck(value, o.value)) {
|
||||
if (equalsWithNullCheck(confidence, o.confidence)) {
|
||||
return 0; //they are equal
|
||||
} else {
|
||||
return confidence.compareTo(o.confidence);
|
||||
return compareToWithNullCheck(confidence, o.confidence);
|
||||
}
|
||||
} else {
|
||||
return value.compareToIgnoreCase(o.value);
|
||||
return compareToIgnoreCaseWithNullCheck(value, o.value);
|
||||
}
|
||||
} else {
|
||||
return name.compareToIgnoreCase(o.name);
|
||||
return compareToIgnoreCaseWithNullCheck(name, o.name);
|
||||
}
|
||||
} else {
|
||||
return source.compareToIgnoreCase(o.source);
|
||||
return compareToIgnoreCaseWithNullCheck(source, o.source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality check with an exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private boolean equalsWithNullCheck(String me, String other) {
|
||||
if (me == null && other == null) {
|
||||
return true;
|
||||
} else if (me == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return me.equals(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality check with an exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private boolean equalsWithNullCheck(Confidence me, Confidence other) {
|
||||
if (me == null && other == null) {
|
||||
return true;
|
||||
} else if (me == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return me.equals(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link java.lang.String#compareToIgnoreCase(java.lang.String) String.compareToIgnoreCase} with an
|
||||
* exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private int compareToIgnoreCaseWithNullCheck(String me, String other) {
|
||||
if (me == null && other == null) {
|
||||
return 0;
|
||||
} else if (me == null) {
|
||||
return -1; //the other string is greater then me
|
||||
} else if (other == null) {
|
||||
return 1; //me is greater then the other string
|
||||
}
|
||||
return me.compareToIgnoreCase(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link java.lang.Enum#compareTo(java.lang.Enum) Enum.compareTo} with an exhaustive, possibly
|
||||
* duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private int compareToWithNullCheck(Confidence me, Confidence other) {
|
||||
if (me == null && other == null) {
|
||||
return 0;
|
||||
} else if (me == null) {
|
||||
return -1; //the other string is greater then me
|
||||
} else if (other == null) {
|
||||
return 1; //me is greater then the other string
|
||||
}
|
||||
return me.compareTo(other);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -36,7 +37,7 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class EvidenceCollection implements Iterable<Evidence> {
|
||||
public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
@@ -311,6 +312,26 @@ public class EvidenceCollection implements Iterable<Evidence> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple EvidenceCollections together; flattening all of the evidence items by removing the confidence.
|
||||
*
|
||||
* @param ec One or more EvidenceCollections
|
||||
* @return new set of evidence resulting from merging the evidence in the collections
|
||||
*/
|
||||
public static Set<Evidence> mergeForDisplay(EvidenceCollection... ec) {
|
||||
final Set<Evidence> ret = new TreeSet<Evidence>();
|
||||
for (EvidenceCollection col : ec) {
|
||||
for (Evidence e : col) {
|
||||
if (e.isUsed()) {
|
||||
final Evidence newEvidence = new Evidence(e.getSource(), e.getName(), e.getValue(), null);
|
||||
newEvidence.setUsed(true);
|
||||
ret.add(newEvidence);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string of evidence 'values'.
|
||||
*
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Identifier implements Comparable<Identifier> {
|
||||
public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
|
||||
/**
|
||||
* Constructs a new Identifier with the specified data.
|
||||
|
||||
@@ -77,19 +77,19 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
if (cpeName != null && cpeName.length() > 7) {
|
||||
final String[] data = cpeName.substring(7).split(":");
|
||||
if (data.length >= 1) {
|
||||
this.setVendor(URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8"));
|
||||
this.setVendor(urlDecode(data[0]));
|
||||
}
|
||||
if (data.length >= 2) {
|
||||
this.setProduct(URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8"));
|
||||
this.setProduct(urlDecode(data[1]));
|
||||
}
|
||||
if (data.length >= 3) {
|
||||
version = URLDecoder.decode(data[2].replace("+", "%2B"), "UTF-8");
|
||||
version = urlDecode(data[2]);
|
||||
}
|
||||
if (data.length >= 4) {
|
||||
revision = URLDecoder.decode(data[3].replace("+", "%2B"), "UTF-8");
|
||||
revision = urlDecode(data[3]);
|
||||
}
|
||||
if (data.length >= 5) {
|
||||
edition = URLDecoder.decode(data[4].replace("+", "%2B"), "UTF-8");
|
||||
edition = urlDecode(data[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,4 +341,25 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
public void setEdition(String edition) {
|
||||
this.edition = edition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default.
|
||||
*
|
||||
* @param string the string to URL Decode
|
||||
* @return the URL Decoded string
|
||||
*/
|
||||
private String urlDecode(String string) {
|
||||
final String text = string.replace("+", "%2B");
|
||||
String result;
|
||||
try {
|
||||
result = URLDecoder.decode(text, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
try {
|
||||
result = URLDecoder.decode(text, "ASCII");
|
||||
} catch (UnsupportedEncodingException ex1) {
|
||||
result = URLDecoder.decode(text);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class ScanAgentException extends IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NoDataException.
|
||||
* Creates a new ScanAgentException.
|
||||
*
|
||||
* @param ex the cause of the exception.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,10 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
* The CWE element name.
|
||||
*/
|
||||
public static final String CWE = "cwe";
|
||||
/**
|
||||
* The GAV element name.
|
||||
*/
|
||||
public static final String GAV = "gav";
|
||||
/**
|
||||
* The cvssBelow element name.
|
||||
*/
|
||||
@@ -95,13 +99,16 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
*/
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
currentAttributes = null;
|
||||
currentAttributes = attributes;
|
||||
currentText = new StringBuffer();
|
||||
|
||||
if (SUPPRESS.equals(qName)) {
|
||||
rule = new SuppressionRule();
|
||||
} else if (FILE_PATH.equals(qName)) {
|
||||
currentAttributes = attributes;
|
||||
final String base = currentAttributes.getValue("base");
|
||||
if (base != null) {
|
||||
rule.setBase(Boolean.parseBoolean(base));
|
||||
} else {
|
||||
rule.setBase(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +130,9 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
rule.setFilePath(pt);
|
||||
} else if (SHA1.equals(qName)) {
|
||||
rule.setSha1(currentText.toString());
|
||||
} else if (GAV.equals(qName)) {
|
||||
final PropertyType pt = processPropertyType();
|
||||
rule.setGav(pt);
|
||||
} else if (CPE.equals(qName)) {
|
||||
final PropertyType pt = processPropertyType();
|
||||
rule.addCpe(pt);
|
||||
|
||||
@@ -66,10 +66,35 @@ public class SuppressionParser {
|
||||
* @throws SuppressionParseException thrown if the xml file cannot be parsed
|
||||
*/
|
||||
public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
return parseSuppressionRules(fis);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new SuppressionParseException(ex);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to close stream", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given xml stream and returns a list of the suppression rules contained.
|
||||
*
|
||||
* @param inputStream an InputStream containing suppression rues
|
||||
* @return a list of suppression rules
|
||||
* @throws SuppressionParseException if the xml cannot be parsed
|
||||
*/
|
||||
public List<SuppressionRule> parseSuppressionRules(InputStream inputStream) throws SuppressionParseException {
|
||||
try {
|
||||
final InputStream schemaStream = this.getClass().getClassLoader().getResourceAsStream("schema/suppression.xsd");
|
||||
final SuppressionHandler handler = new SuppressionHandler();
|
||||
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
@@ -80,7 +105,6 @@ public class SuppressionParser {
|
||||
xmlReader.setErrorHandler(new SuppressionErrorHandler());
|
||||
xmlReader.setContentHandler(handler);
|
||||
|
||||
final InputStream inputStream = new FileInputStream(file);
|
||||
final Reader reader = new InputStreamReader(inputStream, "UTF-8");
|
||||
final InputSource in = new InputSource(reader);
|
||||
//in.setEncoding("UTF-8");
|
||||
|
||||
@@ -234,6 +234,57 @@ public class SuppressionRule {
|
||||
public boolean hasCve() {
|
||||
return cve.size() > 0;
|
||||
}
|
||||
/**
|
||||
* A Maven GAV to suppression.
|
||||
*/
|
||||
private PropertyType gav = null;
|
||||
|
||||
/**
|
||||
* Get the value of Maven GAV.
|
||||
*
|
||||
* @return the value of gav
|
||||
*/
|
||||
public PropertyType getGav() {
|
||||
return gav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of Maven GAV.
|
||||
*
|
||||
* @param gav new value of Maven gav
|
||||
*/
|
||||
public void setGav(PropertyType gav) {
|
||||
this.gav = gav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this suppression rule as GAV entries.
|
||||
*
|
||||
* @return whether or not this suppression rule as GAV entries
|
||||
*/
|
||||
public boolean hasGav() {
|
||||
return gav != null;
|
||||
}
|
||||
|
||||
private boolean base;
|
||||
|
||||
/**
|
||||
* Get the value of base
|
||||
*
|
||||
* @return the value of base
|
||||
*/
|
||||
public boolean isBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of base
|
||||
*
|
||||
* @param base new value of base
|
||||
*/
|
||||
public void setBase(boolean base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a given dependency to determine if any CPE, CVE, CWE, or CVSS scores should be suppressed. If any
|
||||
@@ -248,13 +299,30 @@ public class SuppressionRule {
|
||||
if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
|
||||
return;
|
||||
}
|
||||
if (gav != null) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
boolean gavFound = false;
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
if (identifierMatches("maven", this.gav, i)) {
|
||||
gavFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gavFound) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hasCpe()) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
for (PropertyType c : this.cpe) {
|
||||
if (cpeMatches(c, i)) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
if (identifierMatches("cpe", c, i)) {
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
}
|
||||
itr.remove();
|
||||
break;
|
||||
}
|
||||
@@ -293,7 +361,9 @@ public class SuppressionRule {
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
}
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
@@ -309,7 +379,7 @@ public class SuppressionRule {
|
||||
boolean cpeHasNoVersion(PropertyType c) {
|
||||
if (c.isRegex()) {
|
||||
return false;
|
||||
} // cpe:/a:jboss:jboss:1.0.0:
|
||||
}
|
||||
if (countCharacter(c.getValue(), ':') == 3) {
|
||||
return true;
|
||||
}
|
||||
@@ -336,26 +406,75 @@ public class SuppressionRule {
|
||||
/**
|
||||
* Determines if the cpeEntry specified as a PropertyType matches the given Identifier.
|
||||
*
|
||||
* @param cpeEntry a suppression rule entry
|
||||
* @param identifierType the type of identifier ("cpe", "maven", etc.)
|
||||
* @param suppressionEntry a suppression rule entry
|
||||
* @param identifier a CPE identifier to check
|
||||
* @return true if the entry matches; otherwise false
|
||||
*/
|
||||
boolean cpeMatches(PropertyType cpeEntry, Identifier identifier) {
|
||||
if (cpeEntry.matches(identifier.getValue())) {
|
||||
return true;
|
||||
} else if (cpeHasNoVersion(cpeEntry)) {
|
||||
if (cpeEntry.isCaseSensitive()) {
|
||||
if (identifier.getValue().startsWith(cpeEntry.getValue())) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
final String id = identifier.getValue().toLowerCase();
|
||||
final String check = cpeEntry.getValue().toLowerCase();
|
||||
if (id.startsWith(check)) {
|
||||
return true;
|
||||
boolean identifierMatches(String identifierType, PropertyType suppressionEntry, Identifier identifier) {
|
||||
if (identifierType.equals(identifier.getType())) {
|
||||
if (suppressionEntry.matches(identifier.getValue())) {
|
||||
return true;
|
||||
} else if ("cpe".equals(identifierType) && cpeHasNoVersion(suppressionEntry)) {
|
||||
if (suppressionEntry.isCaseSensitive()) {
|
||||
return identifier.getValue().startsWith(suppressionEntry.getValue());
|
||||
} else {
|
||||
final String id = identifier.getValue().toLowerCase();
|
||||
final String check = suppressionEntry.getValue().toLowerCase();
|
||||
return id.startsWith(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard toString implementation.
|
||||
*
|
||||
* @return a string representation of this object
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("SuppressionRule{");
|
||||
if (filePath != null) {
|
||||
sb.append("filePath=").append(filePath).append(",");
|
||||
}
|
||||
if (sha1 != null) {
|
||||
sb.append("sha1=").append(sha1).append(",");
|
||||
}
|
||||
if (gav != null) {
|
||||
sb.append("gav=").append(gav).append(",");
|
||||
}
|
||||
if (cpe != null && cpe.size() > 0) {
|
||||
sb.append("cpe={");
|
||||
for (PropertyType pt : cpe) {
|
||||
sb.append(pt).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cwe != null && cwe.size() > 0) {
|
||||
sb.append("cwe={");
|
||||
for (String s : cwe) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cve != null && cve.size() > 0) {
|
||||
sb.append("cve={");
|
||||
for (String s : cve) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cvssBelow != null && cvssBelow.size() > 0) {
|
||||
sb.append("cvssBelow={");
|
||||
for (Float s : cvssBelow) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,17 +189,23 @@ public class DependencyVersion implements Iterable, Comparable<DependencyVersion
|
||||
if (version == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ret = true;
|
||||
int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
if (max > 3) {
|
||||
max = 3;
|
||||
if (Math.abs(this.versionParts.size() - version.versionParts.size()) >= 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
boolean ret = true;
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (this.versionParts.get(i) == null || !this.versionParts.get(i).equals(version.versionParts.get(i))) {
|
||||
String thisVersion = this.versionParts.get(i);
|
||||
String otherVersion = version.getVersionParts().get(i);
|
||||
if (i >= 3) {
|
||||
if (thisVersion.compareToIgnoreCase(otherVersion) >= 0) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
} else if (!thisVersion.equals(otherVersion)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import static org.owasp.dependencycheck.utils.FileUtils.getFileExtension;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class ExtractionUtil {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ExtractionUtil.class.getName());
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Private constructor for a utility class.
|
||||
*/
|
||||
private ExtractionUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @throws ExtractionException thrown if an exception occurs while extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo) throws ExtractionException {
|
||||
extractFiles(archive, extractTo, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory. The files are only extracted if they are
|
||||
* supported by the analyzers loaded into the specified engine. If the engine is specified as null then all files
|
||||
* are extracted.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @param engine the scanning engine
|
||||
* @throws ExtractionException thrown if there is an error extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo, Engine engine) throws ExtractionException {
|
||||
if (archive == null || extractTo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new ExtractionException("Archive file was not found.", ex);
|
||||
}
|
||||
zis = new ZipInputStream(new BufferedInputStream(fis));
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.isDirectory()) {
|
||||
final File d = new File(extractTo, entry.getName());
|
||||
if (!d.exists() && !d.mkdirs()) {
|
||||
final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
|
||||
throw new ExtractionException(msg);
|
||||
}
|
||||
} else {
|
||||
final File file = new File(extractTo, entry.getName());
|
||||
final String ext = getFileExtension(file.getName());
|
||||
if (engine == null || engine.supportsExtension(ext)) {
|
||||
BufferedOutputStream bos = null;
|
||||
FileOutputStream fos;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||
int count;
|
||||
final byte data[] = new byte[BUFFER_SIZE];
|
||||
while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
if (bos != null) {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
try {
|
||||
zis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
dependency-check-core/src/main/resources/GrokAssembly.exe
Executable file → Normal file
BIN
dependency-check-core/src/main/resources/GrokAssembly.exe
Executable file → Normal file
Binary file not shown.
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses false positives identified on spring security.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.springframework\.security:spring.*</gav>
|
||||
<cpe>cpe:/a:mod_security:mod_security</cpe>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppreses additional false positives for the xstream library that occur because spring has a copy of this library.
|
||||
com.springsource.com.thoughtworks.xstream-1.3.1.jar
|
||||
]]></notes>
|
||||
<gav regex="true">com\.thoughtworks\.xstream:xstream:.*</gav>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on velocity tools.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.apache\.velocity:velocity-tools:.*</gav>
|
||||
<cpe>cpe:/a:apache:struts</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Sandbox is a php blog platform and should not be flagged as a CPE for java or .net dependencies.
|
||||
]]></notes>
|
||||
<filePath regex="true">.*\.(jar|dll|exe|ear|war|pom)</filePath>
|
||||
<cpe>cpe:/a:sandbox:sandbox</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on Jersey core client.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.glassfish\.jersey\.core:jersey-(client|common):.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -0,0 +1,10 @@
|
||||
analyzer.AssemblyAnalyzer.notdeployed=GrokAssembly didn't get deployed
|
||||
analyzer.AssemblyAnalyzer.grokassembly.stderr=Error from GrokAssembly: {0}
|
||||
analyzer.AssemblyAnalyzer.notassembly={0} is not a .NET assembly or executable and as such cannot be analyzed by dependency-check
|
||||
analyzer.AssemblyAnalyzer.grokassembly.rc=Return code {0} from GrokAssembly
|
||||
analyzer.AssemblyAnalyzer.grokassembly.deployed=Extracted GrokAssembly.exe to {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.notdeployed=Could not extract GrokAssembly.exe: {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.initialization.failed=An error occurred with the .NET AssemblyAnalyzer; \
|
||||
this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.
|
||||
analyzer.AssemblyAnalyzer.grokassembly.initialization.message=Could not execute GrokAssembly {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.notdeleted=Can't delete temporary GrokAssembly.exe
|
||||
@@ -13,8 +13,10 @@ max.download.threads=3
|
||||
# will not be used. The data.directory will be resolved and if the connection string
|
||||
# below contains a %s then the data.directory will replace the %s.
|
||||
data.directory=[JAR]/data
|
||||
#if the filename has a %s it will be replaced with the current expected version
|
||||
data.file_name=cve.%s.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
# user name and password for the database connection. The inherent case is to use H2.
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
<xs:element name="filePath" type="dc:regexStringType"/>
|
||||
<xs:element name="sha1" type="dc:sha1Type"/>
|
||||
<xs:element name="gav" type="dc:regexStringType"/>
|
||||
</xs:choice>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cpe" type="dc:regexStringType"/>
|
||||
@@ -49,6 +50,7 @@
|
||||
<xs:element name="cvssBelow" type="dc:cvssScoreType"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="base" use="optional" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
|
||||
@@ -33,8 +33,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$(".expandable").click(function (e) {
|
||||
e = e || window.event;
|
||||
$(".expandable").click(function (event) {
|
||||
e = event || window.event;
|
||||
var h = e.target || e.srcElement;
|
||||
var content = "#content" + h.id.substr(6);
|
||||
var header = "#" + h.id;
|
||||
@@ -56,6 +56,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
$(header).addClass("expandablesubsection");
|
||||
$(header).removeClass("collaspablesubsection");
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -84,13 +85,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
$('#modal-text').focus();
|
||||
$('#modal-text').select();
|
||||
}
|
||||
function toggleDisplay(el, clzName) {
|
||||
function toggleDisplay(el, clzName, all, some) {
|
||||
$(clzName).toggle();
|
||||
if (el.innerHTML == 'show all') {
|
||||
el.innerHTML = 'less';
|
||||
if (el.innerHTML == all) {
|
||||
el.innerHTML = some;
|
||||
} else {
|
||||
el.innerHTML = 'show all';
|
||||
el.innerHTML = all;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
@@ -427,15 +429,24 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
.indent {
|
||||
margin-left:20px;
|
||||
}
|
||||
td, th {
|
||||
td{
|
||||
vertical-align:text-top;
|
||||
padding:6px;
|
||||
margin:0px;
|
||||
}
|
||||
th {
|
||||
text-align:left
|
||||
vertical-align:text-top;
|
||||
padding:6px;
|
||||
margin:0px;
|
||||
border-bottom:1px;
|
||||
border-color: black;
|
||||
}
|
||||
table {
|
||||
border: 0px;
|
||||
}
|
||||
table.lined tr:nth-child(even) {
|
||||
background-color: #fbfbfb;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
.fullwidth {
|
||||
width:100%;
|
||||
@@ -448,10 +459,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
margin-bottom:3px;
|
||||
}
|
||||
.vulnerable {
|
||||
color: #f00;
|
||||
}
|
||||
.vulnerable li {
|
||||
color: #000;
|
||||
color: #000;
|
||||
}
|
||||
.notvulnerable {
|
||||
display:none;
|
||||
@@ -481,7 +489,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<div id="modal-content">
|
||||
<div>Press CTR-C to copy XML <a href="http://jeremylong.github.io/DependencyCheck/suppression.html" class="infolink" target="_blank" title="Help with suppressing false positives">[help]</a></div>
|
||||
<textarea id="modal-text" cols="50" rows="10"></textarea><br/>
|
||||
<button id="modal-add-header" class="modal-button">Complete XML Doc</button><button id="modal-close" class="modal-button-right">Close</button>
|
||||
<button id="modal-add-header" title="Add the parent XML nodes to create the complete XML file that can be used to suppress this finding" class="modal-button">Complete XML Doc</button><button id="modal-close" class="modal-button-right">Close</button>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<h1>Dependency-Check Report</h1>
|
||||
@@ -513,7 +521,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#set($vulnSuppressedCount=$vulnSuppressedCount+$dependency.getSuppressedVulnerabilities().size())
|
||||
#end
|
||||
#end
|
||||
Scan Information (<a href="#" onclick="toggleDisplay(this, '.scaninfo'); return false;">show all</a>):<br/>
|
||||
Scan Information (<a href="#" title="Click to toggle display" onclick="return toggleDisplay(this, '.scaninfo', 'show all', 'show less'); return false;">show all</a>):<br/>
|
||||
<ul class="indent">
|
||||
<li><i>dependency-check version</i>: $version</li>
|
||||
<li><i>Report Generated On</i>: $scanDate</li>
|
||||
@@ -526,30 +534,101 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<li class="scaninfo hidden"><i>$enc.html($prop.key)</i>: $enc.html($prop.value)</li>
|
||||
#end
|
||||
</ul><br/>
|
||||
Dependency Display: <a href="#" onclick="toggleDisplay(this,'.notvulnerable'); return false;">show all</a><br/><br/>
|
||||
<ul class="indent">
|
||||
Display: <a href="#" title="Click to toggle display" onclick="return toggleDisplay(this, '.notvulnerable', 'Showing Vulnerable Dependencies', 'Showing All Dependencies'); return false;">Showing Vulnerable Dependencies</a><br/><br/>
|
||||
#set($lnkcnt=0)
|
||||
#foreach($dependency in $dependencies)
|
||||
<table class="lined">
|
||||
<tr style="text-align:left">
|
||||
<th title="The name of the dependency">Dependency</th>
|
||||
<th title="The Common Platform Enumeration">CPE</th>
|
||||
<th title="The Maven GAV Coordinates">GAV</th>
|
||||
<th title="The highest CVE Severity">Highest Severity</th>
|
||||
<th title="The number of Common Vulnerability and Exposure (CVE) entries">CVE Count</th>
|
||||
<th title="The confidence rating dependency-check has for the identified CPE">CPE Confidence</th>
|
||||
<th title="The count of evidence used to identify the CPE">Evidence Count</th>
|
||||
</tr>
|
||||
#foreach($dependency in $dependencies)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<li class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
<a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.FileName)</a>
|
||||
#if($dependency.getRelatedDependencies().size()>0)
|
||||
<ul>
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
<li>$enc.html($related.FileName)</li>
|
||||
<tr class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
<td><a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a></td>
|
||||
#set($mavenlink="")
|
||||
#set($cpeIdCount=0)
|
||||
#set($cpeIdConf="")
|
||||
<td>
|
||||
#foreach($id in $dependency.getIdentifiers())
|
||||
#if ($id.type=="maven")
|
||||
#if ($mavenlink=="" || !$mavenlink.url)
|
||||
#set($mavenlink=$id)
|
||||
#end
|
||||
#else
|
||||
#if ($cpeIdCount>=1)
|
||||
<br/>
|
||||
#end
|
||||
#if( $id.url )
|
||||
<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>
|
||||
#else
|
||||
$enc.html($id.value)
|
||||
#end
|
||||
#if ($cpeIdConf == "")
|
||||
#set($cpeIdConf=$id.confidence)
|
||||
#elseif ($cpeIdConf.compareTo($id.confidence)>0)
|
||||
#set($cpeIdConf=$id.confidence)
|
||||
#end
|
||||
#set($cpeIdCount=$cpeIdCount+1)
|
||||
#end
|
||||
#end
|
||||
</ul>
|
||||
</td>
|
||||
<td>#if( $mavenlink.url )
|
||||
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
|
||||
<a href="$enc.html($mavenlink.url)" target="_blank">$enc.html($mavenlink.value)</a>
|
||||
#elseif ($mavenlink.value)
|
||||
$enc.html($mavenlink.value)
|
||||
#end</td>
|
||||
#set($cveImpact=-1)
|
||||
#foreach($vuln in $dependency.getVulnerabilities())
|
||||
#if ($cveImpact<$vuln.cvssScore)
|
||||
#set($cveImpact=$vuln.cvssScore)
|
||||
#end
|
||||
#end
|
||||
<td>
|
||||
#if ($cveImpact<0)
|
||||
|
||||
#elseif ($cveImpact<4.0)
|
||||
Low
|
||||
#elseif ($cveImpact>=7.0)
|
||||
High
|
||||
#else
|
||||
Medium
|
||||
#end
|
||||
</td>
|
||||
<td>$dependency.getVulnerabilities().size()</td>
|
||||
<td>$cpeIdConf</td>
|
||||
<td>$dependency.getEvidenceForDisplay().size()</td>
|
||||
</tr>
|
||||
#end
|
||||
</li>
|
||||
#end
|
||||
</ul>
|
||||
</table>
|
||||
## <ul class="indent">
|
||||
## #set($lnkcnt=0)
|
||||
## #foreach($dependency in $dependencies)
|
||||
## #set($lnkcnt=$lnkcnt+1)
|
||||
## <li class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
## <a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a>
|
||||
## #if($dependency.getRelatedDependencies().size()>0)
|
||||
## <ul>
|
||||
## #foreach($related in $dependency.getRelatedDependencies())
|
||||
## <li>$enc.html($related.DisplayFileName)</li>
|
||||
## #end
|
||||
## </ul>
|
||||
## #end
|
||||
## </li>
|
||||
## #end
|
||||
## </ul>
|
||||
<h2>Dependencies</h2>
|
||||
#set($lnkcnt=0)
|
||||
#set($cnt=0)
|
||||
#set($vsctr=0) ##counter to create unique groups for vulnerable software
|
||||
#foreach($dependency in $dependencies)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<h3 class="subsectionheader standardsubsection#if($dependency.getVulnerabilities().size()==0) notvulnerable#end"><a name="l${lnkcnt}_$enc.html($dependency.Sha1sum)"></a>$enc.html($dependency.FileName)</h3>
|
||||
<h3 class="subsectionheader standardsubsection#if($dependency.getVulnerabilities().size()==0) notvulnerable#end"><a name="l${lnkcnt}_$enc.html($dependency.Sha1sum)"></a>$enc.html($dependency.DisplayFileName)</h3>
|
||||
<div class="subsectioncontent#if($dependency.getVulnerabilities().size()==0) notvulnerable#end">
|
||||
#if ($dependency.description)
|
||||
<p><b>Description:</b> $enc.html($dependency.description)<br/></p>
|
||||
@@ -571,7 +650,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<table class="lined fullwidth" border="0">
|
||||
<tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr>
|
||||
#foreach($evidence in $dependency.getEvidenceUsed())
|
||||
#foreach($evidence in $dependency.getEvidenceForDisplay())
|
||||
<tr><td>$enc.html($evidence.getSource())</td><td>$enc.html($evidence.getName())</td><td>$enc.html($evidence.getValue())</td></tr>
|
||||
#end
|
||||
</table>
|
||||
@@ -582,7 +661,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<ul>
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
<li>$enc.html($related.FileName)
|
||||
<li>$enc.html($related.DisplayFileName)
|
||||
<ul>
|
||||
<li>File Path: $enc.html($related.FilePath)</li>
|
||||
<li>SHA1: $enc.html($related.Sha1sum)</li>
|
||||
@@ -612,7 +691,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#end
|
||||
<h4 id="header$cnt" class="subsectionheader white">Identifiers</h4>
|
||||
##: <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
##: <a href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#if ($dependency.getIdentifiers().size()==0)
|
||||
<ul><li><b>None</b></li></ul>
|
||||
@@ -630,7 +709,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#if ($id.type=="cpe")
|
||||
##yes, we are HTML Encoding into JavaScript... the escape utils don't have a JS Encode and I haven't written one yet
|
||||
<button class="copybutton" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
<button class="copybutton" title="Generate Suppression XML for this CPE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
#end
|
||||
#if ($id.description)
|
||||
<br/>$enc.html($id.description)
|
||||
@@ -646,7 +725,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#foreach($vuln in $dependency.getVulnerabilities())
|
||||
#set($vsctr=$vsctr+1)
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" title="Generate Suppression XML for this CCE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p>Severity:
|
||||
#if ($vuln.cvssScore<4.0)
|
||||
Low
|
||||
@@ -668,13 +747,20 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
</ul>
|
||||
#end
|
||||
</p>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
|
||||
#if ($vuln.getVulnerableSoftware().size()<2)
|
||||
<p>Vulnerable Software & Versions:<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</div>
|
||||
#end
|
||||
@@ -692,7 +778,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#foreach($dependency in $dependencies)
|
||||
#if ($dependency.getSuppressedIdentifiers().size()>0 || $dependency.getSuppressedVulnerabilities().size()>0)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<h3 class="subsectionheader standardsubsection">$enc.html($dependency.FileName)</h3>
|
||||
<h3 class="subsectionheader standardsubsection">$enc.html($dependency.DisplayFileName)</h3>
|
||||
<div class="subsectioncontent">
|
||||
#if ($dependency.description)
|
||||
<p><b>Description:</b> $enc.html($dependency.description)<br/></p>
|
||||
@@ -714,7 +800,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<table class="lined fullwidth" border="0">
|
||||
<tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr>
|
||||
#foreach($evidence in $dependency.getEvidenceUsed())
|
||||
#foreach($evidence in $dependency.getEvidenceForDisplay())
|
||||
<tr><td>$enc.html($evidence.getSource())</td><td>$enc.html($evidence.getName())</td><td>$enc.html($evidence.getValue())</td></tr>
|
||||
#end
|
||||
</table>
|
||||
@@ -725,7 +811,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<ul>
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
<li>$enc.html($related.FileName)
|
||||
<li>$enc.html($related.DisplayFileName)
|
||||
<ul>
|
||||
<li>File Path: $enc.html($related.FilePath)</li>
|
||||
<li>SHA1: $enc.html($related.Sha1sum)</li>
|
||||
@@ -744,7 +830,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#end
|
||||
<h4 id="header$cnt" class="subsectionheader white">Suppressed Identifiers</h4>
|
||||
##: <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
##: <a href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#if ($dependency.getSuppressedIdentifiers().size()==0)
|
||||
<ul><li><b>None</b></li></ul>
|
||||
@@ -796,13 +882,19 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
</ul>
|
||||
#end
|
||||
</p>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
#if ($vuln.getVulnerableSoftware().size()<2)
|
||||
<p>Vulnerable Software & Versions:<ul>
|
||||
git st<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</div>
|
||||
#end
|
||||
|
||||
@@ -222,10 +222,10 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
($vuln.cvssScore)
|
||||
<td>#set($cnt=$cnt+1)
|
||||
#if($dependency.getRelatedDependencies().size()>0)<span id="header$cnt" class="expandable collapsedList">#end
|
||||
$enc.html($dependency.FileName)
|
||||
$enc.html($dependency.DisplayFileName)
|
||||
#if($dependency.getRelatedDependencies().size()>0) </span><div id="content$cnt" class="hidden">#end
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
$enc.html($related.FileName)<br/>
|
||||
$enc.html($related.DisplayFileName)<br/>
|
||||
#end
|
||||
#if($dependency.getRelatedDependencies().size()>0)</div#end
|
||||
</td>
|
||||
|
||||
@@ -36,7 +36,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependencies>
|
||||
#foreach($dependency in $dependencies)
|
||||
<dependency>
|
||||
<fileName>$enc.xml($dependency.FileName)</fileName>
|
||||
<fileName>$enc.xml($dependency.DisplayFileName)</fileName>
|
||||
<filePath>$enc.xml($dependency.FilePath)</filePath>
|
||||
<md5>$enc.xml($dependency.Md5sum)</md5>
|
||||
<sha1>$enc.xml($dependency.Sha1sum)</sha1>
|
||||
@@ -68,7 +68,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</relatedDependencies>
|
||||
#end
|
||||
<evidenceCollected>
|
||||
#foreach($evidence in $dependency.getEvidenceUsed())
|
||||
#foreach($evidence in $dependency.getEvidenceForDisplay())
|
||||
<evidence>
|
||||
<source>$enc.xml($evidence.getSource())</source>
|
||||
<name>$enc.xml($evidence.getName())</name>
|
||||
|
||||
@@ -32,6 +32,6 @@ public class BaseTest {
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
@Test
|
||||
public void testEngine() throws Exception {
|
||||
String testClasses = "target/test-classes";
|
||||
// boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Engine instance = new Engine();
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
instance.scan(testClasses);
|
||||
assertTrue(instance.getDependencies().size() > 0);
|
||||
instance.analyzeDependencies();
|
||||
|
||||
@@ -17,31 +17,78 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class AbstractSuppressionAnalyzerTest extends BaseTest {
|
||||
|
||||
private AbstractSuppressionAnalyzer instance;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
public void createObjectUnderTest() throws Exception {
|
||||
instance = new AbstractSuppressionAnalyzerImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSupportedExtensions method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
Set<String> result = instance.getSupportedExtensions();
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getRules method, of class AbstractSuppressionAnalyzer for suppression file declared as URL.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRulesFromSuppressionFileFromURL() throws Exception {
|
||||
setSupressionFileFromURL();
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertTrue(expCount <= result.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getRules method, of class AbstractSuppressionAnalyzer for suppression file declared as URL.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRulesFromSuppressionFileInClasspath() throws Exception {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, "suppressions.xml");
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertTrue(expCount <= result.size());
|
||||
}
|
||||
|
||||
@Test(expected = SuppressionParseException.class)
|
||||
public void testFailureToLocateSuppressionFileAnywhere() throws Exception {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, "doesnotexist.xml");
|
||||
instance.initialize();
|
||||
}
|
||||
|
||||
private void setSupressionFileFromURL() throws Exception {
|
||||
try {
|
||||
final String uri = this.getClass().getClassLoader().getResource("suppressions.xml").toURI().toURL().toString();
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, uri);
|
||||
@@ -52,37 +99,6 @@ public class AbstractSuppressionAnalyzerTest extends BaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSupportedExtensions method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
|
||||
Set<String> result = instance.getSupportedExtensions();
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of initialize method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testInitialize() throws Exception {
|
||||
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
|
||||
instance.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getRules method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRules() throws Exception {
|
||||
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertEquals(expCount, result.size());
|
||||
}
|
||||
|
||||
public class AbstractSuppressionAnalyzerImpl extends AbstractSuppressionAnalyzer {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -81,12 +81,24 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*/
|
||||
@Test
|
||||
public void testDetermineCPE_full() throws Exception {
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5");
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0");
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2");
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null);
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
|
||||
try {
|
||||
//callDetermineCPE_full("struts2-core-2.3.16.3.jar", "cpe:/a:apache:struts:2.3.16.3", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
} finally {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,37 +106,25 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs
|
||||
*/
|
||||
public void callDetermineCPE_full(String depName, String expResult) throws Exception {
|
||||
public void callDetermineCPE_full(String depName, String expResult, CPEAnalyzer instance, FileNameAnalyzer fnAnalyzer, JarAnalyzer jarAnalyzer, HintAnalyzer hAnalyzer, FalsePositiveAnalyzer fp) throws Exception {
|
||||
|
||||
File file = new File(this.getClass().getClassLoader().getResource(depName).getPath());
|
||||
|
||||
Dependency dep = new Dependency(file);
|
||||
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
fnAnalyzer.analyze(dep, null);
|
||||
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
jarAnalyzer.analyze(dep, null);
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
hAnalyzer.analyze(dep, null);
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
instance.analyze(dep, null);
|
||||
instance.close();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
fp.analyze(dep, null);
|
||||
|
||||
// for (Identifier i : dep.getIdentifiers()) {
|
||||
// System.out.println(i.getValue());
|
||||
// }
|
||||
if (expResult != null) {
|
||||
Identifier expIdentifier = new Identifier("cpe", expResult, expResult);
|
||||
Assert.assertTrue("Incorrect match: { dep:'" + dep.getFileName() + "' }", dep.getIdentifiers().contains(expIdentifier));
|
||||
} else if (dep.getIdentifiers().isEmpty()) {
|
||||
Assert.assertTrue("Match found when an Identifier should not have been found: { dep:'" + dep.getFileName() + "' }", dep.getIdentifiers().isEmpty());
|
||||
} else {
|
||||
Assert.assertTrue("Match found when an Identifier should not have been found: { dep:'" + dep.getFileName() + "', identifier:'" + dep.getIdentifiers().iterator().next().getValue() + "' }", dep.getIdentifiers().isEmpty());
|
||||
for (Identifier i : dep.getIdentifiers()) {
|
||||
Assert.assertFalse(String.format("%s - found a CPE identifier when should have been none (found '%s')", dep.getFileName(), i.getValue()), "cpe".equals(i.getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,10 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
String expResultSpring = "cpe:/a:springsource:spring_framework:2.5.5";
|
||||
String expResultSpring3 = "cpe:/a:vmware:springsource_spring_framework:3.0.0";
|
||||
|
||||
Assert.assertTrue("Apache Common Validator - found an identifier?", commonValidator.getIdentifiers().isEmpty());
|
||||
for (Identifier i : commonValidator.getIdentifiers()) {
|
||||
Assert.assertFalse("Apache Common Validator - found a CPE identifier?", "cpe".equals(i.getType()));
|
||||
}
|
||||
|
||||
Assert.assertTrue("Incorrect match size - struts", struts.getIdentifiers().size() >= 1);
|
||||
Assert.assertTrue("Incorrect match - struts", struts.getIdentifiers().contains(expIdentifier));
|
||||
Assert.assertTrue("Incorrect match size - spring3 - " + spring3.getIdentifiers().size(), spring3.getIdentifiers().size() >= 1);
|
||||
|
||||
@@ -56,6 +56,7 @@ public class FalsePositiveAnalyzerTest {
|
||||
public void testAnalyze() throws Exception {
|
||||
Dependency dependency = new Dependency();
|
||||
dependency.setFileName("pom.xml");
|
||||
dependency.setFilePath("pom.xml");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:file:file:1.2.1", "http://some.org/url");
|
||||
Engine engine = null;
|
||||
FalsePositiveAnalyzer instance = new FalsePositiveAnalyzer();
|
||||
|
||||
@@ -85,7 +85,7 @@ public class HintAnalyzerTest extends BaseTest {
|
||||
for (Dependency d : engine.getDependencies()) {
|
||||
if (d.getActualFile().equals(guice)) {
|
||||
gdep = d;
|
||||
} else {
|
||||
} else if (d.getActualFile().equals(spring)) {
|
||||
sdep = d;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,19 +61,26 @@ public class VulnerabilitySuppressionAnalyzerIntegrationTest extends AbstractDat
|
||||
@Test
|
||||
public void testAnalyze() throws Exception {
|
||||
|
||||
File file = new File(this.getClass().getClassLoader().getResource("FileHelpers.2.0.0.0.nupkg").getPath());
|
||||
File suppression = new File(this.getClass().getClassLoader().getResource("FileHelpers.2.0.0.0.suppression.xml").getPath());
|
||||
File file = new File(this.getClass().getClassLoader().getResource("commons-fileupload-1.2.1.jar").getPath());
|
||||
File suppression = new File(this.getClass().getClassLoader().getResource("commons-fileupload-1.2.1.suppression.xml").getPath());
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, false);
|
||||
Engine engine = new Engine();
|
||||
engine.scan(file);
|
||||
engine.analyzeDependencies();
|
||||
Dependency dependency = getDependency(engine, file);
|
||||
assertTrue(dependency.getVulnerabilities().size() > 0);
|
||||
int cveSize = dependency.getVulnerabilities().size();
|
||||
int cpeSize = dependency.getIdentifiers().size();
|
||||
assertTrue(cveSize > 0);
|
||||
assertTrue(cpeSize > 0);
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppression.getAbsolutePath());
|
||||
VulnerabilitySuppressionAnalyzer instance = new VulnerabilitySuppressionAnalyzer();
|
||||
instance.initialize();
|
||||
instance.analyze(dependency, engine);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 0);
|
||||
cveSize = cveSize > 1 ? cveSize - 2 : 0;
|
||||
cpeSize = cpeSize > 0 ? cpeSize - 1 : 0;
|
||||
assertTrue(dependency.getVulnerabilities().size() == cveSize);
|
||||
assertTrue(dependency.getIdentifiers().size() == cpeSize);
|
||||
engine.cleanup();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,10 @@ public abstract class BaseDBTestCase extends BaseTest {
|
||||
|
||||
public static void ensureDBExists() throws Exception {
|
||||
|
||||
java.io.File dataPath = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
|
||||
if (!dataPath.exists() || (dataPath.isDirectory() && dataPath.listFiles().length < 3)) {
|
||||
java.io.File dataPath = Settings.getDataDirectory();
|
||||
String fileName = String.format(Settings.getString(Settings.KEYS.DB_FILE_NAME), Settings.getString(Settings.KEYS.DB_VERSION));
|
||||
java.io.File dataFile = new File(dataPath, fileName);
|
||||
if (!dataPath.exists() || !dataFile.exists()) {
|
||||
dataPath.mkdirs();
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zin = null;
|
||||
|
||||
@@ -17,8 +17,12 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Calendar;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -26,6 +30,32 @@ import org.owasp.dependencycheck.BaseTest;
|
||||
*/
|
||||
public class NvdCveUpdaterIntegrationTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
int year = Calendar.getInstance().get(Calendar.YEAR);
|
||||
if (year <= 2014) {
|
||||
File f = new File(NvdCveUpdaterIntegrationTest.class.getClassLoader().getResource("nvdcve-2.0-2014.xml").getPath());
|
||||
String baseURL = f.toURI().toURL().toString();
|
||||
String modified12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-modified.xml");
|
||||
String modified20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-modified.xml");
|
||||
String full12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-%d.xml");
|
||||
String full20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-%d.xml");
|
||||
// cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
// cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
// cve.startyear=2014
|
||||
// cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
// cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, modified12);
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, modified20);
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, full12);
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, full20);
|
||||
Settings.setString(Settings.KEYS.CVE_START_YEAR, "2014");
|
||||
} else {
|
||||
System.err.println("Consider updating the local data files to make the NvdCveUpdaterIntegrationTest perform faster");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of update method, of class NvdCveUpdater.
|
||||
*/
|
||||
|
||||
@@ -67,16 +67,16 @@ public class StandardUpdateIntegrationTest extends BaseTest {
|
||||
result = instance.withinRange(lastRun, current, range);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of update method, of class StandardUpdate.
|
||||
*/
|
||||
@Test
|
||||
public void testUpdate() throws Exception {
|
||||
StandardUpdate instance = getStandardUpdateTask();
|
||||
instance.update();
|
||||
//TODO make this an actual test
|
||||
}
|
||||
// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest
|
||||
// /**
|
||||
// * Test of update method, of class StandardUpdate.
|
||||
// */
|
||||
// @Test
|
||||
// public void testUpdate() throws Exception {
|
||||
// StandardUpdate instance = getStandardUpdateTask();
|
||||
// instance.update();
|
||||
// //TODO make this an actual test
|
||||
// }
|
||||
|
||||
/**
|
||||
* Test of updatesNeeded method, of class StandardUpdate.
|
||||
|
||||
@@ -88,7 +88,15 @@ public class SuppressionHandlerTest {
|
||||
|
||||
xmlReader.parse(in);
|
||||
|
||||
List result = handler.getSuppressionRules();
|
||||
List<SuppressionRule> result = handler.getSuppressionRules();
|
||||
assertTrue(result.size() > 3);
|
||||
int baseCount = 0;
|
||||
for (SuppressionRule r : result) {
|
||||
if (r.isBase()) {
|
||||
baseCount++;
|
||||
}
|
||||
}
|
||||
assertTrue(baseCount > 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,17 @@ public class SuppressionRuleTest {
|
||||
List<String> result = instance.getCve();
|
||||
assertEquals(cve, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of base property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testBase() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
assertFalse(instance.isBase());
|
||||
instance.setBase(true);
|
||||
assertTrue(instance.isBase());
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Ignored duplicate tests, left in, as empty tests, so IDE doesn't re-generate them">
|
||||
@@ -339,55 +350,70 @@ public class SuppressionRuleTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of cpeMatches method, of class SuppressionRule.
|
||||
* Test of identifierMatches method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCpeMatches() {
|
||||
Identifier identifier = new Identifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
Identifier identifier = new Identifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
|
||||
PropertyType cpe = new PropertyType();
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.5");
|
||||
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
boolean expResult = true;
|
||||
boolean result = instance.cpeMatches(cpe, identifier);
|
||||
boolean result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.0");
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.net_framework:4.5");
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework");
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:apache:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
identifier = new Identifier("maven", "org.springframework:spring-core:2.5.5", "https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.springframework&a=spring-core&v=2.5.5&e=jar");
|
||||
cpe.setValue("org.springframework:spring-core:2.5.5");
|
||||
cpe.setRegex(false);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = true;
|
||||
result = instance.identifierMatches("maven", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("org\\.springframework\\.security:spring.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = false;
|
||||
result = instance.identifierMatches("maven", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
@@ -398,7 +424,7 @@ public class SuppressionRuleTest {
|
||||
public void testProcess() {
|
||||
File struts = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
|
||||
Dependency dependency = new Dependency(struts);
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
String sha1 = dependency.getSha1sum();
|
||||
dependency.setSha1sum("384FAA82E193D4E4B0546059CA09572654BC3970");
|
||||
Vulnerability v = createVulnerability();
|
||||
@@ -409,33 +435,33 @@ public class SuppressionRuleTest {
|
||||
instance.setSha1(sha1);
|
||||
instance.addCwe("287");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
dependency.setSha1sum(sha1);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cvss
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCvssBelow(5f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCvssBelow(8f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cve
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCve("CVE-2012-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCve("CVE-2013-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cpe
|
||||
instance = new SuppressionRule();
|
||||
@@ -453,18 +479,58 @@ public class SuppressionRuleTest {
|
||||
instance.setFilePath(pt);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
instance = new SuppressionRule();
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:microsoft:.net_framework");
|
||||
instance.addCpe(pt);
|
||||
assertTrue(dependency.getIdentifiers().size() == 3);
|
||||
instance.setBase(true);
|
||||
assertEquals(3, dependency.getIdentifiers().size());
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 3);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of process method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testProcessGAV() {
|
||||
File spring = new File(this.getClass().getClassLoader().getResource("spring-security-web-3.0.0.RELEASE.jar").getPath());
|
||||
Dependency dependency = new Dependency(spring);
|
||||
dependency.addIdentifier("cpe", "cpe:/a:vmware:springsource_spring_framework:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:springsource:spring_framework:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:mod_security:mod_security:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:vmware:springsource_spring_security:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("maven", "org.springframework.security:spring-security-web:3.0.0.RELEASE", "some url not needed for this test");
|
||||
|
||||
//cpe
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
PropertyType pt = new PropertyType();
|
||||
|
||||
pt.setValue("org\\.springframework\\.security:spring.*");
|
||||
pt.setRegex(true);
|
||||
pt.setCaseSensitive(false);
|
||||
instance.setGav(pt);
|
||||
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:mod_security:mod_security");
|
||||
instance.addCpe(pt);
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:springsource:spring_framework");
|
||||
instance.addCpe(pt);
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:vmware:springsource_spring_framework");
|
||||
instance.addCpe(pt);
|
||||
|
||||
instance.process(dependency);
|
||||
assertEquals(2, dependency.getIdentifiers().size());
|
||||
|
||||
}
|
||||
|
||||
private Vulnerability createVulnerability() {
|
||||
|
||||
@@ -134,14 +134,14 @@ public class DependencyVersionTest {
|
||||
@Test
|
||||
public void testMatchesAtLeastThreeLevels() {
|
||||
|
||||
DependencyVersion instance = new DependencyVersion("1.2.3.4");
|
||||
DependencyVersion version = new DependencyVersion("1.2.3.5");
|
||||
DependencyVersion instance = new DependencyVersion("2.3.16.3");
|
||||
DependencyVersion version = new DependencyVersion("2.3.16.4");
|
||||
//true tests
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("1.2");
|
||||
version = new DependencyVersion("2.3");
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
//false tests
|
||||
version = new DependencyVersion("1.2.2.5");
|
||||
version = new DependencyVersion("2.3.16.1");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("2");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: FileHelpers.2.0.0.0.nupkg
|
||||
]]></notes>
|
||||
<sha1>30FB37D6163CF16E3BA740343BECDD14D5457619</sha1>
|
||||
<cve>CVE-2007-1536</cve>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: commons-fileupload-1.2.1.jar
|
||||
]]></notes>
|
||||
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
|
||||
<cpe>cpe:/a:apache:commons_fileupload:1.2.1</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: commons-fileupload-1.2.1.jar
|
||||
]]></notes>
|
||||
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
|
||||
<cve>CVE-2014-0050</cve>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: commons-fileupload-1.2.1.jar
|
||||
]]></notes>
|
||||
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
|
||||
<cve>CVE-2013-0248</cve>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -13,8 +13,12 @@ max.download.threads=3
|
||||
# will not be used. The data.directory will be resolved and if the connection string
|
||||
# below contains a %s then the data.directory will replace the %s.
|
||||
data.directory=[JAR]/data
|
||||
# if the filename has a %s it will be replaced with the current expected version. For file
|
||||
# based databases the below filename will be added to the data directory above and then
|
||||
# if the connection string has a %s it will be replaced by the directory/filename path.
|
||||
data.file_name=cve.%s.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
# user name and password for the database connection. The inherent case is to use H2.
|
||||
|
||||
12297
dependency-check-core/src/test/resources/nvdcve-modified.xml
Normal file
12297
dependency-check-core/src/test/resources/nvdcve-modified.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@
|
||||
<filePath>c:\path\to\some.jar</filePath>
|
||||
<cpe>cpe:/a:csv:csv:1.0</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses any jboss:jboss cpe for any test.jar in any directory.
|
||||
]]></notes>
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<description>This plug-in can independently execute a Dependency-Check analysis and visualize the results.</description>
|
||||
<url>http://wiki.jenkins-ci.org/display/JENKINS/OWASP+Dependency-Check+Plugin</url>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.5</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-jenkins</artifactId>
|
||||
<name>Dependency-Check Jenkins Plugin</name>
|
||||
<url>http://wiki.jenkins-ci.org/display/JENKINS/OWASP+Dependency-Check+Plugin</url>
|
||||
<description>dependency-check-jenkins is a Jenkins plugin that runs dependency-check-core on a project to detect publicly disclosed vulnerabilities associated with the project's dependencies. The plugin will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries. This module is simply a placeholder and does not contain the actual plugin source code. The source code and distribution of the plugin is handled via https://github.com/jenkinsci/dependency-check-jenkins and Jenkin's plugin management.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-jenkins</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
<organization>
|
||||
@@ -31,15 +39,6 @@
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-maven</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:jenkinsci/dependency-check-jenkins.git</connection>
|
||||
<url>https://github.com/jenkinsci/dependency-check-jenkins</url>
|
||||
|
||||
@@ -15,7 +15,6 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<url>http://maven.apache.org</url>
|
||||
@@ -23,14 +22,14 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<packaging>maven-plugin</packaging>
|
||||
|
||||
<name>Dependency-Check Maven Plugin</name>
|
||||
<description>Dependency-Check-Maven is a Maven Plugin that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-maven is a Maven Plugin that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The plugin will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<inceptionYear>2013</inceptionYear>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
@@ -150,6 +149,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -239,7 +241,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
<exclude>**/generated/**/*.java</exclude>
|
||||
<exclude>**/HelpMojo.java</exclude>
|
||||
</excludes>
|
||||
<rulesets>
|
||||
@@ -277,6 +279,11 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* This file is part of dependency-check-maven.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.Component;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.reporting.MavenReport;
|
||||
import org.apache.maven.reporting.MavenReportException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is an abstract reporting mojo that enables report aggregation. Some of the code in the this class was copied
|
||||
* from the CoberturaReportMojo (http://mojo.codehaus.org/cobertura-maven-plugin/, version 2.6). The authors of the
|
||||
* CoberturaReportMojo were <a href="will.gwaltney@sas.com">Will Gwaltney</a> and
|
||||
* <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>. There working example of how to do report aggregation was
|
||||
* invaluable.</p>
|
||||
* <p>
|
||||
* An important point about using this abstract class is that it is intended for one to write some form of serialized
|
||||
* data (via the {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#writeDataFile() }; note that the
|
||||
* <code>writeDataFile()</code> function is called automatically after either {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeNonAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } or {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } are called. When <code>executeAggregateReport()</code> is implemented, one can call {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#getChildDataFiles()
|
||||
* } to obtain a list of the data files to aggregate.</p>
|
||||
*
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class ReportAggregationMojo extends AbstractMojo implements MavenReport {
|
||||
|
||||
/**
|
||||
* The Maven Project Object.
|
||||
*/
|
||||
@Component
|
||||
private MavenProject project;
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportAggregationMojo.class.getName());
|
||||
|
||||
/**
|
||||
* List of Maven project of the current build
|
||||
*/
|
||||
@Parameter(readonly = true, required = true, property = "reactorProjects")
|
||||
private List<MavenProject> reactorProjects;
|
||||
|
||||
/**
|
||||
* Generate aggregate reports in multi-module projects.
|
||||
*/
|
||||
@Parameter(property = "aggregate", defaultValue = "false")
|
||||
private boolean aggregate;
|
||||
|
||||
/**
|
||||
* Sets whether or not the external report format should be used.
|
||||
*/
|
||||
@Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
|
||||
private String dataFileName;
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check report. This generally maps to
|
||||
* "target/site".
|
||||
*/
|
||||
@Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true)
|
||||
private File reportOutputDirectory;
|
||||
|
||||
/**
|
||||
* Sets the Reporting output directory.
|
||||
*
|
||||
* @param directory the output directory
|
||||
*/
|
||||
@Override
|
||||
public void setReportOutputDirectory(File directory) {
|
||||
reportOutputDirectory = directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory.
|
||||
*
|
||||
* @return the output directory
|
||||
*/
|
||||
@Override
|
||||
public File getReportOutputDirectory() {
|
||||
return reportOutputDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory for the given project.
|
||||
*
|
||||
* @param project the Maven project to get the output directory for
|
||||
* @return the output directory for the given project
|
||||
*/
|
||||
public File getReportOutputDirectory(MavenProject project) {
|
||||
final Object o = project.getContextValue(getOutputDirectoryContextKey());
|
||||
if (o != null && o instanceof File) {
|
||||
return (File) o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is an external report. This method always returns true.
|
||||
*
|
||||
* @return <code>true</code>
|
||||
*/
|
||||
@Override
|
||||
public final boolean isExternalReport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The collection of child projects.
|
||||
*/
|
||||
private final Map<MavenProject, Set<MavenProject>> projectChildren = new HashMap<MavenProject, Set<MavenProject>>();
|
||||
|
||||
/**
|
||||
* Called before execute; allows for any setup that is needed. If this is overridden you must call
|
||||
* </code>super.preExecute()</code>.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void preExecute() throws MojoExecutionException, MojoFailureException {
|
||||
buildAggregateInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mojo is being executed.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected abstract void performExecute() throws MojoExecutionException, MojoFailureException;
|
||||
|
||||
/**
|
||||
* Runs after the mojo has executed. This implementation will call <code>writeDataFile()</code>. As such, it is
|
||||
* important that if this method is overriden that <code>super.postExecute()</code> is called.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void postExecute() throws MojoExecutionException, MojoFailureException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key
|
||||
* is used in the <code>MavenProject.(set|get)ContextValue</code>.
|
||||
*
|
||||
* @return the key used to store the path to the data file
|
||||
*/
|
||||
protected String getDataFileContextKey() {
|
||||
return "dependency-check-path-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the output directory. When generating the report in the
|
||||
* <code>executeAggregateReport()</code> the output directory should be obtained by using this key.
|
||||
*
|
||||
* @return the key used to store the path to the output directory
|
||||
*/
|
||||
protected String getOutputDirectoryContextKey() {
|
||||
return "dependency-output-dir-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called by Maven to execute the mojo.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
public final void execute() throws MojoExecutionException, MojoFailureException {
|
||||
try {
|
||||
preExecute();
|
||||
performExecute();
|
||||
} finally {
|
||||
postExecute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs prior to the site report generation.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void preGenerate() throws MavenReportException {
|
||||
buildAggregateInfo();
|
||||
|
||||
project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes after the site report has been generated.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void postGenerate() throws MavenReportException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the non aggregate report.
|
||||
*
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeNonAggregateReport(Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the aggregate Site Report.
|
||||
*
|
||||
* @param project the maven project used to generate the aggregate report
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeAggregateReport(MavenProject project, Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
* @deprecated use {@link #generate(org.apache.maven.doxia.sink.Sink, java.util.Locale) instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
|
||||
generate((Sink) sink, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
public final void generate(Sink sink, Locale locale) throws MavenReportException {
|
||||
try {
|
||||
preGenerate();
|
||||
if (canGenerateNonAggregateReport()) {
|
||||
executeNonAggregateReport(locale);
|
||||
}
|
||||
|
||||
if (canGenerateAggregateReport()) {
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
if (!isMultiModule(proj)) {
|
||||
continue;
|
||||
}
|
||||
executeAggregateReport(proj, locale);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
postGenerate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo can generate a non-aggregate report for this project.
|
||||
*
|
||||
* @return <code>true</code> if a non-aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateNonAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns whether or not we can generate any aggregate reports at this time.
|
||||
*
|
||||
* @return <code>true</code> if an aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns the name of the data file that contains the serialized data.
|
||||
*
|
||||
* @return the name of the data file that contains the serialized data
|
||||
*/
|
||||
protected String getDataFileName() {
|
||||
return dataFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data file to disk in the target directory.
|
||||
*
|
||||
* @return the File object referencing the data file that was written
|
||||
*/
|
||||
protected abstract File writeDataFile();
|
||||
|
||||
/**
|
||||
* Collects the information needed for building aggregate reports.
|
||||
*/
|
||||
private void buildAggregateInfo() {
|
||||
// build parent-child map
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
Set<MavenProject> depList = projectChildren.get(proj.getParent());
|
||||
if (depList == null) {
|
||||
depList = new HashSet<MavenProject>();
|
||||
projectChildren.put(proj.getParent(), depList);
|
||||
}
|
||||
depList.add(proj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren() {
|
||||
return getAllChildren(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @param parentProject the parent project to collect the child project references
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren(MavenProject parentProject) {
|
||||
final Set<MavenProject> children = projectChildren.get(parentProject);
|
||||
if (children == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<MavenProject> result = new ArrayList<MavenProject>();
|
||||
for (MavenProject child : children) {
|
||||
if (isMultiModule(child)) {
|
||||
result.addAll(getAllChildren(child));
|
||||
} else {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of data files that were produced by the direct children of the given MavenProject.
|
||||
*
|
||||
* @param project the Maven project to obtain the child data files from
|
||||
* @return a list of the data files
|
||||
*/
|
||||
protected List<File> getAllChildDataFiles(MavenProject project) {
|
||||
final List<MavenProject> children = getAllChildren(project);
|
||||
return getDataFiles(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any existing output files from the given list of projects.
|
||||
*
|
||||
* @param projects the list of projects to obtain the output files from
|
||||
* @return a list of output files
|
||||
*/
|
||||
protected List<File> getDataFiles(List<MavenProject> projects) {
|
||||
final List<File> files = new ArrayList<File>();
|
||||
for (MavenProject proj : projects) {
|
||||
final Object path = project.getContextValue(getDataFileContextKey());
|
||||
if (path == null) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - aggregate data file was not generated",
|
||||
proj.getName());
|
||||
LOGGER.warning(msg);
|
||||
} else {
|
||||
final File outputFile = new File((String) path);
|
||||
if (outputFile.exists()) {
|
||||
files.add(outputFile);
|
||||
} else {
|
||||
if (!isMultiModule(project)) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - missing data file '%s'",
|
||||
proj.getName(), outputFile.getPath());
|
||||
LOGGER.warning(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the project has pom packaging
|
||||
*
|
||||
* @param mavenProject Project to test
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule(MavenProject mavenProject) {
|
||||
return "pom".equals(mavenProject.getPackaging());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the current project has pom packaging
|
||||
*
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule() {
|
||||
return isMultiModule(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current project is the last project in a multi-module build. If the maven build is not a
|
||||
* multi-module project then this will always return true.
|
||||
*
|
||||
* @return <code>true</code> if the current project is the last project in a multi-module build; otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
protected boolean isLastProject() {
|
||||
return project.equals(reactorProjects.get(reactorProjects.size() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo is configured to perform report aggregation.
|
||||
*
|
||||
* @return <code>true</code> if report aggregation is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
public boolean isAggregate() {
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the current project. This method is used instead of auto-binding the project via component
|
||||
* annotation in concrete implementations of this. If the child has a <code>@Component MavenProject project;</code>
|
||||
* defined then the abstract class (i.e. this class) will not have access to the current project (just the way Maven
|
||||
* works with the binding).
|
||||
*
|
||||
* @return returns a reference to the current project
|
||||
*/
|
||||
protected MavenProject getProject() {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* This file is part of dependency-check-maven.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Reference;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
|
||||
/**
|
||||
* A utility class that encapsulates the report generation for dependency-check-maven.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
final class ReportingUtil {
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportingUtil.class.getName());
|
||||
|
||||
/**
|
||||
* Empty private constructor for this utility class.
|
||||
*/
|
||||
private ReportingUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the reports for a given dependency-check engine.
|
||||
*
|
||||
* @param engine a dependency-check engine
|
||||
* @param outDirectory the directory to write the reports to
|
||||
* @param projectName the name of the project that a report is being generated for
|
||||
* @param format the format of the report to generate
|
||||
*/
|
||||
static void generateExternalReports(Engine engine, File outDirectory, String projectName, String format) {
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator r = new ReportGenerator(projectName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
try {
|
||||
r.generateReports(outDirectory.getCanonicalPath(), format);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a dependency-check report using the Maven Site format.
|
||||
*
|
||||
* @param engine the engine used to scan the dependencies
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
static void generateMavenSiteReport(final Engine engine, Sink sink, String projectName) {
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
|
||||
writeSiteReportHeader(sink, projectName);
|
||||
writeSiteReportTOC(sink, dependencies);
|
||||
|
||||
int cnt = 0;
|
||||
for (Dependency d : dependencies) {
|
||||
writeSiteReportDependencyHeader(sink, d);
|
||||
cnt = writeSiteReportDependencyEvidenceUsed(d, cnt, sink);
|
||||
cnt = writeSiteReportDependencyRelatedDependencies(d, cnt, sink);
|
||||
writeSiteReportDependencyIdentifiers(d, sink);
|
||||
writeSiteReportDependencyVulnerabilities(d, sink, cnt);
|
||||
}
|
||||
sink.body_();
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="various writeXXXXX methods to generate the Site Report">
|
||||
/**
|
||||
* Writes the vulnerabilities to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
*/
|
||||
private static void writeSiteReportDependencyVulnerabilities(Dependency d, Sink sink, int collapsibleHeaderCount) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getVulnerabilities() != null && !d.getVulnerabilities().isEmpty()) {
|
||||
for (Vulnerability v : d.getVulnerabilities()) {
|
||||
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + URLEncoder.encode(v.getName(), "US-ASCII"));
|
||||
sink.text(v.getName());
|
||||
sink.link_();
|
||||
sink.bold_();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(v.getName());
|
||||
sink.bold_();
|
||||
sink.lineBreak();
|
||||
sink.text("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + v.getName());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text("Severity: ");
|
||||
if (v.getCvssScore() < 4.0) {
|
||||
sink.text("Low");
|
||||
} else {
|
||||
if (v.getCvssScore() >= 7.0) {
|
||||
sink.text("High");
|
||||
} else {
|
||||
sink.text("Medium");
|
||||
}
|
||||
}
|
||||
sink.lineBreak();
|
||||
sink.text("CVSS Score: " + v.getCvssScore());
|
||||
if (v.getCwe() != null && !v.getCwe().isEmpty()) {
|
||||
sink.lineBreak();
|
||||
sink.text("CWE: ");
|
||||
sink.text(v.getCwe());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text(v.getDescription());
|
||||
if (v.getReferences() != null && !v.getReferences().isEmpty()) {
|
||||
sink.list();
|
||||
for (Reference ref : v.getReferences()) {
|
||||
sink.listItem();
|
||||
sink.text(ref.getSource());
|
||||
sink.text(" - ");
|
||||
sink.link(ref.getUrl());
|
||||
sink.text(ref.getName());
|
||||
sink.link_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.paragraph_();
|
||||
if (v.getVulnerableSoftware() != null && !v.getVulnerableSoftware().isEmpty()) {
|
||||
sink.paragraph();
|
||||
|
||||
cnt += 1;
|
||||
sink.rawText("Vulnerable Software <a href=\"javascript:toggleElement(this, 'vulnSoft" + cnt + "')\">[-]</a>");
|
||||
sink.rawText("<div id=\"vulnSoft" + cnt + "\" style=\"display:block\">");
|
||||
sink.list();
|
||||
for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
|
||||
sink.listItem();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + URLEncoder.encode(vs.getName(), "US-ASCII"));
|
||||
sink.text(vs.getName());
|
||||
sink.link_();
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(vs.getName());
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
sink.text(" (http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + vs.getName() + ")");
|
||||
}
|
||||
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the identifiers to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyIdentifiers(Dependency d, Sink sink) {
|
||||
if (d.getIdentifiers() != null && !d.getIdentifiers().isEmpty()) {
|
||||
sink.sectionTitle4();
|
||||
sink.text("Identifiers");
|
||||
sink.sectionTitle4_();
|
||||
sink.list();
|
||||
for (Identifier i : d.getIdentifiers()) {
|
||||
sink.listItem();
|
||||
sink.text(i.getType());
|
||||
sink.text(": ");
|
||||
if (i.getUrl() != null && i.getUrl().length() > 0) {
|
||||
sink.link(i.getUrl());
|
||||
sink.text(i.getValue());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(i.getValue());
|
||||
}
|
||||
if (i.getDescription() != null && i.getDescription().length() > 0) {
|
||||
sink.lineBreak();
|
||||
sink.text(i.getDescription());
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the related dependencies to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyRelatedDependencies(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getRelatedDependencies() != null && !d.getRelatedDependencies().isEmpty()) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Related Dependencies <a href=\"javascript:toggleElement(this, 'related" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"related" + cnt + "\" style=\"display:none\">");
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
sink.listItem();
|
||||
sink.text(r.getFileName());
|
||||
sink.list();
|
||||
writeListItem(sink, "File Path: " + r.getFilePath());
|
||||
writeListItem(sink, "SHA1: " + r.getSha1sum());
|
||||
writeListItem(sink, "MD5: " + r.getMd5sum());
|
||||
sink.list_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the evidence used to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyEvidenceUsed(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
final Set<Evidence> evidence = d.getEvidenceForDisplay();
|
||||
if (evidence != null && evidence.size() > 0) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Evidence Collected <a href=\"javascript:toggleElement(this, 'evidence" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"evidence" + cnt + "\" style=\"display:none\">");
|
||||
sink.table();
|
||||
sink.tableRow();
|
||||
writeTableHeaderCell(sink, "Source");
|
||||
writeTableHeaderCell(sink, "Name");
|
||||
writeTableHeaderCell(sink, "Value");
|
||||
sink.tableRow_();
|
||||
for (Evidence e : evidence) {
|
||||
sink.tableRow();
|
||||
writeTableCell(sink, e.getSource());
|
||||
writeTableCell(sink, e.getName());
|
||||
writeTableCell(sink, e.getValue());
|
||||
sink.tableRow_();
|
||||
}
|
||||
sink.table_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the dependency header to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyHeader(Sink sink, Dependency d) {
|
||||
sink.sectionTitle2();
|
||||
sink.anchor("sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.anchor_();
|
||||
sink.sectionTitle2_();
|
||||
if (d.getDescription() != null && d.getDescription().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("Description: ");
|
||||
sink.bold_();
|
||||
sink.text(d.getDescription());
|
||||
sink.paragraph_();
|
||||
}
|
||||
if (d.getLicense() != null && d.getLicense().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("License: ");
|
||||
sink.bold_();
|
||||
if (d.getLicense().startsWith("http://") && !d.getLicense().contains(" ")) {
|
||||
sink.link(d.getLicense());
|
||||
sink.text(d.getLicense());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(d.getLicense());
|
||||
}
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list item to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeListItem(Sink sink, String text) {
|
||||
sink.listItem();
|
||||
sink.text(text);
|
||||
sink.listItem_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableCell(Sink sink, String text) {
|
||||
sink.tableCell();
|
||||
sink.text(text);
|
||||
sink.tableCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table header cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableHeaderCell(Sink sink, String text) {
|
||||
sink.tableHeaderCell();
|
||||
sink.text(text);
|
||||
sink.tableHeaderCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the TOC for the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param dependencies the dependencies that are being reported on
|
||||
*/
|
||||
private static void writeSiteReportTOC(Sink sink, final List<Dependency> dependencies) {
|
||||
sink.list();
|
||||
for (Dependency d : dependencies) {
|
||||
sink.listItem();
|
||||
sink.link("#sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.link_();
|
||||
if (!d.getVulnerabilities().isEmpty()) {
|
||||
sink.rawText(" <font style=\"color:red\">•</font>");
|
||||
}
|
||||
if (!d.getRelatedDependencies().isEmpty()) {
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
writeListItem(sink, r.getFileName());
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the site report header.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
private static void writeSiteReportHeader(Sink sink, String projectName) {
|
||||
sink.head();
|
||||
sink.title();
|
||||
sink.text("Dependency-Check Report: " + projectName);
|
||||
sink.title_();
|
||||
sink.head_();
|
||||
sink.body();
|
||||
sink.rawText("<script type=\"text/javascript\">");
|
||||
sink.rawText("function toggleElement(el, targetId) {");
|
||||
sink.rawText("if (el.innerText == '[+]') {");
|
||||
sink.rawText(" el.innerText = '[-]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='block';");
|
||||
sink.rawText("} else {");
|
||||
sink.rawText(" el.innerText = '[+]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='none';");
|
||||
sink.rawText("}");
|
||||
|
||||
sink.rawText("}");
|
||||
sink.rawText("</script>");
|
||||
sink.section1();
|
||||
sink.sectionTitle1();
|
||||
sink.text("Project: " + projectName);
|
||||
sink.sectionTitle1_();
|
||||
sink.date();
|
||||
final Date now = new Date();
|
||||
sink.text(DateFormat.getDateTimeInstance().format(now));
|
||||
sink.date_();
|
||||
sink.section1_();
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
}
|
||||
@@ -4,8 +4,8 @@ The following properties can be set on the dependency-check-maven plugin.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
aggregate | Sets whether report aggregation will be performed for multi-module site reports. This option only affects the report generation when configured within the reporting section. | false
|
||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
||||
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
||||
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
|
||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
@@ -31,7 +31,7 @@ jarAnalyzer | Sets whether Jar Analyzer will be used.
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems |
|
||||
|
||||
@@ -40,32 +40,27 @@ Advanced Configuration
|
||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
||||
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|-------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2. | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year. | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
connectionTimeout | Sets the URL Connection Timeout used when downloading external data. |
|
||||
dataDirectory | Sets the data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||
connectionString | The connection string used to connect to the database. |
|
||||
databaseUser | The username used when connecting to the database. |
|
||||
databasePassword | The password used when connecting to the database. |
|
||||
metaFileName | Sets the name of the file to use for storing the metadata about the project. | dependency-check.ser
|
||||
|
||||
|
||||
Deprecated Configuration
|
||||
Proxy Configuration
|
||||
====================
|
||||
The following properties have been deprecated. These can still be set in
|
||||
the dependency-check-maven plugin's configuration. However, future versions
|
||||
will remove these properties. Instead using these properties you should
|
||||
use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to
|
||||
configure a proxy.
|
||||
Use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to configure a proxy server. If multiple proxies
|
||||
are configured in the Maven settings file you must tell dependency-check which proxy to use with the following property:
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------------------|------------------
|
||||
mavenSettingsProxyId | The id for the proxy, configured via settings.xml, that dependency-check should use. |
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
proxyUrl | The Proxy URL. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
|
||||
@@ -17,7 +17,9 @@ Create the DependencyCheck-report.html in the target directory
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -41,11 +43,48 @@ Create the DependencyCheck-report.html in the target directory
|
||||
```
|
||||
|
||||
$H$H$H Example 2:
|
||||
Create an aggregated dependency-check report within the site
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<reporting>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration>
|
||||
<aggregate>true</aggregate>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>check</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
</plugin>
|
||||
...
|
||||
</plugins>
|
||||
...
|
||||
</reporting>
|
||||
...
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 3:
|
||||
Create the DependencyCheck-report.html and fail the build for CVSS greater then 8
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -71,44 +110,14 @@ Create the DependencyCheck-report.html and fail the build for CVSS greater then
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 3:
|
||||
Create the dependency-check report within the site
|
||||
|
||||
```xml
|
||||
<project>
|
||||
<build>
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<configuration>
|
||||
<reportPlugins>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration>
|
||||
<externalReport>false</externalReport>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
...
|
||||
</plugins>
|
||||
...
|
||||
</build>
|
||||
...
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 4:
|
||||
Create the DependencyCheck-report.html and skip artifacts no bundled in distribution (Provided and Runtime scope)
|
||||
Create the DependencyCheck-report.html and skip artifacts not bundled in distribution (Provided and Runtime scope)
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -140,7 +149,9 @@ Create the DependencyCheck-report.html and use internal mirroring of CVE content
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
|
||||
283
dependency-check-utils/pom.xml
Normal file
283
dependency-check-utils/pom.xml
Normal file
@@ -0,0 +1,283 @@
|
||||
<!--
|
||||
This file is part of dependency-check-utils.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<name>Dependency-Check Utils</name>
|
||||
<description>dependency-check-utils is a collection of common utlity classes used within dependency-check that might be useful in other projects.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-utils</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<instrumentation>
|
||||
<ignoreTrivial>true</ignoreTrivial>
|
||||
</instrumentation>
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
<haltOnFailure>false</haltOnFailure>
|
||||
<totalBranchRate>85</totalBranchRate>
|
||||
<totalLineRate>85</totalLineRate>
|
||||
<packageLineRate>85</packageLineRate>
|
||||
<packageBranchRate>85</packageBranchRate>
|
||||
<regexes>
|
||||
<regex>
|
||||
<pattern>.*\$.*</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
</regexes>
|
||||
</check>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>clean</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<excludes>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*IntegrationTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
<artifactId>doxia-module-markdown</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<skipDeploy>true</skipDeploy>
|
||||
<reportPlugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<rulesets>
|
||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,9 +1,27 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.logging.Level;
|
||||
@@ -12,19 +30,16 @@ import java.util.logging.Logger;
|
||||
/**
|
||||
* Includes methods to generate the MD5 and SHA1 checksum.
|
||||
*
|
||||
* This code was copied from Real's How To. It has been slightly modified.
|
||||
*
|
||||
* Written and compiled by Réal Gagnon ©1998-2012
|
||||
*
|
||||
* @author Real's How To: http://www.rgagnon.com/javadetails/java-0416.html
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*
|
||||
*/
|
||||
public final class Checksum {
|
||||
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(Checksum.class.getName());
|
||||
|
||||
/**
|
||||
* Private constructor for a utility class.
|
||||
*/
|
||||
@@ -32,30 +47,43 @@ public final class Checksum {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates the cryptographic checksum of a given file using the specified
|
||||
* algorithm.</p> <p>This algorithm was copied and heavily modified from
|
||||
* Real's How To: http://www.rgagnon.com/javadetails/java-0416.html</p>
|
||||
* <p>
|
||||
* Creates the cryptographic checksum of a given file using the specified algorithm.</p>
|
||||
*
|
||||
* @param algorithm the algorithm to use to calculate the checksum
|
||||
* @param file the file to calculate the checksum for
|
||||
* @return the checksum
|
||||
* @throws IOException when the file does not exist
|
||||
* @throws NoSuchAlgorithmException when an algorithm is specified that does
|
||||
* not exist
|
||||
* @throws NoSuchAlgorithmException when an algorithm is specified that does not exist
|
||||
*/
|
||||
@SuppressWarnings("empty-statement")
|
||||
public static byte[] getChecksum(String algorithm, File file) throws NoSuchAlgorithmException, IOException {
|
||||
InputStream fis = null;
|
||||
byte[] buffer = new byte[1024];
|
||||
MessageDigest complete = MessageDigest.getInstance(algorithm);
|
||||
int numRead;
|
||||
MessageDigest digest = MessageDigest.getInstance(algorithm);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
do {
|
||||
numRead = fis.read(buffer);
|
||||
if (numRead > 0) {
|
||||
complete.update(buffer, 0, numRead);
|
||||
FileChannel ch = fis.getChannel();
|
||||
long remainingToRead = file.length();
|
||||
long start = 0;
|
||||
while (remainingToRead > 0) {
|
||||
long amountToRead;
|
||||
if (remainingToRead > Integer.MAX_VALUE) {
|
||||
remainingToRead -= Integer.MAX_VALUE;
|
||||
amountToRead = Integer.MAX_VALUE;
|
||||
} else {
|
||||
amountToRead = remainingToRead;
|
||||
remainingToRead = 0;
|
||||
}
|
||||
} while (numRead != -1);
|
||||
MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, start, amountToRead);
|
||||
digest.update(byteBuffer);
|
||||
start += amountToRead;
|
||||
}
|
||||
|
||||
// BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
// DigestInputStream dis = new DigestInputStream(bis, digest);
|
||||
// //yes, we are reading in a buffer for performance reasons - 1 byte at a time is SLOW
|
||||
// byte[] buffer = new byte[8192];
|
||||
// while (dis.read(buffer) != -1);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
@@ -65,7 +93,7 @@ public final class Checksum {
|
||||
}
|
||||
}
|
||||
}
|
||||
return complete.digest();
|
||||
return digest.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,12 +121,17 @@ public final class Checksum {
|
||||
byte[] b = getChecksum("SHA1", file);
|
||||
return getHex(b);
|
||||
}
|
||||
/**
|
||||
* Hex code characters used in getHex.
|
||||
*/
|
||||
private static final String HEXES = "0123456789ABCDEF";
|
||||
|
||||
/**
|
||||
* <p>Converts a byte array into a hex string.</p>
|
||||
* <p>
|
||||
* Converts a byte array into a hex string.</p>
|
||||
*
|
||||
* <p>This method was copied from <a
|
||||
* <p>
|
||||
* This method was copied from <a
|
||||
* href="http://www.rgagnon.com/javadetails/java-0596.html">http://www.rgagnon.com/javadetails/java-0596.html</a></p>
|
||||
*
|
||||
* @param raw a byte array
|
||||
@@ -110,7 +143,7 @@ public final class Checksum {
|
||||
}
|
||||
final StringBuilder hex = new StringBuilder(2 * raw.length);
|
||||
for (final byte b : raw) {
|
||||
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
|
||||
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt(b & 0x0F));
|
||||
}
|
||||
return hex.toString();
|
||||
}
|
||||
@@ -166,7 +166,7 @@ public final class Downloader {
|
||||
try {
|
||||
lastModifiedFile = new File(url.toURI());
|
||||
} catch (URISyntaxException ex) {
|
||||
final String msg = String.format("Unable to locate '%s'; is the cve.url-2.0.modified property set correctly?", url.toString());
|
||||
final String msg = String.format("Unable to locate '%s'", url.toString());
|
||||
throw new DownloadFailedException(msg);
|
||||
}
|
||||
timestamp = lastModifiedFile.lastModified();
|
||||
@@ -176,7 +176,12 @@ public final class Downloader {
|
||||
conn = URLConnectionFactory.createHttpURLConnection(url);
|
||||
conn.setRequestMethod("HEAD");
|
||||
conn.connect();
|
||||
timestamp = conn.getLastModified();
|
||||
final int t = conn.getResponseCode();
|
||||
if (t >= 200 && t < 300) {
|
||||
timestamp = conn.getLastModified();
|
||||
} else {
|
||||
throw new DownloadFailedException("HEAD request returned a non-200 status code");
|
||||
}
|
||||
} catch (URLConnectionFailureException ex) {
|
||||
throw new DownloadFailedException("Error creating URL Connection for HTTP HEAD request.", ex);
|
||||
} catch (IOException ex) {
|
||||
@@ -17,21 +17,13 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
|
||||
/**
|
||||
* A collection of utilities for processing information about files.
|
||||
@@ -54,11 +46,6 @@ public final class FileUtils {
|
||||
*/
|
||||
private static final String BIT_BUCKET_WIN = "NUL";
|
||||
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Private constructor for a utility class.
|
||||
*/
|
||||
@@ -155,99 +142,6 @@ public final class FileUtils {
|
||||
return jarPath.getParentFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @throws ExtractionException thrown if an exception occurs while extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo) throws ExtractionException {
|
||||
extractFiles(archive, extractTo, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory. The files are only extracted if they are
|
||||
* supported by the analyzers loaded into the specified engine. If the engine is specified as null then all files
|
||||
* are extracted.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @param engine the scanning engine
|
||||
* @throws ExtractionException thrown if there is an error extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo, Engine engine) throws ExtractionException {
|
||||
if (archive == null || extractTo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new ExtractionException("Archive file was not found.", ex);
|
||||
}
|
||||
zis = new ZipInputStream(new BufferedInputStream(fis));
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.isDirectory()) {
|
||||
final File d = new File(extractTo, entry.getName());
|
||||
if (!d.exists() && !d.mkdirs()) {
|
||||
final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
|
||||
throw new ExtractionException(msg);
|
||||
}
|
||||
} else {
|
||||
final File file = new File(extractTo, entry.getName());
|
||||
final String ext = getFileExtension(file.getName());
|
||||
if (engine == null || engine.supportsExtension(ext)) {
|
||||
BufferedOutputStream bos = null;
|
||||
FileOutputStream fos;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||
int count;
|
||||
final byte data[] = new byte[BUFFER_SIZE];
|
||||
while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
if (bos != null) {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
try {
|
||||
zis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bit bucket for the OS. '/dev/null' for Unix and 'NUL' for Windows
|
||||
*
|
||||
@@ -53,20 +53,24 @@ public final class LogUtils {
|
||||
try {
|
||||
LogManager.getLogManager().reset();
|
||||
LogManager.getLogManager().readConfiguration(in);
|
||||
|
||||
if (verboseLogFile != null && !verboseLogFile.isEmpty()) {
|
||||
verboseLoggingEnabled = true;
|
||||
final Logger logger = Logger.getLogger("");
|
||||
final FileHandler handler = new FileHandler(verboseLogFile, true);
|
||||
handler.setFormatter(new SimpleFormatter());
|
||||
handler.setLevel(Level.FINE);
|
||||
handler.setFilter(new LogFilter());
|
||||
logger.addHandler(handler);
|
||||
final FileHandler fileHandler = new FileHandler(verboseLogFile, true);
|
||||
fileHandler.setFormatter(new SimpleFormatter());
|
||||
fileHandler.setLevel(Level.FINE);
|
||||
fileHandler.setFilter(new LogFilter());
|
||||
|
||||
logger.addHandler(fileHandler);
|
||||
logger.setLevel(Level.FINE);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, "IO Error preparing the logger", ex);
|
||||
LOGGER.log(Level.WARNING, "IO Error preparing the logger", ex);
|
||||
} catch (SecurityException ex) {
|
||||
LOGGER.log(Level.FINE, "Error preparing the logger", ex);
|
||||
LOGGER.log(Level.WARNING, "Error preparing the logger", ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.WARNING, "Error preparing the logger", ex);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
@@ -78,6 +78,14 @@ public final class Settings {
|
||||
* The base path to use for the data directory (for embedded db).
|
||||
*/
|
||||
public static final String DATA_DIRECTORY = "data.directory";
|
||||
/**
|
||||
* The database file name.
|
||||
*/
|
||||
public static final String DB_FILE_NAME = "data.file_name";
|
||||
/**
|
||||
* The database schema version.
|
||||
*/
|
||||
public static final String DB_VERSION = "data.version";
|
||||
/**
|
||||
* The properties key for the URL to retrieve the "meta" data from about the CVE entries.
|
||||
*/
|
||||
@@ -97,7 +105,7 @@ public final class Settings {
|
||||
*/
|
||||
public static final String CVE_MODIFIED_VALID_FOR_DAYS = "cve.url.modified.validfordays";
|
||||
/**
|
||||
* The properties key for the telling us how many cvr.url.* URLs exists. This is used in combination with
|
||||
* The properties key for the telling us how many cve.url.* URLs exists. This is used in combination with
|
||||
* CVE_BASE_URL to be able to retrieve the URLs for all of the files that make up the NVD CVE listing.
|
||||
*/
|
||||
public static final String CVE_START_YEAR = "cve.startyear";
|
||||
@@ -110,9 +118,16 @@ public final class Settings {
|
||||
*/
|
||||
public static final String CVE_SCHEMA_2_0 = "cve.url-2.0.base";
|
||||
/**
|
||||
* The properties key for the proxy url.
|
||||
* The properties key for the proxy server.
|
||||
*
|
||||
* @deprecated use {@link org.owasp.dependencycheck.utils.Settings.KEYS#PROXY_SERVER} instead.
|
||||
*/
|
||||
public static final String PROXY_URL = "proxy.url";
|
||||
@Deprecated
|
||||
public static final String PROXY_URL = "proxy.server";
|
||||
/**
|
||||
* The properties key for the proxy server.
|
||||
*/
|
||||
public static final String PROXY_SERVER = "proxy.server";
|
||||
/**
|
||||
* The properties key for the proxy port - this must be an integer value.
|
||||
*/
|
||||
@@ -193,6 +208,28 @@ public final class Settings {
|
||||
* The properties key for whether Provided Scope dependencies should be skipped.
|
||||
*/
|
||||
public static final String SKIP_PROVIDED_SCOPE = "skip.provided.scope";
|
||||
|
||||
/**
|
||||
* The key to obtain the path to the VFEED data file.
|
||||
*/
|
||||
public static final String VFEED_DATA_FILE = "vfeed.data_file";
|
||||
/**
|
||||
* The key to obtain the VFEED connection string.
|
||||
*/
|
||||
public static final String VFEED_CONNECTION_STRING = "vfeed.connection_string";
|
||||
|
||||
/**
|
||||
* The key to obtain the base download URL for the VFeed data file.
|
||||
*/
|
||||
public static final String VFEED_DOWNLOAD_URL = "vfeed.download_url";
|
||||
/**
|
||||
* The key to obtain the download file name for the VFeed data.
|
||||
*/
|
||||
public static final String VFEED_DOWNLOAD_FILE = "vfeed.download_file";
|
||||
/**
|
||||
* The key to obtain the VFeed update status.
|
||||
*/
|
||||
public static final String VFEED_UPDATE_STATUS = "vfeed.update_status";
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
@@ -215,12 +252,14 @@ public final class Settings {
|
||||
|
||||
/**
|
||||
* Private constructor for the Settings class. This class loads the properties files.
|
||||
*
|
||||
* @param propertiesFilePath the path to the base properties file to load
|
||||
*/
|
||||
private Settings() {
|
||||
private Settings(String propertiesFilePath) {
|
||||
InputStream in = null;
|
||||
props = new Properties();
|
||||
try {
|
||||
in = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
|
||||
in = this.getClass().getClassLoader().getResourceAsStream(propertiesFilePath);
|
||||
props.load(in);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to load default settings.");
|
||||
@@ -242,14 +281,34 @@ public final class Settings {
|
||||
* However, you must also call Settings.cleanup() to properly release resources.
|
||||
*/
|
||||
public static void initialize() {
|
||||
localSettings.set(new Settings());
|
||||
localSettings.set(new Settings(PROPERTIES_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the thread local settings object. Note, to use the settings object you must call this method.
|
||||
* However, you must also call Settings.cleanup() to properly release resources.
|
||||
*
|
||||
* @param propertiesFilePath the path to the base properties file to load
|
||||
*/
|
||||
public static void initialize(String propertiesFilePath) {
|
||||
localSettings.set(new Settings(propertiesFilePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up resources to prevent memory leaks.
|
||||
*
|
||||
*/
|
||||
public static void cleanup() {
|
||||
if (tempDirectory != null && tempDirectory.exists()) {
|
||||
cleanup(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up resources to prevent memory leaks.
|
||||
*
|
||||
* @param deleteTemporary flag indicating whether any temporary directories generated should be removed
|
||||
*/
|
||||
public static void cleanup(boolean deleteTemporary) {
|
||||
if (deleteTemporary && tempDirectory != null && tempDirectory.exists()) {
|
||||
FileUtils.delete(tempDirectory);
|
||||
}
|
||||
try {
|
||||
@@ -353,8 +412,19 @@ public final class Settings {
|
||||
* @throws IOException is thrown when there is an exception loading/merging the properties
|
||||
*/
|
||||
public static void mergeProperties(File filePath) throws FileNotFoundException, IOException {
|
||||
final FileInputStream fis = new FileInputStream(filePath);
|
||||
mergeProperties(fis);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(filePath);
|
||||
mergeProperties(fis);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "close error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,8 +437,19 @@ public final class Settings {
|
||||
* @throws IOException is thrown when there is an exception loading/merging the properties
|
||||
*/
|
||||
public static void mergeProperties(String filePath) throws FileNotFoundException, IOException {
|
||||
final FileInputStream fis = new FileInputStream(filePath);
|
||||
mergeProperties(fis);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(filePath);
|
||||
mergeProperties(fis);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "close error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,7 +493,7 @@ public final class Settings {
|
||||
* @param key the key to lookup within the properties file
|
||||
* @return the property from the properties file converted to a File object
|
||||
*/
|
||||
public static File getDataFile(String key) {
|
||||
protected static File getDataFile(String key) {
|
||||
final String file = getString(key);
|
||||
LOGGER.log(Level.FINE, String.format("Settings.getDataFile() - file: '%s'", file));
|
||||
if (file == null) {
|
||||
@@ -612,4 +693,74 @@ public final class Settings {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a connection string from the configured properties. If the connection string contains a %s, this method
|
||||
* will determine the 'data' directory and replace the %s with the path to the data directory. If the data directory
|
||||
* does not exists it will be created.
|
||||
*
|
||||
* @param connectionStringKey the property file key for the connection string
|
||||
* @param dbFileNameKey the settings key for the db filename
|
||||
* @param dbVersionKey the settings key for the dbVersion
|
||||
* @return the connection string
|
||||
* @throws IOException thrown the data directory cannot be created
|
||||
* @throws InvalidSettingException thrown if there is an invalid setting
|
||||
*/
|
||||
public static String getConnectionString(String connectionStringKey, String dbFileNameKey, String dbVersionKey)
|
||||
throws IOException, InvalidSettingException {
|
||||
final String connStr = Settings.getString(connectionStringKey);
|
||||
if (connStr == null) {
|
||||
final String msg = String.format("Invalid properties file to get the connection string; '%s' must be defined.",
|
||||
connectionStringKey);
|
||||
throw new InvalidSettingException(msg);
|
||||
}
|
||||
if (connStr.contains("%s")) {
|
||||
final File directory = getDataDirectory();
|
||||
String fileName = null;
|
||||
if (dbFileNameKey != null) {
|
||||
fileName = Settings.getString(dbFileNameKey);
|
||||
}
|
||||
if (fileName == null) {
|
||||
final String msg = String.format("Invalid properties file to get a file based connection string; '%s' must be defined.",
|
||||
dbFileNameKey);
|
||||
throw new InvalidSettingException(msg);
|
||||
}
|
||||
if (fileName.contains("%s")) {
|
||||
String version = null;
|
||||
if (dbVersionKey != null) {
|
||||
version = Settings.getString(dbVersionKey);
|
||||
}
|
||||
if (version == null) {
|
||||
final String msg = String.format("Invalid properties file to get a file based connection string; '%s' must be defined.",
|
||||
dbFileNameKey);
|
||||
throw new InvalidSettingException(msg);
|
||||
}
|
||||
fileName = String.format(fileName, version);
|
||||
}
|
||||
if (connStr.startsWith("jdbc:h2:file:") && fileName.endsWith(".h2.db")) {
|
||||
fileName = fileName.substring(0, fileName.length() - 6);
|
||||
}
|
||||
// yes, for H2 this path won't actually exists - but this is sufficient to get the value needed
|
||||
final File dbFile = new File(directory, fileName);
|
||||
final String cString = String.format(connStr, dbFile.getCanonicalPath());
|
||||
LOGGER.log(Level.FINE, String.format("Connection String: '%s'", cString));
|
||||
return cString;
|
||||
}
|
||||
return connStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the directory that the JAR file exists in so that we can ensure we always use a common data directory
|
||||
* for the embedded H2 database. This is public solely for some unit tests; otherwise this should be private.
|
||||
*
|
||||
* @return the data directory to store data files
|
||||
* @throws IOException is thrown if an IOException occurs of course...
|
||||
*/
|
||||
public static File getDataDirectory() throws IOException {
|
||||
final File path = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
|
||||
if (path.exists() || path.mkdirs()) {
|
||||
return path;
|
||||
}
|
||||
throw new IOException(String.format("Unable to create the data directory '%s'", path.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
@@ -50,8 +50,8 @@ public final class URLConnectionFactory {
|
||||
*/
|
||||
public static HttpURLConnection createHttpURLConnection(URL url) throws URLConnectionFailureException {
|
||||
HttpURLConnection conn = null;
|
||||
Proxy proxy = null;
|
||||
final String proxyUrl = Settings.getString(Settings.KEYS.PROXY_URL);
|
||||
Proxy proxy;
|
||||
final String proxyUrl = Settings.getString(Settings.KEYS.PROXY_SERVER);
|
||||
try {
|
||||
if (proxyUrl != null) {
|
||||
final int proxyPort = Settings.getInt(Settings.KEYS.PROXY_PORT);
|
||||
@@ -96,7 +96,7 @@ public final class URLConnectionFactory {
|
||||
* Utility method to create an HttpURLConnection. The use of a proxy here is optional as there may be cases where a
|
||||
* proxy is configured but we don't want to use it (for example, if there's an internal repository configured)
|
||||
*
|
||||
* @param url the url to connect to
|
||||
* @param url the URL to connect to
|
||||
* @param proxy whether to use the proxy (if configured)
|
||||
* @return a newly constructed HttpURLConnection
|
||||
* @throws URLConnectionFailureException thrown if there is an exception
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.utils</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* Includes various utility classes such as a Settings wrapper, utilities to make URL Connections, etc.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
30
dependency-check-utils/src/site/site.xml
Normal file
30
dependency-check-utils/src/site/site.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!--
|
||||
This file is part of dependency-check-ant.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
<project name="dependency-check-ant">
|
||||
<bannerLeft>
|
||||
<name>dependency-check-utils</name>
|
||||
</bannerLeft>
|
||||
<body>
|
||||
<breadcrumbs>
|
||||
<item name="dependency-check" href="../index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu ref="Project Documentation" />
|
||||
<menu ref="reports" />
|
||||
</body>
|
||||
</project>
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2014 OWASP.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class BaseTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
Settings.initialize();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -21,7 +21,6 @@ import java.io.File;
|
||||
import java.net.URL;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -39,7 +38,7 @@ public class DownloaderIntegrationTest extends BaseTest {
|
||||
|
||||
// Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, "1000");
|
||||
// Settings.setString(Settings.KEYS.PROXY_PORT, "8080");
|
||||
// Settings.setString(Settings.KEYS.PROXY_URL, "127.0.0.1");
|
||||
// Settings.setString(Settings.KEYS.PROXY_SERVER, "127.0.0.1");
|
||||
URL url = new URL(Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL));
|
||||
File outputPath = new File("target/downloaded_cve.xml");
|
||||
Downloader.fetchFile(url, outputPath);
|
||||
@@ -19,12 +19,9 @@ package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,25 +29,9 @@ import org.junit.Test;
|
||||
*/
|
||||
public class DownloaderTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLastModified_file() throws Exception {
|
||||
File f = new File("target/test-classes/nvdcve-2.0-2012.xml");
|
||||
File f = new File("target/test-classes/dependencycheck.properties");
|
||||
URL url = new URL("file:///" + f.getCanonicalPath());
|
||||
long timestamp = Downloader.getLastModified(url);
|
||||
assertTrue("timestamp equal to zero?", timestamp > 0);
|
||||
@@ -23,7 +23,6 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -22,7 +22,6 @@ import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -158,4 +157,35 @@ public class SettingsTest extends BaseTest {
|
||||
ret = Settings.getString(key, dfault);
|
||||
Assert.assertEquals(dfault, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getConnectionString.
|
||||
*/
|
||||
@Test
|
||||
public void testGetConnectionString() throws Exception {
|
||||
String value = Settings.getConnectionString(Settings.KEYS.DB_CONNECTION_STRING, Settings.KEYS.DB_FILE_NAME, Settings.KEYS.DB_VERSION);
|
||||
Assert.assertNotNull(value);
|
||||
String msg = null;
|
||||
try {
|
||||
value = Settings.getConnectionString(Settings.KEYS.DB_CONNECTION_STRING, Settings.KEYS.DB_FILE_NAME, null);
|
||||
} catch (InvalidSettingException e) {
|
||||
msg = e.getMessage();
|
||||
}
|
||||
Assert.assertNotNull(msg, msg);
|
||||
try {
|
||||
value = Settings.getConnectionString("invalidKey", null, null);
|
||||
} catch (InvalidSettingException e) {
|
||||
msg = e.getMessage();
|
||||
}
|
||||
Assert.assertNotNull(msg, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getTempDirectory.
|
||||
*/
|
||||
@Test
|
||||
public void testGetTempDirectory() throws Exception {
|
||||
File tmp = Settings.getTempDirectory();
|
||||
Assert.assertTrue(tmp.exists());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
application.name=${pom.name}
|
||||
application.version=${pom.version}
|
||||
autoupdate=true
|
||||
max.download.threads=3
|
||||
|
||||
#temp.directory defaults to System.getProperty("java.io.tmpdir")
|
||||
#temp.directory=[path to temp directory]
|
||||
|
||||
# the path to the data directory; the [JAR] signifies to use the relative path
|
||||
# to the dependency-check-core JAR file. This path is only used to construct
|
||||
# the connection string for the H2 driver (or other drivers that require a file path
|
||||
# to be supplied. If you are using another database (MySQL, Oracle, etc.) this property
|
||||
# will not be used. The data.directory will be resolved and if the connection string
|
||||
# below contains a %s then the data.directory will replace the %s.
|
||||
data.directory=[JAR]/data
|
||||
data.file_name=cve.%s.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
# user name and password for the database connection. The inherent case is to use H2.
|
||||
# As such, this unsecure username/password exist.
|
||||
data.user=dcuser
|
||||
data.password=DC-Pass1337!
|
||||
# The following are only used if the DB Driver is not JDBC4 compliant and/or the driver
|
||||
# is not in the current classpath. Setting these properties will add the give path(s) to
|
||||
# the class loader and then register the driver with the DriverManager. If the class is
|
||||
# not in the path you must specify both the driver name (aka the fully qualified driver name)
|
||||
# and the driver path. The driver path can be a semi-colon separated list of files/directories
|
||||
# to ensure any and all needed files can be added to the classpath to load the driver.
|
||||
# For non-JDBC4 drivers in the classpath only the driver_name needs to be set.
|
||||
# For MOST situations these properties likely do not need to be set.
|
||||
data.driver_name=org.h2.Driver
|
||||
data.driver_path=
|
||||
|
||||
# the path to the cpe xml file
|
||||
cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.xml.gz
|
||||
# the path to the cpe meta data file.
|
||||
cpe.meta.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.meta
|
||||
|
||||
# the number of days that the modified nvd cve data holds data for. We don't need
|
||||
# to update the other files if we are within this timespan. Per NIST this file
|
||||
# holds 8 days of updates, we are using 7 just to be safe.
|
||||
cve.url.modified.validfordays=7
|
||||
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2014
|
||||
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
|
||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||
analyzer.nexus.enabled=true
|
||||
analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||
# are configured
|
||||
analyzer.nexus.proxy=true
|
||||
@@ -0,0 +1 @@
|
||||
proxy.port=80
|
||||
15
pom.xml
15
pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.5</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
@@ -29,10 +29,11 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<module>dependency-check-ant</module>
|
||||
<module>dependency-check-maven</module>
|
||||
<module>dependency-check-jenkins</module>
|
||||
<module>dependency-check-utils</module>
|
||||
</modules>
|
||||
<name>Dependency-Check</name>
|
||||
<url>https://github.com/jeremylong/DependencyCheck.git</url>
|
||||
<description>dependency-check is a utility that identifies project dependencies and checks if there are any known, publicly disclosed, vulnerabilities. This tool can be part of the solution to the OWASP Top 10 2013: A9 - Using Components with Known Vulnerabilities.</description>
|
||||
<description>dependency-check is a utility that identifies project dependencies and checks if there are any known, publicly disclosed vulnerabilities. This tool can be part of the solution to the OWASP Top 10 2013: A9 - Using Components with Known Vulnerabilities.</description>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
|
||||
<organization>
|
||||
@@ -140,14 +141,6 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-13 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -244,4 +237,4 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
16
src/site/markdown/archive-analyzer.md
Normal file
16
src/site/markdown/archive-analyzer.md
Normal file
@@ -0,0 +1,16 @@
|
||||
Archive Analyzer
|
||||
==============
|
||||
|
||||
Dependency-check includes an analyzer an archive analyzer that will attempt
|
||||
to extract files from the archive that are supported by the other file type
|
||||
analyzers.
|
||||
|
||||
Files Types Scanned: ZIP, EAR, WAR, JAR, SAR, APK, NUPKG, TAR, GZ, TGZ
|
||||
|
||||
Additional file extensions for ZIP archives can be added, see the configuration
|
||||
section in the Maven, Ant, or CLI interfaces for more information on configuration.
|
||||
|
||||
Note, since this analyzer does examine the contents of a JAR file there are times
|
||||
that you may see additional entries in the report and/or warnings in the log file (if used)
|
||||
for DLL or EXE files contained within the JAR file. In almost all cases these can
|
||||
be ignored as it is fairly rare to have a .NET dll or exe within a JAR file.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user