mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0b549e427 | ||
|
|
75207169e3 | ||
|
|
e07f568237 | ||
|
|
e2cd99d40d | ||
|
|
27f2682a98 | ||
|
|
34a2110e9a | ||
|
|
96ba51db4f | ||
|
|
9c6053a60a | ||
|
|
358367ef9e | ||
|
|
a12bc44ecd | ||
|
|
773ac019f8 | ||
|
|
e751b7b814 | ||
|
|
824aa23b9b | ||
|
|
b7b97960a6 | ||
|
|
40f0e907e1 | ||
|
|
5ff0dc885d | ||
|
|
e70a0ee238 | ||
|
|
9338697079 | ||
|
|
4018a4e1de | ||
|
|
e8788dd2a4 | ||
|
|
e70c2f2b05 | ||
|
|
5ed0583039 | ||
|
|
f76d7295f9 | ||
|
|
6e280c4958 | ||
|
|
48b4ef1944 | ||
|
|
9150df964f | ||
|
|
b2237394e1 | ||
|
|
b3a0f7ad26 | ||
|
|
782ba42abc | ||
|
|
74b93ce602 | ||
|
|
e907c40f17 | ||
|
|
13a9dedb1e | ||
|
|
b37698f245 | ||
|
|
d30d000346 | ||
|
|
446239a5bd | ||
|
|
ac25aa795b | ||
|
|
f117a9ded0 | ||
|
|
947d38ccd2 | ||
|
|
23f7996db8 | ||
|
|
9fdff51f26 | ||
|
|
9b43bf004a | ||
|
|
5d73faa1f0 | ||
|
|
9e70279b31 | ||
|
|
9e671d1065 | ||
|
|
7e2c4af0b3 | ||
|
|
11f9092a65 | ||
|
|
6017e5c217 | ||
|
|
b2149ff4b9 | ||
|
|
1a5177c576 | ||
|
|
7020c9931a | ||
|
|
9bc43e2e8e | ||
|
|
26a4e7451e | ||
|
|
3470d33bdc | ||
|
|
51c96894b4 | ||
|
|
7fc2be6a0a | ||
|
|
110c97bc15 | ||
|
|
8d51d8fa1f | ||
|
|
4b02a567e0 | ||
|
|
5a939ec108 | ||
|
|
d9c4480627 | ||
|
|
9388340e23 | ||
|
|
2285d2ef4b | ||
|
|
f84aea0040 | ||
|
|
452969cc92 | ||
|
|
128a600f18 | ||
|
|
7dd9a52e78 | ||
|
|
ff341b7228 | ||
|
|
92a8b4ca85 | ||
|
|
384199b28d | ||
|
|
44edcabe15 | ||
|
|
1a5e9884fc | ||
|
|
cda81315d2 | ||
|
|
d7100e54d1 | ||
|
|
989caead9c | ||
|
|
a9d3b627f1 | ||
|
|
99a1606df1 | ||
|
|
6326513c63 | ||
|
|
f6cfae595a | ||
|
|
0794efcf41 | ||
|
|
b9ea82f2c1 | ||
|
|
8b705b3370 | ||
|
|
c684607a4d | ||
|
|
b00833c2de | ||
|
|
0ca6bc6ab6 | ||
|
|
60faddff9b | ||
|
|
b35da8ad4b | ||
|
|
79887c148a | ||
|
|
1ae3457ee6 | ||
|
|
d2154c9d29 | ||
|
|
40ede24a99 | ||
|
|
5960ba919d | ||
|
|
f6aaaa8815 | ||
|
|
6f1b20c936 | ||
|
|
7734a50427 | ||
|
|
aef118d375 | ||
|
|
22cae71999 | ||
|
|
29d127303c |
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM java:8
|
||||
|
||||
MAINTAINER Timo Pagel <dependencycheckmaintainer@timo-pagel.de>
|
||||
|
||||
RUN wget -O /tmp/current.txt http://jeremylong.github.io/DependencyCheck/current.txt && current=$(cat /tmp/current.txt) && wget https://dl.bintray.com/jeremy-long/owasp/dependency-check-$current-release.zip && unzip dependency-check-$current-release.zip && mv dependency-check /usr/share/
|
||||
|
||||
RUN useradd -ms /bin/bash dockeruser && chown -R dockeruser:dockeruser /usr/share/dependency-check && mkdir /report && chown -R dockeruser:dockeruser /report
|
||||
USER dockeruser
|
||||
|
||||
VOLUME "/src /usr/share/dependency-check/data /report"
|
||||
|
||||
WORKDIR /report
|
||||
|
||||
ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh", "--scan", "/src"]
|
||||
31
README.md
31
README.md
@@ -97,6 +97,37 @@ On Windows
|
||||
|
||||
Then load the resulting 'DependencyCheck-Report.html' into your favorite browser.
|
||||
|
||||
### Docker
|
||||
|
||||
In the following example it is assumed that the source to be checked is in the actual directory. A persistent data directory and a persistent report directory is used so that the container can be destroyed after running it to make sure that you use the newst version, always.
|
||||
```
|
||||
# After the first run, feel free to change the owner of the directories to the owner of the creted files and the permissions to 744
|
||||
DATA_DIRECTORY=$HOME/OWASP-Dependency-Check/data
|
||||
REPORT_DIRECTORY=/$HOME/OWASP-Dependency-Check/reports
|
||||
|
||||
if [ ! -d $DATA_DIRECTORY ]; then
|
||||
echo "Initially creating persistent directories"
|
||||
mkdir -p $DATA_DIRECTORY
|
||||
chmod -R 777 $DATA_DIRECTORY
|
||||
|
||||
mkdir -p $REPORT_DIRECTORY
|
||||
chmod -R 777 $REPORT_DIRECTORY
|
||||
fi
|
||||
|
||||
docker pull owasp/dependency-check # Make sure it is the actual version
|
||||
|
||||
docker run --rm \
|
||||
--volume $(pwd):/src \
|
||||
--volume $DATA_DIRECTORY:/usr/share/dependency-check/data \
|
||||
--volume $REPORT_DIRECTORY:/report \
|
||||
--name dependency-check \
|
||||
dc \
|
||||
--suppression "/src/security/dependency-check-suppression.xml"\
|
||||
--format "ALL" \
|
||||
--project "My OWASP Dependency Check Projekt" \
|
||||
```
|
||||
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.3</version>
|
||||
<version>1.4.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
|
||||
@@ -24,16 +24,21 @@ import org.slf4j.helpers.MarkerIgnoringBase;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
/**
|
||||
* An instance of {@link org.slf4j.Logger} which simply calls the log method on the delegate Ant task.
|
||||
* An instance of {@link org.slf4j.Logger} which simply calls the log method on
|
||||
* the delegate Ant task.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class AntLoggerAdapter extends MarkerIgnoringBase {
|
||||
|
||||
/**
|
||||
* serialization UID.
|
||||
*/
|
||||
private static final long serialVersionUID = -1337;
|
||||
/**
|
||||
* A reference to the Ant task used for logging.
|
||||
*/
|
||||
private Task task;
|
||||
private transient Task task;
|
||||
|
||||
/**
|
||||
* Constructs an Ant Logger Adapter.
|
||||
|
||||
@@ -346,6 +346,28 @@ public class Check extends Update {
|
||||
public void setSuppressionFile(String suppressionFile) {
|
||||
this.suppressionFile = suppressionFile;
|
||||
}
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
private String hintsFile;
|
||||
|
||||
/**
|
||||
* Get the value of hintsFile.
|
||||
*
|
||||
* @return the value of hintsFile
|
||||
*/
|
||||
public String getHintsFile() {
|
||||
return hintsFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of hintsFile.
|
||||
*
|
||||
* @param hintsFile new value of hintsFile
|
||||
*/
|
||||
public void setHintsFile(String hintsFile) {
|
||||
this.hintsFile = hintsFile;
|
||||
}
|
||||
/**
|
||||
* flag indicating whether or not to show a summary of findings.
|
||||
*/
|
||||
@@ -904,6 +926,7 @@ public class Check extends Update {
|
||||
super.populateSettings();
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, enableExperimental);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
|
||||
|
||||
@@ -2,7 +2,7 @@ Configuration
|
||||
====================
|
||||
The dependency-check-purge task deletes the local copy of the NVD. This task
|
||||
should rarely be used, if ever. This is included as a convenience method in
|
||||
the rare circumstance that the local H2 database because corrupt.
|
||||
the rare circumstance that the local H2 database becomes corrupt.
|
||||
|
||||
```xml
|
||||
<target name="dependency-check-purge" description="Dependency-Check purge">
|
||||
|
||||
@@ -39,6 +39,7 @@ projectName | The name of the project being scanned.
|
||||
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) |
|
||||
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |
|
||||
proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.3</version>
|
||||
<version>1.4.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.owasp.dependencycheck;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@@ -177,7 +178,7 @@ public class App {
|
||||
} catch (ExceptionCollection ex) {
|
||||
if (ex.isFatal()) {
|
||||
exitCode = -13;
|
||||
LOGGER.error("One or more fatal errors occured");
|
||||
LOGGER.error("One or more fatal errors occurred");
|
||||
} else {
|
||||
exitCode = -14;
|
||||
}
|
||||
@@ -347,6 +348,7 @@ public class App {
|
||||
final String dataDirectory = cli.getDataDirectory();
|
||||
final File propertiesFile = cli.getPropertiesFile();
|
||||
final String suppressionFile = cli.getSuppressionFile();
|
||||
final String hintsFile = cli.getHintsFile();
|
||||
final String nexusUrl = cli.getNexusUrl();
|
||||
final String databaseDriverName = cli.getDatabaseDriverName();
|
||||
final String databaseDriverPath = cli.getDatabaseDriverPath();
|
||||
@@ -394,6 +396,7 @@ public class App {
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPass);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
|
||||
Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||
|
||||
//File Type Analyzer Settings
|
||||
@@ -445,7 +448,7 @@ public class App {
|
||||
encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
|
||||
encoder.setContext(context);
|
||||
encoder.start();
|
||||
final FileAppender fa = new FileAppender();
|
||||
final FileAppender<ILoggingEvent> fa = new FileAppender<ILoggingEvent>();
|
||||
fa.setAppend(true);
|
||||
fa.setEncoder(encoder);
|
||||
fa.setContext(context);
|
||||
|
||||
@@ -277,6 +277,10 @@ public final class CliParser {
|
||||
.desc("The file path to the suppression XML file.")
|
||||
.build();
|
||||
|
||||
final Option hintsFile = Option.builder().argName("file").hasArg().longOpt(ARGUMENT.HINTS_FILE)
|
||||
.desc("The file path to the hints 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();
|
||||
@@ -305,6 +309,7 @@ public final class CliParser {
|
||||
.addOption(props)
|
||||
.addOption(verboseLog)
|
||||
.addOption(suppressionFile)
|
||||
.addOption(hintsFile)
|
||||
.addOption(cveValidForHours)
|
||||
.addOption(experimentalEnabled);
|
||||
}
|
||||
@@ -962,6 +967,15 @@ public final class CliParser {
|
||||
return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the hints file.
|
||||
*
|
||||
* @return the path to the hints file
|
||||
*/
|
||||
public String getHintsFile() {
|
||||
return line.getOptionValue(ARGUMENT.HINTS_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Prints the manifest information to standard output.</p>
|
||||
@@ -1273,9 +1287,14 @@ public final class CliParser {
|
||||
*/
|
||||
public static final String SUPPRESSION_FILE = "suppression";
|
||||
/**
|
||||
* The CLI argument name for setting the location of the suppression
|
||||
* The CLI argument name for setting the location of the hint
|
||||
* file.
|
||||
*/
|
||||
public static final String HINTS_FILE = "hints";
|
||||
/**
|
||||
* The CLI argument name for setting the number of hours to wait before
|
||||
* checking for new updates from the NVD.
|
||||
*/
|
||||
public static final String CVE_VALID_FOR_HOURS = "cveValidForHours";
|
||||
/**
|
||||
* Disables the Jar Analyzer.
|
||||
|
||||
@@ -9,10 +9,7 @@ Installation & Usage
|
||||
====================
|
||||
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
||||
Extract the zip file to a location on your computer and put the 'bin' directory into the
|
||||
path environment variable. On \*nix systems you will likely need to make the shell
|
||||
script executable:
|
||||
|
||||
$ chmod +777 dependency-check.sh
|
||||
path environment variable.
|
||||
|
||||
#set( $H = '#' )
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.3</version>
|
||||
<version>1.4.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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) 2016 Stefan Neuhaus. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Task to support parallelism of dependency-check analysis.
|
||||
* Analyses a single {@link Dependency} by a specific {@link Analyzer}.
|
||||
*
|
||||
* @author Stefan Neuhaus
|
||||
*/
|
||||
class AnalysisTask implements Callable<Void> {
|
||||
|
||||
/**
|
||||
* Instance of the logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AnalysisTask.class);
|
||||
|
||||
/**
|
||||
* A reference to the analyzer.
|
||||
*/
|
||||
private final Analyzer analyzer;
|
||||
/**
|
||||
* The dependency to analyze.
|
||||
*/
|
||||
private final Dependency dependency;
|
||||
/**
|
||||
* A reference to the dependency-check engine.
|
||||
*/
|
||||
private final Engine engine;
|
||||
/**
|
||||
* The list of exceptions that may occur during analysis.
|
||||
*/
|
||||
private final List<Throwable> exceptions;
|
||||
|
||||
/**
|
||||
* Creates a new analysis task.
|
||||
*
|
||||
* @param analyzer a reference of the analyzer to execute
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the dependency-check engine
|
||||
* @param exceptions exceptions that occur during analysis will be added to
|
||||
* this collection of exceptions
|
||||
*/
|
||||
AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions) {
|
||||
this.analyzer = analyzer;
|
||||
this.dependency = dependency;
|
||||
this.engine = engine;
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the analysis task.
|
||||
*
|
||||
* @return null
|
||||
* @throws Exception thrown if unable to execute the analysis task
|
||||
*/
|
||||
@Override
|
||||
public Void call() {
|
||||
Settings.initialize();
|
||||
|
||||
if (shouldAnalyze()) {
|
||||
LOGGER.debug("Begin Analysis of '{}' ({})", dependency.getActualFilePath(), analyzer.getName());
|
||||
try {
|
||||
analyzer.analyze(dependency, engine);
|
||||
} catch (AnalysisException ex) {
|
||||
LOGGER.warn("An error occurred while analyzing '{}' ({}).", dependency.getActualFilePath(), analyzer.getName());
|
||||
LOGGER.debug("", ex);
|
||||
exceptions.add(ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.warn("An unexpected error occurred during analysis of '{}' ({}): {}",
|
||||
dependency.getActualFilePath(), analyzer.getName(), ex.getMessage());
|
||||
LOGGER.debug("", ex);
|
||||
exceptions.add(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the analyzer can analyze the given dependency.
|
||||
*
|
||||
* @return whether or not the analyzer can analyze the dependency
|
||||
*/
|
||||
boolean shouldAnalyze() {
|
||||
if (analyzer instanceof FileTypeAnalyzer) {
|
||||
final FileTypeAnalyzer fileTypeAnalyzer = (FileTypeAnalyzer) analyzer;
|
||||
return fileTypeAnalyzer.accept(dependency.getActualFile());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import org.owasp.dependencycheck.analyzer.AnalysisPhase;
|
||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||
import org.owasp.dependencycheck.analyzer.AnalyzerService;
|
||||
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
@@ -29,9 +28,9 @@ import org.owasp.dependencycheck.data.update.CachedWebDataSource;
|
||||
import org.owasp.dependencycheck.data.update.UpdateService;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.exception.NoDataException;
|
||||
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
import org.owasp.dependencycheck.exception.NoDataException;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
@@ -41,12 +40,19 @@ import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and
|
||||
@@ -61,7 +67,7 @@ public class Engine implements FileFilter {
|
||||
/**
|
||||
* The list of dependencies.
|
||||
*/
|
||||
private List<Dependency> dependencies = new ArrayList<Dependency>();
|
||||
private final List<Dependency> dependencies = Collections.synchronizedList(new ArrayList<Dependency>());
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
@@ -156,9 +162,14 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dependencies identified.
|
||||
* Get the dependencies identified. The returned list is a reference to the
|
||||
* engine's synchronized list. You must synchronize on it, when you modify
|
||||
* and iterate over it from multiple threads. E.g. this holds for analyzers
|
||||
* supporting parallel processing during their analysis phase.
|
||||
*
|
||||
* @return the dependencies identified
|
||||
* @see Collections#synchronizedList(List)
|
||||
* @see Analyzer#supportsParallelProcessing()
|
||||
*/
|
||||
public List<Dependency> getDependencies() {
|
||||
return dependencies;
|
||||
@@ -170,7 +181,10 @@ public class Engine implements FileFilter {
|
||||
* @param dependencies the dependencies
|
||||
*/
|
||||
public void setDependencies(List<Dependency> dependencies) {
|
||||
this.dependencies = dependencies;
|
||||
synchronized (this.dependencies) {
|
||||
this.dependencies.clear();
|
||||
this.dependencies.addAll(dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,9 +197,24 @@ public class Engine implements FileFilter {
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public List<Dependency> scan(String[] paths) {
|
||||
return scan(paths, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans an array of files or directories. If a directory is specified, it
|
||||
* will be scanned recursively. Any dependencies identified are added to the
|
||||
* dependency collection.
|
||||
*
|
||||
* @param paths an array of paths to files or directories to be analyzed
|
||||
* @param projectReference the name of the project or scope in which the
|
||||
* dependency was identified
|
||||
* @return the list of dependencies scanned
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(String[] paths, String projectReference) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (String path : paths) {
|
||||
final List<Dependency> d = scan(path);
|
||||
final List<Dependency> d = scan(path, projectReference);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
@@ -202,8 +231,23 @@ public class Engine implements FileFilter {
|
||||
* @return the list of dependencies scanned
|
||||
*/
|
||||
public List<Dependency> scan(String path) {
|
||||
return scan(path, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be
|
||||
* scanned recursively. Any dependencies identified are added to the
|
||||
* dependency collection.
|
||||
*
|
||||
* @param path the path to a file or directory to be analyzed
|
||||
* @param projectReference the name of the project or scope in which the
|
||||
* dependency was identified
|
||||
* @return the list of dependencies scanned
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(String path, String projectReference) {
|
||||
final File file = new File(path);
|
||||
return scan(file);
|
||||
return scan(file, projectReference);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,9 +260,24 @@ public class Engine implements FileFilter {
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public List<Dependency> scan(File[] files) {
|
||||
return scan(files, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans an array 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 an array of paths to files or directories to be analyzed.
|
||||
* @param projectReference the name of the project or scope in which the
|
||||
* dependency was identified
|
||||
* @return the list of dependencies
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(File[] files, String projectReference) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
final List<Dependency> d = scan(file);
|
||||
final List<Dependency> d = scan(file, projectReference);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
@@ -236,9 +295,24 @@ public class Engine implements FileFilter {
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public List<Dependency> scan(Collection<File> files) {
|
||||
return scan(files, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param projectReference the name of the project or scope in which the
|
||||
* dependency was identified
|
||||
* @return the list of dependencies scanned
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(Collection<File> files, String projectReference) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
final List<Dependency> d = scan(file);
|
||||
final List<Dependency> d = scan(file, projectReference);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
@@ -256,11 +330,26 @@ public class Engine implements FileFilter {
|
||||
* @since v0.3.2.4
|
||||
*/
|
||||
public List<Dependency> scan(File file) {
|
||||
return scan(file, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be
|
||||
* scanned recursively. Any dependencies identified are added to the
|
||||
* dependency collection.
|
||||
*
|
||||
* @param file the path to a file or directory to be analyzed
|
||||
* @param projectReference the name of the project or scope in which the
|
||||
* dependency was identified
|
||||
* @return the list of dependencies scanned
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(File file, String projectReference) {
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
return scanDirectory(file);
|
||||
return scanDirectory(file, projectReference);
|
||||
} else {
|
||||
final Dependency d = scanFile(file);
|
||||
final Dependency d = scanFile(file, projectReference);
|
||||
if (d != null) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
deps.add(d);
|
||||
@@ -279,17 +368,31 @@ public class Engine implements FileFilter {
|
||||
* @return the list of Dependency objects scanned
|
||||
*/
|
||||
protected List<Dependency> scanDirectory(File dir) {
|
||||
return scanDirectory(dir, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scans files and directories. Any dependencies identified are
|
||||
* added to the dependency collection.
|
||||
*
|
||||
* @param dir the directory to scan
|
||||
* @param projectReference the name of the project or scope in which the
|
||||
* dependency was identified
|
||||
* @return the list of Dependency objects scanned
|
||||
* @since v1.4.4
|
||||
*/
|
||||
protected List<Dependency> scanDirectory(File dir, String projectReference) {
|
||||
final File[] files = dir.listFiles();
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
final List<Dependency> d = scanDirectory(f);
|
||||
final List<Dependency> d = scanDirectory(f, projectReference);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
} else {
|
||||
final Dependency d = scanFile(f);
|
||||
final Dependency d = scanFile(f, projectReference);
|
||||
deps.add(d);
|
||||
}
|
||||
}
|
||||
@@ -305,14 +408,54 @@ public class Engine implements FileFilter {
|
||||
* @return the scanned dependency
|
||||
*/
|
||||
protected Dependency scanFile(File file) {
|
||||
return scanFile(file, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a specified file. If a dependency is identified it is added to the
|
||||
* dependency collection.
|
||||
*
|
||||
* @param file The file to scan
|
||||
* @param projectReference the name of the project or scope in which the
|
||||
* dependency was identified
|
||||
* @return the scanned dependency
|
||||
* @since v1.4.4
|
||||
*/
|
||||
protected Dependency scanFile(File file, String projectReference) {
|
||||
Dependency dependency = null;
|
||||
if (file.isFile()) {
|
||||
if (accept(file)) {
|
||||
dependency = new Dependency(file);
|
||||
dependencies.add(dependency);
|
||||
if (projectReference != null) {
|
||||
dependency.addProjectReference(projectReference);
|
||||
}
|
||||
final String sha1 = dependency.getSha1sum();
|
||||
boolean found = false;
|
||||
synchronized (dependencies) {
|
||||
if (sha1 != null) {
|
||||
for (Dependency existing : dependencies) {
|
||||
if (sha1.equals(existing.getSha1sum())) {
|
||||
found = true;
|
||||
if (projectReference != null) {
|
||||
existing.addProjectReference(projectReference);
|
||||
}
|
||||
if (existing.getActualFilePath() != null && dependency.getActualFilePath() != null
|
||||
&& !existing.getActualFilePath().equals(dependency.getActualFilePath())) {
|
||||
existing.addRelatedDependency(dependency);
|
||||
} else {
|
||||
dependency = existing;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
|
||||
}
|
||||
return dependency;
|
||||
}
|
||||
@@ -323,7 +466,7 @@ public class Engine implements FileFilter {
|
||||
* iterates over a copy of the dependencies list. Thus, the potential for
|
||||
* {@link java.util.ConcurrentModificationException}s is avoided, and
|
||||
* analyzers may safely add or remove entries from the dependencies list.
|
||||
*
|
||||
* <p>
|
||||
* Every effort is made to complete analysis on the dependencies. In some
|
||||
* cases an exception will occur with part of the analysis being performed
|
||||
* which may not affect the entire analysis. If an exception occurs it will
|
||||
@@ -333,7 +476,7 @@ public class Engine implements FileFilter {
|
||||
* during analysis
|
||||
*/
|
||||
public void analyzeDependencies() throws ExceptionCollection {
|
||||
final List<Throwable> exceptions = new ArrayList<Throwable>();
|
||||
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
@@ -356,15 +499,9 @@ public class Engine implements FileFilter {
|
||||
try {
|
||||
ensureDataExists();
|
||||
} catch (NoDataException ex) {
|
||||
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
LOGGER.debug("", ex);
|
||||
exceptions.add(ex);
|
||||
throw new ExceptionCollection("Unable to continue dependency-check analysis.", exceptions, true);
|
||||
throwFatalExceptionCollection("Unable to continue dependency-check analysis.", ex, exceptions);
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
LOGGER.debug("", ex);
|
||||
exceptions.add(ex);
|
||||
throw new ExceptionCollection("Unable to connect to the dependency-check database", exceptions, true);
|
||||
throwFatalExceptionCollection("Unable to connect to the dependency-check database.", ex, exceptions);
|
||||
}
|
||||
|
||||
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
|
||||
@@ -375,42 +512,20 @@ public class Engine implements FileFilter {
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||
|
||||
for (Analyzer a : analyzerList) {
|
||||
for (final Analyzer analyzer : analyzerList) {
|
||||
final long analyzerStart = System.currentTimeMillis();
|
||||
try {
|
||||
a = initializeAnalyzer(a);
|
||||
initializeAnalyzer(analyzer);
|
||||
} catch (InitializationException ex) {
|
||||
exceptions.add(ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* need to create a copy of the collection because some of the
|
||||
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
|
||||
* This is okay for adds/deletes because it happens per analyzer.
|
||||
*/
|
||||
LOGGER.debug("Begin Analyzer '{}'", a.getName());
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>(dependencies);
|
||||
for (Dependency d : dependencySet) {
|
||||
boolean shouldAnalyze = true;
|
||||
if (a instanceof FileTypeAnalyzer) {
|
||||
final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
|
||||
shouldAnalyze = fAnalyzer.accept(d.getActualFile());
|
||||
}
|
||||
if (shouldAnalyze) {
|
||||
LOGGER.debug("Begin Analysis of '{}'", d.getActualFilePath());
|
||||
try {
|
||||
a.analyze(d, this);
|
||||
} catch (AnalysisException ex) {
|
||||
LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath());
|
||||
LOGGER.debug("", ex);
|
||||
exceptions.add(ex);
|
||||
} catch (Throwable ex) {
|
||||
//final AnalysisException ax = new AnalysisException(axMsg, ex);
|
||||
LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath());
|
||||
LOGGER.debug("", ex);
|
||||
exceptions.add(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
executeAnalysisTasks(analyzer, exceptions);
|
||||
|
||||
final long analyzerDurationMillis = System.currentTimeMillis() - analyzerStart;
|
||||
final long analyzerDurationSeconds = TimeUnit.MILLISECONDS.toSeconds(analyzerDurationMillis);
|
||||
LOGGER.info("Finished {} ({} seconds)", analyzer.getName(), analyzerDurationSeconds);
|
||||
}
|
||||
}
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
@@ -422,9 +537,80 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
|
||||
LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
|
||||
LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart);
|
||||
final long analysisDurationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - analysisStart);
|
||||
LOGGER.info("Analysis Complete ({} seconds)", analysisDurationSeconds);
|
||||
if (exceptions.size() > 0) {
|
||||
throw new ExceptionCollection("One or more exceptions occured during dependency-check analysis", exceptions);
|
||||
throw new ExceptionCollection("One or more exceptions occurred during dependency-check analysis", exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes executes the analyzer using multiple threads.
|
||||
*
|
||||
* @param exceptions a collection of exceptions that occurred during
|
||||
* analysis
|
||||
* @param analyzer the analyzer to execute
|
||||
* @throws ExceptionCollection thrown if exceptions occurred during analysis
|
||||
*/
|
||||
void executeAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) throws ExceptionCollection {
|
||||
LOGGER.debug("Starting {}", analyzer.getName());
|
||||
final List<AnalysisTask> analysisTasks = getAnalysisTasks(analyzer, exceptions);
|
||||
final ExecutorService executorService = getExecutorService(analyzer);
|
||||
|
||||
try {
|
||||
final List<Future<Void>> results = executorService.invokeAll(analysisTasks, 10, TimeUnit.MINUTES);
|
||||
|
||||
// ensure there was no exception during execution
|
||||
for (Future<Void> result : results) {
|
||||
try {
|
||||
result.get();
|
||||
} catch (ExecutionException e) {
|
||||
throwFatalExceptionCollection("Analysis task failed with a fatal exception.", e, exceptions);
|
||||
} catch (CancellationException e) {
|
||||
throwFatalExceptionCollection("Analysis task timed out.", e, exceptions);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throwFatalExceptionCollection("Analysis has been interrupted.", e, exceptions);
|
||||
} finally {
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis tasks for the dependencies.
|
||||
*
|
||||
* @param analyzer the analyzer to create tasks for
|
||||
* @param exceptions the collection of exceptions to collect
|
||||
* @return a collection of analysis tasks
|
||||
*/
|
||||
List<AnalysisTask> getAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) {
|
||||
final List<AnalysisTask> result = new ArrayList<AnalysisTask>();
|
||||
synchronized (dependencies) {
|
||||
for (final Dependency dependency : dependencies) {
|
||||
final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions);
|
||||
result.add(task);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the executor service for a given analyzer.
|
||||
*
|
||||
* @param analyzer the analyzer to obtain an executor
|
||||
* @return the executor service
|
||||
*/
|
||||
ExecutorService getExecutorService(Analyzer analyzer) {
|
||||
if (analyzer.supportsParallelProcessing()) {
|
||||
// just a fair trade-off that should be reasonable for all analyzer types
|
||||
final int maximumNumberOfThreads = 4 * Runtime.getRuntime().availableProcessors();
|
||||
|
||||
LOGGER.debug("Parallel processing with up to {} threads: {}.", maximumNumberOfThreads, analyzer.getName());
|
||||
return Executors.newFixedThreadPool(maximumNumberOfThreads);
|
||||
} else {
|
||||
LOGGER.debug("Parallel processing is not supported: {}.", analyzer.getName());
|
||||
return Executors.newSingleThreadExecutor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,6 +725,16 @@ public class Engine implements FileFilter {
|
||||
return this.fileTypeAnalyzers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file type analyzer. This has been added solely to assist in unit
|
||||
* testing the Engine.
|
||||
*
|
||||
* @param fta the file type analyzer to add
|
||||
*/
|
||||
protected void addFileTypeAnalyzer(FileTypeAnalyzer fta) {
|
||||
this.fileTypeAnalyzers.add(fta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the CPE Index to ensure documents exists. If none exist a
|
||||
* NoDataException is thrown.
|
||||
@@ -560,4 +756,20 @@ public class Engine implements FileFilter {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and throws a fatal exception collection.
|
||||
*
|
||||
* @param message the exception message
|
||||
* @param throwable the cause
|
||||
* @param exceptions a collection of exception to include
|
||||
* @throws ExceptionCollection a collection of exceptions that occurred
|
||||
* during analysis
|
||||
*/
|
||||
private void throwFatalExceptionCollection(String message, Throwable throwable, List<Throwable> exceptions) throws ExceptionCollection {
|
||||
LOGGER.error("{}\n\n{}", throwable.getMessage(), message);
|
||||
LOGGER.debug("", throwable);
|
||||
exceptions.add(throwable);
|
||||
throw new ExceptionCollection(message, exceptions, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,12 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||
public void close() throws Exception {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* The default is to support parallel processing.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParallelProcessing() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
/**
|
||||
* A flag indicating whether or not the analyzer is enabled.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
private volatile boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Get the value of enabled.
|
||||
|
||||
@@ -155,6 +155,11 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
}
|
||||
if (file != null) {
|
||||
if (!file.exists()) {
|
||||
final String msg = String.format("Suppression file '%s' does not exists", file.getPath());
|
||||
LOGGER.warn(msg);
|
||||
throw new SuppressionParseException(msg);
|
||||
}
|
||||
try {
|
||||
rules.addAll(parser.parseSuppressionRules(file));
|
||||
LOGGER.debug("{} suppression rules were loaded.", rules.size());
|
||||
@@ -168,6 +173,8 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
|
||||
} catch (MalformedURLException ex) {
|
||||
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
|
||||
} catch (SuppressionParseException ex) {
|
||||
throw ex;
|
||||
} catch (IOException ex) {
|
||||
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
|
||||
} finally {
|
||||
|
||||
@@ -75,4 +75,12 @@ public interface Analyzer {
|
||||
* @throws Exception is thrown if an exception occurs closing the analyzer.
|
||||
*/
|
||||
void close() throws Exception;
|
||||
|
||||
/**
|
||||
* Returns whether multiple instances of the same type of analyzer can run in parallel.
|
||||
* Note that running analyzers of different types in parallel is not supported at all.
|
||||
*
|
||||
* @return {@code true} if the analyzer supports parallel processing, {@code false} else
|
||||
*/
|
||||
boolean supportsParallelProcessing();
|
||||
}
|
||||
|
||||
@@ -25,10 +25,8 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -220,6 +218,18 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not support parallel processing as it both modifies and iterates
|
||||
* over the engine's list of dependencies.
|
||||
*
|
||||
* @see #analyzeFileType(Dependency, Engine)
|
||||
* @see #findMoreDependencies(Engine, File)
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParallelProcessing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a
|
||||
* WAR or EAR, the contents are extracted, scanned, and added to the list of
|
||||
@@ -236,25 +246,42 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
extractFiles(f, tmpDir, engine);
|
||||
|
||||
//make a copy
|
||||
final Set<Dependency> dependencySet = findMoreDependencies(engine, tmpDir);
|
||||
final List<Dependency> dependencySet = findMoreDependencies(engine, tmpDir);
|
||||
|
||||
if (!dependencySet.isEmpty()) {
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
final String displayPath = String.format("%s%s",
|
||||
dependency.getFilePath(),
|
||||
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||
final String displayName = String.format("%s: %s",
|
||||
dependency.getFileName(),
|
||||
d.getFileName());
|
||||
d.setFilePath(displayPath);
|
||||
d.setFileName(displayName);
|
||||
if (d.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
|
||||
//fix the dependency's display name and path
|
||||
final String displayPath = String.format("%s%s",
|
||||
dependency.getFilePath(),
|
||||
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||
final String displayName = String.format("%s: %s",
|
||||
dependency.getFileName(),
|
||||
d.getFileName());
|
||||
d.setFilePath(displayPath);
|
||||
d.setFileName(displayName);
|
||||
d.setProjectReferences(dependency.getProjectReferences());
|
||||
|
||||
//TODO - can we get more evidence from the parent? EAR contains module name, etc.
|
||||
//analyze the dependency (i.e. extract files) if it is a supported type.
|
||||
if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
|
||||
scanDepth += 1;
|
||||
analyze(d, engine);
|
||||
scanDepth -= 1;
|
||||
//TODO - can we get more evidence from the parent? EAR contains module name, etc.
|
||||
//analyze the dependency (i.e. extract files) if it is a supported type.
|
||||
if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
|
||||
scanDepth += 1;
|
||||
analyze(d, engine);
|
||||
scanDepth -= 1;
|
||||
}
|
||||
} else {
|
||||
for (Dependency sub : dependencySet) {
|
||||
if (sub.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
|
||||
final String displayPath = String.format("%s%s",
|
||||
dependency.getFilePath(),
|
||||
sub.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||
final String displayName = String.format("%s: %s",
|
||||
dependency.getFileName(),
|
||||
sub.getFileName());
|
||||
sub.setFilePath(displayPath);
|
||||
sub.setFileName(displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,30 +306,37 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String fileName = dependency.getFileName();
|
||||
|
||||
LOGGER.info("The zip file '{}' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName);
|
||||
|
||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
//store the archives sha1 and change it so that the engine doesn't think the zip and jar file are the same
|
||||
// and add it is a related dependency.
|
||||
final String archiveSha1 = dependency.getSha1sum();
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
|
||||
final Set<Dependency> dependencySet = findMoreDependencies(engine, tmpLoc);
|
||||
dependency.setSha1sum("");
|
||||
org.apache.commons.io.FileUtils.copyFile(dependency.getActualFile(), tmpLoc);
|
||||
final List<Dependency> dependencySet = findMoreDependencies(engine, tmpLoc);
|
||||
if (!dependencySet.isEmpty()) {
|
||||
if (dependencySet.size() != 1) {
|
||||
LOGGER.info("Deep copy of ZIP to JAR file resulted in more than one dependency?");
|
||||
}
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
d.setFilePath(dependency.getFilePath());
|
||||
d.setDisplayFileName(dependency.getFileName());
|
||||
if (d.getActualFile().equals(tmpLoc)) {
|
||||
d.setFilePath(dependency.getFilePath());
|
||||
d.setDisplayFileName(dependency.getFileName());
|
||||
} else {
|
||||
for (Dependency sub : d.getRelatedDependencies()) {
|
||||
if (sub.getActualFile().equals(tmpLoc)) {
|
||||
sub.setFilePath(dependency.getFilePath());
|
||||
sub.setDisplayFileName(dependency.getFileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Unable to perform deep copy on '{}'", dependency.getActualFile().getPath(), ex);
|
||||
} finally {
|
||||
dependency.setSha1sum(archiveSha1);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* An empty dependency set.
|
||||
*/
|
||||
private static final Set<Dependency> EMPTY_DEPENDENCY_SET = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* Scan the given file/folder, and return any new dependencies found.
|
||||
@@ -311,20 +345,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param file target of scanning
|
||||
* @return any dependencies that weren't known to the engine before
|
||||
*/
|
||||
private static Set<Dependency> findMoreDependencies(Engine engine, File file) {
|
||||
final List<Dependency> before = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(file);
|
||||
final List<Dependency> after = engine.getDependencies();
|
||||
final boolean sizeChanged = before.size() != after.size();
|
||||
final Set<Dependency> newDependencies;
|
||||
if (sizeChanged) {
|
||||
//get the new dependencies
|
||||
newDependencies = new HashSet<Dependency>(after);
|
||||
newDependencies.removeAll(before);
|
||||
} else {
|
||||
newDependencies = EMPTY_DEPENDENCY_SET;
|
||||
}
|
||||
return newDependencies;
|
||||
private static List<Dependency> findMoreDependencies(Engine engine, File file) {
|
||||
final List<Dependency> added = engine.scan(file);
|
||||
return added;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,31 +386,43 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
archiveExt = archiveExt.toLowerCase();
|
||||
|
||||
FileInputStream fis;
|
||||
final FileInputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new AnalysisException("Archive file was not found.", ex);
|
||||
}
|
||||
BufferedInputStream in = null;
|
||||
ZipArchiveInputStream zin = null;
|
||||
TarArchiveInputStream tin = null;
|
||||
GzipCompressorInputStream gin = null;
|
||||
BZip2CompressorInputStream bzin = null;
|
||||
try {
|
||||
if (ZIPPABLES.contains(archiveExt)) {
|
||||
final BufferedInputStream in = new BufferedInputStream(fis);
|
||||
in = new BufferedInputStream(fis);
|
||||
ensureReadableJar(archiveExt, in);
|
||||
extractArchive(new ZipArchiveInputStream(in), destination, engine);
|
||||
zin = new ZipArchiveInputStream(in);
|
||||
extractArchive(zin, destination, engine);
|
||||
} else if ("tar".equals(archiveExt)) {
|
||||
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||
in = new BufferedInputStream(fis);
|
||||
tin = new TarArchiveInputStream(in);
|
||||
extractArchive(tin, destination, engine);
|
||||
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
|
||||
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
|
||||
final File f = new File(destination, uncompressedName);
|
||||
if (engine.accept(f)) {
|
||||
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), f);
|
||||
in = new BufferedInputStream(fis);
|
||||
gin = new GzipCompressorInputStream(in);
|
||||
decompressFile(gin, f);
|
||||
}
|
||||
} else if ("bz2".equals(archiveExt) || "tbz2".equals(archiveExt)) {
|
||||
final String uncompressedName = BZip2Utils.getUncompressedFilename(archive.getName());
|
||||
final File f = new File(destination, uncompressedName);
|
||||
if (engine.accept(f)) {
|
||||
decompressFile(new BZip2CompressorInputStream(new BufferedInputStream(fis)), f);
|
||||
in = new BufferedInputStream(fis);
|
||||
bzin = new BZip2CompressorInputStream(in);
|
||||
decompressFile(bzin, f);
|
||||
}
|
||||
}
|
||||
} catch (ArchiveExtractionException ex) {
|
||||
@@ -397,7 +432,14 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.warn("Exception reading archive '{}'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
//overly verbose and not needed... but keeping it anyway due to
|
||||
//having issue with file handles being left open
|
||||
close(fis);
|
||||
close(in);
|
||||
close(zin);
|
||||
close(tin);
|
||||
close(gin);
|
||||
close(bzin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,10 +72,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* The temp value for GrokAssembly.exe
|
||||
*/
|
||||
private File grokAssemblyExe = null;
|
||||
/**
|
||||
* The DocumentBuilder for parsing the XML
|
||||
*/
|
||||
private DocumentBuilder builder;
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
@@ -128,6 +124,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
final Process proc = pb.start();
|
||||
|
||||
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
doc = builder.parse(proc.getInputStream());
|
||||
|
||||
// Try evacuating the error stream
|
||||
@@ -176,6 +173,8 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
product, Confidence.HIGH));
|
||||
}
|
||||
|
||||
} catch (ParserConfigurationException pce) {
|
||||
throw new AnalysisException("Error initializing the assembly analyzer", pce);
|
||||
} catch (IOException ioe) {
|
||||
throw new AnalysisException(ioe);
|
||||
} catch (SAXException saxe) {
|
||||
@@ -233,9 +232,9 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
// Now, need to see if GrokAssembly actually runs from this location.
|
||||
final List<String> args = buildArgumentList();
|
||||
//TODO this creaes an "unreported" error - if someone doesn't look
|
||||
//TODO this creates an "unreported" error - if someone doesn't look
|
||||
// at the command output this could easily be missed (especially in an
|
||||
// Ant or Mmaven build.
|
||||
// Ant or Maven build.
|
||||
//
|
||||
// We need to create a non-fatal warning error type that will
|
||||
// get added to the report.
|
||||
@@ -244,7 +243,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
setEnabled(false);
|
||||
LOGGER.error("----------------------------------------------------");
|
||||
LOGGER.error(".NET Assembly Analyzer could not be initialized and at least one "
|
||||
+ "'exe' or 'dll' was scanned. The 'mono' executale could not be found on "
|
||||
+ "'exe' or 'dll' was scanned. The 'mono' executable could not be found on "
|
||||
+ "the path; either disable the Assembly Analyzer or configure the path mono.");
|
||||
LOGGER.error("----------------------------------------------------");
|
||||
return;
|
||||
@@ -255,7 +254,10 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
// Try evacuating the error stream
|
||||
IOUtils.copy(p.getErrorStream(), NullOutputStream.NULL_OUTPUT_STREAM);
|
||||
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
final Document doc = builder.parse(p.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
if (p.waitFor() != 1 || error == null || error.isEmpty()) {
|
||||
@@ -275,12 +277,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
setEnabled(false);
|
||||
throw new InitializationException("An error occurred with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
try {
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
} catch (ParserConfigurationException ex) {
|
||||
setEnabled(false);
|
||||
throw new InitializationException("Error initializing the assembly analyzer", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,8 +31,6 @@ import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
@@ -178,11 +176,7 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy, alter and set in case some other thread is iterating over
|
||||
final List<Dependency> dependencies = new ArrayList<Dependency>(
|
||||
engine.getDependencies());
|
||||
dependencies.remove(dependency);
|
||||
engine.setDependencies(dependencies);
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,24 +92,10 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(".cmake")
|
||||
.addFilenames("CMakeLists.txt").build();
|
||||
|
||||
/**
|
||||
* A reference to SHA1 message digest.
|
||||
*/
|
||||
private static MessageDigest sha1 = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
sha1 = MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the CMake analyzer.
|
||||
*
|
||||
* @return the name of the analyzer
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -137,13 +123,19 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* No-op initializer implementation.
|
||||
* Initializes the analyzer.
|
||||
*
|
||||
* @throws InitializationException never thrown
|
||||
* @throws InitializationException thrown if an exception occurs getting an
|
||||
* instance of SHA1
|
||||
*/
|
||||
@Override
|
||||
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||
// Nothing to do here.
|
||||
try {
|
||||
getSha1MessageDigest();
|
||||
} catch (IllegalStateException ex) {
|
||||
setEnabled(false);
|
||||
throw new InitializationException("Unable to create SHA1 MessageDigest", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,6 +221,7 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
path = filePath.getBytes();
|
||||
}
|
||||
final MessageDigest sha1 = getSha1MessageDigest();
|
||||
currentDep.setSha1sum(Checksum.getHex(sha1.digest(path)));
|
||||
engine.getDependencies().add(currentDep);
|
||||
}
|
||||
@@ -245,4 +238,18 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_CMAKE_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sha1 message digest.
|
||||
*
|
||||
* @return the sha1 message digest
|
||||
*/
|
||||
private MessageDigest getSha1MessageDigest() {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
throw new IllegalStateException("Failed to obtain the SHA1 message digest.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
@@ -59,7 +60,7 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class CPEAnalyzer implements Analyzer {
|
||||
public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
@@ -155,10 +156,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
cve.open();
|
||||
cpe = CpeMemoryIndex.getInstance();
|
||||
try {
|
||||
LOGGER.info("Creating the CPE Index");
|
||||
final long creationStart = System.currentTimeMillis();
|
||||
cpe.open(cve);
|
||||
LOGGER.info("CPE Index Created ({} ms)", System.currentTimeMillis() - creationStart);
|
||||
final long creationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - creationStart);
|
||||
LOGGER.info("Created CPE Index ({} seconds)", creationSeconds);
|
||||
} catch (IndexException ex) {
|
||||
LOGGER.debug("IndexException", ex);
|
||||
throw new DatabaseException(ex);
|
||||
|
||||
@@ -75,7 +75,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* The analyzer should be disabled if there are errors, so this is a flag to
|
||||
* determine if such an error has occurred.
|
||||
*/
|
||||
private boolean errorFlag = false;
|
||||
private volatile boolean errorFlag = false;
|
||||
|
||||
/**
|
||||
* The searcher itself.
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.owasp.dependencycheck.data.composer.ComposerException;
|
||||
import org.owasp.dependencycheck.data.composer.ComposerLockParser;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -36,7 +37,6 @@ import java.io.FileNotFoundException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
|
||||
/**
|
||||
* Used to analyze a composer.lock file for a composer PHP app.
|
||||
@@ -85,19 +85,13 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
@Override
|
||||
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||
try {
|
||||
sha1 = MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
getSha1MessageDigest();
|
||||
} catch (IllegalStateException ex) {
|
||||
setEnabled(false);
|
||||
throw new InitializationException("Unable to create SHA1 MmessageDigest", ex);
|
||||
throw new InitializationException("Unable to create SHA1 MessageDigest", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The MessageDigest for calculating a new digest for the new dependencies
|
||||
* added.
|
||||
*/
|
||||
private MessageDigest sha1 = null;
|
||||
|
||||
/**
|
||||
* Entry point for the analyzer.
|
||||
*
|
||||
@@ -117,6 +111,7 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final Dependency d = new Dependency(dependency.getActualFile());
|
||||
d.setDisplayFileName(String.format("%s:%s/%s", dependency.getDisplayFileName(), dep.getGroup(), dep.getProject()));
|
||||
final String filePath = String.format("%s:%s/%s", dependency.getFilePath(), dep.getGroup(), dep.getProject());
|
||||
final MessageDigest sha1 = getSha1MessageDigest();
|
||||
d.setFilePath(filePath);
|
||||
d.setSha1sum(Checksum.getHex(sha1.digest(filePath.getBytes(Charset.defaultCharset()))));
|
||||
d.getVendorEvidence().addEvidence(COMPOSER_LOCK, "vendor", dep.getGroup(), Confidence.HIGHEST);
|
||||
@@ -169,4 +164,18 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sha1 message digest.
|
||||
*
|
||||
* @return the sha1 message digest
|
||||
*/
|
||||
private MessageDigest getSha1MessageDigest() {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
throw new IllegalStateException("Failed to obtain the SHA1 message digest.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
@@ -58,10 +58,23 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
* A pattern for obtaining the first part of a filename.
|
||||
*/
|
||||
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z0-9]*");
|
||||
|
||||
/**
|
||||
* a flag indicating if this analyzer has run. This analyzer only runs once.
|
||||
*/
|
||||
private boolean analyzed = false;
|
||||
|
||||
/**
|
||||
* Returns a flag indicating if this analyzer has run. This analyzer only
|
||||
* runs once. Note this is currently only used in the unit tests.
|
||||
*
|
||||
* @return a flag indicating if this analyzer has run. This analyzer only
|
||||
* runs once
|
||||
*/
|
||||
protected boolean getAnalyzed() {
|
||||
return analyzed;
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
@@ -94,6 +107,18 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Does not support parallel processing as it only runs once and then
|
||||
* operates on <em>all</em> dependencies.
|
||||
*
|
||||
* @return whether or not parallel processing is enabled
|
||||
* @see #analyze(Dependency, Engine)
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParallelProcessing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes a set of dependencies. If they have been found to have the same
|
||||
* base path and the same set of identifiers they are likely related. The
|
||||
@@ -350,11 +375,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
|| dependency2.getPackagePath() == null) {
|
||||
return false;
|
||||
}
|
||||
if (dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,10 +426,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
|| dependency2.getPackagePath() == null) {
|
||||
return false;
|
||||
}
|
||||
if (dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -517,6 +535,9 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
* <code>false</code>
|
||||
*/
|
||||
protected boolean firstPathIsShortest(String left, String right) {
|
||||
if (left.contains("dctemp")) {
|
||||
return false;
|
||||
}
|
||||
final String leftPath = left.replace('\\', '/');
|
||||
final String rightPath = right.replace('\\', '/');
|
||||
|
||||
|
||||
@@ -423,28 +423,30 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
String parentPath = dependency.getFilePath().toLowerCase();
|
||||
if (parentPath.contains(".jar")) {
|
||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||
final Dependency parent = findDependency(parentPath, engine.getDependencies());
|
||||
if (parent != null) {
|
||||
boolean remove = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(i.getType())) {
|
||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||
for (Identifier parentId : parent.getIdentifiers()) {
|
||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||
remove |= true;
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
synchronized (dependencies) {
|
||||
final Dependency parent = findDependency(parentPath, dependencies);
|
||||
if (parent != null) {
|
||||
boolean remove = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(i.getType())) {
|
||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||
for (Identifier parentId : parent.getIdentifiers()) {
|
||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||
remove |= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!remove) { //we can escape early
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!remove) { //we can escape early
|
||||
return;
|
||||
if (remove) {
|
||||
dependencies.remove(dependency);
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public class FileNameAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
|
||||
@@ -51,7 +51,7 @@ import org.xml.sax.SAXException;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public class HintAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
@@ -323,7 +323,7 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
|
||||
} catch (IOException ex) {
|
||||
throw new HintParseException("Unable to locate suppressions file in classpath", ex);
|
||||
throw new HintParseException("Unable to locate hints file in classpath", ex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -35,6 +34,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
@@ -76,7 +76,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* The count of directories created during analysis. This is used for
|
||||
* creating temporary directories.
|
||||
*/
|
||||
private static int dirCount = 0;
|
||||
private static final AtomicInteger DIR_COUNT = new AtomicInteger(0);
|
||||
/**
|
||||
* The system independent newline character.
|
||||
*/
|
||||
@@ -318,7 +318,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
pom.processProperties(pomProperties);
|
||||
setPomEvidence(newDependency, pom, null);
|
||||
engine.getDependencies().add(newDependency);
|
||||
Collections.sort(engine.getDependencies());
|
||||
} else {
|
||||
if (externalPom == null) {
|
||||
pom = PomUtils.readPom(path, jar);
|
||||
@@ -932,8 +931,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
LOGGER.debug("Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success) {
|
||||
LOGGER.warn("Failed to delete some temporary files, see the log for more details");
|
||||
if (!success && tempFileLocation.exists()) {
|
||||
final String[] l = tempFileLocation.list();
|
||||
if (l != null && l.length > 0) {
|
||||
LOGGER.warn("Failed to delete some temporary files, see the log for more details");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1218,7 +1220,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @throws AnalysisException thrown if unable to create temporary directory
|
||||
*/
|
||||
private File getNextTempDirectory() throws AnalysisException {
|
||||
dirCount += 1;
|
||||
final int dirCount = DIR_COUNT.incrementAndGet();
|
||||
final File directory = new File(tempFileLocation, String.valueOf(dirCount));
|
||||
//getting an exception for some directories not being able to be created; might be because the directory already exists?
|
||||
if (directory.exists()) {
|
||||
|
||||
@@ -87,6 +87,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final String SUPPORTED_EXTENSIONS = "jar";
|
||||
|
||||
private boolean useProxy;
|
||||
/**
|
||||
* The Nexus Search to be set up for this analyzer.
|
||||
*/
|
||||
@@ -144,10 +145,11 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.debug("Initializing Nexus Analyzer");
|
||||
LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
|
||||
if (isEnabled()) {
|
||||
useProxy = useProxy();
|
||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||
LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
|
||||
try {
|
||||
searcher = new NexusSearch(new URL(searchUrl));
|
||||
searcher = new NexusSearch(new URL(searchUrl), useProxy);
|
||||
if (!searcher.preflightRequest()) {
|
||||
setEnabled(false);
|
||||
throw new InitializationException("There was an issue getting Nexus status. Disabling analyzer.");
|
||||
@@ -263,4 +265,19 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.debug("Could not connect to nexus repository", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a proxy should be used.
|
||||
*
|
||||
* @return {@code true} if a proxy should be used
|
||||
*/
|
||||
public static boolean useProxy() {
|
||||
try {
|
||||
return Settings.getString(Settings.KEYS.PROXY_SERVER) != null
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY);
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warn("Failed to parse proxy settings.", ise);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class NvdCveAnalyzer implements Analyzer {
|
||||
public class NvdCveAnalyzer extends AbstractAnalyzer {
|
||||
/**
|
||||
* The Logger for use throughout the class
|
||||
*/
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Used to analyze a Wheel or egg distribution files, or their contents in
|
||||
@@ -76,7 +77,7 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* The count of directories created during analysis. This is used for
|
||||
* creating temporary directories.
|
||||
*/
|
||||
private static int dirCount = 0;
|
||||
private static final AtomicInteger DIR_COUNT = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
@@ -276,9 +277,11 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
LOGGER.debug("Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success) {
|
||||
LOGGER.warn(
|
||||
"Failed to delete some temporary files, see the log for more details");
|
||||
if (!success && tempFileLocation.exists()) {
|
||||
final String[] l = tempFileLocation.list();
|
||||
if (l != null && l.length > 0) {
|
||||
LOGGER.warn("Failed to delete some temporary files, see the log for more details");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,7 +394,7 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
// getting an exception for some directories not being able to be
|
||||
// created; might be because the directory already exists?
|
||||
do {
|
||||
dirCount += 1;
|
||||
final int dirCount = DIR_COUNT.incrementAndGet();
|
||||
directory = new File(tempFileLocation, String.valueOf(dirCount));
|
||||
} while (directory.exists());
|
||||
if (!directory.mkdirs()) {
|
||||
|
||||
@@ -33,8 +33,6 @@ import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
@@ -193,11 +191,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy, alter and set in case some other thread is iterating over
|
||||
final List<Dependency> dependencies = new ArrayList<Dependency>(
|
||||
engine.getDependencies());
|
||||
dependencies.remove(dependency);
|
||||
engine.setDependencies(dependencies);
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (InterruptedException ie) {
|
||||
throw new AnalysisException("bundle-audit process interrupted", ie);
|
||||
}
|
||||
if (exitValue != 0) {
|
||||
if (exitValue < 0 || exitValue > 1) {
|
||||
final String msg = String.format("Unexpected exit code from bundle-audit process; exit code: %s", exitValue);
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class CentralSearch {
|
||||
/**
|
||||
* Whether to use the Proxy when making requests
|
||||
*/
|
||||
private boolean useProxy;
|
||||
private final boolean useProxy;
|
||||
|
||||
/**
|
||||
* Used for logging.
|
||||
@@ -110,8 +110,9 @@ public class CentralSearch {
|
||||
if (conn.getResponseCode() == 200) {
|
||||
boolean missing = false;
|
||||
try {
|
||||
final DocumentBuilder builder = DocumentBuilderFactory
|
||||
.newInstance().newDocumentBuilder();
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String numFound = xpath.evaluate("/response/result/@numFound", doc);
|
||||
|
||||
@@ -25,6 +25,7 @@ import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
@@ -47,7 +48,7 @@ public class NexusSearch {
|
||||
/**
|
||||
* Whether to use the Proxy when making requests.
|
||||
*/
|
||||
private boolean useProxy;
|
||||
private final boolean useProxy;
|
||||
/**
|
||||
* Used for logging.
|
||||
*/
|
||||
@@ -56,32 +57,26 @@ public class NexusSearch {
|
||||
/**
|
||||
* Creates a NexusSearch for the given repository URL.
|
||||
*
|
||||
* @param rootURL the root URL of the repository on which searches should execute. full URL's are calculated relative to this
|
||||
* URL, so it should end with a /
|
||||
* @param rootURL the root URL of the repository on which searches should
|
||||
* execute. full URL's are calculated relative to this URL, so it should end
|
||||
* with a /
|
||||
* @param useProxy flag indicating if the proxy settings should be used
|
||||
*/
|
||||
public NexusSearch(URL rootURL) {
|
||||
public NexusSearch(URL rootURL, boolean useProxy) {
|
||||
this.rootURL = rootURL;
|
||||
try {
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY)) {
|
||||
useProxy = true;
|
||||
LOGGER.debug("Using proxy");
|
||||
} else {
|
||||
useProxy = false;
|
||||
LOGGER.debug("Not using proxy");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
useProxy = false;
|
||||
}
|
||||
this.useProxy = useProxy;
|
||||
LOGGER.debug("Using proxy: {}", useProxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the configured Nexus repository for the given sha1 hash. If the artifact is found, a <code>MavenArtifact</code> is
|
||||
* populated with the coordinate information.
|
||||
* Searches the configured Nexus repository for the given sha1 hash. If the
|
||||
* artifact is found, a <code>MavenArtifact</code> is populated with the
|
||||
* coordinate information.
|
||||
*
|
||||
* @param sha1 The SHA-1 hash string for which to search
|
||||
* @return the populated Maven coordinates
|
||||
* @throws IOException if it's unable to connect to the specified repository or if the specified artifact is not found.
|
||||
* @throws IOException if it's unable to connect to the specified repository
|
||||
* or if the specified artifact is not found.
|
||||
*/
|
||||
public MavenArtifact searchSha1(String sha1) throws IOException {
|
||||
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
||||
@@ -106,57 +101,60 @@ public class NexusSearch {
|
||||
conn.addRequestProperty("Accept", "application/xml");
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == 200) {
|
||||
try {
|
||||
final DocumentBuilder builder = DocumentBuilderFactory
|
||||
.newInstance().newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String groupId = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/groupId",
|
||||
doc);
|
||||
final String artifactId = xpath.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactId",
|
||||
doc);
|
||||
final String version = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/version",
|
||||
doc);
|
||||
final String link = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
|
||||
doc);
|
||||
final String pomLink = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/pomLink",
|
||||
doc);
|
||||
final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
|
||||
if (link != null && !link.isEmpty()) {
|
||||
ma.setArtifactUrl(link);
|
||||
switch (conn.getResponseCode()) {
|
||||
case 200:
|
||||
try {
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String groupId = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/groupId",
|
||||
doc);
|
||||
final String artifactId = xpath.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactId",
|
||||
doc);
|
||||
final String version = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/version",
|
||||
doc);
|
||||
final String link = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
|
||||
doc);
|
||||
final String pomLink = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/pomLink",
|
||||
doc);
|
||||
final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
|
||||
if (link != null && !link.isEmpty()) {
|
||||
ma.setArtifactUrl(link);
|
||||
}
|
||||
if (pomLink != null && !pomLink.isEmpty()) {
|
||||
ma.setPomUrl(pomLink);
|
||||
}
|
||||
return ma;
|
||||
} catch (Throwable e) {
|
||||
// Anything else is jacked-up XML stuff that we really can't recover
|
||||
// from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
if (pomLink != null && !pomLink.isEmpty()) {
|
||||
ma.setPomUrl(pomLink);
|
||||
}
|
||||
return ma;
|
||||
} catch (Throwable e) {
|
||||
// Anything else is jacked-up XML stuff that we really can't recover
|
||||
// from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
} else if (conn.getResponseCode() == 404) {
|
||||
throw new FileNotFoundException("Artifact not found in Nexus");
|
||||
} else {
|
||||
LOGGER.debug("Could not connect to Nexus received response code: {} {}",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
throw new IOException("Could not connect to Nexus");
|
||||
case 404:
|
||||
throw new FileNotFoundException("Artifact not found in Nexus");
|
||||
default:
|
||||
LOGGER.debug("Could not connect to Nexus received response code: {} {}",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
throw new IOException("Could not connect to Nexus");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a preflight request to see if the repository is actually working.
|
||||
*
|
||||
* @return whether the repository is listening and returns the /status URL correctly
|
||||
* @return whether the repository is listening and returns the /status URL
|
||||
* correctly
|
||||
*/
|
||||
public boolean preflightRequest() {
|
||||
HttpURLConnection conn;
|
||||
|
||||
@@ -36,7 +36,8 @@ public class XPathNuspecParser implements NuspecParser {
|
||||
* Gets the string value of a node or null if it's not present
|
||||
*
|
||||
* @param n the node to test
|
||||
* @return the string content of the node, or null if the node itself is null
|
||||
* @return the string content of the node, or null if the node itself is
|
||||
* null
|
||||
*/
|
||||
private String getOrNull(Node n) {
|
||||
if (n != null) {
|
||||
@@ -56,7 +57,10 @@ public class XPathNuspecParser implements NuspecParser {
|
||||
@Override
|
||||
public NugetPackage parse(InputStream stream) throws NuspecParseException {
|
||||
try {
|
||||
final Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(stream);
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final Document d = factory.newDocumentBuilder().parse(stream);
|
||||
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final NugetPackage nuspec = new NugetPackage();
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown if there is an error opening the
|
||||
* database connection
|
||||
*/
|
||||
public final void open() throws DatabaseException {
|
||||
public final synchronized void open() throws DatabaseException {
|
||||
if (!isOpen()) {
|
||||
conn = ConnectionFactory.getConnection();
|
||||
}
|
||||
@@ -129,7 +129,7 @@ public class CveDB {
|
||||
* Closes the DB4O database. Close should be called on this object when it
|
||||
* is done being used.
|
||||
*/
|
||||
public void close() {
|
||||
public synchronized void close() {
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
@@ -149,7 +149,7 @@ public class CveDB {
|
||||
*
|
||||
* @return whether the database connection is open or closed
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
public synchronized boolean isOpen() {
|
||||
return conn != null;
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ public class CveDB {
|
||||
*
|
||||
* @throws SQLException thrown if a SQL Exception occurs
|
||||
*/
|
||||
public void commit() throws SQLException {
|
||||
public synchronized void commit() throws SQLException {
|
||||
//temporary remove this as autocommit is on.
|
||||
//if (conn != null) {
|
||||
// conn.commit();
|
||||
@@ -202,7 +202,7 @@ public class CveDB {
|
||||
* analyzed
|
||||
* @return a set of vulnerable software
|
||||
*/
|
||||
public Set<VulnerableSoftware> getCPEs(String vendor, String product) {
|
||||
public synchronized Set<VulnerableSoftware> getCPEs(String vendor, String product) {
|
||||
final Set<VulnerableSoftware> cpe = new HashSet<VulnerableSoftware>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
@@ -234,7 +234,7 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown when there is an error retrieving the
|
||||
* data from the DB
|
||||
*/
|
||||
public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
public synchronized Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
final Set<Pair<String, String>> data = new HashSet<Pair<String, String>>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
@@ -259,7 +259,7 @@ public class CveDB {
|
||||
*
|
||||
* @return the properties from the database
|
||||
*/
|
||||
Properties getProperties() {
|
||||
synchronized Properties getProperties() {
|
||||
final Properties prop = new Properties();
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -285,7 +285,7 @@ public class CveDB {
|
||||
* @param key the property key
|
||||
* @param value the property value
|
||||
*/
|
||||
void saveProperty(String key, String value) {
|
||||
synchronized void saveProperty(String key, String value) {
|
||||
try {
|
||||
try {
|
||||
final PreparedStatement mergeProperty = getConnection().prepareStatement(statementBundle.getString("MERGE_PROPERTY"));
|
||||
@@ -328,7 +328,7 @@ public class CveDB {
|
||||
* @return a list of Vulnerabilities
|
||||
* @throws DatabaseException thrown if there is an exception retrieving data
|
||||
*/
|
||||
public List<Vulnerability> getVulnerabilities(String cpeStr) throws DatabaseException {
|
||||
public synchronized List<Vulnerability> getVulnerabilities(String cpeStr) throws DatabaseException {
|
||||
final VulnerableSoftware cpe = new VulnerableSoftware();
|
||||
try {
|
||||
cpe.parseName(cpeStr);
|
||||
@@ -389,7 +389,7 @@ public class CveDB {
|
||||
* @return a vulnerability object
|
||||
* @throws DatabaseException if an exception occurs
|
||||
*/
|
||||
public Vulnerability getVulnerability(String cve) throws DatabaseException {
|
||||
public synchronized Vulnerability getVulnerability(String cve) throws DatabaseException {
|
||||
PreparedStatement psV = null;
|
||||
PreparedStatement psR = null;
|
||||
PreparedStatement psS = null;
|
||||
@@ -462,7 +462,7 @@ public class CveDB {
|
||||
* @param vuln the vulnerability to add to the database
|
||||
* @throws DatabaseException is thrown if the database
|
||||
*/
|
||||
public void updateVulnerability(Vulnerability vuln) throws DatabaseException {
|
||||
public synchronized void updateVulnerability(Vulnerability vuln) throws DatabaseException {
|
||||
PreparedStatement selectVulnerabilityId = null;
|
||||
PreparedStatement deleteVulnerability = null;
|
||||
PreparedStatement deleteReferences = null;
|
||||
@@ -638,7 +638,7 @@ public class CveDB {
|
||||
*
|
||||
* @return <code>true</code> if data exists; otherwise <code>false</code>
|
||||
*/
|
||||
public boolean dataExists() {
|
||||
public synchronized boolean dataExists() {
|
||||
Statement cs = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
@@ -674,7 +674,7 @@ public class CveDB {
|
||||
* updates. This should be called after all updates have been completed to
|
||||
* ensure orphan entries are removed.
|
||||
*/
|
||||
public void cleanupDatabase() {
|
||||
public synchronized void cleanupDatabase() {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("CLEANUP_ORPHANS"));
|
||||
@@ -812,7 +812,7 @@ public class CveDB {
|
||||
*
|
||||
* Deletes unused dictionary entries from the database.
|
||||
*/
|
||||
public void deleteUnusedCpe() {
|
||||
public synchronized void deleteUnusedCpe() {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
|
||||
@@ -834,7 +834,7 @@ public class CveDB {
|
||||
* @param vendor the CPE vendor
|
||||
* @param product the CPE product
|
||||
*/
|
||||
public void addCpe(String cpe, String vendor, String product) {
|
||||
public synchronized void addCpe(String cpe, String vendor, String product) {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("ADD_DICT_CPE"));
|
||||
|
||||
@@ -44,11 +44,14 @@ import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is currently unused and if enabled will likely not work on MySQL as the MERGE statement is used.
|
||||
* This class is currently unused and if enabled will likely not work on MySQL
|
||||
* as the MERGE statement is used.
|
||||
*
|
||||
* The CpeUpdater is designed to download the CPE data file from NIST and import the data into the database. However, as this
|
||||
* currently adds no beneficial data, compared to what is in the CPE data contained in the CVE data files, this class is not
|
||||
* currently used. The code is being kept as a future update may utilize more data from the CPE xml files.
|
||||
* The CpeUpdater is designed to download the CPE data file from NIST and import
|
||||
* the data into the database. However, as this currently adds no beneficial
|
||||
* data, compared to what is in the CPE data contained in the CVE data files,
|
||||
* this class is not currently used. The code is being kept as a future update
|
||||
* may utilize more data from the CPE XML files.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -84,7 +87,8 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
* Downloads the CPE XML file.
|
||||
*
|
||||
* @return the file reference to the CPE.xml file
|
||||
* @throws UpdateException thrown if there is an issue downloading the XML file
|
||||
* @throws UpdateException thrown if there is an issue downloading the XML
|
||||
* file
|
||||
*/
|
||||
private File downloadCpe() throws UpdateException {
|
||||
File xml;
|
||||
@@ -112,11 +116,13 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
*
|
||||
* @param xml the CPE data file
|
||||
* @return the list of CPE entries
|
||||
* @throws UpdateException thrown if there is an issue with parsing the XML file
|
||||
* @throws UpdateException thrown if there is an issue with parsing the XML
|
||||
* file
|
||||
*/
|
||||
private List<Cpe> processXML(final File xml) throws UpdateException {
|
||||
try {
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final SAXParser saxParser = factory.newSAXParser();
|
||||
final CPEHandler handler = new CPEHandler();
|
||||
saxParser.parse(xml, handler);
|
||||
@@ -131,7 +137,8 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to find the last time the CPE data was refreshed and if it needs to be updated.
|
||||
* Checks to find the last time the CPE data was refreshed and if it needs
|
||||
* to be updated.
|
||||
*
|
||||
* @return true if the CPE data should be refreshed
|
||||
*/
|
||||
@@ -147,7 +154,8 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file specified.
|
||||
* Extracts the file contained in a gzip archive. The extracted file is
|
||||
* placed in the exact same path as the file specified.
|
||||
*
|
||||
* @param file the archive file
|
||||
* @throws FileNotFoundException thrown if the file does not exist
|
||||
|
||||
@@ -118,7 +118,7 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.debug("Database Exception opening databases to retrieve properties", ex);
|
||||
throw new UpdateException("Error occured updating database properties.");
|
||||
throw new UpdateException("Error occurred updating database properties.");
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
|
||||
} finally {
|
||||
|
||||
@@ -38,7 +38,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* A callable task that will process a given set of NVD CVE xml files and update the Cve Database accordingly.
|
||||
* A callable task that will process a given set of NVD CVE xml files and update
|
||||
* the Cve Database accordingly.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -91,9 +92,11 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
* Constructs a new ProcessTask used to process an NVD CVE update.
|
||||
*
|
||||
* @param cveDB the data store object
|
||||
* @param filePair the download task that contains the URL references to download
|
||||
* @param settings a reference to the global settings object; this is necessary so that when the thread is started the
|
||||
* dependencies have a correct reference to the global settings.
|
||||
* @param filePair the download task that contains the URL references to
|
||||
* download
|
||||
* @param settings a reference to the global settings object; this is
|
||||
* necessary so that when the thread is started the dependencies have a
|
||||
* correct reference to the global settings.
|
||||
*/
|
||||
public ProcessTask(final CveDB cveDB, final DownloadTask filePair, Settings settings) {
|
||||
this.cveDB = cveDB;
|
||||
@@ -106,8 +109,8 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
* Implements the callable interface.
|
||||
*
|
||||
* @return this object
|
||||
* @throws Exception thrown if there is an exception; note that any UpdateExceptions are simply added to the tasks exception
|
||||
* collection
|
||||
* @throws Exception thrown if there is an exception; note that any
|
||||
* UpdateExceptions are simply added to the tasks exception collection
|
||||
*/
|
||||
@Override
|
||||
public ProcessTask call() throws Exception {
|
||||
@@ -127,17 +130,20 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
*
|
||||
* @param file the file containing the NVD CVE XML
|
||||
* @param oldVersion contains the file containing the NVD CVE XML 1.2
|
||||
* @throws ParserConfigurationException is thrown if there is a parser configuration exception
|
||||
* @throws ParserConfigurationException is thrown if there is a parser
|
||||
* configuration exception
|
||||
* @throws SAXException is thrown if there is a SAXException
|
||||
* @throws IOException is thrown if there is a IO Exception
|
||||
* @throws SQLException is thrown if there is a SQL exception
|
||||
* @throws DatabaseException is thrown if there is a database exception
|
||||
* @throws ClassNotFoundException thrown if the h2 database driver cannot be loaded
|
||||
* @throws ClassNotFoundException thrown if the h2 database driver cannot be
|
||||
* loaded
|
||||
*/
|
||||
protected void importXML(File file, File oldVersion) throws ParserConfigurationException,
|
||||
SAXException, IOException, SQLException, DatabaseException, ClassNotFoundException {
|
||||
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final SAXParser saxParser = factory.newSAXParser();
|
||||
|
||||
final NvdCve12Handler cve12Handler = new NvdCve12Handler();
|
||||
@@ -153,7 +159,8 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
/**
|
||||
* Processes the NVD CVE XML file and imports the data into the DB.
|
||||
*
|
||||
* @throws UpdateException thrown if there is an error loading the data into the database
|
||||
* @throws UpdateException thrown if there is an error loading the data into
|
||||
* the database
|
||||
*/
|
||||
private void processFiles() throws UpdateException {
|
||||
LOGGER.info("Processing Started for NVD CVE - {}", filePair.getNvdCveInfo().getId());
|
||||
@@ -180,6 +187,6 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
filePair.cleanup();
|
||||
}
|
||||
LOGGER.info("Processing Complete for NVD CVE - {} ({} ms)", filePair.getNvdCveInfo().getId(),
|
||||
System.currentTimeMillis() - startProcessing);
|
||||
System.currentTimeMillis() - startProcessing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
/**
|
||||
* Creates a new Evidence objects.
|
||||
*
|
||||
* @param source the source of the evidence.
|
||||
* @param name the name of the evidence.
|
||||
* @param value the value of the evidence.
|
||||
* @param source the source of the evidence.
|
||||
* @param name the name of the evidence.
|
||||
* @param value the value of the evidence.
|
||||
* @param confidence the confidence of the evidence.
|
||||
*/
|
||||
public Evidence(String source, String name, String value, Confidence confidence) {
|
||||
@@ -127,9 +127,11 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of value. If setUsed is set to false this call to get will not mark the evidence as used.
|
||||
* Get the value of value. If setUsed is set to false this call to get will
|
||||
* not mark the evidence as used.
|
||||
*
|
||||
* @param setUsed whether or not this call to getValue should cause the used flag to be updated
|
||||
* @param setUsed whether or not this call to getValue should cause the used
|
||||
* flag to be updated
|
||||
* @return the value of value
|
||||
*/
|
||||
public String getValue(Boolean setUsed) {
|
||||
@@ -200,11 +202,11 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
|
||||
.append(StringUtils.lowerCase(name))
|
||||
.append(StringUtils.lowerCase(source))
|
||||
.append(StringUtils.lowerCase(value))
|
||||
.append(confidence)
|
||||
.toHashCode();
|
||||
.append(StringUtils.lowerCase(name))
|
||||
.append(StringUtils.lowerCase(source))
|
||||
.append(StringUtils.lowerCase(value))
|
||||
.append(confidence)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,6 +215,7 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
* @param that an object to check the equality of.
|
||||
* @return whether the two objects are equal.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (this == that) {
|
||||
@@ -223,6 +226,8 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
}
|
||||
final Evidence e = (Evidence) that;
|
||||
|
||||
//TODO the call to ObjectUtils.equals needs to be replaced when we
|
||||
//stop supporting Jenkins 1.6 requirement.
|
||||
return StringUtils.equalsIgnoreCase(name, e.name)
|
||||
&& StringUtils.equalsIgnoreCase(source, e.source)
|
||||
&& StringUtils.equalsIgnoreCase(value, e.value)
|
||||
@@ -235,6 +240,7 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
* @param o the evidence being compared
|
||||
* @return an integer indicating the ordering of the two objects
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public int compareTo(Evidence o) {
|
||||
if (o == null) {
|
||||
@@ -243,6 +249,8 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
if (StringUtils.equalsIgnoreCase(source, o.source)) {
|
||||
if (StringUtils.equalsIgnoreCase(name, o.name)) {
|
||||
if (StringUtils.equalsIgnoreCase(value, o.value)) {
|
||||
//TODO the call to ObjectUtils.equals needs to be replaced when we
|
||||
//stop supporting Jenkins 1.6 requirement.
|
||||
if (ObjectUtils.equals(confidence, o.confidence)) {
|
||||
return 0; //they are equal
|
||||
} else {
|
||||
@@ -260,10 +268,11 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link java.lang.String#compareToIgnoreCase(java.lang.String) String.compareToIgnoreCase} with an
|
||||
* exhaustive, possibly duplicative, check against nulls.
|
||||
* Wrapper around
|
||||
* {@link java.lang.String#compareToIgnoreCase(java.lang.String) String.compareToIgnoreCase}
|
||||
* with an exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.util.List;
|
||||
/**
|
||||
* A collection of several exceptions.
|
||||
*
|
||||
* @author Jeremy Lomg
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class ExceptionCollection extends Exception {
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ExceptionCollection extends Exception {
|
||||
* Instantiates a new exception collection.
|
||||
*
|
||||
* @param exceptions a list of exceptions
|
||||
* @param fatal indicates if the exception that occurred is fatal - meaning
|
||||
* @param fatal indicates if any of the exceptions that occurred is fatal - meaning
|
||||
* that no analysis was performed.
|
||||
*/
|
||||
public ExceptionCollection(List<Throwable> exceptions, boolean fatal) {
|
||||
@@ -68,7 +68,7 @@ public class ExceptionCollection extends Exception {
|
||||
*
|
||||
* @param msg the exception message
|
||||
* @param exceptions a list of exceptions
|
||||
* @param fatal indicates if the exception that occurred is fatal - meaning
|
||||
* @param fatal indicates if any of the exceptions that occurred is fatal - meaning
|
||||
* that no analysis was performed.
|
||||
*/
|
||||
public ExceptionCollection(String msg, List<Throwable> exceptions, boolean fatal) {
|
||||
@@ -181,7 +181,7 @@ public class ExceptionCollection extends Exception {
|
||||
*/
|
||||
@Override
|
||||
public void printStackTrace(PrintWriter s) {
|
||||
s.println("Multiple Exceptions Occured");
|
||||
s.println("Multiple Exceptions Occurred");
|
||||
super.printStackTrace(s);
|
||||
for (Throwable t : this.exceptions) {
|
||||
s.println("Next Exception:");
|
||||
@@ -215,7 +215,7 @@ public class ExceptionCollection extends Exception {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final String msg = super.getMessage();
|
||||
if (msg == null || msg.isEmpty()) {
|
||||
sb.append("One or more exceptions occured during analysis:");
|
||||
sb.append("One or more exceptions occurred during analysis:");
|
||||
} else {
|
||||
sb.append(msg);
|
||||
}
|
||||
|
||||
@@ -26,14 +26,15 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Simple object to track the parts of a version number. The parts are contained in a List such that version 1.2.3 will
|
||||
* be stored as: <code>versionParts[0] = 1;
|
||||
* Simple object to track the parts of a version number. The parts are contained
|
||||
* in a List such that version 1.2.3 will be stored as: <code>versionParts[0] = 1;
|
||||
* versionParts[1] = 2;
|
||||
* versionParts[2] = 3;
|
||||
* </code></p>
|
||||
* <p>
|
||||
* Note, the parser contained in this class expects the version numbers to be separated by periods. If a different
|
||||
* separator is used the parser will likely fail.</p>
|
||||
* Note, the parser contained in this class expects the version numbers to be
|
||||
* separated by periods. If a different separator is used the parser will likely
|
||||
* fail.</p>
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -47,8 +48,9 @@ public class DependencyVersion implements Iterable<String>, Comparable<Dependenc
|
||||
|
||||
/**
|
||||
* Constructor for a DependencyVersion that will parse a version string.
|
||||
* <b>Note</b>, this should only be used when the version passed in is already known to be a well formatted version
|
||||
* number. Otherwise, DependencyVersionUtil.parseVersion() should be used instead.
|
||||
* <b>Note</b>, this should only be used when the version passed in is
|
||||
* already known to be a well formatted version number. Otherwise,
|
||||
* DependencyVersionUtil.parseVersion() should be used instead.
|
||||
*
|
||||
* @param version the well formatted version number to parse
|
||||
*/
|
||||
@@ -57,8 +59,9 @@ public class DependencyVersion implements Iterable<String>, Comparable<Dependenc
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a version string into its sub parts: major, minor, revision, build, etc. <b>Note</b>, this should only be
|
||||
* used to parse something that is already known to be a version number.
|
||||
* Parses a version string into its sub parts: major, minor, revision,
|
||||
* build, etc. <b>Note</b>, this should only be used to parse something that
|
||||
* is already known to be a version number.
|
||||
*
|
||||
* @param version the version string to parse
|
||||
*/
|
||||
@@ -133,26 +136,33 @@ public class DependencyVersion implements Iterable<String>, Comparable<Dependenc
|
||||
return false;
|
||||
}
|
||||
final DependencyVersion other = (DependencyVersion) obj;
|
||||
final int max = (this.versionParts.size() < other.versionParts.size())
|
||||
final int minVersionMatchLength = (this.versionParts.size() < other.versionParts.size())
|
||||
? this.versionParts.size() : other.versionParts.size();
|
||||
final int maxVersionMatchLength = (this.versionParts.size() > other.versionParts.size())
|
||||
? this.versionParts.size() : other.versionParts.size();
|
||||
|
||||
if (minVersionMatchLength == 1 && maxVersionMatchLength >= 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO steal better version of code from compareTo
|
||||
for (int i = 0; i < max; i++) {
|
||||
for (int i = 0; i < minVersionMatchLength; i++) {
|
||||
final String thisPart = this.versionParts.get(i);
|
||||
final String otherPart = other.versionParts.get(i);
|
||||
if (!thisPart.equals(otherPart)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.versionParts.size() > max) {
|
||||
for (int i = max; i < this.versionParts.size(); i++) {
|
||||
if (this.versionParts.size() > minVersionMatchLength) {
|
||||
for (int i = minVersionMatchLength; i < this.versionParts.size(); i++) {
|
||||
if (!"0".equals(this.versionParts.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (other.versionParts.size() > max) {
|
||||
for (int i = max; i < other.versionParts.size(); i++) {
|
||||
if (other.versionParts.size() > minVersionMatchLength) {
|
||||
for (int i = minVersionMatchLength; i < other.versionParts.size(); i++) {
|
||||
if (!"0".equals(other.versionParts.get(i))) {
|
||||
return false;
|
||||
}
|
||||
@@ -180,8 +190,9 @@ public class DependencyVersion implements Iterable<String>, Comparable<Dependenc
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the three most major major version parts are identical. For instances, if version 1.2.3.4 was
|
||||
* compared to 1.2.3 this function would return true.
|
||||
* Determines if the three most major major version parts are identical. For
|
||||
* instances, if version 1.2.3.4 was compared to 1.2.3 this function would
|
||||
* return true.
|
||||
*
|
||||
* @param version the version number to compare
|
||||
* @return true if the first three major parts of the version are identical
|
||||
|
||||
@@ -109,6 +109,7 @@ public class HintParser {
|
||||
schemaStream = this.getClass().getClassLoader().getResourceAsStream(HINT_SCHEMA);
|
||||
final HintHandler handler = new HintHandler();
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
final SAXParser saxParser = factory.newSAXParser();
|
||||
|
||||
@@ -348,7 +348,7 @@ public class Model {
|
||||
* Utility class that can provide values from a Properties object to a
|
||||
* StrSubstitutor.
|
||||
*/
|
||||
private static class PropertyLookup extends StrLookup {
|
||||
private static class PropertyLookup extends StrLookup<String> {
|
||||
|
||||
/**
|
||||
* Reference to the properties to lookup.
|
||||
|
||||
@@ -47,10 +47,12 @@ public class PomParser {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PomParser.class);
|
||||
|
||||
/**
|
||||
* Parses the given xml file and returns a Model object containing only the fields dependency-check requires.
|
||||
* Parses the given xml file and returns a Model object containing only the
|
||||
* fields dependency-check requires.
|
||||
*
|
||||
* @param file a pom.xml
|
||||
* @return a Model object containing only the fields dependency-check requires
|
||||
* @return a Model object containing only the fields dependency-check
|
||||
* requires
|
||||
* @throws PomParseException thrown if the xml file cannot be parsed
|
||||
*/
|
||||
public Model parse(File file) throws PomParseException {
|
||||
@@ -73,7 +75,8 @@ public class PomParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given XML file and returns a Model object containing only the fields dependency-check requires.
|
||||
* Parses the given XML file and returns a Model object containing only the
|
||||
* fields dependency-check requires.
|
||||
*
|
||||
* @param inputStream an InputStream containing suppression rues
|
||||
* @return a list of suppression rules
|
||||
@@ -85,6 +88,7 @@ public class PomParser {
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
// factory.setNamespaceAware(true);
|
||||
// factory.setValidating(true);
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final SAXParser saxParser = factory.newSAXParser();
|
||||
final XMLReader xmlReader = saxParser.getXMLReader();
|
||||
xmlReader.setContentHandler(handler);
|
||||
|
||||
@@ -128,6 +128,7 @@ public class SuppressionParser {
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
final SAXParser saxParser = factory.newSAXParser();
|
||||
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
|
||||
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<evidence type="product" source="hint analyzer" name="product" value="springsource_spring_framework" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="SpringSource" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="vmware" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal software" confidence="HIGH"/>
|
||||
</add>
|
||||
</hint>
|
||||
<hint>
|
||||
@@ -22,7 +22,7 @@
|
||||
<evidence type="product" source="hint analyzer" name="product" value="springsource_spring_framework" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="SpringSource" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="vmware" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal software" confidence="HIGH"/>
|
||||
</add>
|
||||
</hint>
|
||||
<hint>
|
||||
@@ -32,7 +32,7 @@
|
||||
<add>
|
||||
<evidence type="product" source="hint analyzer" name="product" value="springsource_spring_framework" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="vmware" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal software" confidence="HIGH"/>
|
||||
</add>
|
||||
</hint>
|
||||
<hint>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
<cpe>cpe:/a:mod_security:mod_security</cpe>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
<cpe>cpe:/a:pivotal:spring_framework</cpe>
|
||||
<cpe>cpe:/a:pivotal_software:spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
@@ -18,6 +20,7 @@
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
<cpe>cpe:/a:pivotal:spring_framework</cpe>
|
||||
<cpe>cpe:/a:pivotal_software:spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
@@ -333,6 +336,8 @@
|
||||
<filePath regex="true">.*\.(jar|ear|war|pom)</filePath>
|
||||
<cpe>cpe:/a:pam:pam</cpe>
|
||||
<cpe>cpe:/a:pam_ssh:pam_ssh</cpe>
|
||||
<cpe>cpe:/a:sun:linux</cpe>
|
||||
<cpe>cpe:/a:sun:sunos</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
@@ -427,4 +432,25 @@
|
||||
<gav regex="true">com\.offbytwo\.jenkins:jenkins-client:.*</gav>
|
||||
<cpe>cpe:/a:jenkins:jenkins</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
xstream false positives
|
||||
]]></notes>
|
||||
<gav regex="true">^(?!com.thoughtworks).*xstream.*$</gav>
|
||||
<cpe>cpe:/a:x-stream:xstream</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
false positive per issue #582
|
||||
]]></notes>
|
||||
<gav regex="true">^org\.glassfish\.jersey\.ext:jersey-proxy-client:.*$</gav>
|
||||
<cpe>cpe:/a:oracle:oracle_client</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
file name: smiley-http-proxy-servlet-1.7.jar
|
||||
]]></notes>
|
||||
<gav regex="true">^org\.mitre\.dsmiley\.httpproxy:smiley-http-proxy-servlet:.*$</gav>
|
||||
<cpe>cpe:/a:shttp:shttp</cpe>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
|
||||
@@ -4,7 +4,7 @@ autoupdate=true
|
||||
max.download.threads=3
|
||||
|
||||
# the url to obtain the current engine version from
|
||||
engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt
|
||||
engine.version.url=https://jeremylong.github.io/DependencyCheck/current.txt
|
||||
|
||||
#temp.directory defaults to System.getProperty("java.io.tmpdir")
|
||||
#temp.directory=[path to temp directory]
|
||||
@@ -62,7 +62,7 @@ cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
cve.cpe.startswith.filter=cpe:/a:
|
||||
|
||||
cpe.validfordays=30
|
||||
cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz
|
||||
cpe.url=https://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz
|
||||
|
||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||
analyzer.nexus.enabled=true
|
||||
@@ -73,13 +73,14 @@ analyzer.nexus.proxy=true
|
||||
|
||||
# the URL for searching search.maven.org for SHA-1 and whether it's enabled
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
analyzer.central.url=https://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
|
||||
downloader.tls.protocols=TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
|
||||
|
||||
analyzer.experimental.enabled=false
|
||||
analyzer.jar.enabled=true
|
||||
|
||||
@@ -83,16 +83,68 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
xml += $("#modal-text").text().replace(/\n/g,'\n ');
|
||||
xml += '\n</suppressions>';
|
||||
$('#modal-text').text(xml).focus().select();
|
||||
$('#modal-add-header').toggleClass('active');
|
||||
});
|
||||
});
|
||||
function copyText(name, sha1, type, val) {
|
||||
function suppressSwitchTo(switchTo) {
|
||||
$('#modal-suppress-change-to-sha1').toggleClass('active');
|
||||
$('#modal-suppress-change-to-gav').toggleClass('active');
|
||||
setCopyText($('#suppress-name').val(),
|
||||
switchTo,
|
||||
$('#suppress-'+switchTo).val(),
|
||||
$('#suppress-type').val(),
|
||||
$('#suppress-val').val());
|
||||
}
|
||||
function copyText(name, sha1, gav, type, val) {
|
||||
$('#suppress-name').val(name);
|
||||
$('#suppress-type').val(type);
|
||||
$('#suppress-val').val(val);
|
||||
$('#suppress-sha1').val(sha1);
|
||||
$('#suppress-gav').val(gav);
|
||||
if (gav=='') {
|
||||
if ($('#modal-suppress-change-to-gav').hasClass('active')) {
|
||||
$('#modal-suppress-change-to-gav').toggleClass('active');
|
||||
}
|
||||
if ($('#modal-suppress-change-to-sha1').hasClass('active')) {
|
||||
$('#modal-suppress-change-to-sha1').toggleClass('active');
|
||||
}
|
||||
setCopyText(name, 'sha1', sha1, type, val);
|
||||
} else {
|
||||
if ($('#modal-suppress-change-to-gav').hasClass('active')) {
|
||||
$('#modal-suppress-change-to-gav').toggleClass('active');
|
||||
}
|
||||
if (!$('#modal-suppress-change-to-sha1').hasClass('active')) {
|
||||
$('#modal-suppress-change-to-sha1').toggleClass('active');
|
||||
}
|
||||
setCopyText(name, 'gav', gav, type, val);
|
||||
}
|
||||
}
|
||||
function setCopyText(name, matchType, matchValue, suppressType, suppressVal) {
|
||||
xml = '<suppress>\n';
|
||||
xml += ' <notes><!'+'[CDATA[\n file name: ' + name + '\n ]]'+'></notes>\n';
|
||||
xml += ' <sha1>' + sha1 + '</sha1>\n';
|
||||
xml += ' <'+type+'>' + val + '</'+type+'>\n';
|
||||
if (matchType=='gav') {
|
||||
v = matchValue.match(/^[^:]+:[^:]+:/);
|
||||
if (v && v[0]) {
|
||||
xml += ' <'+matchType+' regex="true">^' + v[0].replace(/\./g,'\\.') + '.*$</'+matchType+'>\n';
|
||||
} else {
|
||||
xml += ' <'+matchType+'>' + matchValue + '</'+matchType+'>\n';
|
||||
}
|
||||
} else {
|
||||
xml += ' <'+matchType+'>' + matchValue + '</'+matchType+'>\n';
|
||||
}
|
||||
if (suppressType=='cpe') {
|
||||
v = suppressVal.match(/^cpe:\/a:[^:]+:[^:]+/);
|
||||
if (v && v[0]) {
|
||||
xml += ' <'+suppressType+'>' + v[0] + '</'+suppressType+'>\n';
|
||||
} else {
|
||||
xml += ' <'+suppressType+'>' + suppressVal + '</'+suppressType+'>\n';
|
||||
}
|
||||
} else {
|
||||
xml += ' <'+suppressType+'>' + suppressVal + '</'+suppressType+'>\n';
|
||||
}
|
||||
xml += '</suppress>';
|
||||
$('#modal-text').text(xml);
|
||||
$('#modal-content,#modal-background').toggleClass('active');
|
||||
$('#modal-content,#modal-background').addClass('active');
|
||||
$('#modal-text').focus();
|
||||
$('#modal-text').select();
|
||||
}
|
||||
@@ -150,6 +202,12 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
#modal-text:focus {
|
||||
outline: none;
|
||||
}
|
||||
.suppresstype {
|
||||
display: none;
|
||||
}
|
||||
.suppresstype.active {
|
||||
display: block;
|
||||
}
|
||||
.suppressedLabel {
|
||||
cursor: default;
|
||||
padding:1px;
|
||||
@@ -504,6 +562,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<div id="modal-background"></div>
|
||||
<div id="modal-content">
|
||||
<div>Press CTR-C to copy XML <a href="http://jeremylong.github.io/DependencyCheck/general/suppression.html" class="infolink" target="_blank" title="Help with suppressing false positives">[help]</a></div>
|
||||
<button onclick="suppressSwitchTo('gav')" id="modal-suppress-change-to-gav" class="modal-button suppresstype" title="Supress by Maven Group Artifact Version">Suppress By GAV</button>
|
||||
<button onclick="suppressSwitchTo('sha1')" id="modal-suppress-change-to-sha1" class="modal-button suppresstype" title="Supress by SHA1 hash">Suppress By SHA1</button><br/>
|
||||
<input type="hidden" id="suppress-name"/>
|
||||
<input type="hidden" id="suppress-type"/><input type="hidden" id="suppress-val"/>
|
||||
<input type="hidden" id="suppress-sha1"/><input type="hidden" id="suppress-gav"/>
|
||||
<textarea id="modal-text" cols="50" rows="10" readonly></textarea><br/>
|
||||
<button id="modal-add-header" title="Add the parent XML nodes to create the complete XML file that can be used to suppress this finding" class="modal-button">Complete XML Doc</button><button id="modal-close" class="modal-button-right">Close</button>
|
||||
</div>
|
||||
@@ -515,6 +578,10 @@ the reporting provided constitutes acceptance for use in an AS IS condition, and
|
||||
implied or otherwise, with regard to the analysis or its use. Any use of the tool and the reporting provided
|
||||
is at the user’s risk. In no event shall the copyright holder or OWASP be held liable for any damages whatsoever
|
||||
arising out of or in connection with the use of this tool, the analysis performed, or the resulting report.</p>
|
||||
<h3><a href="http://jeremylong.github.io/DependencyCheck/general/thereport.html" target="_bank">How to read the report</a> |
|
||||
<a href="http://jeremylong.github.io/DependencyCheck/general/suppression.html" target="_bank">Suppressing false positives</a> |
|
||||
Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check" target="_blank">google group</a> |
|
||||
<a href="https://github.com/jeremylong/DependencyCheck/issues" target="_blank">github issues</a></h3>
|
||||
]]#
|
||||
<h2 class="">Project: $enc.html($applicationName)</h2>
|
||||
<div class="">
|
||||
@@ -577,8 +644,8 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
<td data-sort-value="$sortValue">
|
||||
#set($sortValue="")
|
||||
#set($cpeSort=0)
|
||||
#foreach($id in $dependency.getIdentifiers())
|
||||
#set($cpeSort=0)
|
||||
#if ($id.type=="maven")
|
||||
#if ($mavenlink=="" || !$mavenlink.url)
|
||||
#set($mavenlink=$id)
|
||||
@@ -725,6 +792,12 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<ul><li><b>None</b></li></ul>
|
||||
#else ## ($dependency.getIdentifiers().size()>0)
|
||||
<ul>
|
||||
#set($suppressGav='')
|
||||
#foreach($id in $dependency.getIdentifiers())
|
||||
#if ($id.type=="maven")
|
||||
#set($suppressGav=$id.value)
|
||||
#end
|
||||
#end
|
||||
#foreach($id in $dependency.getIdentifiers())
|
||||
#if( $id.url )
|
||||
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
|
||||
@@ -737,7 +810,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#if ($id.type=="cpe")
|
||||
##yes, we are HTML Encoding into JavaScript... the escape utils don't have a JS Encode and I haven't written one yet
|
||||
<button class="copybutton" title="Generate Suppression XML for this CPE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
<button class="copybutton" title="Generate Suppression XML for this CPE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', '$enc.html($suppressGav)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
#end
|
||||
#if ($id.description)
|
||||
<br/>$enc.html($id.description)
|
||||
@@ -753,7 +826,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#foreach($vuln in $dependency.getVulnerabilities())
|
||||
#set($vsctr=$vsctr+1)
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" title="Generate Suppression XML for this CCE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" title="Generate Suppression XML for this CCE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', '$enc.html($suppressGav)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p>Severity:
|
||||
#if ($vuln.cvssScore<4.0)
|
||||
Low
|
||||
|
||||
@@ -177,6 +177,11 @@ the reporting provided constitutes acceptance for use in an AS IS condition, and
|
||||
implied or otherwise, with regard to the analysis or its use. Any use of the tool and the reporting provided
|
||||
is at the user’s risk. In no event shall the copyright holder or OWASP be held liable for any damages whatsoever
|
||||
arising out of or in connection with the use of this tool, the analysis performed, or the resulting report.</p>
|
||||
<h3>About The Vulnerability Report | Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check" target="_blank">google group</a> |
|
||||
<a href="https://github.com/jeremylong/DependencyCheck/issues" target="_blank">github issues</a></h3>
|
||||
<p>This report is intended to be a quick summary of findings. It is highly recommended that you use the full HTML
|
||||
report to determine if any <a href="http://jeremylong.github.io/DependencyCheck/general/suppression.html">false positives</a>
|
||||
have been reported. Additionally, the HTML report provides many features not found in the vulnerability report.</p>
|
||||
]]#
|
||||
<h2 class="sectionheader white">Vulnerability Report for $enc.html($applicationName)</h2>
|
||||
<div class="sectioncontent">Report Generated On: $scanDate<br/><br/>
|
||||
@@ -190,7 +195,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#end
|
||||
Dependencies Scanned: $depCount<br/>
|
||||
Vulnerable Dependencies: $vulnCount<br/><br/>
|
||||
Vulnerable Dependencies: <span id="volnCount">$vulnCount</span><br/><br/>
|
||||
<h2>Vulnerable Dependencies</h2>
|
||||
#set($cnt=0)
|
||||
<table id="vulnTable" class="lined">
|
||||
@@ -222,10 +227,10 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
($vuln.cvssScore)
|
||||
<td>#set($cnt=$cnt+1)
|
||||
#if($dependency.getRelatedDependencies().size()>0)<span id="header$cnt" class="expandable collapsedList">#end
|
||||
$enc.html($dependency.DisplayFileName)
|
||||
<span title="$enc.html($dependency.FilePath)">$enc.html($dependency.DisplayFileName)</span>
|
||||
#if($dependency.getRelatedDependencies().size()>0) </span><div id="content$cnt" class="hidden">#end
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
$enc.html($related.DisplayFileName)<br/>
|
||||
<span title="$enc.html($related.FilePath)">$enc.html($related.DisplayFileName)</span><br/>
|
||||
#end
|
||||
#if($dependency.getRelatedDependencies().size()>0)</div#end
|
||||
</td>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import mockit.Expectations;
|
||||
import mockit.Mocked;
|
||||
import mockit.Verifications;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
||||
import org.owasp.dependencycheck.analyzer.HintAnalyzer;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class AnalysisTaskTest {
|
||||
|
||||
@Mocked
|
||||
FileTypeAnalyzer fileTypeAnalyzer;
|
||||
|
||||
@Mocked
|
||||
Dependency dependency;
|
||||
|
||||
@Mocked
|
||||
Engine engine;
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldAnalyzeReturnsTrueForNonFileTypeAnalyzers() {
|
||||
AnalysisTask instance = new AnalysisTask(new HintAnalyzer(), null, null, null);
|
||||
boolean shouldAnalyze = instance.shouldAnalyze();
|
||||
assertTrue(shouldAnalyze);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAnalyzeReturnsTrueIfTheFileTypeAnalyzersAcceptsTheDependency() {
|
||||
final File dependencyFile = new File("");
|
||||
new Expectations() {{
|
||||
dependency.getActualFile();
|
||||
result = dependencyFile;
|
||||
|
||||
fileTypeAnalyzer.accept(dependencyFile);
|
||||
result = true;
|
||||
}};
|
||||
|
||||
AnalysisTask analysisTask = new AnalysisTask(fileTypeAnalyzer, dependency, null, null);
|
||||
|
||||
boolean shouldAnalyze = analysisTask.shouldAnalyze();
|
||||
assertTrue(shouldAnalyze);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAnalyzeReturnsFalseIfTheFileTypeAnalyzerDoesNotAcceptTheDependency() {
|
||||
final File dependencyFile = new File("");
|
||||
new Expectations() {{
|
||||
dependency.getActualFile();
|
||||
result = dependencyFile;
|
||||
|
||||
fileTypeAnalyzer.accept(dependencyFile);
|
||||
result = false;
|
||||
}};
|
||||
|
||||
AnalysisTask analysisTask = new AnalysisTask(fileTypeAnalyzer, dependency, null, null);
|
||||
|
||||
boolean shouldAnalyze = analysisTask.shouldAnalyze();
|
||||
assertFalse(shouldAnalyze);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskAnalyzes() throws Exception {
|
||||
final AnalysisTask analysisTask = new AnalysisTask(fileTypeAnalyzer, dependency, engine, null);
|
||||
new Expectations(analysisTask) {{
|
||||
analysisTask.shouldAnalyze();
|
||||
result = true;
|
||||
}};
|
||||
|
||||
analysisTask.call();
|
||||
|
||||
new Verifications() {{
|
||||
fileTypeAnalyzer.analyze(dependency, engine);
|
||||
times = 1;
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskDoesNothingIfItShouldNotAnalyze() throws Exception {
|
||||
final AnalysisTask analysisTask = new AnalysisTask(fileTypeAnalyzer, dependency, engine, null);
|
||||
new Expectations(analysisTask) {{
|
||||
analysisTask.shouldAnalyze();
|
||||
result = false;
|
||||
}};
|
||||
|
||||
analysisTask.call();
|
||||
|
||||
new Verifications() {{
|
||||
fileTypeAnalyzer.analyze(dependency, engine);
|
||||
times = 0;
|
||||
}};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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) 2016 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import mockit.Expectations;
|
||||
import mockit.Mocked;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||
import org.owasp.dependencycheck.analyzer.JarAnalyzer;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class EngineTest extends BaseDBTestCase {
|
||||
|
||||
@Mocked
|
||||
Analyzer analyzer;
|
||||
|
||||
@Mocked
|
||||
AnalysisTask analysisTask;
|
||||
|
||||
|
||||
/**
|
||||
* Test of scanFile method, of class Engine.
|
||||
*/
|
||||
@Test
|
||||
public void testScanFile() throws DatabaseException {
|
||||
Engine instance = new Engine();
|
||||
instance.addFileTypeAnalyzer(new JarAnalyzer());
|
||||
File file = BaseTest.getResourceAsFile(this, "dwr.jar");
|
||||
Dependency dwr = instance.scanFile(file);
|
||||
file = BaseTest.getResourceAsFile(this, "org.mortbay.jmx.jar");
|
||||
instance.scanFile(file);
|
||||
assertEquals(2, instance.getDependencies().size());
|
||||
|
||||
file = BaseTest.getResourceAsFile(this, "dwr.jar");
|
||||
Dependency secondDwr = instance.scanFile(file);
|
||||
|
||||
assertEquals(2, instance.getDependencies().size());
|
||||
assertTrue(dwr == secondDwr);
|
||||
}
|
||||
|
||||
@Test(expected = ExceptionCollection.class)
|
||||
public void exceptionDuringAnalysisTaskExecutionIsFatal() throws DatabaseException, ExceptionCollection {
|
||||
final ExecutorService executorService = Executors.newFixedThreadPool(3);
|
||||
final Engine instance = new Engine();
|
||||
final List<Throwable> exceptions = new ArrayList<Throwable>();
|
||||
|
||||
new Expectations() {{
|
||||
analysisTask.call();
|
||||
result = new IllegalStateException("Analysis task execution threw an exception");
|
||||
}};
|
||||
|
||||
final List<AnalysisTask> failingAnalysisTask = new ArrayList<AnalysisTask>();
|
||||
failingAnalysisTask.add(analysisTask);
|
||||
|
||||
new Expectations(instance) {{
|
||||
instance.getExecutorService(analyzer);
|
||||
result = executorService;
|
||||
|
||||
instance.getAnalysisTasks(analyzer, exceptions);
|
||||
result = failingAnalysisTask;
|
||||
}};
|
||||
|
||||
instance.executeAnalysisTasks(analyzer, exceptions);
|
||||
|
||||
assertTrue(executorService.isShutdown());
|
||||
}
|
||||
}
|
||||
@@ -17,23 +17,31 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import mockit.Mock;
|
||||
import mockit.MockUp;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
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.BaseDBTestCase;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Unit tests for CmakeAnalyzer.
|
||||
@@ -150,4 +158,21 @@ public class CMakeAnalyzerTest extends BaseDBTestCase {
|
||||
assertTrue("Expected version evidence to contain \"" + version + "\".",
|
||||
result.getVersionEvidence().toString().contains(version));
|
||||
}
|
||||
|
||||
@Test(expected = InitializationException.class)
|
||||
public void analyzerIsDisabledInCaseOfMissingMessageDigest() throws InitializationException {
|
||||
new MockUp<MessageDigest>() {
|
||||
@Mock
|
||||
MessageDigest getInstance(String ignore) throws NoSuchAlgorithmException {
|
||||
throw new NoSuchAlgorithmException();
|
||||
}
|
||||
};
|
||||
|
||||
analyzer = new CMakeAnalyzer();
|
||||
analyzer.setFilesMatched(true);
|
||||
assertTrue(analyzer.isEnabled());
|
||||
analyzer.initialize();
|
||||
|
||||
assertFalse(analyzer.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,19 +17,25 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import mockit.Mock;
|
||||
import mockit.MockUp;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
|
||||
/**
|
||||
* Unit tests for NodePackageAnalyzer.
|
||||
@@ -96,4 +102,22 @@ public class ComposerLockAnalyzerTest extends BaseDBTestCase {
|
||||
"composer.lock"));
|
||||
analyzer.analyze(result, engine);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = InitializationException.class)
|
||||
public void analyzerIsDisabledInCaseOfMissingMessageDigest() throws InitializationException {
|
||||
new MockUp<MessageDigest>() {
|
||||
@Mock
|
||||
MessageDigest getInstance(String ignore) throws NoSuchAlgorithmException {
|
||||
throw new NoSuchAlgorithmException();
|
||||
}
|
||||
};
|
||||
|
||||
analyzer = new ComposerLockAnalyzer();
|
||||
analyzer.setFilesMatched(true);
|
||||
assertTrue(analyzer.isEnabled());
|
||||
analyzer.initialize();
|
||||
|
||||
assertFalse(analyzer.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,25 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import mockit.Mocked;
|
||||
import mockit.Verifications;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class DependencyBundlingAnalyzerTest extends BaseTest {
|
||||
|
||||
@Mocked
|
||||
Engine engineMock;
|
||||
|
||||
/**
|
||||
* Test of getName method, of class DependencyBundlingAnalyzer.
|
||||
*/
|
||||
@@ -52,15 +60,27 @@ public class DependencyBundlingAnalyzerTest extends BaseTest {
|
||||
|
||||
/**
|
||||
* Test of analyze method, of class DependencyBundlingAnalyzer.
|
||||
* The actually passed dependency does not matter. The analyzer only runs once.
|
||||
*/
|
||||
@Test
|
||||
public void testAnalyze() throws Exception {
|
||||
// Dependency ignore = null;
|
||||
// Engine engine = null;
|
||||
// DependencyBundlingAnalyzer instance = new DependencyBundlingAnalyzer();
|
||||
// instance.analyze(ignore, engine);
|
||||
// // TODO review the generated test code and remove the default call to fail.
|
||||
// fail("The test case is a prototype.");
|
||||
DependencyBundlingAnalyzer instance = new DependencyBundlingAnalyzer();
|
||||
|
||||
// the actual dependency does not matter
|
||||
assertFalse(instance.getAnalyzed());
|
||||
instance.analyze(null, engineMock);
|
||||
|
||||
// the second runs basically does nothing
|
||||
assertTrue(instance.getAnalyzed());
|
||||
instance.analyze(null, engineMock);
|
||||
instance.analyze(null, engineMock);
|
||||
instance.analyze(null, engineMock);
|
||||
assertTrue(instance.getAnalyzed());
|
||||
|
||||
new Verifications() {{
|
||||
engineMock.getDependencies();
|
||||
times = 2;
|
||||
}};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +139,5 @@ public class DependencyBundlingAnalyzerTest extends BaseTest {
|
||||
expResult = true;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.analyzer.NexusAnalyzer;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -39,7 +40,7 @@ public class NexusSearchTest extends BaseTest {
|
||||
public void setUp() throws Exception {
|
||||
String nexusUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||
LOGGER.debug(nexusUrl);
|
||||
searcher = new NexusSearch(new URL(nexusUrl));
|
||||
searcher = new NexusSearch(new URL(nexusUrl), NexusAnalyzer.useProxy());
|
||||
Assume.assumeTrue(searcher.preflightRequest());
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,19 @@ public class DependencyVersionTest extends BaseTest {
|
||||
expResult = true;
|
||||
result = instance.equals(obj);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
instance = new DependencyVersion("2.0.0");
|
||||
obj = new DependencyVersion("2");
|
||||
expResult = false;
|
||||
result = instance.equals(obj);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
obj = new DependencyVersion("2.0");
|
||||
expResult = true;
|
||||
result = instance.equals(obj);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -75,6 +75,7 @@ archive.scan.depth=3
|
||||
|
||||
# use HEAD (default) or GET as HTTP request method for query timestamp
|
||||
downloader.quick.query.timestamp=true
|
||||
downloader.tls.protocols=TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
|
||||
|
||||
analyzer.experimental.enabled=true
|
||||
analyzer.jar.enabled=true
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.3</version>
|
||||
<version>1.4.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
@@ -38,8 +38,11 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
<properties>
|
||||
<version.maven-plugin-plugin>3.4</version.maven-plugin-plugin>
|
||||
<version.maven-plugin-plugin>3.5</version.maven-plugin-plugin>
|
||||
</properties>
|
||||
<prerequisites>
|
||||
<maven>3.1</maven>
|
||||
</prerequisites>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
|
||||
@@ -123,9 +123,9 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
|
||||
exCol.addException(ex);
|
||||
}
|
||||
if (this.isFailOnError()) {
|
||||
throw new MojoExecutionException("One or more exceptions occured during dependency-check analysis", exCol);
|
||||
throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol);
|
||||
} else {
|
||||
getLog().debug("One or more exceptions occured during dependency-check analysis", exCol);
|
||||
getLog().debug("One or more exceptions occurred during dependency-check analysis", exCol);
|
||||
}
|
||||
}
|
||||
showSummary(this.getProject(), engine.getDependencies());
|
||||
@@ -240,7 +240,7 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
|
||||
if (getLog().isDebugEnabled()) {
|
||||
getLog().debug("Database connection error", ex);
|
||||
}
|
||||
final String msg = "An exception occured connecting to the local database. Please see the log file for more details.";
|
||||
final String msg = "An exception occurred connecting to the local database. Please see the log file for more details.";
|
||||
if (this.isFailOnError()) {
|
||||
throw new MojoExecutionException(msg, ex);
|
||||
}
|
||||
|
||||
@@ -206,6 +206,13 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
|
||||
*/
|
||||
@Parameter(property = "suppressionFile", defaultValue = "", required = false)
|
||||
private String suppressionFile;
|
||||
|
||||
/**
|
||||
* The path to the hints file.
|
||||
*/
|
||||
@Parameter(property = "hintsFile", defaultValue = "", required = false)
|
||||
private String hintsFile;
|
||||
|
||||
/**
|
||||
* Flag indicating whether or not to show a summary in the output.
|
||||
*/
|
||||
@@ -654,7 +661,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
|
||||
try {
|
||||
final ArtifactResult result = repoSystem.resolveArtifact(repoSession, request);
|
||||
if (result.isResolved() && result.getArtifact() != null && result.getArtifact().getFile() != null) {
|
||||
final List<Dependency> deps = engine.scan(result.getArtifact().getFile().getAbsoluteFile());
|
||||
final List<Dependency> deps = engine.scan(result.getArtifact().getFile().getAbsoluteFile(),
|
||||
project.getName() + ":" + dependencyNode.getArtifact().getScope());
|
||||
if (deps != null) {
|
||||
if (deps.size() == 1) {
|
||||
final Dependency d = deps.get(0);
|
||||
@@ -662,7 +670,6 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
|
||||
final Artifact a = result.getArtifact();
|
||||
final MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
|
||||
d.addAsEvidence("pom", ma, Confidence.HIGHEST);
|
||||
d.addProjectReference(project.getName() + ":" + dependencyNode.getArtifact().getScope());
|
||||
if (getLog().isDebugEnabled()) {
|
||||
getLog().debug(String.format("Adding project reference %s on dependency %s",
|
||||
project.getName(), d.getDisplayFileName()));
|
||||
@@ -848,6 +855,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
|
||||
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
|
||||
|
||||
//File Type Analyzer Settings
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
|
||||
|
||||
@@ -81,7 +81,7 @@ public class CheckMojo extends BaseDependencyCheckMojo {
|
||||
if (getLog().isDebugEnabled()) {
|
||||
getLog().debug("Database connection error", ex);
|
||||
}
|
||||
final String msg = "An exception occured connecting to the local database. Please see the log file for more details.";
|
||||
final String msg = "An exception occurred connecting to the local database. Please see the log file for more details.";
|
||||
if (this.isFailOnError()) {
|
||||
throw new MojoExecutionException(msg, ex);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class CheckMojo extends BaseDependencyCheckMojo {
|
||||
engine.analyzeDependencies();
|
||||
} catch (ExceptionCollection ex) {
|
||||
if (this.isFailOnError() && ex.isFatal()) {
|
||||
throw new MojoExecutionException("One or more exceptions occured during analysis", ex);
|
||||
throw new MojoExecutionException("One or more exceptions occurred during analysis", ex);
|
||||
}
|
||||
exCol = ex;
|
||||
}
|
||||
@@ -112,11 +112,11 @@ public class CheckMojo extends BaseDependencyCheckMojo {
|
||||
}
|
||||
}
|
||||
}
|
||||
writeDataFile(getProject(), null, engine.getDependencies());
|
||||
//writeDataFile(getProject(), null, engine.getDependencies());
|
||||
showSummary(getProject(), engine.getDependencies());
|
||||
checkForFailure(engine.getDependencies());
|
||||
if (exCol != null && this.isFailOnError()) {
|
||||
throw new MojoExecutionException("One or more exceptions occured during dependency-check analysis", exCol);
|
||||
throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,13 +71,13 @@ public class UpdateMojo extends BaseDependencyCheckMojo {
|
||||
if (getLog().isDebugEnabled()) {
|
||||
getLog().debug("Database connection error", ex);
|
||||
}
|
||||
final String msg = "An exception occured connecting to the local database. Please see the log file for more details.";
|
||||
final String msg = "An exception occurred connecting to the local database. Please see the log file for more details.";
|
||||
if (this.isFailOnError()) {
|
||||
throw new MojoExecutionException(msg, ex);
|
||||
}
|
||||
getLog().error(msg);
|
||||
} catch (UpdateException ex) {
|
||||
final String msg = "An exception occured while downloading updates. Please see the log file for more details.";
|
||||
final String msg = "An exception occurred while downloading updates. Please see the log file for more details.";
|
||||
if (this.isFailOnError()) {
|
||||
throw new MojoExecutionException(msg, ex);
|
||||
}
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-ant.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven.slf4j;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.slf4j.helpers.MarkerIgnoringBase;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
/**
|
||||
* Created on 6/14/15.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class MavenLoggerAdapter extends MarkerIgnoringBase {
|
||||
|
||||
/**
|
||||
* A reference to the Maven log.
|
||||
*/
|
||||
private final Log log;
|
||||
|
||||
/**
|
||||
* Creates a new Maven Logger Adapter.
|
||||
*
|
||||
* @param log the Maven log
|
||||
*/
|
||||
public MavenLoggerAdapter(Log log) {
|
||||
super();
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if trace is enabled.
|
||||
*
|
||||
* @return whether or not trace is enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isTraceEnabled() {
|
||||
if (log != null) {
|
||||
return log.isDebugEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg) {
|
||||
if (log != null) {
|
||||
log.debug(msg);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object arg) {
|
||||
final String message = MessageFormatter.format(format, arg).getMessage();
|
||||
if (log != null) {
|
||||
log.debug(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object arg1, Object arg2) {
|
||||
final String message = MessageFormatter.format(format, arg1, arg2).getMessage();
|
||||
if (log != null) {
|
||||
log.debug(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object... arguments) {
|
||||
final String message = MessageFormatter.format(format, arguments).getMessage();
|
||||
if (log != null) {
|
||||
log.debug(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Throwable t) {
|
||||
if (log != null) {
|
||||
log.debug(msg, t);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
if (log != null) {
|
||||
return log.isDebugEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg) {
|
||||
if (log != null) {
|
||||
log.debug(msg);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object arg) {
|
||||
final String message = MessageFormatter.format(format, arg).getMessage();
|
||||
if (log != null) {
|
||||
log.debug(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object arg1, Object arg2) {
|
||||
final String message = MessageFormatter.format(format, arg1, arg2).getMessage();
|
||||
if (log != null) {
|
||||
log.debug(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object... arguments) {
|
||||
final String message = MessageFormatter.format(format, arguments).getMessage();
|
||||
if (log != null) {
|
||||
log.debug(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Throwable t) {
|
||||
if (log != null) {
|
||||
log.debug(msg, t);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled() {
|
||||
if (log != null) {
|
||||
return log.isInfoEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg) {
|
||||
if (log != null) {
|
||||
log.info(msg);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String format, Object arg) {
|
||||
final String message = MessageFormatter.format(format, arg).getMessage();
|
||||
if (log != null) {
|
||||
log.info(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String format, Object arg1, Object arg2) {
|
||||
final String message = MessageFormatter.format(format, arg1, arg2).getMessage();
|
||||
if (log != null) {
|
||||
log.info(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String format, Object... arguments) {
|
||||
final String message = MessageFormatter.format(format, arguments).getMessage();
|
||||
if (log != null) {
|
||||
log.info(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Throwable t) {
|
||||
if (log != null) {
|
||||
log.info(msg, t);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled() {
|
||||
if (log != null) {
|
||||
return log.isWarnEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg) {
|
||||
if (log != null) {
|
||||
log.warn(msg);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object arg) {
|
||||
final String message = MessageFormatter.format(format, arg).getMessage();
|
||||
if (log != null) {
|
||||
log.warn(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object arg1, Object arg2) {
|
||||
final String message = MessageFormatter.format(format, arg1, arg2).getMessage();
|
||||
if (log != null) {
|
||||
log.warn(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object... arguments) {
|
||||
final String message = MessageFormatter.format(format, arguments).getMessage();
|
||||
if (log != null) {
|
||||
log.warn(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable t) {
|
||||
if (log != null) {
|
||||
log.warn(msg, t);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled() {
|
||||
if (log != null) {
|
||||
return log.isErrorEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg) {
|
||||
if (log != null) {
|
||||
log.error(msg);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object arg) {
|
||||
final String message = MessageFormatter.format(format, arg).getMessage();
|
||||
if (log != null) {
|
||||
log.error(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object arg1, Object arg2) {
|
||||
final String message = MessageFormatter.format(format, arg1, arg2).getMessage();
|
||||
if (log != null) {
|
||||
log.error(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object... arguments) {
|
||||
final String message = MessageFormatter.format(format, arguments).getMessage();
|
||||
if (log != null) {
|
||||
log.error(message);
|
||||
} else {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable t) {
|
||||
if (log != null) {
|
||||
log.error(msg, t);
|
||||
} else {
|
||||
System.out.println(msg);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-ant.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven.slf4j;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Created on 6/14/15.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class MavenLoggerFactory implements ILoggerFactory {
|
||||
|
||||
/**
|
||||
* A reference to the Maven log adapter.
|
||||
*/
|
||||
private final MavenLoggerAdapter mavenLoggerAdapter;
|
||||
|
||||
/**
|
||||
* Constructs a new logger factory.
|
||||
*
|
||||
* @param log a reference to the Maven log
|
||||
*/
|
||||
public MavenLoggerFactory(Log log) {
|
||||
super();
|
||||
this.mavenLoggerAdapter = new MavenLoggerAdapter(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Maven Logger Adapter.
|
||||
*
|
||||
* @param name ignored in this implementation
|
||||
* @return the maven logger adapter
|
||||
*/
|
||||
@Override
|
||||
public Logger getLogger(String name) {
|
||||
return mavenLoggerAdapter;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* This package contains the the slf4j adapter that wraps the maven logger.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven.slf4j;
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-ant.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||
*/
|
||||
package org.slf4j.impl;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.owasp.dependencycheck.maven.slf4j.MavenLoggerFactory;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.spi.LoggerFactoryBinder;
|
||||
|
||||
/**
|
||||
* The binding of org.slf4j.LoggerFactory class with an actual instance of
|
||||
* org.slf4j.ILoggerFactory is performed using information returned by this
|
||||
* class.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
//CSOFF: FinalClass
|
||||
public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
//CSON: FinalClass
|
||||
|
||||
/**
|
||||
* The unique instance of this class
|
||||
*/
|
||||
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
||||
|
||||
/**
|
||||
* Return the singleton of this class.
|
||||
*
|
||||
* @return the StaticLoggerBinder singleton
|
||||
*/
|
||||
public static final StaticLoggerBinder getSingleton() {
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maven mojos have their own logger, so we'll use one of those.
|
||||
*/
|
||||
private Log log = null;
|
||||
|
||||
/**
|
||||
* Set the Task which will this is to log through.
|
||||
*
|
||||
* @param log the task through which to log
|
||||
*/
|
||||
public void setLog(Log log) {
|
||||
this.log = log;
|
||||
loggerFactory = new MavenLoggerFactory(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare the version of the SLF4J API this implementation is compiled
|
||||
* against. The value of this filed is usually modified with each release.
|
||||
*/
|
||||
// to avoid constant folding by the compiler, this field must *not* be final
|
||||
//CSOFF: StaticVariableName
|
||||
//CSOFF: VisibilityModifier
|
||||
public static String REQUESTED_API_VERSION = "1.7.12"; // final
|
||||
//CSON: VisibilityModifier
|
||||
//CSON: StaticVariableName
|
||||
|
||||
/**
|
||||
* The logger factory class string.
|
||||
*/
|
||||
private static final String LOGGER_FACTORY_CLASS = MavenLoggerFactory.class.getName();
|
||||
|
||||
/**
|
||||
* The ILoggerFactory instance returned by the {@link #getLoggerFactory}
|
||||
* method should always be the same object
|
||||
*/
|
||||
private ILoggerFactory loggerFactory;
|
||||
|
||||
/**
|
||||
* Constructs the static logger factory.
|
||||
*/
|
||||
private StaticLoggerBinder() {
|
||||
loggerFactory = new MavenLoggerFactory(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logger factory.
|
||||
*
|
||||
* @return the logger factory
|
||||
*/
|
||||
@Override
|
||||
public ILoggerFactory getLoggerFactory() {
|
||||
return loggerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logger factory class string.
|
||||
*
|
||||
* @return the logger factory class string
|
||||
*/
|
||||
@Override
|
||||
public String getLoggerFactoryClassStr() {
|
||||
return LOGGER_FACTORY_CLASS;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* This package contains the static binder for the slf4j-maven logger.
|
||||
*/
|
||||
package org.slf4j.impl;
|
||||
@@ -26,6 +26,7 @@ skipTestScope | Skip analysis for artifacts with Test Scope
|
||||
skipProvidedScope | Skip analysis for artifacts with Provided Scope | false
|
||||
skipRuntimeScope | Skip analysis for artifacts with Runtime Scope | false
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |
|
||||
enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false
|
||||
|
||||
Analyzer Configuration
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
Usage
|
||||
======================
|
||||
Dependency-check-maven is very simple to utilize and can be used as a stand-alone
|
||||
plugin or as part of the site plugin.
|
||||
plug-in or as part of the site plug-in. The plug-in requires Maven 3.1 or higher.
|
||||
|
||||
It is important to understand that the first time this task is executed it may
|
||||
take 20 minutes or more as it downloads and processes the data from the National
|
||||
Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov
|
||||
|
||||
After the first batch download, as long as the plugin is executed at least once every
|
||||
After the first batch download, as long as the plug-in is executed at least once every
|
||||
seven days the update will only take a few seconds.
|
||||
|
||||
#set( $H = '#' )
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.3</version>
|
||||
<version>1.4.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -49,36 +49,42 @@ public final class Checksum {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates the cryptographic checksum of a given file using the specified algorithm.</p>
|
||||
* Creates the cryptographic checksum of a given file using the specified
|
||||
* algorithm.</p>
|
||||
*
|
||||
* @param algorithm the algorithm to use to calculate the checksum
|
||||
* @param file the file to calculate the checksum for
|
||||
* @return the checksum
|
||||
* @throws IOException when the file does not exist
|
||||
* @throws NoSuchAlgorithmException when an algorithm is specified that does not exist
|
||||
* @throws NoSuchAlgorithmException when an algorithm is specified that does
|
||||
* not exist
|
||||
*/
|
||||
public static byte[] getChecksum(String algorithm, File file) throws NoSuchAlgorithmException, IOException {
|
||||
final MessageDigest digest = MessageDigest.getInstance(algorithm);
|
||||
final MessageDigest md = MessageDigest.getInstance(algorithm);
|
||||
FileInputStream fis = null;
|
||||
FileChannel ch = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
final FileChannel ch = fis.getChannel();
|
||||
long remainingToRead = file.length();
|
||||
long start = 0;
|
||||
while (remainingToRead > 0) {
|
||||
long amountToRead;
|
||||
if (remainingToRead > Integer.MAX_VALUE) {
|
||||
remainingToRead -= Integer.MAX_VALUE;
|
||||
amountToRead = Integer.MAX_VALUE;
|
||||
} else {
|
||||
amountToRead = remainingToRead;
|
||||
remainingToRead = 0;
|
||||
}
|
||||
final MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, start, amountToRead);
|
||||
digest.update(byteBuffer);
|
||||
start += amountToRead;
|
||||
ch = fis.getChannel();
|
||||
final ByteBuffer buf = ByteBuffer.allocateDirect(8192);
|
||||
int b = ch.read(buf);
|
||||
while ((b != -1) && (b != 0)) {
|
||||
buf.flip();
|
||||
final byte[] bytes = new byte[b];
|
||||
buf.get(bytes);
|
||||
md.update(bytes, 0, b);
|
||||
buf.clear();
|
||||
b = ch.read(buf);
|
||||
}
|
||||
return md.digest();
|
||||
} finally {
|
||||
if (ch != null) {
|
||||
try {
|
||||
ch.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("Error closing channel '{}'.", file.getName(), ex);
|
||||
}
|
||||
}
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
@@ -87,7 +93,6 @@ public final class Checksum {
|
||||
}
|
||||
}
|
||||
}
|
||||
return digest.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -151,6 +151,13 @@ public final class Downloader {
|
||||
} finally {
|
||||
conn = null;
|
||||
}
|
||||
if ("Connection reset".equalsIgnoreCase(ex.getMessage())) {
|
||||
final String msg = format("TLS Connection Reset%nPlease see "
|
||||
+ "http://jeremylong.github.io/DependencyCheck/general/tlsfailures.html "
|
||||
+ "for more information regarding how to resolve the issue.");
|
||||
LOGGER.error(msg);
|
||||
throw new DownloadFailedException(msg, ex);
|
||||
}
|
||||
final String msg = format("Error downloading file %s; unable to connect.", url.toString());
|
||||
throw new DownloadFailedException(msg, ex);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,8 @@ public final class FileUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file. If the File is a directory it will recursively delete the contents.
|
||||
* Deletes a file. If the File is a directory it will recursively delete the
|
||||
* contents.
|
||||
*
|
||||
* @param file the File to delete
|
||||
* @return true if the file was deleted successfully, otherwise false
|
||||
@@ -79,13 +80,33 @@ public final class FileUtils {
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique temporary directory in the given directory.
|
||||
*
|
||||
* @param base the base directory to create a temporary directory within
|
||||
* @return the temporary directory
|
||||
* @throws IOException thrown when a directory cannot be created within the
|
||||
* base directory
|
||||
*/
|
||||
public static File createTempDirectory(File base) throws IOException {
|
||||
final File tempDir = new File(base, "dctemp" + UUID.randomUUID().toString());
|
||||
if (tempDir.exists()) {
|
||||
return createTempDirectory(base);
|
||||
}
|
||||
if (!tempDir.mkdirs()) {
|
||||
throw new IOException("Could not create temp directory `" + tempDir.getAbsolutePath() + "`");
|
||||
}
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new temporary file name that is guaranteed to be unique.
|
||||
*
|
||||
* @param prefix the prefix for the file name to generate
|
||||
* @param extension the extension of the generated file name
|
||||
* @return a temporary File
|
||||
* @throws java.io.IOException thrown if the temporary folder could not be created
|
||||
* @throws java.io.IOException thrown if the temporary folder could not be
|
||||
* created
|
||||
*/
|
||||
public static File getTempFile(String prefix, String extension) throws IOException {
|
||||
final File dir = Settings.getTempDirectory();
|
||||
@@ -98,7 +119,8 @@ public final class FileUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bit bucket for the OS. '/dev/null' for Unix and 'NUL' for Windows
|
||||
* Return the bit bucket for the OS. '/dev/null' for Unix and 'NUL' for
|
||||
* Windows
|
||||
*
|
||||
* @return a String containing the bit bucket
|
||||
*/
|
||||
|
||||
@@ -243,17 +243,24 @@ public class SSLSocketFactoryEx extends SSLSocketFactory {
|
||||
* @return the protocol list
|
||||
*/
|
||||
protected String[] getProtocolList() {
|
||||
final String[] preferredProtocols = {"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
|
||||
String[] availableProtocols = null;
|
||||
|
||||
SSLSocket socket = null;
|
||||
|
||||
String[] availableProtocols = null;
|
||||
final String[] preferredProtocols = Settings.getString(
|
||||
Settings.KEYS.DOWNLOADER_TLS_PROTOCOL_LIST,
|
||||
"TLSv1,TLSv1.1,TLSv1.2,TLSv1.3")
|
||||
.split(",");
|
||||
try {
|
||||
final SSLSocketFactory factory = sslCtxt.getSocketFactory();
|
||||
socket = (SSLSocket) factory.createSocket();
|
||||
|
||||
availableProtocols = socket.getSupportedProtocols();
|
||||
Arrays.sort(availableProtocols);
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Available Protocols:");
|
||||
for (String p : availableProtocols) {
|
||||
LOGGER.debug(p);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOGGER.debug("Error getting protocol list, using TLSv1", ex);
|
||||
return new String[]{"TLSv1"};
|
||||
|
||||
@@ -293,7 +293,8 @@ public final class Settings {
|
||||
*/
|
||||
public static final String ANALYZER_COCOAPODS_ENABLED = "analyzer.cocoapods.enabled";
|
||||
/**
|
||||
* The properties key for whether the SWIFT package manager analyzer is enabled.
|
||||
* The properties key for whether the SWIFT package manager analyzer is
|
||||
* enabled.
|
||||
*/
|
||||
public static final String ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED = "analyzer.swift.package.manager.enabled";
|
||||
/**
|
||||
@@ -338,6 +339,10 @@ public final class Settings {
|
||||
* The HTTP request method for query last modified date.
|
||||
*/
|
||||
public static final String DOWNLOADER_QUICK_QUERY_TIMESTAMP = "downloader.quick.query.timestamp";
|
||||
/**
|
||||
* The HTTP protocol list to use.
|
||||
*/
|
||||
public static final String DOWNLOADER_TLS_PROTOCOL_LIST = "downloader.tls.protocols";
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
@@ -370,8 +375,11 @@ public final class Settings {
|
||||
try {
|
||||
in = this.getClass().getClassLoader().getResourceAsStream(propertiesFilePath);
|
||||
props.load(in);
|
||||
} catch (NullPointerException ex) {
|
||||
LOGGER.error("Did not find settings file '{}'.", propertiesFilePath);
|
||||
LOGGER.debug("", ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("Unable to load default settings.");
|
||||
LOGGER.error("Unable to load settings from '{}'.", propertiesFilePath);
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
@@ -419,17 +427,10 @@ public final class Settings {
|
||||
* @param deleteTemporary flag indicating whether any temporary directories
|
||||
* generated should be removed
|
||||
*/
|
||||
public static void cleanup(boolean deleteTemporary) {
|
||||
public static synchronized void cleanup(boolean deleteTemporary) {
|
||||
if (deleteTemporary && tempDirectory != null && tempDirectory.exists()) {
|
||||
FileUtils.delete(tempDirectory);
|
||||
if (tempDirectory.exists()) {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException ex) {
|
||||
LOGGER.trace("ignore", ex);
|
||||
}
|
||||
FileUtils.delete(tempDirectory);
|
||||
}
|
||||
tempDirectory = null;
|
||||
}
|
||||
try {
|
||||
LOCAL_SETTINGS.remove();
|
||||
@@ -743,14 +744,12 @@ public final class Settings {
|
||||
* @throws java.io.IOException thrown if the temporary directory does not
|
||||
* exist and cannot be created
|
||||
*/
|
||||
public static File getTempDirectory() throws IOException {
|
||||
final File tmpDir = new File(Settings.getString(Settings.KEYS.TEMP_DIRECTORY, System.getProperty("java.io.tmpdir")), "dctemp");
|
||||
if (!tmpDir.exists() && !tmpDir.mkdirs()) {
|
||||
final String msg = String.format("Unable to make a temporary folder '%s'", tmpDir.getPath());
|
||||
throw new IOException(msg);
|
||||
public static synchronized File getTempDirectory() throws IOException {
|
||||
if (tempDirectory == null) {
|
||||
final File baseTemp = new File(Settings.getString(Settings.KEYS.TEMP_DIRECTORY, System.getProperty("java.io.tmpdir")));
|
||||
tempDirectory = FileUtils.createTempDirectory(baseTemp);
|
||||
}
|
||||
tempDirectory = tmpDir;
|
||||
return tmpDir;
|
||||
return tempDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -198,7 +198,7 @@ public final class URLConnectionFactory {
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
LOGGER.debug("Unsupported algorithm in SSLSocketFactoryEx", ex);
|
||||
} catch (KeyManagementException ex) {
|
||||
LOGGER.debug("Key mnagement eception in SSLSocketFactoryEx", ex);
|
||||
LOGGER.debug("Key management exception in SSLSocketFactoryEx", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,4 +66,5 @@ analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
# use HEAD (default) or GET as HTTP request method for query timestamp
|
||||
downloader.quick.query.timestamp=true
|
||||
downloader.quick.query.timestamp=true
|
||||
downloader.tls.protocols=TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
|
||||
14
pom.xml
14
pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.3</version>
|
||||
<version>1.4.4</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
@@ -149,7 +149,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<prerequisites>
|
||||
<maven>3.0</maven>
|
||||
<maven>3.1</maven>
|
||||
</prerequisites>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
@@ -222,7 +222,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -500,7 +500,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>3.0.3</version>
|
||||
<version>3.0.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
@@ -529,7 +529,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<version>2.3</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
@@ -572,7 +572,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>mailapi</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
@@ -648,7 +648,7 @@ Copyright (c) 2012 - Jeremy Long
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-tools</groupId>
|
||||
<artifactId>maven-plugin-annotations</artifactId>
|
||||
<version>3.4</version>
|
||||
<version>3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.reporting</groupId>
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
^ \* See the License for the specific language governing permissions and\s*$
|
||||
^ \* limitations under the License\.\s*$
|
||||
^ \*\s*$
|
||||
^ \* Copyright \(c\) 201[0-9] (Jeremy Long|Steve Springett|Bianca Jiang|IBM Corporation|The OWASP Foundation|Institute for Defense Analyses)\. All Rights Reserved\.\s*$
|
||||
^ \* Copyright \(c\) 201[0-9] (Jeremy Long|Steve Springett|Stefan Neuhaus|Bianca Jiang|IBM Corporation|The OWASP Foundation|Institute for Defense Analyses)\. All Rights Reserved\.\s*$
|
||||
^ \*/\s*$
|
||||
^package
|
||||
|
||||
11
src/site/markdown/analyzers/cocoapods.md
Normal file
11
src/site/markdown/analyzers/cocoapods.md
Normal file
@@ -0,0 +1,11 @@
|
||||
CocoaPods Analyzer
|
||||
================
|
||||
|
||||
*Experimental*: This analyzer is considered experimental. While this analyzer may
|
||||
be useful and provide valid results more testing must be completed to ensure that
|
||||
the false negative/false positive rates are acceptable.
|
||||
|
||||
OWASP dependency-check includes an analyzer that will analyze SWIFT and Objective-C
|
||||
packages by scanning [CocoaPods](https://cocoapods.org/) specification file.
|
||||
|
||||
Files Types Scanned: [*.podspec](https://guides.cocoapods.org/making/specs-and-specs-repo.html)
|
||||
@@ -24,7 +24,9 @@ several teams have found them useful in their current state.
|
||||
| -------- | ------------------ | --------------- |
|
||||
| [Autoconf](./autoconf.html) | Autoconf project configuration files (configure, configure.in, configure.ac) | [Regex](https://en.wikipedia.org/wiki/Regular_expression) scan for AC_INIT metadata, including in generated configuration script. |
|
||||
| [CMake](./cmake.html) | CMake project files (CMakeLists.txt) and scripts (\*.cmake) | Regex scan for project initialization and version setting commands. |
|
||||
| [CocoaPods](./cocoapods.html) | CocoaPods `.podspec` files | Extracts dependency information from specification file. |
|
||||
| [Composer Lock](./composer-lock.html) | PHP [Composer](http://getcomposer.org) Lock files (composer.lock) | Parses PHP [Composer](http://getcomposer.org) lock files for exact versions of dependencies. |
|
||||
| [Node.js](./nodejs.html) | NPM package specification files (package.json) | Parse JSON format for metadata. |
|
||||
| [Python](./python.html) | Python source files (\*.py); Package metadata files (PKG-INFO, METADATA); Package Distribution Files (\*.whl, \*.egg, \*.zip) | Regex scan of Python source files for setuptools metadata; Parse RFC822 header format for metadata in all other artifacts. |
|
||||
| [Ruby Gemspec](./ruby-gemspec.html) | Ruby makefiles (Rakefile); Ruby Gemspec files (\*.gemspec) | Regex scan Gemspec initialization blocks for metadata. |
|
||||
| [SWIFT](./swift.html) | SWIFT Package Manager's `Package.swift` | Extracts dependency information from swift package file. |
|
||||
|
||||
11
src/site/markdown/analyzers/swift.md
Normal file
11
src/site/markdown/analyzers/swift.md
Normal file
@@ -0,0 +1,11 @@
|
||||
SWIFT Package Manager Analyzer
|
||||
================
|
||||
|
||||
*Experimental*: This analyzer is considered experimental. While this analyzer may
|
||||
be useful and provide valid results more testing must be completed to ensure that
|
||||
the false negative/false positive rates are acceptable.
|
||||
|
||||
OWASP dependency-check includes an analyzer that will scan the [SWIFT Package
|
||||
Manager](https://swift.org/package-manager/)'s `Package.swift` file to obtain information on the dependencies used.
|
||||
|
||||
Files Types Scanned: [Package.swift](https://swift.org/package-manager/#example-usage)
|
||||
@@ -6,13 +6,16 @@ constraints.
|
||||
|
||||
Local NVD Database
|
||||
----------------------------------
|
||||
OWASP dependency-check maintains a local copy of the NVD data hosted by NIST. By default,
|
||||
OWASP dependency-check maintains a local copy of the NVD CVE data hosted by NIST. By default,
|
||||
a local [H2 database](http://www.h2database.com/html/main.html) instance is used.
|
||||
As each instance maintains its own copy of the NVD the machine will need access
|
||||
to nvd.nist.gov in order to download the NVD data feeds. While the initial download of the NVD
|
||||
data feed is large, if after the initial download the tool is run at least once every seven
|
||||
days only two small XML files containing the recent modifications will need to be downloaded.
|
||||
|
||||
In some installations OpenJDK may not be able to download the NVD CVE data. Please see the
|
||||
[TLS Failures article](./tlsfailure.html) for more information.
|
||||
|
||||
If your build servers are using dependency-check and are unable to access the Internet you
|
||||
have a few options:
|
||||
|
||||
|
||||
10
src/site/markdown/data/tlsfailure.md
Normal file
10
src/site/markdown/data/tlsfailure.md
Normal file
@@ -0,0 +1,10 @@
|
||||
NVD CVE Download Failures
|
||||
=========================
|
||||
In some installations of the JRE (such as OpenJDK on CentOS/RHEL/Amazon Linux) do not
|
||||
have the correct libraries to support EC cryptography. If you run into problems running
|
||||
dependency-check you may need to install Bouncy Castle and configure Java to use the
|
||||
more robust cryptographic provider.
|
||||
|
||||
Helpful Links
|
||||
* [Stackoverflow discussion](http://stackoverflow.com/a/33521718/1995422)
|
||||
* [Bouncy Castle](https://www.bouncycastle.org/java.html)
|
||||
@@ -20,6 +20,7 @@ format | The report format to be generated (HTML, XML, VULN, ALL).
|
||||
outputDirectory | The location to write the report(s). This directory will be located in the build directory. | build/reports
|
||||
skipTestGroups | When set to true (the default) all dependency groups that being with 'test' will be skipped. | true
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |
|
||||
skipConfigurations | A list of configurations that will be skipped. This is mutually exclusive with the scanConfigurations property. | `[]` which means no configuration is skipped.
|
||||
scanConfigurations | A list of configurations that will be scanned, all other configurations are skipped. This is mutually exclusive with the skipConfigurations property. | `[]` which implicitly means all configurations get scanned.
|
||||
|
||||
|
||||
@@ -32,15 +32,16 @@ apply plugin: 'org.owasp.dependencycheck'
|
||||
|
||||
$H$H$H Step 2, Run the dependencyCheck task
|
||||
|
||||
Once gradle plugin applied, run following gradle task to check dependencies:
|
||||
Once the dependency-check plugin is applied, if the [Java plugin](https://docs.gradle.org/current/userguide/java_plugin.html)
|
||||
is being used dependency-check will automatically be added to the `check` task.
|
||||
Alternatively, you can run dependency-check directly:
|
||||
|
||||
```
|
||||
```bash
|
||||
gradle dependencyCheck --info
|
||||
```
|
||||
|
||||
The reports will be generated automatically under `build/reports` folder.
|
||||
|
||||
|
||||
$H$H Task Configuration
|
||||
The OWASP dependency-check-gradle plugin contains three tasks: [dependencyCheck](configuration.html),
|
||||
[dependencyCheckUpdate](configuration-update.html), and [dependencyCheckPurge](configuration-purge.html).
|
||||
@@ -60,7 +61,6 @@ Permission to modify and redistribute is granted under the terms of the Apache 2
|
||||
|
||||
Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt] [notices] file for more information.
|
||||
|
||||
|
||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||
[post]: mailto:dependency-check@googlegroups.com
|
||||
[license]: https://github.com/jeremylong/DependencyCheck/blob/master/dependency-check-gradle/LICENSE.txt
|
||||
|
||||
69
src/site/markdown/general/hints.md
Normal file
69
src/site/markdown/general/hints.md
Normal file
@@ -0,0 +1,69 @@
|
||||
Resolving False Negatives
|
||||
====================
|
||||
Due to how dependency-check identifies libraries, false negatives may occur (a CPE was NOT identified for a library). Identifying these false negatives can be accomplished using the HTML report. In the report, click on the "Display: Showing Vulnerable Dependencies (click to show all)" link. You can then browse the dependencies and review the CPEs that are there for accuracy. You can also review the dependencies where no CPE match was made. Using the CPE dictionary search manually to verify that there is a CPE to match is a good verification that a false negative has been found. If you identify a dependency that is missing a CPE you can add evidence to help identify the correct CPE.
|
||||
|
||||
A possible reason for false negatives is re-naming of either the vendor or library name over time. Another case is when an artifact has missing info (manifest with no vendor).
|
||||
|
||||
Dependency Check has a built in [hints](https://github.com/jeremylong/DependencyCheck/blob/master/dependency-check-core/src/main/resources/dependencycheck-base-hint.xml) file that is used in every check to help correct well known false negatives.
|
||||
|
||||
A sample hints file that add a product name and possible vendors for Spring framework dependencies would look like:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hints xmlns="https://jeremylong.github.io/DependencyCheck/dependency-hint.1.1.xsd">
|
||||
<hint>
|
||||
<given>
|
||||
<evidence type="product" source="Manifest" name="Implementation-Title" value="Spring Framework" confidence="HIGH"/>
|
||||
<evidence type="product" source="Manifest" name="Implementation-Title" value="org.springframework.core" confidence="HIGH"/>
|
||||
<evidence type="product" source="Manifest" name="Implementation-Title" value="spring-core" confidence="HIGH"/>
|
||||
</given>
|
||||
<add>
|
||||
<evidence type="product" source="hint analyzer" name="product" value="springsource_spring_framework" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="SpringSource" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="vmware" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal" confidence="HIGH"/>
|
||||
</add>
|
||||
</hint>
|
||||
</hints>
|
||||
|
||||
```
|
||||
The above XML file will add the 4 evidence entries to any dependency that matches any one of the 3 givens.
|
||||
|
||||
The following shows some other ways to add evidence
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hints xmlns="https://jeremylong.github.io/DependencyCheck/dependency-hint.1.1.xsd">
|
||||
<hint>
|
||||
<given>
|
||||
<evidence type="product" source="jar" name="package name" value="springframework" confidence="LOW"/>
|
||||
<fileName contains="spring"/>
|
||||
</given>
|
||||
<add>
|
||||
<evidence type="product" source="hint analyzer" name="product" value="springsource_spring_framework" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="SpringSource" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="vmware" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="pivotal" confidence="HIGH"/>
|
||||
</add>
|
||||
</hint>
|
||||
<hint>
|
||||
<given>
|
||||
<fileName contains="my-thelib-.*\.jar" regex="true" caseSensitive="true"/>
|
||||
</given>
|
||||
<add>
|
||||
<evidence type="product" source="hint analyzer" name="product" value="thelib" confidence="HIGH"/>
|
||||
<evidence type="vendor" source="hint analyzer" name="vendor" value="thevendor" confidence="HIGH"/>
|
||||
</add>
|
||||
</hint>
|
||||
</hints>
|
||||
```
|
||||
|
||||
|
||||
The full schema for hints files can be found here: [dependency-hint.xsd](https://github.com/jeremylong/DependencyCheck/blob/master/dependency-check-core/src/main/resources/schema/dependency-hint.1.1.xsd "Hint Schema")
|
||||
|
||||
Please see the appropriate configuration option in each interfaces configuration guide:
|
||||
|
||||
- [Command Line Tool](../dependency-check-cli/arguments.html)
|
||||
- [Maven Plugin](../dependency-check-maven/configuration.html)
|
||||
- [Ant Task](../dependency-check-ant/configuration.html)
|
||||
- [Jenkins Plugin](../dependency-check-jenkins/index.html)
|
||||
@@ -1,6 +1,6 @@
|
||||
Suppressing False Positives
|
||||
====================
|
||||
Due to how dependency-check identifies libraries false positives may occur (a CPE was identified that is incorrect). Suppressing these false positives is fairly easy using the HTML report. In the report next to each CPE identified (and on CVE entries) there is a suppress button. Clicking the suppression button will create a dialogue box which you can simple hit Control-C to copy the XML that you would place into a suppression XML file. If this is the first time you are creating the suppression file you should click the "Complete XML Doc" button on the top of the dialogue box to add the necessary schema elements.
|
||||
Due to [how dependency-check identifies libraries](internals.html) false positives may occur (i.e. a CPE was identified that is incorrect). Suppressing these false positives is fairly easy using the HTML report. In the report next to each CPE identified (and on CVE entries) there is a suppress button. Clicking the suppression button will create a dialogue box which you can simple hit Control-C to copy the XML that you would place into a suppression XML file. If this is the first time you are creating the suppression file you should click the "Complete XML Doc" button on the top of the dialogue box to add the necessary schema elements.
|
||||
|
||||
A sample suppression file would look like:
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ OWASP dependency-check's core analysis engine can be used as:
|
||||
- [Command Line Tool](dependency-check-cli/index.html)
|
||||
- [Gradle Plugin](dependency-check-gradle/index.html)
|
||||
- [Jenkins Plugin](dependency-check-jenkins/index.html)
|
||||
- [Maven Plugin](dependency-check-maven/index.html)
|
||||
- [Maven Plugin](dependency-check-maven/index.html) - Maven 3.1 or newer required
|
||||
- [SBT Plugin](https://github.com/albuch/sbt-dependency-check)
|
||||
|
||||
For help with dependency-check the following resource can be used:
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
@@ -80,6 +80,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<item name="False Positives" href="./general/suppression.html">
|
||||
<description>Suppressing False Positives</description>
|
||||
</item>
|
||||
<item name="False Negatives" href="./general/hints.html">
|
||||
<description>Resolving False Negatives</description>
|
||||
</item>
|
||||
<item collapse="true" name="Internet Access Required" href="./data/index.html">
|
||||
<item name="Proxy" href="./data/proxy.html" />
|
||||
<item name="Mirroring NVD" href="./data/mirrornvd.html" />
|
||||
@@ -118,6 +121,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<item name="CMake" href="./analyzers/cmake.html">
|
||||
<description>CMake Analyzer</description>
|
||||
</item>
|
||||
<item name="CocoaPods" href="./analyzers/cocoapods.html">
|
||||
<description>CocoaPods Analyzer</description>
|
||||
</item>
|
||||
<item name="Jar" href="./analyzers/jar-analyzer.html">
|
||||
<description>Jar Analyzer</description>
|
||||
</item>
|
||||
@@ -139,6 +145,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<item name="Ruby Gemspec" href="./analyzers/ruby-gemspec.html">
|
||||
<description>Ruby Gemspec Analyzer</description>
|
||||
</item>
|
||||
<item name="Swift" href="./analyzers/swift.html">
|
||||
<description>Swift Package Manager Analyzer</description>
|
||||
</item>
|
||||
</item>
|
||||
<item collapse="true" name="Modules" href="./modules.html">
|
||||
<item name="CLI" href="./dependency-check-cli/index.html">
|
||||
|
||||
Reference in New Issue
Block a user