mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-13 23:33:37 +01:00
Fixed merge conflict in App.java
This commit is contained in:
@@ -1,25 +1,134 @@
|
||||
Dependency-Check Ant Task
|
||||
Dependency-Check-Gradle
|
||||
=========
|
||||
|
||||
Dependency-Check Ant Task can be used to check the project dependencies for published security vulnerabilities. The checks
|
||||
performed are a "best effort" and as such, there could be false positives as well as false negatives. However,
|
||||
vulnerabilities in 3rd party components is a well-known problem and is currently documented in the 2013 OWASP
|
||||
Top 10 as [A9 - Using Components with Known Vulnerabilities](https://www.owasp.org/index.php/Top_10_2013-A9-Using_Components_with_Known_Vulnerabilities).
|
||||
**Working in progress**
|
||||
|
||||
Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/installation.html).
|
||||
This is a DependencyCheck gradle plugin designed for project which use Gradle as build script.
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
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.
|
||||
|
||||
Subscribe: [dependency-check+subscribe@googlegroups.com](mailto:dependency-check+subscribe@googlegroups.com)
|
||||
=========
|
||||
|
||||
Post: [dependency-check@googlegroups.com](mailto:dependency-check@googlegroups.com)
|
||||
## What's New
|
||||
Current latest version is `0.0.8`
|
||||
|
||||
Copyright & License
|
||||
-------------------
|
||||
## Usage
|
||||
|
||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
||||
### Step 1, Apply dependency check gradle plugin
|
||||
|
||||
Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://raw.githubusercontent.com/jeremylong/DependencyCheck/master/LICENSE.txt) file for the full license.
|
||||
Install from Maven central repo
|
||||
|
||||
Dependency-Check-Ant makes use of other open source libraries. Please see the [NOTICE.txt](https://raw.githubusercontent.com/jeremylong/DependencyCheck/master/dependency-check-ant/NOTICE.txt) file for more information.
|
||||
```groovy
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.owasp:dependency-check-gradle:1.3.2'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'dependency-check-gradle'
|
||||
```
|
||||
|
||||
### Step 2, Run gradle task
|
||||
|
||||
Once gradle plugin applied, run following gradle task to check dependencies:
|
||||
|
||||
```
|
||||
gradle dependencyCheck --info
|
||||
```
|
||||
|
||||
The reports will be generated automatically under `./reports` folder.
|
||||
|
||||
If your project includes multiple sub-projects, the report will be generated for each sub-project in different sub-directory.
|
||||
|
||||
## FAQ
|
||||
|
||||
> **Questions List:**
|
||||
> - What if I'm behind a proxy?
|
||||
> - What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?
|
||||
> - How to customize the report directory?
|
||||
|
||||
### What if I'm behind a proxy?
|
||||
|
||||
Maybe you have to use proxy to access internet, in this case, you could configure proxy settings for this plugin:
|
||||
|
||||
```groovy
|
||||
dependencyCheck {
|
||||
proxy {
|
||||
server = "127.0.0.1" // required, the server name or IP address of the proxy
|
||||
port = 3128 // required, the port number of the proxy
|
||||
|
||||
// optional, the proxy server might require username
|
||||
// username = "username"
|
||||
|
||||
// optional, the proxy server might require password
|
||||
// password = "password"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In addition, if the proxy only allow HTTP `GET` or `POST` methods, you will find that the update process will always fail,
|
||||
the root cause is that every time you run `dependencyCheck` task, it will try to query the latest timestamp to determine whether need to perform an update action,
|
||||
and for performance reason the HTTP method it uses by default is `HEAD`, which probably is disabled or not supported by the proxy. To avoid this problem, you can simply change the HTTP method by below configuration:
|
||||
|
||||
```groovy
|
||||
dependencyCheck {
|
||||
quickQueryTimestamp = false // when set to false, it means use HTTP GET method to query timestamp. (default value is true)
|
||||
}
|
||||
```
|
||||
|
||||
### What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?
|
||||
|
||||
Try put 'apply plugin: "dependency-check"' inside the 'allprojects' or 'subprojects' if you'd like to check all sub-projects only, see below:
|
||||
|
||||
(1) For all projects including root project:
|
||||
|
||||
```groovy
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "gradle.plugin.com.tools.security:dependency-check:0.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: "dependency-check"
|
||||
}
|
||||
```
|
||||
|
||||
(2) For all sub-projects:
|
||||
|
||||
```groovy
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "gradle.plugin.com.tools.security:dependency-check:0.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: "dependency-check"
|
||||
}
|
||||
```
|
||||
|
||||
In this way, the dependency check will be executed for all projects (including root project) or just sub projects.
|
||||
|
||||
### How to customize the report directory?
|
||||
|
||||
By default, all reports will be placed under `./reports` folder, to change the default directory, just modify it in the configuration section like this:
|
||||
|
||||
```groovy
|
||||
subprojects {
|
||||
apply plugin: "dependency-check"
|
||||
|
||||
dependencyCheck {
|
||||
outputDirectory = "./customized-path/security-report"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<version>1.3.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
|
||||
@@ -245,14 +245,14 @@ public class Check extends Update {
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
|
||||
* is true.
|
||||
*/
|
||||
private boolean autoUpdate = true;
|
||||
private Boolean autoUpdate;
|
||||
|
||||
/**
|
||||
* Get the value of autoUpdate.
|
||||
*
|
||||
* @return the value of autoUpdate
|
||||
*/
|
||||
public boolean isAutoUpdate() {
|
||||
public Boolean isAutoUpdate() {
|
||||
return autoUpdate;
|
||||
}
|
||||
|
||||
@@ -261,19 +261,24 @@ public class Check extends Update {
|
||||
*
|
||||
* @param autoUpdate new value of autoUpdate
|
||||
*/
|
||||
public void setAutoUpdate(boolean autoUpdate) {
|
||||
public void setAutoUpdate(Boolean autoUpdate) {
|
||||
this.autoUpdate = autoUpdate;
|
||||
}
|
||||
/**
|
||||
* Whether only the update phase should be executed.
|
||||
*
|
||||
* @deprecated Use the update task instead
|
||||
*/
|
||||
@Deprecated
|
||||
private boolean updateOnly = false;
|
||||
|
||||
/**
|
||||
* Get the value of updateOnly.
|
||||
*
|
||||
* @return the value of updateOnly
|
||||
* @deprecated Use the update task instead
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isUpdateOnly() {
|
||||
return updateOnly;
|
||||
}
|
||||
@@ -282,7 +287,9 @@ public class Check extends Update {
|
||||
* Set the value of updateOnly.
|
||||
*
|
||||
* @param updateOnly new value of updateOnly
|
||||
* @deprecated Use the update task instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setUpdateOnly(boolean updateOnly) {
|
||||
this.updateOnly = updateOnly;
|
||||
}
|
||||
@@ -357,14 +364,14 @@ public class Check extends Update {
|
||||
/**
|
||||
* Whether or not the Jar Analyzer is enabled.
|
||||
*/
|
||||
private boolean jarAnalyzerEnabled = true;
|
||||
private Boolean jarAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isJarAnalyzerEnabled() {
|
||||
public Boolean isJarAnalyzerEnabled() {
|
||||
return jarAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -373,33 +380,33 @@ public class Check extends Update {
|
||||
*
|
||||
* @param jarAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setJarAnalyzerEnabled(boolean jarAnalyzerEnabled) {
|
||||
public void setJarAnalyzerEnabled(Boolean jarAnalyzerEnabled) {
|
||||
this.jarAnalyzerEnabled = jarAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the Archive Analyzer is enabled.
|
||||
*/
|
||||
private boolean archiveAnalyzerEnabled = true;
|
||||
private Boolean archiveAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isArchiveAnalyzerEnabled() {
|
||||
public Boolean isArchiveAnalyzerEnabled() {
|
||||
return archiveAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the .NET Assembly Analyzer is enabled.
|
||||
*/
|
||||
private boolean assemblyAnalyzerEnabled = true;
|
||||
private Boolean assemblyAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Sets whether or not the analyzer is enabled.
|
||||
*
|
||||
* @param archiveAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setArchiveAnalyzerEnabled(boolean archiveAnalyzerEnabled) {
|
||||
public void setArchiveAnalyzerEnabled(Boolean archiveAnalyzerEnabled) {
|
||||
this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -408,7 +415,7 @@ public class Check extends Update {
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isAssemblyAnalyzerEnabled() {
|
||||
public Boolean isAssemblyAnalyzerEnabled() {
|
||||
return assemblyAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -417,20 +424,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param assemblyAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setAssemblyAnalyzerEnabled(boolean assemblyAnalyzerEnabled) {
|
||||
public void setAssemblyAnalyzerEnabled(Boolean assemblyAnalyzerEnabled) {
|
||||
this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the .NET Nuspec Analyzer is enabled.
|
||||
*/
|
||||
private boolean nuspecAnalyzerEnabled = true;
|
||||
private Boolean nuspecAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isNuspecAnalyzerEnabled() {
|
||||
public Boolean isNuspecAnalyzerEnabled() {
|
||||
return nuspecAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -439,20 +446,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param nuspecAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
|
||||
public void setNuspecAnalyzerEnabled(Boolean nuspecAnalyzerEnabled) {
|
||||
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the PHP Composer Analyzer is enabled.
|
||||
*/
|
||||
private boolean composerAnalyzerEnabled = true;
|
||||
private Boolean composerAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of composerAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of composerAnalyzerEnabled
|
||||
*/
|
||||
public boolean isComposerAnalyzerEnabled() {
|
||||
public Boolean isComposerAnalyzerEnabled() {
|
||||
return composerAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -461,20 +468,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param composerAnalyzerEnabled new value of composerAnalyzerEnabled
|
||||
*/
|
||||
public void setComposerAnalyzerEnabled(boolean composerAnalyzerEnabled) {
|
||||
public void setComposerAnalyzerEnabled(Boolean composerAnalyzerEnabled) {
|
||||
this.composerAnalyzerEnabled = composerAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the autoconf analyzer should be enabled.
|
||||
*/
|
||||
private boolean autoconfAnalyzerEnabled = true;
|
||||
private Boolean autoconfAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of autoconfAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of autoconfAnalyzerEnabled
|
||||
*/
|
||||
public boolean isAutoconfAnalyzerEnabled() {
|
||||
public Boolean isAutoconfAnalyzerEnabled() {
|
||||
return autoconfAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -483,20 +490,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param autoconfAnalyzerEnabled new value of autoconfAnalyzerEnabled
|
||||
*/
|
||||
public void setAutoconfAnalyzerEnabled(boolean autoconfAnalyzerEnabled) {
|
||||
public void setAutoconfAnalyzerEnabled(Boolean autoconfAnalyzerEnabled) {
|
||||
this.autoconfAnalyzerEnabled = autoconfAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the CMake analyzer should be enabled.
|
||||
*/
|
||||
private boolean cmakeAnalyzerEnabled = true;
|
||||
private Boolean cmakeAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of cmakeAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of cmakeAnalyzerEnabled
|
||||
*/
|
||||
public boolean isCMakeAnalyzerEnabled() {
|
||||
public Boolean isCMakeAnalyzerEnabled() {
|
||||
return cmakeAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -505,20 +512,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param cmakeAnalyzerEnabled new value of cmakeAnalyzerEnabled
|
||||
*/
|
||||
public void setCMakeAnalyzerEnabled(boolean cmakeAnalyzerEnabled) {
|
||||
public void setCMakeAnalyzerEnabled(Boolean cmakeAnalyzerEnabled) {
|
||||
this.cmakeAnalyzerEnabled = cmakeAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the openssl analyzer is enabled.
|
||||
*/
|
||||
private boolean opensslAnalyzerEnabled = true;
|
||||
private Boolean opensslAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of opensslAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of opensslAnalyzerEnabled
|
||||
*/
|
||||
public boolean isOpensslAnalyzerEnabled() {
|
||||
public Boolean isOpensslAnalyzerEnabled() {
|
||||
return opensslAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -527,20 +534,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param opensslAnalyzerEnabled new value of opensslAnalyzerEnabled
|
||||
*/
|
||||
public void setOpensslAnalyzerEnabled(boolean opensslAnalyzerEnabled) {
|
||||
public void setOpensslAnalyzerEnabled(Boolean opensslAnalyzerEnabled) {
|
||||
this.opensslAnalyzerEnabled = opensslAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the Node.js Analyzer is enabled.
|
||||
*/
|
||||
private boolean nodeAnalyzerEnabled = true;
|
||||
private Boolean nodeAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of nodeAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of nodeAnalyzerEnabled
|
||||
*/
|
||||
public boolean isNodeAnalyzerEnabled() {
|
||||
public Boolean isNodeAnalyzerEnabled() {
|
||||
return nodeAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -549,20 +556,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param nodeAnalyzerEnabled new value of nodeAnalyzerEnabled
|
||||
*/
|
||||
public void setNodeAnalyzerEnabled(boolean nodeAnalyzerEnabled) {
|
||||
public void setNodeAnalyzerEnabled(Boolean nodeAnalyzerEnabled) {
|
||||
this.nodeAnalyzerEnabled = nodeAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the ruby gemspec analyzer should be enabled.
|
||||
*/
|
||||
private boolean rubygemsAnalyzerEnabled = true;
|
||||
private Boolean rubygemsAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of rubygemsAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of rubygemsAnalyzerEnabled
|
||||
*/
|
||||
public boolean isRubygemsAnalyzerEnabled() {
|
||||
public Boolean isRubygemsAnalyzerEnabled() {
|
||||
return rubygemsAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -571,20 +578,20 @@ public class Check extends Update {
|
||||
*
|
||||
* @param rubygemsAnalyzerEnabled new value of rubygemsAnalyzerEnabled
|
||||
*/
|
||||
public void setRubygemsAnalyzerEnabled(boolean rubygemsAnalyzerEnabled) {
|
||||
public void setRubygemsAnalyzerEnabled(Boolean rubygemsAnalyzerEnabled) {
|
||||
this.rubygemsAnalyzerEnabled = rubygemsAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the python package analyzer should be enabled.
|
||||
*/
|
||||
private boolean pyPackageAnalyzerEnabled = true;
|
||||
private Boolean pyPackageAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of pyPackageAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of pyPackageAnalyzerEnabled
|
||||
*/
|
||||
public boolean isPyPackageAnalyzerEnabled() {
|
||||
public Boolean isPyPackageAnalyzerEnabled() {
|
||||
return pyPackageAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -593,21 +600,21 @@ public class Check extends Update {
|
||||
*
|
||||
* @param pyPackageAnalyzerEnabled new value of pyPackageAnalyzerEnabled
|
||||
*/
|
||||
public void setPyPackageAnalyzerEnabled(boolean pyPackageAnalyzerEnabled) {
|
||||
public void setPyPackageAnalyzerEnabled(Boolean pyPackageAnalyzerEnabled) {
|
||||
this.pyPackageAnalyzerEnabled = pyPackageAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the python distribution analyzer should be enabled.
|
||||
*/
|
||||
private boolean pyDistributionAnalyzerEnabled = true;
|
||||
private Boolean pyDistributionAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of pyDistributionAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of pyDistributionAnalyzerEnabled
|
||||
*/
|
||||
public boolean isPyDistributionAnalyzerEnabled() {
|
||||
public Boolean isPyDistributionAnalyzerEnabled() {
|
||||
return pyDistributionAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -616,21 +623,21 @@ public class Check extends Update {
|
||||
*
|
||||
* @param pyDistributionAnalyzerEnabled new value of pyDistributionAnalyzerEnabled
|
||||
*/
|
||||
public void setPyDistributionAnalyzerEnabled(boolean pyDistributionAnalyzerEnabled) {
|
||||
public void setPyDistributionAnalyzerEnabled(Boolean pyDistributionAnalyzerEnabled) {
|
||||
this.pyDistributionAnalyzerEnabled = pyDistributionAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the central analyzer is enabled.
|
||||
*/
|
||||
private boolean centralAnalyzerEnabled = false;
|
||||
private Boolean centralAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of centralAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of centralAnalyzerEnabled
|
||||
*/
|
||||
public boolean isCentralAnalyzerEnabled() {
|
||||
public Boolean isCentralAnalyzerEnabled() {
|
||||
return centralAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -639,21 +646,21 @@ public class Check extends Update {
|
||||
*
|
||||
* @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
|
||||
*/
|
||||
public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
|
||||
public void setCentralAnalyzerEnabled(Boolean centralAnalyzerEnabled) {
|
||||
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the nexus analyzer is enabled.
|
||||
*/
|
||||
private boolean nexusAnalyzerEnabled = true;
|
||||
private Boolean nexusAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of nexusAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of nexusAnalyzerEnabled
|
||||
*/
|
||||
public boolean isNexusAnalyzerEnabled() {
|
||||
public Boolean isNexusAnalyzerEnabled() {
|
||||
return nexusAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -662,7 +669,7 @@ public class Check extends Update {
|
||||
*
|
||||
* @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
|
||||
*/
|
||||
public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
|
||||
public void setNexusAnalyzerEnabled(Boolean nexusAnalyzerEnabled) {
|
||||
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
||||
}
|
||||
|
||||
@@ -691,14 +698,14 @@ public class Check extends Update {
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
private boolean nexusUsesProxy = true;
|
||||
private Boolean nexusUsesProxy;
|
||||
|
||||
/**
|
||||
* Get the value of nexusUsesProxy.
|
||||
*
|
||||
* @return the value of nexusUsesProxy
|
||||
*/
|
||||
public boolean isNexusUsesProxy() {
|
||||
public Boolean isNexusUsesProxy() {
|
||||
return nexusUsesProxy;
|
||||
}
|
||||
|
||||
@@ -707,7 +714,7 @@ public class Check extends Update {
|
||||
*
|
||||
* @param nexusUsesProxy new value of nexusUsesProxy
|
||||
*/
|
||||
public void setNexusUsesProxy(boolean nexusUsesProxy) {
|
||||
public void setNexusUsesProxy(Boolean nexusUsesProxy) {
|
||||
this.nexusUsesProxy = nexusUsesProxy;
|
||||
}
|
||||
|
||||
@@ -839,42 +846,32 @@ public class Check extends Update {
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||
* required to change the proxy server, port, and connection timeout.
|
||||
*
|
||||
* @throws BuildException thrown when an invalid setting is configured.
|
||||
*/
|
||||
@Override
|
||||
protected void populateSettings() {
|
||||
protected void populateSettings() throws BuildException {
|
||||
super.populateSettings();
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, pyPackageAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, rubygemsAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, opensslAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED, cmakeAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, autoconfAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled);
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
|
||||
if (zipExtensions != null && !zipExtensions.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, pyPackageAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, rubygemsAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, opensslAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CMAKE_ENABLED, cmakeAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, autoconfAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -357,6 +357,26 @@ public class Update extends Purge {
|
||||
this.cveUrl20Base = cveUrl20Base;
|
||||
}
|
||||
|
||||
private Integer cveValidForHours;
|
||||
|
||||
/**
|
||||
* Get the value of cveValidForHours
|
||||
*
|
||||
* @return the value of cveValidForHours
|
||||
*/
|
||||
public Integer getCveValidForHours() {
|
||||
return cveValidForHours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveValidForHours
|
||||
*
|
||||
* @param cveValidForHours new value of cveValidForHours
|
||||
*/
|
||||
public void setCveValidForHours(Integer cveValidForHours) {
|
||||
this.cveValidForHours = cveValidForHours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the update by initializing the settings, downloads the NVD XML data, and then processes the data storing it in the
|
||||
* local database.
|
||||
@@ -383,51 +403,32 @@ public class Update extends Purge {
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||
* required to change the proxy server, port, and connection timeout.
|
||||
*
|
||||
* @throws BuildException thrown when an invalid setting is configured.
|
||||
*/
|
||||
@Override
|
||||
protected void populateSettings() {
|
||||
protected void populateSettings() throws BuildException {
|
||||
super.populateSettings();
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
}
|
||||
if (proxyUsername != null && !proxyUsername.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||
}
|
||||
if (proxyPassword != null && !proxyPassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||
}
|
||||
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
}
|
||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
}
|
||||
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
}
|
||||
if (connectionString != null && !connectionString.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
}
|
||||
if (databaseUser != null && !databaseUser.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_USER, databaseUser);
|
||||
}
|
||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
}
|
||||
if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
}
|
||||
if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
}
|
||||
if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
}
|
||||
if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
if (cveValidForHours != null) {
|
||||
if (cveValidForHours >= 0) {
|
||||
Settings.setInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||
} else {
|
||||
throw new BuildException("Invalid setting: `cpeValidForHours` must be 0 or greater");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ may be the cvedUrl properties, which can be used to host a mirror of the NVD wit
|
||||
|
||||
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
|
||||
cveUrl12Modified | URL for the modified CVE 1.2. | https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
cveUrl20Modified | URL for the modified CVE 2.0. | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year. | https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
dataDirectory | Data directory that is used to store the local copy of the NVD. This should generally not be changed. | data
|
||||
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. |
|
||||
|
||||
@@ -29,19 +29,20 @@ Configuration: dependency-check Task
|
||||
--------------------
|
||||
The following properties can be set on the dependency-check-update task.
|
||||
|
||||
Property | Description | Default Value
|
||||
----------------------|------------------------------------|------------------
|
||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||
projectName | The name of the project being scanned. | Dependency-Check
|
||||
reportOutputDirectory | 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
|
||||
reportFormat | 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
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
Property | Description | Default Value
|
||||
----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------
|
||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||
cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD | 4
|
||||
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
|
||||
projectName | The name of the project being scanned. | Dependency-Check
|
||||
reportFormat | 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
|
||||
reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
|
||||
Analyzer Configuration
|
||||
====================
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<version>1.3.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
|
||||
@@ -280,6 +280,7 @@ public class App {
|
||||
final String cveMod20 = cli.getModifiedCve20Url();
|
||||
final String cveBase12 = cli.getBaseCve12Url();
|
||||
final String cveBase20 = cli.getBaseCve20Url();
|
||||
final Integer cveValidForHours = cli.getCveValidForHours();
|
||||
|
||||
if (propertiesFile != null) {
|
||||
try {
|
||||
@@ -309,24 +310,13 @@ public class App {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
}
|
||||
if (proxyUser != null && !proxyUser.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUser);
|
||||
}
|
||||
if (proxyPass != null && !proxyPass.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPass);
|
||||
}
|
||||
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
}
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPass);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||
|
||||
//File Type Analyzer Settings
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !cli.isJarDisabled());
|
||||
@@ -342,38 +332,19 @@ public class App {
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, !cli.isComposerDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, !cli.isNodeJsDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, !cli.isRubyGemspecDisabled());
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, !cli.isCentralDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !cli.isNexusDisabled());
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
}
|
||||
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
}
|
||||
if (connectionString != null && !connectionString.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
}
|
||||
if (databaseUser != null && !databaseUser.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_USER, databaseUser);
|
||||
}
|
||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
}
|
||||
if (additionalZipExtensions != null && !additionalZipExtensions.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
|
||||
}
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
String pathToBundleAudit = cli.getPathToBundleAudit();
|
||||
if (!StringUtils.isEmpty(pathToBundleAudit)){
|
||||
Settings.setString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, pathToBundleAudit);
|
||||
}
|
||||
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, cli.getPathToBundleAudit());
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
if (cveBase12 != null && !cveBase12.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveBase12);
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveBase20);
|
||||
|
||||
@@ -90,6 +90,19 @@ public final class CliParser {
|
||||
* @throws ParseException is thrown if there is an exception parsing the command line.
|
||||
*/
|
||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
||||
if (isUpdateOnly() || isRunScan()) {
|
||||
String value = line.getOptionValue(ARGUMENT.CVE_VALID_FOR_HOURS);
|
||||
if (value != null) {
|
||||
try {
|
||||
int i = Integer.parseInt(value);
|
||||
if (i < 0) {
|
||||
throw new ParseException("Invalid Setting: cveValidForHours must be a number greater than or equal to 0.");
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new ParseException("Invalid Setting: cveValidForHours must be a number greater than or equal to 0.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRunScan()) {
|
||||
validatePathExists(getScanFiles(), ARGUMENT.SCAN);
|
||||
validatePathExists(getReportDirectory(), ARGUMENT.OUT);
|
||||
@@ -255,6 +268,10 @@ public final class CliParser {
|
||||
.desc("The file path to the suppression XML file.")
|
||||
.build();
|
||||
|
||||
final Option cveValidForHours = Option.builder().argName("hours").hasArg().longOpt(ARGUMENT.CVE_VALID_FOR_HOURS)
|
||||
.desc("The number of hours to wait before checking for new updates from the NVD.")
|
||||
.build();
|
||||
|
||||
//This is an option group because it can be specified more then once.
|
||||
final OptionGroup og = new OptionGroup();
|
||||
og.addOption(path);
|
||||
@@ -274,7 +291,8 @@ public final class CliParser {
|
||||
.addOption(symLinkDepth)
|
||||
.addOption(props)
|
||||
.addOption(verboseLog)
|
||||
.addOption(suppressionFile);
|
||||
.addOption(suppressionFile)
|
||||
.addOption(cveValidForHours);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -672,7 +690,7 @@ public final class CliParser {
|
||||
// still honor the property if it's set.
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
|
||||
try {
|
||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
|
||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY);
|
||||
} catch (InvalidSettingException ise) {
|
||||
return true;
|
||||
}
|
||||
@@ -997,6 +1015,19 @@ public final class CliParser {
|
||||
return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of cveValidForHours
|
||||
*
|
||||
* @return the value of cveValidForHours
|
||||
*/
|
||||
public Integer getCveValidForHours() {
|
||||
String v = line.getOptionValue(ARGUMENT.CVE_VALID_FOR_HOURS);
|
||||
if (v != null) {
|
||||
return Integer.parseInt(v);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of static final strings that represent the possible command line arguments.
|
||||
*/
|
||||
@@ -1160,6 +1191,10 @@ public final class CliParser {
|
||||
* The CLI argument name for setting the location of the suppression file.
|
||||
*/
|
||||
public static final String SUPPRESSION_FILE = "suppression";
|
||||
/**
|
||||
* The CLI argument name for setting the location of the suppression file.
|
||||
*/
|
||||
public static final String CVE_VALID_FOR_HOURS = "cveValidForHours";
|
||||
/**
|
||||
* Disables the Jar Analyzer.
|
||||
*/
|
||||
|
||||
@@ -17,15 +17,17 @@ Short | Argument Name | Parameter | Description | Requir
|
||||
\-h | \-\-help | | Print the help message. | Optional
|
||||
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
||||
\-v | \-\-version | | Print the version information. | Optional
|
||||
| \-\-cveValidForHours | \<hours\> | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional
|
||||
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|----------------------------------------------------------------------------------|-------------------
|
||||
| \-\-cveUrl12Modified | \<url\> | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
| \-\-cveUrl20Modified | \<url\> | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
| \-\-cveUrl12Base | \<url\> | 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 | \<url\> | 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
|
||||
| \-\-cveUrl12Modified | \<url\> | URL for the modified CVE 1.2 | https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
| \-\-cveUrl20Modified | \<url\> | URL for the modified CVE 2.0 | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
| \-\-cveUrl12Base | \<url\> | Base URL for each year's CVE 1.2, the %d will be replaced with the year | https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
| \-\-cveUrl20Base | \<url\> | Base URL for each year's CVE 2.0, the %d will be replaced with the year | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
\-P | \-\-propertyfile | \<file\> | Specifies a file that contains properties to use instead of applicaion defaults. |
|
||||
| \-\-updateonly | | If set only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. |
|
||||
| \-\-disablePyDist | | Sets whether the Python Distribution Analyzer will be used. | false
|
||||
|
||||
@@ -25,10 +25,10 @@ your homebrew installation.
|
||||
To scan a folder on the system you can run:
|
||||
|
||||
$H$H$H Windows
|
||||
dependency-check.bat --app "My App Name" --scan "c:\java\application\lib"
|
||||
dependency-check.bat --project "My App Name" --scan "c:\java\application\lib"
|
||||
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --app "My App Name" --scan "/java/application/lib"
|
||||
dependency-check.sh --project "My App Name" --scan "/java/application/lib"
|
||||
|
||||
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<version>1.3.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
@@ -468,7 +468,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.18.1</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
@@ -476,12 +475,68 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.18.1</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.driver_path</name>
|
||||
<value>${basedir}/${driver_path}</value>
|
||||
<value>${driver_path}</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>data.driver_name</name>
|
||||
<value>${driver_name}</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>data.connection_string</name>
|
||||
<value>${connection_string}</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*MySQLTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>Postgresql-IntegrationTest</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>postgresql</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1204-jdbc42</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.driver_path</name>
|
||||
<value>${driver_path}</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>data.driver_name</name>
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -174,8 +175,7 @@ public class Engine implements FileFilter {
|
||||
public List<Dependency> scan(String[] paths) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (String path : paths) {
|
||||
final File file = new File(path);
|
||||
final List<Dependency> d = scan(file);
|
||||
final List<Dependency> d = scan(path);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
@@ -215,33 +215,14 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* Scans a collection of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public List<Dependency> scan(Set<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public List<Dependency> scan(List<File> files) {
|
||||
public List<Dependency> scan(Collection<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
final List<Dependency> d = scan(file);
|
||||
|
||||
@@ -840,8 +840,7 @@ public class DependencyCheckScanAgent {
|
||||
*/
|
||||
private Engine executeDependencyCheck() throws DatabaseException {
|
||||
populateSettings();
|
||||
Engine engine = null;
|
||||
engine = new Engine();
|
||||
final Engine engine = new Engine();
|
||||
engine.setDependencies(this.dependencies);
|
||||
engine.analyzeDependencies();
|
||||
return engine;
|
||||
@@ -898,67 +897,28 @@ public class DependencyCheckScanAgent {
|
||||
}
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
}
|
||||
if (proxyUsername != null && !proxyUsername.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||
}
|
||||
if (proxyPassword != null && !proxyPassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||
}
|
||||
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
}
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
|
||||
if (centralUrl != null && !centralUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
|
||||
}
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
}
|
||||
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
}
|
||||
if (connectionString != null && !connectionString.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
}
|
||||
if (databaseUser != null && !databaseUser.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_USER, databaseUser);
|
||||
}
|
||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
}
|
||||
if (zipExtensions != null && !zipExtensions.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||
}
|
||||
if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
}
|
||||
if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
}
|
||||
if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
}
|
||||
if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
}
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -214,7 +214,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
* @return a Set of strings.
|
||||
*/
|
||||
protected static Set<String> newHashSet(String... strings) {
|
||||
final Set<String> set = new HashSet<String>();
|
||||
final Set<String> set = new HashSet<String>(strings.length);
|
||||
Collections.addAll(set, strings);
|
||||
return set;
|
||||
}
|
||||
|
||||
@@ -114,8 +114,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
static {
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
final Set<String> ext = new HashSet<String>(Collections.singletonList(additionalZipExt));
|
||||
ZIPPABLES.addAll(ext);
|
||||
String[] ext = additionalZipExt.split("\\s*,\\s*");
|
||||
Collections.addAll(ZIPPABLES, ext);
|
||||
}
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
}
|
||||
@@ -415,11 +415,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory()) {
|
||||
if (!parent.mkdirs()) {
|
||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
fos = new FileOutputStream(file);
|
||||
IOUtils.copy(input, fos);
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.output.NullOutputStream;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
@@ -115,18 +115,15 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final List<String> args = buildArgumentList();
|
||||
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;
|
||||
// CHECKSTYLE:OFF
|
||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
||||
LOGGER.warn("Error from GrokAssembly: {}", line);
|
||||
final String errorStream = IOUtils.toString(proc.getErrorStream(), "UTF-8");
|
||||
if (null != errorStream && !errorStream.isEmpty()) {
|
||||
LOGGER.warn("Error from GrokAssembly: {}", errorStream);
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
int rc = 0;
|
||||
doc = builder.parse(proc.getInputStream());
|
||||
|
||||
@@ -176,14 +173,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (XPathExpressionException xpe) {
|
||||
// This shouldn't happen
|
||||
throw new AnalysisException(xpe);
|
||||
} finally {
|
||||
if (rdr != null) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("ignore", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,11 +189,8 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
fos = new FileOutputStream(tempFile);
|
||||
is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
||||
final byte[] buff = new byte[4096];
|
||||
int bread = -1;
|
||||
while ((bread = is.read(buff)) >= 0) {
|
||||
fos.write(buff, 0, bread);
|
||||
}
|
||||
IOUtils.copy(is, fos);
|
||||
|
||||
grokAssemblyExe = tempFile;
|
||||
// Set the temp file to get deleted when we're done
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
@@ -232,17 +218,12 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
// Now, need to see if GrokAssembly actually runs from this location.
|
||||
final List<String> args = buildArgumentList();
|
||||
BufferedReader rdr = null;
|
||||
try {
|
||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||
final Process p = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
||||
// CHECKSTYLE:OFF
|
||||
while (rdr.ready() && rdr.readLine() != null) {
|
||||
// We expect this to complain
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
IOUtils.copy(p.getErrorStream(), NullOutputStream.NULL_OUTPUT_STREAM);
|
||||
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
@@ -263,14 +244,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
} finally {
|
||||
if (rdr != null) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("ignore", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @return if the append was successful.
|
||||
*/
|
||||
private boolean appendWeightedSearch(StringBuilder sb, String field, String searchText, Set<String> weightedText) {
|
||||
sb.append(" ").append(field).append(":( ");
|
||||
sb.append(' ').append(field).append(":( ");
|
||||
|
||||
final String cleanText = cleanseText(searchText);
|
||||
|
||||
@@ -349,20 +349,27 @@ public class CPEAnalyzer implements Analyzer {
|
||||
final StringTokenizer tokens = new StringTokenizer(cleanText);
|
||||
while (tokens.hasMoreElements()) {
|
||||
final String word = tokens.nextToken();
|
||||
String temp = null;
|
||||
StringBuilder temp = null;
|
||||
for (String weighted : weightedText) {
|
||||
final String weightedStr = cleanseText(weighted);
|
||||
if (equalsIgnoreCaseAndNonAlpha(word, weightedStr)) {
|
||||
temp = LuceneUtils.escapeLuceneQuery(word) + WEIGHTING_BOOST;
|
||||
temp = new StringBuilder(word.length() + 2);
|
||||
LuceneUtils.appendEscapedLuceneQuery(temp, word);
|
||||
temp.append(WEIGHTING_BOOST);
|
||||
if (!word.equalsIgnoreCase(weightedStr)) {
|
||||
temp += " " + LuceneUtils.escapeLuceneQuery(weightedStr) + WEIGHTING_BOOST;
|
||||
temp.append(' ');
|
||||
LuceneUtils.appendEscapedLuceneQuery(temp, weightedStr);
|
||||
temp.append(WEIGHTING_BOOST);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.append(' ');
|
||||
if (temp == null) {
|
||||
temp = LuceneUtils.escapeLuceneQuery(word);
|
||||
LuceneUtils.appendEscapedLuceneQuery(sb, word);
|
||||
} else {
|
||||
sb.append(temp);
|
||||
}
|
||||
sb.append(" ").append(temp);
|
||||
}
|
||||
}
|
||||
sb.append(" ) ");
|
||||
@@ -515,7 +522,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
for (VulnerableSoftware vs : cpes) {
|
||||
DependencyVersion dbVer;
|
||||
if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getUpdate());
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + '.' + vs.getUpdate());
|
||||
} else {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final List<MavenArtifact> mas = searcher.searchSha1(dependency.getSha1sum());
|
||||
final Confidence confidence = mas.size() > 1 ? Confidence.HIGH : Confidence.HIGHEST;
|
||||
for (MavenArtifact ma : mas) {
|
||||
LOGGER.debug("Central analyzer found artifact ({}) for dependency ({})", ma.toString(), dependency.getFileName());
|
||||
LOGGER.debug("Central analyzer found artifact ({}) for dependency ({})", ma, dependency.getFileName());
|
||||
dependency.addAsEvidence("central", ma, confidence);
|
||||
boolean pomAnalyzed = false;
|
||||
for (Evidence e : dependency.getVendorEvidence()) {
|
||||
|
||||
@@ -113,7 +113,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".contains(i.getType())) {
|
||||
if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||
final int endPoint = i.getValue().indexOf(":", 19);
|
||||
final int endPoint = i.getValue().indexOf(':', 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
@@ -472,8 +472,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
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
|
||||
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 {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
@@ -76,13 +77,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
|
||||
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
||||
final File f = dependency.getActualFile();
|
||||
String fileName = f.getName();
|
||||
|
||||
//remove file extension
|
||||
final int pos = fileName.lastIndexOf(".");
|
||||
if (pos > 0) {
|
||||
fileName = fileName.substring(0, pos);
|
||||
}
|
||||
final String fileName = FilenameUtils.removeExtension(f.getName());
|
||||
|
||||
//add version evidence
|
||||
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName);
|
||||
|
||||
@@ -42,6 +42,7 @@ import java.util.jar.Manifest;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
@@ -269,8 +270,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
File externalPom = null;
|
||||
if (pomEntries.isEmpty()) {
|
||||
String pomPath = dependency.getActualFilePath();
|
||||
pomPath = pomPath.substring(0, pomPath.lastIndexOf('.')) + ".pom";
|
||||
final String pomPath = FilenameUtils.removeExtension(dependency.getActualFilePath()) + ".pom";
|
||||
externalPom = new File(pomPath);
|
||||
if (externalPom.isFile()) {
|
||||
pomEntries.add(pomPath);
|
||||
|
||||
@@ -104,7 +104,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
boolean retval = false;
|
||||
try {
|
||||
if ((!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL)))
|
||||
if (!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
|
||||
LOGGER.info("Enabling Nexus analyzer");
|
||||
retval = true;
|
||||
|
||||
@@ -126,7 +126,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
LOGGER.debug("Checking Nuspec file {}", dependency.toString());
|
||||
LOGGER.debug("Checking Nuspec file {}", dependency);
|
||||
try {
|
||||
final NuspecParser parser = new XPathNuspecParser();
|
||||
NugetPackage np = null;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class NvdCveAnalyzer implements Analyzer {
|
||||
* @return true or false.
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return (cveDB != null);
|
||||
return cveDB != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,7 +90,7 @@ public class CentralSearch {
|
||||
|
||||
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1));
|
||||
|
||||
LOGGER.debug("Searching Central url {}", url.toString());
|
||||
LOGGER.debug("Searching Central url {}", url);
|
||||
|
||||
// Determine if we need to use a proxy. The rules:
|
||||
// 1) If the proxy is set, AND the setting is set to true, use the proxy
|
||||
|
||||
@@ -24,6 +24,11 @@ package org.owasp.dependencycheck.data.composer;
|
||||
*/
|
||||
public class ComposerException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* The serial version UID for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a ComposerException with default message.
|
||||
*/
|
||||
|
||||
@@ -149,7 +149,6 @@ public final class CpeMemoryIndex {
|
||||
*
|
||||
* @return the CPE Analyzer.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Analyzer createIndexingAnalyzer() {
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
@@ -161,7 +160,6 @@ public final class CpeMemoryIndex {
|
||||
*
|
||||
* @return the CPE Analyzer.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Analyzer createSearchingAnalyzer() {
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
@@ -173,24 +171,6 @@ public final class CpeMemoryIndex {
|
||||
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(LuceneUtils.CURRENT_VERSION), fieldAnalyzers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a CPE IndexEntry into the Lucene index.
|
||||
*
|
||||
* @param vendor the vendor to index
|
||||
* @param product the product to index
|
||||
* @param indexWriter the index writer to write the entry into
|
||||
* @throws CorruptIndexException is thrown if the index is corrupt
|
||||
* @throws IOException is thrown if an IOException occurs
|
||||
*/
|
||||
public void saveEntry(String vendor, String product, IndexWriter indexWriter) throws CorruptIndexException, IOException {
|
||||
final Document doc = new Document();
|
||||
final Field v = new TextField(Fields.VENDOR, vendor, Field.Store.YES);
|
||||
final Field p = new TextField(Fields.PRODUCT, product, Field.Store.YES);
|
||||
doc.add(v);
|
||||
doc.add(p);
|
||||
indexWriter.addDocument(doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the CPE Index.
|
||||
*/
|
||||
@@ -230,9 +210,20 @@ public final class CpeMemoryIndex {
|
||||
final IndexWriterConfig conf = new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer);
|
||||
indexWriter = new IndexWriter(index, conf);
|
||||
try {
|
||||
// Tip: reuse the Document and Fields for performance...
|
||||
// See "Re-use Document and Field instances" from
|
||||
// http://wiki.apache.org/lucene-java/ImproveIndexingSpeed
|
||||
final Document doc = new Document();
|
||||
final Field v = new TextField(Fields.VENDOR, Fields.VENDOR, Field.Store.YES);
|
||||
final Field p = new TextField(Fields.PRODUCT, Fields.PRODUCT, Field.Store.YES);
|
||||
doc.add(v);
|
||||
doc.add(p);
|
||||
|
||||
final Set<Pair<String, String>> data = cve.getVendorProductList();
|
||||
for (Pair<String, String> pair : data) {
|
||||
saveEntry(pair.getLeft(), pair.getRight(), indexWriter);
|
||||
v.setStringValue(pair.getLeft());
|
||||
p.setStringValue(pair.getRight());
|
||||
indexWriter.addDocument(doc);
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
@@ -287,8 +278,9 @@ public final class CpeMemoryIndex {
|
||||
if (searchString == null || searchString.trim().isEmpty()) {
|
||||
throw new ParseException("Query is null or empty");
|
||||
}
|
||||
LOGGER.debug(searchString);
|
||||
final Query query = queryParser.parse(searchString);
|
||||
return indexSearcher.search(query, maxQueryResults);
|
||||
return search(query, maxQueryResults);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,7 @@ public class IndexEntry implements Serializable {
|
||||
*/
|
||||
public String getDocumentId() {
|
||||
if (documentId == null && vendor != null && product != null) {
|
||||
documentId = vendor + ":" + product;
|
||||
documentId = vendor + ':' + product;
|
||||
}
|
||||
return documentId;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ public final class LuceneUtils {
|
||||
case '*':
|
||||
case '?':
|
||||
case ':':
|
||||
case '/':
|
||||
case '\\': //it is supposed to fall through here
|
||||
buf.append('\\');
|
||||
default:
|
||||
|
||||
@@ -94,13 +94,13 @@ public class MavenArtifact {
|
||||
}
|
||||
if (jarAvailable) {
|
||||
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||
this.artifactUrl = base + groupId.replace('.', '/') + "/" + artifactId + "/"
|
||||
+ version + "/" + artifactId + "-" + version + ".jar";
|
||||
this.artifactUrl = base + groupId.replace('.', '/') + '/' + artifactId + '/'
|
||||
+ version + '/' + artifactId + '-' + version + ".jar";
|
||||
}
|
||||
if (pomAvailable) {
|
||||
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||
this.pomUrl = base + groupId.replace('.', '/') + "/" + artifactId + "/"
|
||||
+ version + "/" + artifactId + "-" + version + ".pom";
|
||||
this.pomUrl = base + groupId.replace('.', '/') + '/' + artifactId + '/'
|
||||
+ version + '/' + artifactId + '-' + version + ".pom";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public class NexusSearch {
|
||||
this.rootURL = rootURL;
|
||||
try {
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY)) {
|
||||
useProxy = true;
|
||||
LOGGER.debug("Using proxy");
|
||||
} else {
|
||||
|
||||
@@ -17,11 +17,9 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
@@ -29,7 +27,10 @@ import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.owasp.dependencycheck.utils.DBUtils;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -58,6 +59,10 @@ public final class ConnectionFactory {
|
||||
* Resource location for SQL file used to create the database schema.
|
||||
*/
|
||||
public static final String DB_STRUCTURE_UPDATE_RESOURCE = "data/upgrade_%s.sql";
|
||||
/**
|
||||
* The URL that discusses upgrading non-H2 databases.
|
||||
*/
|
||||
public static final String UPGRADE_HELP_URL = "http://jeremylong.github.io/DependencyCheck/data/upgrade.html";
|
||||
/**
|
||||
* The database driver used to connect to the database.
|
||||
*/
|
||||
@@ -243,22 +248,15 @@ public final class ConnectionFactory {
|
||||
*/
|
||||
private static void createTables(Connection conn) throws DatabaseException {
|
||||
LOGGER.debug("Creating database structure");
|
||||
InputStream is;
|
||||
InputStreamReader reader;
|
||||
BufferedReader in = null;
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = ConnectionFactory.class.getClassLoader().getResourceAsStream(DB_STRUCTURE_RESOURCE);
|
||||
reader = new InputStreamReader(is, "UTF-8");
|
||||
in = new BufferedReader(reader);
|
||||
final StringBuilder sb = new StringBuilder(2110);
|
||||
String tmp;
|
||||
while ((tmp = in.readLine()) != null) {
|
||||
sb.append(tmp);
|
||||
}
|
||||
final String dbStructure = IOUtils.toString(is, "UTF-8");
|
||||
|
||||
Statement statement = null;
|
||||
try {
|
||||
statement = conn.createStatement();
|
||||
statement.execute(sb.toString());
|
||||
statement.execute(dbStructure);
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new DatabaseException("Unable to create database statement", ex);
|
||||
@@ -268,13 +266,7 @@ public final class ConnectionFactory {
|
||||
} catch (IOException ex) {
|
||||
throw new DatabaseException("Unable to create database schema", ex);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,48 +280,54 @@ public final class ConnectionFactory {
|
||||
* @throws DatabaseException thrown if there is an exception upgrading the database schema
|
||||
*/
|
||||
private static void updateSchema(Connection conn, String schema) throws DatabaseException {
|
||||
LOGGER.debug("Updating database structure");
|
||||
InputStream is;
|
||||
InputStreamReader reader;
|
||||
BufferedReader in = null;
|
||||
String updateFile = null;
|
||||
final String databaseProductName;
|
||||
try {
|
||||
updateFile = String.format(DB_STRUCTURE_UPDATE_RESOURCE, schema);
|
||||
is = ConnectionFactory.class.getClassLoader().getResourceAsStream(updateFile);
|
||||
if (is == null) {
|
||||
throw new DatabaseException(String.format("Unable to load update file '%s'", updateFile));
|
||||
}
|
||||
reader = new InputStreamReader(is, "UTF-8");
|
||||
in = new BufferedReader(reader);
|
||||
final StringBuilder sb = new StringBuilder(2110);
|
||||
String tmp;
|
||||
while ((tmp = in.readLine()) != null) {
|
||||
sb.append(tmp);
|
||||
}
|
||||
Statement statement = null;
|
||||
databaseProductName = conn.getMetaData().getDatabaseProductName();
|
||||
} catch (SQLException ex) {
|
||||
throw new DatabaseException("Unable to get the database product name");
|
||||
}
|
||||
if ("h2".equalsIgnoreCase(databaseProductName)) {
|
||||
LOGGER.debug("Updating database structure");
|
||||
InputStream is = null;
|
||||
String updateFile = null;
|
||||
try {
|
||||
statement = conn.createStatement();
|
||||
statement.execute(sb.toString());
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new DatabaseException("Unable to update database schema", ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(statement);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Upgrade SQL file does not exist: %s", updateFile);
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
updateFile = String.format(DB_STRUCTURE_UPDATE_RESOURCE, schema);
|
||||
is = ConnectionFactory.class.getClassLoader().getResourceAsStream(updateFile);
|
||||
if (is == null) {
|
||||
throw new DatabaseException(String.format("Unable to load update file '%s'", updateFile));
|
||||
}
|
||||
final String dbStructureUpdate = IOUtils.toString(is, "UTF-8");
|
||||
|
||||
Statement statement = null;
|
||||
try {
|
||||
statement = conn.createStatement();
|
||||
final boolean success = statement.execute(dbStructureUpdate);
|
||||
if (!success && statement.getUpdateCount() <= 0) {
|
||||
throw new DatabaseException(String.format("Unable to upgrade the database schema to %s", schema));
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new DatabaseException("Unable to update database schema", ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(statement);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Upgrade SQL file does not exist: %s", updateFile);
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
} else {
|
||||
LOGGER.error("The database schema must be upgraded to use this version of dependency-check. Please see {} for more information.", UPGRADE_HELP_URL);
|
||||
throw new DatabaseException("Database schema is out of date");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counter to ensure that calls to ensureSchemaVersion does not end up in an endless loop.
|
||||
*/
|
||||
private static int callDepth = 0;
|
||||
|
||||
/**
|
||||
* Uses the provided connection to check the specified schema version within the database.
|
||||
*
|
||||
@@ -344,10 +342,15 @@ public final class ConnectionFactory {
|
||||
cs = conn.prepareCall("SELECT value FROM properties WHERE id = 'version'");
|
||||
rs = cs.executeQuery();
|
||||
if (rs.next()) {
|
||||
if (!DB_SCHEMA_VERSION.equals(rs.getString(1))) {
|
||||
final DependencyVersion current = DependencyVersionUtil.parseVersion(DB_SCHEMA_VERSION);
|
||||
final DependencyVersion db = DependencyVersionUtil.parseVersion(rs.getString(1));
|
||||
if (current.compareTo(db) > 0) {
|
||||
LOGGER.debug("Current Schema: " + DB_SCHEMA_VERSION);
|
||||
LOGGER.debug("DB Schema: " + rs.getString(1));
|
||||
updateSchema(conn, rs.getString(1));
|
||||
if (++callDepth < 10) {
|
||||
ensureSchemaVersion(conn);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new DatabaseException("Database schema is missing");
|
||||
|
||||
@@ -29,8 +29,10 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
@@ -74,9 +76,17 @@ public class CveDB {
|
||||
*/
|
||||
public CveDB() throws DatabaseException {
|
||||
super();
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements");
|
||||
try {
|
||||
open();
|
||||
try {
|
||||
final String databaseProductName = conn.getMetaData().getDatabaseProductName();
|
||||
LOGGER.debug("Database dialect: {}", databaseProductName);
|
||||
final Locale dbDialect = new Locale(databaseProductName);
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements", dbDialect);
|
||||
} catch (SQLException se) {
|
||||
LOGGER.warn("Problem loading database specific dialect!", se);
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements");
|
||||
}
|
||||
databaseProperties = new DatabaseProperties(this);
|
||||
} catch (DatabaseException ex) {
|
||||
throw ex;
|
||||
@@ -252,44 +262,6 @@ public class CveDB {
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a set of properties to the database.
|
||||
*
|
||||
* @param props a collection of properties
|
||||
*/
|
||||
void saveProperties(Properties props) {
|
||||
PreparedStatement updateProperty = null;
|
||||
PreparedStatement insertProperty = null;
|
||||
try {
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save properties to the database");
|
||||
LOGGER.debug("Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
for (Entry<Object, Object> entry : props.entrySet()) {
|
||||
final String key = entry.getKey().toString();
|
||||
final String value = entry.getValue().toString();
|
||||
try {
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
DBUtils.closeStatement(insertProperty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a property to the database.
|
||||
*
|
||||
@@ -297,38 +269,38 @@ public class CveDB {
|
||||
* @param value the property value
|
||||
*/
|
||||
void saveProperty(String key, String value) {
|
||||
PreparedStatement updateProperty = null;
|
||||
PreparedStatement insertProperty = null;
|
||||
try {
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save properties to the database");
|
||||
LOGGER.debug("Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
try {
|
||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save properties to the database");
|
||||
LOGGER.debug("Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
insertProperty.execute();
|
||||
final PreparedStatement mergeProperty = getConnection().prepareStatement(statementBundle.getString("MERGE_PROPERTY"));
|
||||
try {
|
||||
mergeProperty.setString(1, key);
|
||||
mergeProperty.setString(2, value);
|
||||
mergeProperty.executeUpdate();
|
||||
} finally {
|
||||
DBUtils.closeStatement(mergeProperty);
|
||||
}
|
||||
} catch (MissingResourceException mre) {
|
||||
// No Merge statement, so doing an Update/Insert...
|
||||
PreparedStatement updateProperty = null;
|
||||
PreparedStatement insertProperty = null;
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
insertProperty.executeUpdate();
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
DBUtils.closeStatement(insertProperty);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
DBUtils.closeStatement(insertProperty);
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +392,7 @@ public class CveDB {
|
||||
if (cwe != null) {
|
||||
final String name = CweDB.getCweName(cwe);
|
||||
if (name != null) {
|
||||
cwe += " " + name;
|
||||
cwe += ' ' + name;
|
||||
}
|
||||
}
|
||||
final int cveId = rsV.getInt(1);
|
||||
|
||||
@@ -45,6 +45,10 @@ public class DatabaseProperties {
|
||||
* updates)..
|
||||
*/
|
||||
public static final String MODIFIED = "Modified";
|
||||
/**
|
||||
* The properties file key for the last checked field - used to store the last check time of the Modified NVD CVE xml file.
|
||||
*/
|
||||
public static final String LAST_CHECKED = "NVD CVE Checked";
|
||||
/**
|
||||
* The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE xml file.
|
||||
*/
|
||||
|
||||
@@ -137,7 +137,7 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
*/
|
||||
private boolean updateNeeded() {
|
||||
final long now = System.currentTimeMillis();
|
||||
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 30);
|
||||
final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
|
||||
long timestamp = 0;
|
||||
final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
|
||||
if (ts != null && ts.matches("^[0-9]+$")) {
|
||||
|
||||
@@ -66,9 +66,11 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
public void update() throws UpdateException {
|
||||
try {
|
||||
openDataStores();
|
||||
final UpdateableNvdCve updateable = getUpdatesNeeded();
|
||||
if (updateable.isUpdateNeeded()) {
|
||||
performUpdate(updateable);
|
||||
if (checkUpdate()) {
|
||||
final UpdateableNvdCve updateable = getUpdatesNeeded();
|
||||
if (updateable.isUpdateNeeded()) {
|
||||
performUpdate(updateable);
|
||||
}
|
||||
}
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.warn(
|
||||
@@ -87,6 +89,35 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the NVD CVE XML files were last checked recently.
|
||||
* As an optimization, we can avoid repetitive checks against the NVD.
|
||||
* Setting CVE_CHECK_VALID_FOR_HOURS determines the duration since last check before checking again.
|
||||
* A database property stores the timestamp of the last check.
|
||||
*
|
||||
* @return true to proceed with the check, or false to skip.
|
||||
*/
|
||||
private boolean checkUpdate () throws UpdateException {
|
||||
boolean proceed = true;
|
||||
// If the valid setting has not been specified, then we proceed to check...
|
||||
final int validForHours = Settings.getInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, 0);
|
||||
if (0 < validForHours) {
|
||||
// ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec
|
||||
final long msValid = validForHours * 60L * 60L * 1000L;
|
||||
final long lastChecked = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_CHECKED, "0"));
|
||||
final long now = System.currentTimeMillis();
|
||||
proceed = (now - lastChecked) > msValid;
|
||||
if (proceed) {
|
||||
getProperties().save(DatabaseProperties.LAST_CHECKED, Long.toString(now));
|
||||
} else {
|
||||
LOGGER.info("Skipping NVD check since last check was within {} hours.", validForHours);
|
||||
LOGGER.debug("Last NVD was at {}, and now {} is within {} ms.",
|
||||
lastChecked, now, msValid);
|
||||
}
|
||||
}
|
||||
return proceed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database.
|
||||
*
|
||||
|
||||
@@ -68,8 +68,8 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
final File file2;
|
||||
|
||||
try {
|
||||
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
|
||||
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
|
||||
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
|
||||
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
|
||||
} catch (IOException ex) {
|
||||
throw new UpdateException("Unable to create temporary files", ex);
|
||||
}
|
||||
|
||||
@@ -114,10 +114,10 @@ public class NvdCve12Handler extends DefaultHandler {
|
||||
in the nvd cve 2.0. */
|
||||
String cpe = "cpe:/a:" + vendor + ":" + product;
|
||||
if (num != null) {
|
||||
cpe += ":" + num;
|
||||
cpe += ':' + num;
|
||||
}
|
||||
if (edition != null) {
|
||||
cpe += ":" + edition;
|
||||
cpe += ':' + edition;
|
||||
}
|
||||
final VulnerableSoftware vs = new VulnerableSoftware();
|
||||
vs.setCpe(cpe);
|
||||
|
||||
@@ -341,7 +341,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LOGGER.debug("Adding new maven identifier {}", mavenArtifact.toString());
|
||||
LOGGER.debug("Adding new maven identifier {}", mavenArtifact);
|
||||
this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.suppression;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
@@ -381,30 +382,7 @@ public class SuppressionRule {
|
||||
* @return true if the property type does not specify a version; otherwise false
|
||||
*/
|
||||
boolean cpeHasNoVersion(PropertyType c) {
|
||||
if (c.isRegex()) {
|
||||
return false;
|
||||
}
|
||||
if (countCharacter(c.getValue(), ':') == 3) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of occurrences of the character found within the string.
|
||||
*
|
||||
* @param str the string to check
|
||||
* @param c the character to count
|
||||
* @return the number of times the character is found in the string
|
||||
*/
|
||||
int countCharacter(String str, char c) {
|
||||
int count = 0;
|
||||
int pos = str.indexOf(c) + 1;
|
||||
while (pos > 0) {
|
||||
count += 1;
|
||||
pos = str.indexOf(c, pos) + 1;
|
||||
}
|
||||
return count;
|
||||
return !c.isRegex() && StringUtils.countMatches(c.getValue(), ':') == 3;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,43 +420,43 @@ public class SuppressionRule {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("SuppressionRule{");
|
||||
if (filePath != null) {
|
||||
sb.append("filePath=").append(filePath).append(",");
|
||||
sb.append("filePath=").append(filePath).append(',');
|
||||
}
|
||||
if (sha1 != null) {
|
||||
sb.append("sha1=").append(sha1).append(",");
|
||||
sb.append("sha1=").append(sha1).append(',');
|
||||
}
|
||||
if (gav != null) {
|
||||
sb.append("gav=").append(gav).append(",");
|
||||
sb.append("gav=").append(gav).append(',');
|
||||
}
|
||||
if (cpe != null && !cpe.isEmpty()) {
|
||||
sb.append("cpe={");
|
||||
for (PropertyType pt : cpe) {
|
||||
sb.append(pt).append(",");
|
||||
sb.append(pt).append(',');
|
||||
}
|
||||
sb.append("}");
|
||||
sb.append('}');
|
||||
}
|
||||
if (cwe != null && !cwe.isEmpty()) {
|
||||
sb.append("cwe={");
|
||||
for (String s : cwe) {
|
||||
sb.append(s).append(",");
|
||||
sb.append(s).append(',');
|
||||
}
|
||||
sb.append("}");
|
||||
sb.append('}');
|
||||
}
|
||||
if (cve != null && !cve.isEmpty()) {
|
||||
sb.append("cve={");
|
||||
for (String s : cve) {
|
||||
sb.append(s).append(",");
|
||||
sb.append(s).append(',');
|
||||
}
|
||||
sb.append("}");
|
||||
sb.append('}');
|
||||
}
|
||||
if (cvssBelow != null && !cvssBelow.isEmpty()) {
|
||||
sb.append("cvssBelow={");
|
||||
for (Float s : cvssBelow) {
|
||||
sb.append(s).append(",");
|
||||
sb.append(s).append(',');
|
||||
}
|
||||
sb.append("}");
|
||||
sb.append('}');
|
||||
}
|
||||
sb.append("}");
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,12 @@ public final class DateUtil {
|
||||
*
|
||||
* @param date the date to be checked.
|
||||
* @param compareTo the date to compare to.
|
||||
* @param range the range in days to be considered valid.
|
||||
* @param dayRange the range in days to be considered valid.
|
||||
* @return whether or not the date is within the range.
|
||||
*/
|
||||
public static boolean withinDateRange(long date, long compareTo, int range) {
|
||||
final double differenceInDays = (compareTo - date) / 1000.0 / 60.0 / 60.0 / 24.0;
|
||||
return differenceInDays < range;
|
||||
public static boolean withinDateRange(long date, long compareTo, int dayRange) {
|
||||
// ms = dayRange x 24 hours/day x 60 min/hour x 60 sec/min x 1000 ms/sec
|
||||
final long msRange = dayRange * 24L * 60L * 60L * 1000L;
|
||||
return (compareTo - date) < msRange;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ public class DependencyVersion implements Iterable<String>, Comparable<Dependenc
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtils.join(versionParts.toArray(), ".");
|
||||
return StringUtils.join(versionParts, '.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -182,13 +182,11 @@ public final class ExtractionUtil {
|
||||
while ((entry = input.getNextEntry()) != null) {
|
||||
if (entry.isDirectory()) {
|
||||
final File dir = new File(destination, entry.getName());
|
||||
if (!dir.exists()) {
|
||||
if (!dir.mkdirs()) {
|
||||
final String msg = String.format(
|
||||
"Unable to create directory '%s'.",
|
||||
dir.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
final String msg = String.format(
|
||||
"Unable to create directory '%s'.",
|
||||
dir.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
} else {
|
||||
extractFile(input, destination, filter, entry);
|
||||
@@ -264,13 +262,11 @@ public final class ExtractionUtil {
|
||||
private static void createParentFile(final File file)
|
||||
throws ExtractionException {
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory()) {
|
||||
if (!parent.mkdirs()) {
|
||||
final String msg = String.format(
|
||||
"Unable to build directory '%s'.",
|
||||
parent.getAbsolutePath());
|
||||
throw new ExtractionException(msg);
|
||||
}
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
final String msg = String.format(
|
||||
"Unable to build directory '%s'.",
|
||||
parent.getAbsolutePath());
|
||||
throw new ExtractionException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* NonClosingStream is a stream filter which prevents another class that processes the stream from closing it. This is
|
||||
* necessary when dealing with things like JAXB and zipInputStreams.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class NonClosingStream extends FilterInputStream {
|
||||
|
||||
/**
|
||||
* Constructs a new NonClosingStream.
|
||||
*
|
||||
* @param in an input stream.
|
||||
*/
|
||||
public NonClosingStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents closing of the stream.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
// don't close the stream.
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.lang3.text.StrLookup;
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
|
||||
/**
|
||||
* A simple pojo to hold data related to a Maven POM file.
|
||||
*
|
||||
@@ -307,33 +310,27 @@ public class Model {
|
||||
* @return the interpolated text.
|
||||
*/
|
||||
public static String interpolateString(String text, Properties properties) {
|
||||
final Properties props = properties;
|
||||
if (text == null) {
|
||||
if (null == text || null == properties) {
|
||||
return text;
|
||||
}
|
||||
if (props == null) {
|
||||
return text;
|
||||
}
|
||||
|
||||
final int pos = text.indexOf("${");
|
||||
if (pos < 0) {
|
||||
return text;
|
||||
}
|
||||
final int end = text.indexOf("}");
|
||||
if (end < pos) {
|
||||
return text;
|
||||
}
|
||||
|
||||
final String propName = text.substring(pos + 2, end);
|
||||
String propValue = interpolateString(props.getProperty(propName), props);
|
||||
if (propValue == null) {
|
||||
propValue = "";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder(propValue.length() + text.length());
|
||||
sb.append(text.subSequence(0, pos));
|
||||
sb.append(propValue);
|
||||
sb.append(text.substring(end + 1));
|
||||
return interpolateString(sb.toString(), props); //yes yes, this should be a loop...
|
||||
final StrSubstitutor substitutor = new StrSubstitutor(new PropertyLookup(properties));
|
||||
return substitutor.replace(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class that can provide values from a Properties object to a StrSubstitutor.
|
||||
*/
|
||||
private static class PropertyLookup extends StrLookup {
|
||||
|
||||
private final Properties props;
|
||||
|
||||
public PropertyLookup(Properties props) {
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookup(String key) {
|
||||
return props.getProperty(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
MERGE_PROPERTY=MERGE INTO properties (id, value) KEY(id) VALUES(?, ?)
|
||||
@@ -0,0 +1,15 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
MERGE_PROPERTY=CALL save_property(?, ?)
|
||||
@@ -0,0 +1,16 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
MERGE_PROPERTY=CALL save_property(?, ?)
|
||||
CLEANUP_ORPHANS=DELETE FROM cpeEntry WHERE id IN (SELECT id FROM cpeEntry LEFT JOIN software ON cpeEntry.id = software.CPEEntryId WHERE software.CPEEntryId IS NULL);
|
||||
@@ -37,4 +37,20 @@ CREATE INDEX idxSoftwareCpe ON software(cpeEntryId);
|
||||
INSERT INTO properties(id,value) VALUES ('version','2.9');
|
||||
|
||||
CREATE USER 'dcuser' IDENTIFIED BY 'DC-Pass1337!';
|
||||
GRANT SELECT, INSERT, DELETE, UPDATE ON dependencycheck.* TO 'dcuser';
|
||||
GRANT SELECT, INSERT, DELETE, UPDATE ON dependencycheck.* TO 'dcuser';
|
||||
|
||||
|
||||
DROP PROCEDURE IF EXISTS save_property;
|
||||
|
||||
DELIMITER //
|
||||
CREATE PROCEDURE save_property
|
||||
(IN prop varchar(50), IN val varchar(500))
|
||||
BEGIN
|
||||
INSERT INTO properties (`id`, `value`) VALUES (prop, val)
|
||||
ON DUPLICATE KEY UPDATE `value`=val;
|
||||
END //
|
||||
DELIMITER ;
|
||||
|
||||
GRANT EXECUTE ON PROCEDURE dependencycheck.save_property TO 'dcuser';
|
||||
|
||||
UPDATE Properties SET value='3.0' WHERE ID='version';
|
||||
@@ -0,0 +1,53 @@
|
||||
CREATE USER dcuser WITH PASSWORD 'DC-Pass1337!';
|
||||
|
||||
DROP TABLE IF EXISTS software;
|
||||
DROP TABLE IF EXISTS cpeEntry;
|
||||
DROP TABLE IF EXISTS reference;
|
||||
DROP TABLE IF EXISTS vulnerability;
|
||||
DROP TABLE IF EXISTS properties;
|
||||
|
||||
CREATE TABLE properties (id varchar(50) PRIMARY KEY, value varchar(500));
|
||||
|
||||
CREATE TABLE vulnerability (id SERIAL PRIMARY KEY, cve VARCHAR(20) UNIQUE,
|
||||
description VARCHAR(8000), cwe VARCHAR(10), cvssScore DECIMAL(3,1), cvssAccessVector VARCHAR(20),
|
||||
cvssAccessComplexity VARCHAR(20), cvssAuthentication VARCHAR(20), cvssConfidentialityImpact VARCHAR(20),
|
||||
cvssIntegrityImpact VARCHAR(20), cvssAvailabilityImpact VARCHAR(20));
|
||||
|
||||
CREATE TABLE reference (cveid INT, name VARCHAR(1000), url VARCHAR(1000), source VARCHAR(255),
|
||||
CONSTRAINT fkReference FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE);
|
||||
|
||||
CREATE TABLE cpeEntry (id SERIAL PRIMARY KEY, cpe VARCHAR(250), vendor VARCHAR(255), product VARCHAR(255));
|
||||
|
||||
CREATE TABLE software (cveid INT, cpeEntryId INT, previousVersion VARCHAR(50)
|
||||
, CONSTRAINT fkSoftwareCve FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE
|
||||
, CONSTRAINT fkSoftwareCpeProduct FOREIGN KEY (cpeEntryId) REFERENCES cpeEntry(id));
|
||||
|
||||
CREATE INDEX idxVulnerability ON vulnerability(cve);
|
||||
CREATE INDEX idxReference ON reference(cveid);
|
||||
CREATE INDEX idxCpe ON cpeEntry(cpe);
|
||||
CREATE INDEX idxCpeEntry ON cpeEntry(vendor, product);
|
||||
CREATE INDEX idxSoftwareCve ON software(cveid);
|
||||
CREATE INDEX idxSoftwareCpe ON software(cpeEntryId);
|
||||
|
||||
INSERT INTO properties(id,value) VALUES ('version','2.9');
|
||||
|
||||
GRANT SELECT, INSERT, DELETE, UPDATE ON ALL TABLES IN SCHEMA public TO dcuser;
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public to dcuser;
|
||||
|
||||
DROP FUNCTION IF EXISTS save_property(varchar(50),varchar(500));
|
||||
|
||||
CREATE FUNCTION save_property (IN prop varchar(50), IN val varchar(500))
|
||||
RETURNS void
|
||||
AS
|
||||
$$
|
||||
UPDATE properties SET "value"=val WHERE id=prop;
|
||||
|
||||
INSERT INTO properties (id, value)
|
||||
SELECT prop, val
|
||||
WHERE NOT EXISTS (SELECT 1 FROM properties WHERE id=prop);
|
||||
$$ LANGUAGE sql;
|
||||
|
||||
|
||||
GRANT EXECUTE ON FUNCTION public.save_property(varchar(50),varchar(500)) TO dcuser;
|
||||
|
||||
UPDATE Properties SET value='3.0' WHERE ID='version';
|
||||
@@ -1,7 +1 @@
|
||||
|
||||
--the following is not currently used.
|
||||
--ALTER TABLE cpeEntry ADD COLUMN IF NOT EXISTS dictionaryEntry BOOLEAN;
|
||||
--ALTER TABLE cpeEntry ALTER COLUMN dictionaryEntry SET DEFAULT FALSE;
|
||||
--UPDATE cpeEntry SET dictionaryEntry=false;
|
||||
|
||||
--UPDATE Properties SET value='3.0' WHERE ID='version';
|
||||
UPDATE Properties SET value='3.0' WHERE ID='version';
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
--the following is not currently used.
|
||||
--ALTER TABLE cpeEntry ADD COLUMN IF NOT EXISTS dictionaryEntry BOOLEAN;
|
||||
--ALTER TABLE cpeEntry ALTER COLUMN dictionaryEntry SET DEFAULT FALSE;
|
||||
--UPDATE cpeEntry SET dictionaryEntry=false;
|
||||
|
||||
--UPDATE Properties SET value='3.1' WHERE ID='version';
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
DROP PROCEDURE IF EXISTS save_property;
|
||||
|
||||
DELIMITER //
|
||||
CREATE PROCEDURE save_property
|
||||
(IN prop varchar(50), IN val varchar(500))
|
||||
BEGIN
|
||||
INSERT INTO properties (`id`, `value`) VALUES (prop, val)
|
||||
ON DUPLICATE KEY UPDATE `value`=val;
|
||||
END //
|
||||
DELIMITER ;
|
||||
|
||||
GRANT EXECUTE ON PROCEDURE dependencycheck.save_property TO 'dcuser';
|
||||
|
||||
UPDATE Properties SET value='3.0' WHERE ID='version';
|
||||
@@ -161,4 +161,32 @@
|
||||
<gav regex="true">.*\bhk2\b.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
file name: petals-se-camel-1.0.0.jar - false positive for apache camel.
|
||||
]]></notes>
|
||||
<gav regex="true">org.ow2.petals:petals-se-camel:.*</gav>
|
||||
<cpe>cpe:/a:apache:camel</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Mina gets flagged as apache-ssl
|
||||
]]></notes>
|
||||
<gav regex="true">org.apache.mina:mina.*</gav>
|
||||
<cpe>cpe:/a:apache-ssl:apache-ssl</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Woden gets flagged as apache-ssl
|
||||
]]></notes>
|
||||
<gav regex="true">org.apache.woden:woden.*</gav>
|
||||
<cpe>cpe:/a:apache-ssl:apache-ssl</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
spec gets flagged as the implementation.
|
||||
]]></notes>
|
||||
<gav regex="true">org.apache.geronimo.specs:.*</gav>
|
||||
<cpe>cpe:/a:apache:geronimo</cpe>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -18,8 +18,8 @@ engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt
|
||||
data.directory=[JAR]/data
|
||||
#if the filename has a %s it will be replaced with the current expected version
|
||||
data.file_name=dc.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
data.version=3.0
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=FS;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,13 +41,15 @@ data.driver_path=
|
||||
# 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 number of hours to wait before checking if updates are available from the NVD.
|
||||
cve.check.validforhours=4
|
||||
#first year to pull data from the URLs below
|
||||
cve.startyear=2002
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
#cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2002
|
||||
cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
#cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
@@ -79,3 +81,22 @@ archive.scan.depth=3
|
||||
|
||||
# use HEAD (default) or GET as HTTP request method for query timestamp
|
||||
downloader.quick.query.timestamp=true
|
||||
|
||||
|
||||
analyzer.jar.enabled=true
|
||||
analyzer.archive.enabled=true
|
||||
analyzer.node.package.enabled=true
|
||||
analyzer.composer.lock.enabled=true
|
||||
analyzer.python.distribution.enabled=true
|
||||
analyzer.python.package.enabled=true
|
||||
analyzer.ruby.gemspec.enabled=true
|
||||
analyzer.autoconf.enabled=true
|
||||
analyzer.cmake.enabled=true
|
||||
analyzer.assembly.enabled=true
|
||||
analyzer.nuspec.enabled=true
|
||||
analyzer.openssl.enabled=true
|
||||
analyzer.central.enabled=true
|
||||
analyzer.nexus.enabled=false
|
||||
#whether the nexus analyzer uses the proxy
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
|
||||
@@ -578,6 +578,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<td data-sort-value="$sortValue">
|
||||
#set($sortValue="")
|
||||
#foreach($id in $dependency.getIdentifiers())
|
||||
#set($cpeSort=0)
|
||||
#if ($id.type=="maven")
|
||||
#if ($mavenlink=="" || !$mavenlink.url)
|
||||
#set($mavenlink=$id)
|
||||
@@ -591,7 +592,6 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#else
|
||||
$enc.html($id.value)
|
||||
#end
|
||||
#set($cpeSort=0)
|
||||
#if ($cpeIdConf == "")
|
||||
#set($cpeIdConf=$id.confidence)
|
||||
#set($cpeSort=$id.confidence.ordinal())
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
@@ -31,6 +31,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* An abstract database test case that is used to ensure the H2 DB exists prior to performing tests that utilize the data
|
||||
* contained within.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -34,7 +34,7 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase.ensureDBExists();
|
||||
org.owasp.dependencycheck.BaseDBTestCase.ensureDBExists();
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
@@ -34,7 +34,7 @@ public class AbstractFileTypeAnalyzerTest extends BaseTest {
|
||||
*/
|
||||
@Test
|
||||
public void testNewHashSet() {
|
||||
Set result = AbstractFileTypeAnalyzer.newHashSet("one", "two");
|
||||
Set<String> result = AbstractFileTypeAnalyzer.newHashSet("one", "two");
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.contains("one"));
|
||||
assertTrue(result.contains("two"));
|
||||
|
||||
@@ -24,7 +24,7 @@ import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
public class ArchiveAnalyzerIntegrationTest extends BaseDBTestCase {
|
||||
|
||||
/**
|
||||
* Test of getSupportedExtensions method, of class ArchiveAnalyzer.
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2015 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.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeNotNull;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeremy
|
||||
*/
|
||||
public class ArchiveAnalyzerTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, "z2, z3");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of analyzeFileType method, of class ArchiveAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testZippableExtensions() throws Exception {
|
||||
assumeFalse(isPreviouslyLoaded("org.owasp.dependencycheck.analyzer.ArchiveAnalyzer"));
|
||||
ArchiveAnalyzer instance = new ArchiveAnalyzer();
|
||||
assertTrue(instance.getFileFilter().accept(new File("c:/test.zip")));
|
||||
assertTrue(instance.getFileFilter().accept(new File("c:/test.z2")));
|
||||
assertTrue(instance.getFileFilter().accept(new File("c:/test.z3")));
|
||||
assertFalse(instance.getFileFilter().accept(new File("c:/test.z4")));
|
||||
}
|
||||
|
||||
private boolean isPreviouslyLoaded(String className) {
|
||||
try {
|
||||
Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[]{String.class});
|
||||
m.setAccessible(true);
|
||||
Object t = m.invoke(Thread.currentThread().getContextClassLoader(), className);
|
||||
return t != null;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzerTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (SecurityException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzerTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzerTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzerTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (InvocationTargetException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzerTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import java.util.regex.Pattern;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
|
||||
/**
|
||||
* Unit tests for CmakeAnalyzer.
|
||||
|
||||
@@ -19,7 +19,7 @@ package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
@@ -28,7 +28,7 @@ import org.junit.Assert;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
@@ -38,7 +38,7 @@ import org.owasp.dependencycheck.dependency.Identifier;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
public class CPEAnalyzerIntegrationTest extends BaseDBTestCase {
|
||||
|
||||
/**
|
||||
* Tests of buildSearch of class CPEAnalyzer.
|
||||
@@ -49,11 +49,9 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*/
|
||||
@Test
|
||||
public void testBuildSearch() throws IOException, CorruptIndexException, ParseException {
|
||||
Set<String> productWeightings = new HashSet<String>(1);
|
||||
productWeightings.add("struts2");
|
||||
Set<String> productWeightings = Collections.singleton("struts2");
|
||||
|
||||
Set<String> vendorWeightings = new HashSet<String>(1);
|
||||
vendorWeightings.add("apache");
|
||||
Set<String> vendorWeightings = Collections.singleton("apache");
|
||||
|
||||
String vendor = "apache software foundation";
|
||||
String product = "struts 2 core";
|
||||
@@ -238,11 +236,9 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
|
||||
Set<String> productWeightings = new HashSet<String>(1);
|
||||
productWeightings.add("struts2");
|
||||
Set<String> productWeightings = Collections.singleton("struts2");
|
||||
|
||||
Set<String> vendorWeightings = new HashSet<String>(1);
|
||||
vendorWeightings.add("apache");
|
||||
Set<String> vendorWeightings = Collections.singleton("apache");
|
||||
|
||||
List<IndexEntry> result = instance.searchCPE(vendor, product, productWeightings, vendorWeightings);
|
||||
instance.close();
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class DependencyBundlingAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
public class DependencyBundlingAnalyzerIntegrationTest extends BaseDBTestCase {
|
||||
|
||||
/**
|
||||
* Test of analyze method, of class DependencyBundlingAnalyzer.
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
@@ -33,12 +34,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class HintAnalyzerTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase.ensureDBExists();
|
||||
}
|
||||
public class HintAnalyzerTest extends BaseDBTestCase {
|
||||
|
||||
/**
|
||||
* Test of getName method, of class HintAnalyzer.
|
||||
|
||||
@@ -21,9 +21,9 @@ import java.io.File;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class VulnerabilitySuppressionAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
public class VulnerabilitySuppressionAnalyzerIntegrationTest extends BaseDBTestCase {
|
||||
|
||||
/**
|
||||
* Test of getName method, of class VulnerabilitySuppressionAnalyzer.
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.cpe;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||
|
||||
/**
|
||||
* An abstract database test case that is used to ensure the H2 DB exists prior to performing tests that utilize the
|
||||
* data contained within.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public abstract class AbstractDatabaseTestCase extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
BaseDBTestCase.ensureDBExists();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2015 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.data.nvdcve;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeremy
|
||||
*/
|
||||
public class ConnectionFactoryTest extends BaseDBTestCase {
|
||||
|
||||
/**
|
||||
* Test of initialize method, of class ConnectionFactory.
|
||||
*
|
||||
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException
|
||||
*/
|
||||
@Test
|
||||
public void testInitialize() throws DatabaseException, SQLException {
|
||||
ConnectionFactory.initialize();
|
||||
Connection result = ConnectionFactory.getConnection();
|
||||
assertNotNull(result);
|
||||
result.close();
|
||||
ConnectionFactory.cleanup();
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -25,7 +25,9 @@ import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -35,10 +37,12 @@ public class CveDBMySQLTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
Settings.initialize();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
Settings.cleanup();
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -93,7 +97,7 @@ public class CveDBMySQLTest {
|
||||
CveDB instance = new CveDB();
|
||||
try {
|
||||
instance.open();
|
||||
List result = instance.getVulnerabilities(cpeStr);
|
||||
List<Vulnerability> result = instance.getVulnerabilities(cpeStr);
|
||||
assertTrue(result.size() > 5);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Unable to access the My SQL database; verify that the db server is running and that the schema has been generated");
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import java.util.Properties;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
|
||||
@@ -185,7 +185,6 @@ public class DependencyTest {
|
||||
@Test
|
||||
public void testGetIdentifiers() {
|
||||
Dependency instance = new Dependency();
|
||||
List expResult = null;
|
||||
Set<Identifier> result = instance.getIdentifiers();
|
||||
|
||||
assertTrue(true); //this is just a getter setter pair.
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ReportGeneratorIntegrationTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase.ensureDBExists();
|
||||
org.owasp.dependencycheck.BaseDBTestCase.ensureDBExists();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ public class SuppressionParserTest {
|
||||
//File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath());
|
||||
File file = BaseTest.getResourceAsFile(this, "suppressions.xml");
|
||||
SuppressionParser instance = new SuppressionParser();
|
||||
List result = instance.parseSuppressionRules(file);
|
||||
List<SuppressionRule> result = instance.parseSuppressionRules(file);
|
||||
assertTrue(result.size() > 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,27 +306,6 @@ public class SuppressionRuleTest {
|
||||
assertTrue(instance.cpeHasNoVersion(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of countCharacter method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCountCharacter() {
|
||||
String str = "cpe:/a:microsoft:.net_framework:4.5";
|
||||
char c = ':';
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
int expResult = 4;
|
||||
int result = instance.countCharacter(str, c);
|
||||
assertEquals(expResult, result);
|
||||
str = "::";
|
||||
expResult = 2;
|
||||
result = instance.countCharacter(str, c);
|
||||
assertEquals(expResult, result);
|
||||
str = "these are not the characters you are looking for";
|
||||
expResult = 0;
|
||||
result = instance.countCharacter(str, c);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of identifierMatches method, of class SuppressionRule.
|
||||
*/
|
||||
|
||||
@@ -61,11 +61,11 @@ public class DependencyVersionTest {
|
||||
@Test
|
||||
public void testIterator() {
|
||||
DependencyVersion instance = new DependencyVersion("1.2.3");
|
||||
Iterator result = instance.iterator();
|
||||
Iterator<String> result = instance.iterator();
|
||||
assertTrue(result.hasNext());
|
||||
int count = 1;
|
||||
while (result.hasNext()) {
|
||||
String v = (String) result.next();
|
||||
String v = result.next();
|
||||
assertTrue(String.valueOf(count++).equals(v));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,9 @@ engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt
|
||||
# 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.
|
||||
#if the filename has a %s it will be replaced with the current expected version
|
||||
data.file_name=dc.h2.db
|
||||
data.version=2.9
|
||||
data.version=3.0
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
@@ -39,19 +37,15 @@ data.password=DC-Pass1337!
|
||||
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
|
||||
cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.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.
|
||||
# the number of hours to wait before checking if updates are available from the NVD.
|
||||
cve.check.validforhours=0
|
||||
#first year to pull data from the URLs below
|
||||
cve.startyear=2014
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
@@ -62,6 +56,14 @@ cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
|
||||
cpe.validfordays=30
|
||||
cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz
|
||||
|
||||
# file type analyzer settings:
|
||||
analyzer.archive.enabled=true
|
||||
analyzer.jar.enabled=true
|
||||
analyzer.nuspec.enabled=true
|
||||
analyzer.assembly.enabled=true
|
||||
analyzer.composer.lock.enabled=true
|
||||
|
||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||
analyzer.nexus.enabled=true
|
||||
@@ -74,5 +76,27 @@ analyzer.nexus.proxy=true
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
|
||||
# the number of nested archives that will be searched.
|
||||
archive.scan.depth=3
|
||||
|
||||
# use HEAD (default) or GET as HTTP request method for query timestamp
|
||||
downloader.quick.query.timestamp=true
|
||||
|
||||
|
||||
analyzer.jar.enabled=true
|
||||
analyzer.archive.enabled=true
|
||||
analyzer.node.package.enabled=true
|
||||
analyzer.composer.lock.enabled=true
|
||||
analyzer.python.distribution.enabled=true
|
||||
analyzer.python.package.enabled=true
|
||||
analyzer.ruby.gemspec.enabled=true
|
||||
analyzer.autoconf.enabled=true
|
||||
analyzer.cmake.enabled=true
|
||||
analyzer.assembly.enabled=true
|
||||
analyzer.nuspec.enabled=true
|
||||
analyzer.openssl.enabled=true
|
||||
analyzer.central.enabled=true
|
||||
analyzer.nexus.enabled=false
|
||||
#whether the nexus analyzer uses the proxy
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
Dependency-Check-Gradle
|
||||
=========
|
||||
|
||||
**Working in progress**
|
||||
|
||||
This is a DependencyCheck gradle plugin designed for project which use Gradle as build script.
|
||||
|
||||
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.
|
||||
The dependency-check gradle plugin allows projects to monitor dependent libraries for
|
||||
known, published vulnerabilities.
|
||||
|
||||
=========
|
||||
|
||||
@@ -24,11 +21,11 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.thoughtworks.tools:dependency-check:0.0.8'
|
||||
classpath 'org.owasp:dependency-check-gradle:1.3.2'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'dependency-check'
|
||||
apply plugin: 'dependency-check-gradle'
|
||||
```
|
||||
|
||||
### Step 2, Run gradle task
|
||||
@@ -59,10 +56,10 @@ dependencyCheck {
|
||||
proxy {
|
||||
server = "127.0.0.1" // required, the server name or IP address of the proxy
|
||||
port = 3128 // required, the port number of the proxy
|
||||
|
||||
|
||||
// optional, the proxy server might require username
|
||||
// username = "username"
|
||||
|
||||
|
||||
// optional, the proxy server might require password
|
||||
// password = "password"
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
* Copyright (c) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
group = 'org.owasp'
|
||||
version = '1.3.2-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
@@ -43,14 +47,15 @@ targetCompatibility = 1.6
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(
|
||||
localGroovy(),
|
||||
gradleApi(),
|
||||
'org.owasp:dependency-check-core:1.3.1',
|
||||
'org.owasp:dependency-check-utils:1.3.1'
|
||||
'org.owasp:dependency-check-core:1.3.2-SNAPSHOT',
|
||||
'org.owasp:dependency-check-utils:1.3.2-SNAPSHOT'
|
||||
)
|
||||
|
||||
testCompile ('com.netflix.nebula:nebula-test:2.2.2'){
|
||||
@@ -75,11 +80,6 @@ task integTest(type: Test) {
|
||||
jvmArgs '-XX:MaxPermSize=256m'
|
||||
}
|
||||
|
||||
group = 'com.thoughtworks.tools'
|
||||
version = '0.0.8'
|
||||
|
||||
targetCompatibility = 1.7
|
||||
|
||||
apply from: 'conf/publish/local.gradle'
|
||||
//apply from: 'conf/publish/maven.gradle'
|
||||
//apply from: 'conf/publish/gradlePluginsPortal.gradle'
|
||||
|
||||
@@ -50,6 +50,11 @@ uploadArchives {
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id 'jeremylong'
|
||||
name 'Jeremy Long'
|
||||
email 'jeremy.long@owasp.org'
|
||||
}
|
||||
developer {
|
||||
id 'wmaintw'
|
||||
name 'Wei Ma'
|
||||
|
||||
@@ -22,11 +22,11 @@ Copyright (c) 2015 Wei Ma. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<version>1.3.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-gradle</artifactId>
|
||||
<version>0.0.6</version>
|
||||
<version>0.0.8</version>
|
||||
<!-- we must use gradle to build this, as such the packaging is pom -->
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
* Copyright (c) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
rootProject.name = 'dependency-check'
|
||||
rootProject.name = 'dependency-check-gradle'
|
||||
@@ -10,7 +10,7 @@ class DependencyCheckGradlePluginIntegSpec extends IntegrationSpec {
|
||||
def "I can add the plugin to a build with no errors"() {
|
||||
setup:
|
||||
buildFile << '''
|
||||
apply plugin: 'dependency-check'
|
||||
apply plugin: 'dependencyCheck'
|
||||
'''.stripIndent()
|
||||
|
||||
when:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @author Sion Williams
|
||||
*/
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'dependency-check'
|
||||
apply plugin: 'dependencyCheck'
|
||||
|
||||
sourceCompatibility = 1.5
|
||||
version = '1.0'
|
||||
@@ -17,5 +17,5 @@ dependencies {
|
||||
}
|
||||
|
||||
dependencyCheck {
|
||||
outputDirectory = "${buildDir}/dependencyCheckReport"
|
||||
reportsDirName = "reports"
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
/**
|
||||
* The analyzer configuration extension. Any value not configured will use the dependency-check-core defaults.
|
||||
*/
|
||||
class AnalyzerExtension {
|
||||
|
||||
/**
|
||||
* Sets whether the Archive Analyzer will be used.
|
||||
*/
|
||||
Boolean archiveEnabled
|
||||
/**
|
||||
* A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed.
|
||||
*/
|
||||
String zipExtensions
|
||||
/**
|
||||
* Sets whether Jar Analyzer will be used.
|
||||
*/
|
||||
Boolean jarEnabled
|
||||
/**
|
||||
* Sets whether Central Analyzer will be used. If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below).
|
||||
*/
|
||||
Boolean centralEnabled
|
||||
/**
|
||||
* Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation.
|
||||
*/
|
||||
Boolean nexusEnabled
|
||||
/**
|
||||
* Defines the Nexus Server's web service end point (example http://domain.enterprise/service/local/). If not set the Nexus Analyzer will be disabled.
|
||||
*/
|
||||
String nexusUrl
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
Boolean nexusUsesProxy
|
||||
/**
|
||||
* Sets whether or not the .NET Nuget Nuspec Analyzer will be used.
|
||||
*/
|
||||
Boolean nuspecEnabled
|
||||
/**
|
||||
* Sets whether or not the .NET Assembly Analyzer should be used.
|
||||
*/
|
||||
Boolean assemblyEnabled
|
||||
/**
|
||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
||||
*/
|
||||
String pathToMono
|
||||
|
||||
|
||||
/**
|
||||
* Sets whether the Python Distribution Analyzer will be used.
|
||||
*/
|
||||
Boolean pyDistributionEnabled
|
||||
/**
|
||||
* Sets whether the Python Package Analyzer will be used.
|
||||
*/
|
||||
Boolean pyPackageEnabled
|
||||
/**
|
||||
* Sets whether the Ruby Gemspec Analyzer will be used.
|
||||
*/
|
||||
Boolean rubygemsEnabled
|
||||
/**
|
||||
* Sets whether or not the openssl Analyzer should be used.
|
||||
*/
|
||||
Boolean opensslEnabled
|
||||
/**
|
||||
* Sets whether or not the CMake Analyzer should be used.
|
||||
*/
|
||||
Boolean cmakeEnabled
|
||||
/**
|
||||
* Sets whether or not the autoconf Analyzer should be used.
|
||||
*/
|
||||
Boolean autoconfEnabled
|
||||
/**
|
||||
* Sets whether or not the PHP Composer Lock File Analyzer should be used.
|
||||
*/
|
||||
Boolean composerEnabled
|
||||
/**
|
||||
* Sets whether or not the Node.js Analyzer should be used.
|
||||
*/
|
||||
Boolean nodeEnabled
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
import static org.owasp.dependencycheck.reporting.ReportGenerator.Format
|
||||
|
||||
/*
|
||||
* Configuration extension for the dependencyCheck plugin.
|
||||
*
|
||||
* @author Wei Ma
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
class CheckExtension extends UpdateExtension {
|
||||
/**
|
||||
* Configuration for the analyzers.
|
||||
*/
|
||||
AnalyzerExtension analyzerExtension
|
||||
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
String suppressionFile
|
||||
/**
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled.
|
||||
*/
|
||||
Boolean autoUpdate
|
||||
|
||||
//The following properties are not used via the settings object, instead
|
||||
// they are directly used by the check task.
|
||||
/**
|
||||
* When set to true dependency groups that start with 'test' will not be included in the analysis.
|
||||
* The default value is true.
|
||||
*/
|
||||
Boolean skipTestGroups = true
|
||||
/**
|
||||
* 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.
|
||||
* The default is HTML.
|
||||
*/
|
||||
Format format = Format.HTML
|
||||
/**
|
||||
* The name of the directory where reports will be written. Defaults to 'reports'.
|
||||
*/
|
||||
String reportsDirName = "reports"
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Float failBuildOnCVSS = 11.0
|
||||
/**
|
||||
* Displays a summary of the findings. Defaults to true.
|
||||
*/
|
||||
Boolean showSummary = true
|
||||
}
|
||||
@@ -18,10 +18,25 @@
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
class CveExtension {
|
||||
public class CveExtension {
|
||||
/**
|
||||
* URL for the modified CVE 1.2:
|
||||
* https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
**/
|
||||
String url20Modified
|
||||
/**
|
||||
* URL for the modified CVE 1.2:
|
||||
* https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
**/
|
||||
String url12Modified
|
||||
Integer startYear
|
||||
/**
|
||||
* URL for the modified CVE 1.2:
|
||||
* https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
**/
|
||||
String url20Base
|
||||
/**
|
||||
* Base URL for each year's CVE 2.0, the %d will be replaced with the year.
|
||||
* https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
**/
|
||||
String url12Base
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
/**
|
||||
* The update data configuration extension. Any value not configured will use the dependency-check-core defaults.
|
||||
*/
|
||||
class DataExtension extends PurgeDataExtension {
|
||||
/**
|
||||
* The connection string to the database.
|
||||
*/
|
||||
String connectionString
|
||||
/**
|
||||
* The user name to use when connecting to the database.
|
||||
*/
|
||||
String username
|
||||
/**
|
||||
* The password to use when connecting to the database.
|
||||
*/
|
||||
String password
|
||||
/**
|
||||
* The database dirver name (e.g. org.h2.Driver).
|
||||
*/
|
||||
String driver
|
||||
/**
|
||||
* The path to the driver (JAR) in case it is not already in the classpath.
|
||||
*/
|
||||
String driverPath
|
||||
}
|
||||
@@ -17,7 +17,10 @@
|
||||
*/
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
/**
|
||||
* TODO - this should not be needed, instead rely on the configured HTTP or HTTPS proxies
|
||||
* https://docs.gradle.org/current/userguide/build_environment.html
|
||||
*/
|
||||
class ProxyExtension {
|
||||
String server
|
||||
Integer port
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
/**
|
||||
* The data configuration extension. Any value not configured will use the dependency-check-core defaults.
|
||||
*/
|
||||
class PurgeDataExtension {
|
||||
/**
|
||||
* The directory to store the H2 database that contains the cache of the NVD CVE data.
|
||||
*/
|
||||
String directory="[JAR]/../../dependency-check-data"
|
||||
}
|
||||
@@ -18,10 +18,6 @@
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
class DependencyCheckExtension {
|
||||
ProxyExtension proxyExtension
|
||||
CveExtension cveExtension
|
||||
|
||||
String outputDirectory = "./reports"
|
||||
Boolean quickQueryTimestamp;
|
||||
class PurgeExtension {
|
||||
PurgeDataExtension dataExtension
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.extension
|
||||
|
||||
class UpdateExtension extends PurgeExtension {
|
||||
ProxyExtension proxyExtension
|
||||
CveExtension cveExtension
|
||||
DataExtension dataExtension
|
||||
/**
|
||||
* Set to false if the proxy does not support HEAD requests. The default is true.
|
||||
*/
|
||||
Boolean quickQueryTimestamp
|
||||
/**
|
||||
* The number of hours to wait before checking for additional updates from the NVD.
|
||||
*/
|
||||
Integer cveValidForHours
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.plugin
|
||||
|
||||
import com.tools.security.extension.CveExtension
|
||||
import com.tools.security.extension.CheckExtension
|
||||
import com.tools.security.extension.ProxyExtension
|
||||
import com.tools.security.extension.DataExtension
|
||||
import com.tools.security.extension.AnalyzerExtension
|
||||
import com.tools.security.extension.UpdateExtension
|
||||
import com.tools.security.extension.PurgeExtension
|
||||
import com.tools.security.extension.PurgeDataExtension
|
||||
import com.tools.security.tasks.Check
|
||||
import com.tools.security.tasks.Update
|
||||
import com.tools.security.tasks.Purge
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
class DependencyCheck implements Plugin<Project> {
|
||||
private static final String CHECK_TASK = 'dependencyCheck'
|
||||
private static final String UPDATE_TASK = 'dependencyCheckUpdate'
|
||||
private static final String PURGE_TASK = 'dependencyCheckPurge'
|
||||
|
||||
|
||||
/* configuration extensions */
|
||||
private static final String PROXY_EXTENSION_NAME = "proxy"
|
||||
private static final String CVE_EXTENSION_NAME = "cve"
|
||||
private static final String DATA_EXTENSION_NAME = "data"
|
||||
private static final String ANALYZER_EXTENSION_NAME = "analyzer"
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
initializeConfigurations(project)
|
||||
registerTasks(project)
|
||||
}
|
||||
|
||||
def initializeConfigurations(Project project) {
|
||||
def ext = project.extensions.create(CHECK_TASK, CheckExtension)
|
||||
ext.extensions.create(PROXY_EXTENSION_NAME, ProxyExtension)
|
||||
ext.extensions.create(CVE_EXTENSION_NAME, CveExtension)
|
||||
ext.extensions.create(DATA_EXTENSION_NAME, DataExtension)
|
||||
ext.extensions.create(ANALYZER_EXTENSION_NAME, AnalyzerExtension)
|
||||
|
||||
def extu = project.extensions.create(UPDATE_TASK, UpdateExtension)
|
||||
extu.extensions.create(CVE_EXTENSION_NAME, CveExtension)
|
||||
extu.extensions.create(DATA_EXTENSION_NAME, DataExtension)
|
||||
extu.extensions.create(PROXY_EXTENSION_NAME, ProxyExtension)
|
||||
|
||||
def extp = project.extensions.create(PURGE_TASK, PurgeExtension)
|
||||
extp.extensions.create(DATA_EXTENSION_NAME, PurgeDataExtension)
|
||||
}
|
||||
|
||||
def registerTasks(Project project) {
|
||||
project.task(CHECK_TASK, type: Check)
|
||||
project.task(UPDATE_TASK, type: Update)
|
||||
project.task(PURGE_TASK, type: Purge)
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.plugin
|
||||
|
||||
import com.tools.security.extension.CveExtension
|
||||
import com.tools.security.extension.DependencyCheckExtension
|
||||
import com.tools.security.extension.ProxyExtension
|
||||
import com.tools.security.tasks.DependencyCheckTask
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
class DependencyCheckGradlePlugin implements Plugin<Project> {
|
||||
private static final String ROOT_EXTENSION_NAME = 'dependencyCheck'
|
||||
private static final String TASK_NAME = 'dependencyCheck'
|
||||
private static final String PROXY_EXTENSION_NAME = "proxy"
|
||||
private static final String CVE_EXTENSION_NAME = "cve"
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
initializeConfigurations(project)
|
||||
registerTasks(project)
|
||||
}
|
||||
|
||||
def initializeConfigurations(Project project) {
|
||||
project.extensions.create(ROOT_EXTENSION_NAME, DependencyCheckExtension)
|
||||
project.dependencyCheck.extensions.create(PROXY_EXTENSION_NAME, ProxyExtension)
|
||||
project.dependencyCheck.extensions.create(CVE_EXTENSION_NAME, CveExtension)
|
||||
}
|
||||
|
||||
def registerTasks(Project project) {
|
||||
project.task(TASK_NAME, type: DependencyCheckTask)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.InvalidUserDataException
|
||||
|
||||
import org.owasp.dependencycheck.Engine
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB
|
||||
import org.owasp.dependencycheck.dependency.Dependency
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator
|
||||
import org.owasp.dependencycheck.utils.Settings
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
|
||||
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_MODIFIED_12_URL
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_MODIFIED_20_URL
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_SCHEMA_1_2
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_SCHEMA_2_0
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_START_YEAR
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DOWNLOADER_QUICK_QUERY_TIMESTAMP
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_PASSWORD
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_PORT
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_SERVER
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_USERNAME
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.AUTO_UPDATE
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DATA_DIRECTORY
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.SUPPRESSION_FILE
|
||||
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DB_DRIVER_NAME
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DB_DRIVER_PATH
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DB_CONNECTION_STRING
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DB_USER
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DB_PASSWORD
|
||||
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_JAR_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_NUSPEC_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_CENTRAL_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_NEXUS_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_NEXUS_URL
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_NEXUS_USES_PROXY
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_ARCHIVE_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_OPENSSL_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_CMAKE_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_AUTOCONF_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED
|
||||
|
||||
/**
|
||||
* Checks the projects dependencies for known vulnerabilities.
|
||||
*/
|
||||
class Check extends DefaultTask {
|
||||
|
||||
def currentProjectName = project.getName()
|
||||
def config = project.dependencyCheck
|
||||
|
||||
/**
|
||||
* Initializes the check task.
|
||||
*/
|
||||
Check() {
|
||||
group = 'OWASP dependency-check'
|
||||
description = 'Produce dependency security report.'
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls dependency-check-core's analysis engine to scan
|
||||
* all of the projects dependencies.
|
||||
*/
|
||||
@TaskAction
|
||||
def check() {
|
||||
initializeSettings()
|
||||
def engine = new Engine()
|
||||
|
||||
scanDependencies(engine)
|
||||
analyzeDependencies(engine)
|
||||
generateReport(engine)
|
||||
showSummary(engine)
|
||||
checkForFailure(engine)
|
||||
cleanup(engine)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the settings object. If the setting is not set the
|
||||
* default from dependency-check-core is used.
|
||||
*/
|
||||
def initializeSettings() {
|
||||
Settings.initialize()
|
||||
|
||||
Settings.setBooleanIfNotNull(AUTO_UPDATE, config.autoUpdate)
|
||||
Settings.setStringIfNotEmpty(SUPPRESSION_FILE, config.suppressionFile)
|
||||
|
||||
Settings.setStringIfNotEmpty(PROXY_SERVER, config.proxy.server)
|
||||
Settings.setStringIfNotEmpty(PROXY_PORT, "${config.proxy.port}")
|
||||
Settings.setStringIfNotEmpty(PROXY_USERNAME, config.proxy.username)
|
||||
Settings.setStringIfNotEmpty(PROXY_PASSWORD, config.proxy.password)
|
||||
//Settings.setStringIfNotEmpty(CONNECTION_TIMEOUT, connectionTimeout)
|
||||
Settings.setStringIfNotNull(DATA_DIRECTORY, config.data.directory)
|
||||
Settings.setStringIfNotEmpty(DB_DRIVER_NAME, config.data.driver)
|
||||
Settings.setStringIfNotEmpty(DB_DRIVER_PATH, config.data.driverPath)
|
||||
Settings.setStringIfNotEmpty(DB_CONNECTION_STRING, config.data.connectionString)
|
||||
Settings.setStringIfNotEmpty(DB_USER, config.data.username)
|
||||
Settings.setStringIfNotEmpty(DB_PASSWORD, config.data.password)
|
||||
Settings.setStringIfNotEmpty(CVE_MODIFIED_12_URL, config.cve.url12Modified)
|
||||
Settings.setStringIfNotEmpty(CVE_MODIFIED_20_URL, config.cve.url20Modified)
|
||||
Settings.setStringIfNotEmpty(CVE_SCHEMA_1_2, config.cve.url12Base)
|
||||
Settings.setStringIfNotEmpty(CVE_SCHEMA_2_0, config.cve.url20Base)
|
||||
|
||||
if (config.cveValidForHours != null) {
|
||||
if (config.cveValidForHours >= 0) {
|
||||
Settings.setInt(CVE_CHECK_VALID_FOR_HOURS, config.cveValidForHours);
|
||||
} else {
|
||||
throw new InvalidUserDataException("Invalid setting: `validForHours` must be 0 or greater");
|
||||
}
|
||||
}
|
||||
Settings.setBooleanIfNotNull(ANALYZER_JAR_ENABLED, config.analyzer.jarEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_NUSPEC_ENABLED, config.analyzer.nuspecEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_CENTRAL_ENABLED, config.analyzer.centralEnabled)
|
||||
|
||||
Settings.setBooleanIfNotNull(ANALYZER_NEXUS_ENABLED, config.analyzer.nexusEnabled)
|
||||
Settings.setStringIfNotEmpty(ANALYZER_NEXUS_URL, config.analyzer.nexusUrl)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_NEXUS_USES_PROXY, config.analyzer.nexusUsesProxy)
|
||||
|
||||
Settings.setBooleanIfNotNull(ANALYZER_ARCHIVE_ENABLED, config.analyzer.archiveEnabled)
|
||||
Settings.setStringIfNotEmpty(ADDITIONAL_ZIP_EXTENSIONS, config.analyzer.zipExtensions)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_ASSEMBLY_ENABLED, config.analyzer.assemblyEnabled)
|
||||
Settings.setStringIfNotEmpty(ANALYZER_ASSEMBLY_MONO_PATH, config.analyzer.pathToMono)
|
||||
|
||||
Settings.setBooleanIfNotNull(ANALYZER_PYTHON_DISTRIBUTION_ENABLED, config.analyzer.pyDistributionEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_PYTHON_PACKAGE_ENABLED, config.analyzer.pyPackageEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_RUBY_GEMSPEC_ENABLED, config.analyzer.rubygemsEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_OPENSSL_ENABLED, config.analyzer.opensslEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_CMAKE_ENABLED, config.analyzer.cmakeEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_AUTOCONF_ENABLED, config.analyzer.autoconfEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_COMPOSER_LOCK_ENABLED, config.analyzer.composerEnabled)
|
||||
Settings.setBooleanIfNotNull(ANALYZER_NODE_PACKAGE_ENABLED, config.analyzer.nodeEnabled)
|
||||
}
|
||||
/**
|
||||
* Relases resources and removes temporary files used.
|
||||
*/
|
||||
def cleanup(engine) {
|
||||
Settings.cleanup(true)
|
||||
engine.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the projects dependencies into the dependency-check analysis engine.
|
||||
*/
|
||||
def scanDependencies(engine) {
|
||||
logger.lifecycle("Verifying dependencies for project ${currentProjectName}")
|
||||
getAllDependencies(project).each {
|
||||
engine.scan(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the dependency-check analysis.
|
||||
*/
|
||||
def analyzeDependencies(Engine engine) {
|
||||
logger.lifecycle("Checking for updates and analyzing vulnerabilities for dependencies")
|
||||
engine.analyzeDependencies()
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a summary of the dependency-check results to the build console.
|
||||
*/
|
||||
def showSummary(Engine engine) {
|
||||
def vulnerabilities = engine.getDependencies().collect { Dependency dependency ->
|
||||
dependency.getVulnerabilities()
|
||||
}.flatten()
|
||||
|
||||
logger.lifecycle("Found ${vulnerabilities.size()} vulnerabilities in project ${currentProjectName}")
|
||||
if (config.showSummary) {
|
||||
final StringBuilder summary = new StringBuilder()
|
||||
for (Dependency d : engine.getDependencies()) {
|
||||
boolean firstEntry = true
|
||||
final StringBuilder ids = new StringBuilder()
|
||||
for (Vulnerability v : d.getVulnerabilities()) {
|
||||
if (firstEntry) {
|
||||
firstEntry = false
|
||||
} else {
|
||||
ids.append(", ")
|
||||
}
|
||||
ids.append(v.getName())
|
||||
}
|
||||
if (ids.length() > 0) {
|
||||
summary.append(d.getFileName()).append(" (")
|
||||
firstEntry = true
|
||||
for (Identifier id : d.getIdentifiers()) {
|
||||
if (firstEntry) {
|
||||
firstEntry = false
|
||||
} else {
|
||||
summary.append(", ")
|
||||
}
|
||||
summary.append(id.getValue())
|
||||
}
|
||||
summary.append(") : ").append(ids).append('\n')
|
||||
}
|
||||
}
|
||||
if (summary.length() > 0) {
|
||||
final String msg = String.format("%n%n"
|
||||
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
|
||||
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString())
|
||||
logger.lifecycle(msg)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* If configured, fails the build if a vulnerability is identified with a CVSS
|
||||
* score higher then the failure threshold configured.
|
||||
*/
|
||||
def checkForFailure(Engine engine) {
|
||||
if (config.failBuildOnCVSS>10) {
|
||||
return
|
||||
}
|
||||
|
||||
def vulnerabilities = engine.getDependencies().collect { Dependency dependency ->
|
||||
dependency.getVulnerabilities()
|
||||
}.flatten()
|
||||
|
||||
final StringBuilder ids = new StringBuilder();
|
||||
|
||||
vulnerabilities.each {
|
||||
if (it.getCvssScore() >= config.failBuildOnCVSS) {
|
||||
if (ids.length() == 0) {
|
||||
ids.append(it.getName());
|
||||
} else {
|
||||
ids.append(", ").append(it.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ids.length() > 0) {
|
||||
final String msg = String.format("%n%nDependency-Check Failure:%n"
|
||||
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
|
||||
+ "See the dependency-check report for more details.%n%n", config.failBuildOnCVSS, ids.toString());
|
||||
throw new GradleException(msg);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Writes the report(s) to the configured output directory.
|
||||
*/
|
||||
def generateReport(Engine engine) {
|
||||
logger.lifecycle("Generating report for project ${currentProjectName}")
|
||||
def reportGenerator = new ReportGenerator(currentProjectName, engine.dependencies, engine.analyzers,
|
||||
new CveDB().databaseProperties)
|
||||
|
||||
reportGenerator.generateReports("$project.buildDir/${config.reportsDirName}", config.format)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all dependencies associated wtihin the configured dependency groups. Test
|
||||
* groups can be excluded by setting the skipTestGroups configuration to true.
|
||||
*/
|
||||
def getAllDependencies(project) {
|
||||
return project.getConfigurations().findAll {
|
||||
!config.skipTestGroups || (config.skipTestGroups && !it.getName().startsWith("test"))
|
||||
}.collect {
|
||||
it.getResolvedConfiguration().getResolvedArtifacts().collect { ResolvedArtifact artifact ->
|
||||
artifact.getFile()
|
||||
}
|
||||
}.flatten().unique();
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
*
|
||||
* 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) 2015 Wei Ma. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.tools.security.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.owasp.dependencycheck.Engine
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB
|
||||
import org.owasp.dependencycheck.dependency.Dependency
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator
|
||||
import org.owasp.dependencycheck.utils.Settings
|
||||
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_MODIFIED_12_URL
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_MODIFIED_20_URL
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_SCHEMA_1_2
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_SCHEMA_2_0
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.CVE_START_YEAR
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.DOWNLOADER_QUICK_QUERY_TIMESTAMP
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_PASSWORD
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_PORT
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_SERVER
|
||||
import static org.owasp.dependencycheck.utils.Settings.KEYS.PROXY_USERNAME
|
||||
import static org.owasp.dependencycheck.utils.Settings.setBoolean
|
||||
import static org.owasp.dependencycheck.utils.Settings.setString
|
||||
|
||||
class DependencyCheckTask extends DefaultTask {
|
||||
|
||||
def currentProjectName = project.getName()
|
||||
def config = project.dependencyCheck
|
||||
|
||||
DependencyCheckTask() {
|
||||
group = 'Dependency Check'
|
||||
description = 'Produce dependency security report.'
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
def check() {
|
||||
initializeSettings()
|
||||
def engine = initializeEngine()
|
||||
|
||||
verifyDependencies(engine)
|
||||
analyzeDependencies(engine)
|
||||
retrieveVulnerabilities(engine)
|
||||
generateReport(engine)
|
||||
|
||||
cleanup(engine)
|
||||
}
|
||||
|
||||
private Engine initializeEngine() {
|
||||
new Engine()
|
||||
}
|
||||
|
||||
def initializeSettings() {
|
||||
Settings.initialize()
|
||||
overrideProxySetting()
|
||||
overrideCveUrlSetting()
|
||||
overrideDownloaderSetting()
|
||||
}
|
||||
|
||||
def cleanup(engine) {
|
||||
Settings.cleanup(true)
|
||||
engine.cleanup();
|
||||
}
|
||||
|
||||
def verifyDependencies(engine) {
|
||||
logger.lifecycle("Verifying dependencies for project ${currentProjectName}")
|
||||
getAllDependencies(project).each { engine.scan(it) }
|
||||
}
|
||||
|
||||
def analyzeDependencies(Engine engine) {
|
||||
logger.lifecycle("Checking for updates and analyzing vulnerabilities for dependencies")
|
||||
engine.analyzeDependencies()
|
||||
}
|
||||
|
||||
def retrieveVulnerabilities(Engine engine) {
|
||||
def vulnerabilities = engine.getDependencies().collect { Dependency dependency ->
|
||||
dependency.getVulnerabilities()
|
||||
}.flatten()
|
||||
|
||||
logger.lifecycle("Found ${vulnerabilities.size()} vulnerabilities in project ${currentProjectName}")
|
||||
}
|
||||
|
||||
def generateReport(Engine engine) {
|
||||
logger.lifecycle("Generating report for project ${currentProjectName}")
|
||||
def reportGenerator = new ReportGenerator(currentProjectName, engine.dependencies, engine.analyzers,
|
||||
new CveDB().databaseProperties)
|
||||
|
||||
reportGenerator.generateReports(generateReportDirectory(currentProjectName), ReportGenerator.Format.ALL)
|
||||
}
|
||||
|
||||
def generateReportDirectory(String currentProjectName) {
|
||||
"${config.outputDirectory}/${currentProjectName}"
|
||||
}
|
||||
|
||||
def overrideProxySetting() {
|
||||
if (isProxySettingExist()) {
|
||||
logger.lifecycle("Using proxy ${config.proxy.server}:${config.proxy.port}")
|
||||
|
||||
overrideStringSetting(PROXY_SERVER, config.proxy.server)
|
||||
overrideStringSetting(PROXY_PORT, "${config.proxy.port}")
|
||||
overrideStringSetting(PROXY_USERNAME, config.proxy.username)
|
||||
overrideStringSetting(PROXY_PASSWORD, config.proxy.password)
|
||||
}
|
||||
}
|
||||
|
||||
def isProxySettingExist() {
|
||||
config.proxy.server != null && config.proxy.port != null
|
||||
}
|
||||
|
||||
def getAllDependencies(project) {
|
||||
return project.getConfigurations().collect { Configuration configuration ->
|
||||
configuration.getResolvedConfiguration().getResolvedArtifacts().collect { ResolvedArtifact artifact ->
|
||||
artifact.getFile()
|
||||
}
|
||||
}.flatten();
|
||||
}
|
||||
|
||||
def overrideCveUrlSetting() {
|
||||
overrideStringSetting(CVE_MODIFIED_20_URL, config.cve.url20Modified)
|
||||
overrideStringSetting(CVE_MODIFIED_12_URL, config.cve.url12Modified)
|
||||
overrideIntegerSetting(CVE_START_YEAR, config.cve.startYear)
|
||||
overrideStringSetting(CVE_SCHEMA_2_0, config.cve.url20Base)
|
||||
overrideStringSetting(CVE_SCHEMA_1_2, config.cve.url12Base)
|
||||
}
|
||||
|
||||
def overrideDownloaderSetting() {
|
||||
overrideBooleanSetting(DOWNLOADER_QUICK_QUERY_TIMESTAMP, config.quickQueryTimestamp)
|
||||
}
|
||||
|
||||
private overrideStringSetting(String key, String providedValue) {
|
||||
if (providedValue != null) {
|
||||
logger.lifecycle("Setting [${key}] overrided with value [${providedValue}]")
|
||||
setString(key, providedValue)
|
||||
}
|
||||
}
|
||||
|
||||
private overrideIntegerSetting(String key, Integer providedValue) {
|
||||
if (providedValue != null) {
|
||||
logger.lifecycle("Setting [${key}] overrided with value [${providedValue}]")
|
||||
setString(key, "${providedValue}")
|
||||
}
|
||||
}
|
||||
|
||||
private overrideBooleanSetting(String key, Boolean providedValue) {
|
||||
if (providedValue != null) {
|
||||
logger.lifecycle("Setting [${key}] overrided with value [${providedValue}]")
|
||||
setBoolean(key, providedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user