continued work on threading and code improvement

This commit is contained in:
Jeremy Long
2017-09-03 09:05:55 -04:00
parent 795de6f9ea
commit ab5de24518
158 changed files with 1266 additions and 964 deletions

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.taskdefs;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@@ -46,6 +47,7 @@ import org.slf4j.impl.StaticLoggerBinder;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class Check extends Update {
/**
@@ -161,6 +163,7 @@ public class Check extends Update {
/**
* Suppression file paths.
*/
@SuppressWarnings("CanBeFinal")
private List<String> suppressionFiles = new ArrayList<>();
/**
@@ -1065,7 +1068,7 @@ public class Check extends Update {
* @throws BuildException thrown if a CVSS score is found that is higher
* than the threshold set
*/
private void checkForFailure(List<Dependency> dependencies) throws BuildException {
private void checkForFailure(Dependency[] dependencies) throws BuildException {
final StringBuilder ids = new StringBuilder();
for (Dependency d : dependencies) {
for (Vulnerability v : d.getVulnerabilities()) {
@@ -1092,7 +1095,7 @@ public class Check extends Update {
*
* @param dependencies a list of dependency objects
*/
private void showSummary(List<Dependency> dependencies) {
private void showSummary(Dependency[] dependencies) {
final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) {
boolean firstEntry = true;

View File

@@ -48,7 +48,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
*
* @return the StaticLoggerBinder singleton
*/
public static final StaticLoggerBinder getSingleton() {
public static StaticLoggerBinder getSingleton() {
return SINGLETON;
}

View File

@@ -312,7 +312,6 @@ public class App {
* @param excludes an array of ant style excludes
* @return returns the set of identified files
* @throws InvalidScanPathException thrown when the scan path is invalid
* @throws IllegalStateException
*/
private Set<File> scanAntStylePaths(List<String> antStylePaths, int symLinkDepth, String[] excludes)
throws InvalidScanPathException {

View File

@@ -21,12 +21,12 @@ 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;
import javax.annotation.concurrent.ThreadSafe;
/**
* Task to support parallelism of dependency-check analysis. Analyses a single
@@ -34,6 +34,7 @@ import java.util.concurrent.Callable;
*
* @author Stefan Neuhaus
*/
@ThreadSafe
public class AnalysisTask implements Callable<Void> {
/**
@@ -57,10 +58,6 @@ public class AnalysisTask implements Callable<Void> {
* The list of exceptions that may occur during analysis.
*/
private final List<Throwable> exceptions;
/**
* A reference to the global settings object.
*/
private final Settings settings;
/**
* Creates a new analysis task.
@@ -70,16 +67,12 @@ public class AnalysisTask implements Callable<Void> {
* @param engine the dependency-check engine
* @param exceptions exceptions that occur during analysis will be added to
* this collection of exceptions
* @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.
*/
AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions, Settings settings) {
AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions) {
this.analyzer = analyzer;
this.dependency = dependency;
this.engine = engine;
this.exceptions = exceptions;
this.settings = settings;
}
/**

View File

@@ -57,6 +57,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.NotThreadSafe;
import static org.owasp.dependencycheck.analyzer.AnalysisPhase.*;
@@ -68,6 +69,7 @@ import static org.owasp.dependencycheck.analyzer.AnalysisPhase.*;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class Engine implements FileFilter, AutoCloseable {
/**
@@ -170,7 +172,7 @@ public class Engine implements FileFilter, AutoCloseable {
* The ClassLoader to use when dynamically loading Analyzer and Update
* services.
*/
private ClassLoader serviceClassLoader;
private final ClassLoader serviceClassLoader;
/**
* A reference to the database.
*/
@@ -304,8 +306,42 @@ public class Engine implements FileFilter, AutoCloseable {
* @see Collections#synchronizedList(List)
* @see Analyzer#supportsParallelProcessing()
*/
public synchronized List<Dependency> getDependencies() {
return dependencies;
// public synchronized List<Dependency> getDependencies() {
// return dependencies;
// }
/**
* Adds a dependency.
*
* @param dependency the dependency to add
*/
public synchronized void addDependency(Dependency dependency) {
dependencies.add(dependency);
}
/**
* Sorts the dependency list.
*/
public synchronized void sortDependencies() {
//TODO - is this actually necassary????
Collections.sort(dependencies);
}
/**
* Removes the dependency.
*
* @param dependency the dependency to remove.
*/
public synchronized void removeDependency(Dependency dependency) {
dependencies.remove(dependency);
}
/**
* Returns a copy of the dependencies as an array.
*
* @return the dependencies identified
*/
public synchronized Dependency[] getDependencies() {
return dependencies.toArray(new Dependency[dependencies.size()]);
}
/**
@@ -750,7 +786,7 @@ public class Engine implements FileFilter, AutoCloseable {
final List<AnalysisTask> result = new ArrayList<>();
synchronized (dependencies) {
for (final Dependency dependency : dependencies) {
final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions, settings);
final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions);
result.add(task);
}
}
@@ -907,9 +943,9 @@ public class Engine implements FileFilter, AutoCloseable {
}
/**
* Returns
* Returns the configured settings.
*
* @return
* @return the configured settings
*/
public Settings getSettings() {
return settings;

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.agent;
import java.io.File;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency;
@@ -59,6 +60,7 @@ import org.slf4j.LoggerFactory;
* @author Steve Springett
*/
@SuppressWarnings("unused")
@NotThreadSafe
public class DependencyCheckScanAgent {
//<editor-fold defaultstate="collapsed" desc="private fields">
@@ -938,7 +940,7 @@ public class DependencyCheckScanAgent {
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
* there is an exception executing the scan.
*/
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
private void checkForFailure(Dependency[] dependencies) throws ScanAgentException {
final StringBuilder ids = new StringBuilder();
for (Dependency d : dependencies) {
boolean addName = true;
@@ -969,7 +971,7 @@ public class DependencyCheckScanAgent {
*
* @param dependencies a list of dependency objects
*/
private void showSummary(List<Dependency> dependencies) {
private void showSummary(Dependency[] dependencies) {
final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) {
boolean firstEntry = true;

View File

@@ -23,6 +23,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,6 +33,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public abstract class AbstractAnalyzer implements Analyzer {
/**
@@ -153,7 +155,7 @@ public abstract class AbstractAnalyzer implements Analyzer {
try {
this.setEnabled(settings.getBoolean(key, true));
} catch (InvalidSettingException ex) {
String msg = String.format("Invalid setting for property '{}'", key);
final String msg = String.format("Invalid setting for property '%s'", key);
LOGGER.warn(msg);
LOGGER.debug(msg, ex);
}

View File

@@ -0,0 +1,125 @@
/*
* 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) 2017 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>
* This analyzer ensures dependencies that should be grouped together, to remove
* excess noise from the report, are grouped. An example would be Spring, Spring
* Beans, Spring MVC, etc. If they are all for the same version and have the
* same relative path then these should be grouped into a single dependency
* under the core/main library.</p>
* <p>
* Note, this grouping only works on dependencies with identified CVE
* entries</p>
*
* @author Jeremy Long
*/
@ThreadSafe
public abstract class AbstractDependencyComparingAnalyzer extends AbstractAnalyzer {
/**
* The Logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDependencyComparingAnalyzer.class);
/**
* 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 synchronized boolean getAnalyzed() {
return analyzed;
}
/**
* 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 final 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
* related dependencies are bundled into a single reportable item.
*
* @param ignore this analyzer ignores the dependency being analyzed
* @param engine the engine that is scanning the dependencies
* @throws AnalysisException is thrown if there is an error reading the JAR
* file.
*/
@Override
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
if (!analyzed) {
analyzed = true;
final Set<Dependency> dependenciesToRemove = new HashSet<>();
final Dependency[] dependencies = engine.getDependencies();
if (dependencies.length < 2) {
return;
}
for (int x = 0; x < dependencies.length - 1; x++) {
final Dependency dependency = dependencies[x];
if (!dependenciesToRemove.contains(dependency)) {
for (int y = x + 1; y < dependencies.length; y++) {
final Dependency nextDependency = dependencies[y];
if (evaluateDependencies(dependency, nextDependency, dependenciesToRemove)) {
break;
}
}
}
}
for (Dependency d : dependenciesToRemove) {
engine.removeDependency(d);
}
}
}
/**
* Evaluates the dependencies
*
* @param dependency a dependency to compare
* @param nextDependency a dependency to compare
* @param dependenciesToRemove a set of dependencies that will be removed
* @return true if a dependency is removed; otherwise false
*/
protected abstract boolean evaluateDependencies(final Dependency dependency,
final Dependency nextDependency, final Set<Dependency> dependenciesToRemove);
}

View File

@@ -25,6 +25,7 @@ import java.io.FileFilter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.exception.InitializationException;
@@ -34,6 +35,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
*
* @author Jeremy Long
*/
@ThreadSafe
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
//<editor-fold defaultstate="collapsed" desc="Field definitions, getters, and setters ">
@@ -46,15 +48,6 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
*/
private boolean filesMatched = false;
/**
* Get the value of filesMatched. A flag indicating whether the scan
* included any file types this analyzer supports.
*
* @return the value of filesMatched
*/
protected boolean isFilesMatched() {
return filesMatched;
}
/**
* Set the value of filesMatched. A flag indicating whether the scan

View File

@@ -22,10 +22,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
@@ -47,6 +48,7 @@ import org.xml.sax.SAXException;
*
* @author Jeremy Long
*/
@ThreadSafe
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
/**
@@ -56,15 +58,15 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
/**
* The list of suppression rules
*/
private List<SuppressionRule> rules;
private SuppressionRule[] rules = null;
/**
* Get the number of suppression rules.
*
* @return the number of suppression rules
*/
protected synchronized int getRuleCount() {
return rules.size();
protected int getRuleCount() {
return rules.length;
}
/**
@@ -83,17 +85,19 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
* @throws InitializationException thrown if there is an exception
*/
@Override
public void initializeAnalyzer(Engine engine) throws InitializationException {
try {
loadSuppressionData();
} catch (SuppressionParseException ex) {
throw new InitializationException("Error initializing the suppression analyzer: " + ex.getLocalizedMessage(), ex);
public synchronized void initializeAnalyzer(Engine engine) throws InitializationException {
if (rules == null) {
try {
rules = loadSuppressionData();
} catch (SuppressionParseException ex) {
throw new InitializationException("Error initializing the suppression analyzer: " + ex.getLocalizedMessage(), ex);
}
}
}
@Override
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
if (rules == null || rules.size() <= 0) {
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
if (rules == null || rules.length <= 0) {
return;
}
for (final SuppressionRule rule : rules) {
@@ -104,40 +108,43 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
/**
* Loads all the suppression rules files configured in the {@link Settings}.
*
* @return the array of rules that were loaded
* @throws SuppressionParseException thrown if the XML cannot be parsed.
*/
private synchronized void loadSuppressionData() throws SuppressionParseException {
private SuppressionRule[] loadSuppressionData() throws SuppressionParseException {
List<SuppressionRule> ruleList;
final SuppressionParser parser = new SuppressionParser();
try {
final InputStream in = FileUtils.getResourceAsStream("dependencycheck-base-suppression.xml");
rules = Collections.synchronizedList(parser.parseSuppressionRules(in));
ruleList = parser.parseSuppressionRules(in);
} catch (SAXException ex) {
throw new SuppressionParseException("Unable to parse the base suppression data file", ex);
}
final String[] suppressionFilePaths = getSettings().getArray(Settings.KEYS.SUPPRESSION_FILE);
if (suppressionFilePaths == null || suppressionFilePaths.length == 0) {
return;
if (suppressionFilePaths != null && suppressionFilePaths.length > 0) {
// Load all the suppression file paths
for (final String suppressionFilePath : suppressionFilePaths) {
ruleList.addAll(loadSuppressionFile(parser, suppressionFilePath));
}
}
// Load all the suppression file paths
for (final String suppressionFilePath : suppressionFilePaths) {
loadSuppressionFile(parser, suppressionFilePath);
}
LOGGER.debug("{} suppression rules were loaded.", rules.size());
LOGGER.debug("{} suppression rules were loaded.", ruleList.size());
return ruleList.toArray(new SuppressionRule[ruleList.size()]);
}
/**
* Load a single suppression rules file from the path provided using the
* parser provided.
*
* @param parser the parser to use for loading the file.
* @param suppressionFilePath the path to load.
* @param parser the parser to use for loading the file
* @param suppressionFilePath the path to load
* @return the list of loaded suppression rules
* @throws SuppressionParseException thrown if the suppression file cannot
* be loaded and parsed.
*/
private synchronized void loadSuppressionFile(final SuppressionParser parser, final String suppressionFilePath) throws SuppressionParseException {
private List<SuppressionRule> loadSuppressionFile(final SuppressionParser parser,
final String suppressionFilePath) throws SuppressionParseException {
LOGGER.debug("Loading suppression rules from '{}'", suppressionFilePath);
final List<SuppressionRule> list = new ArrayList<>();
File file = null;
boolean deleteTempFile = false;
try {
@@ -146,7 +153,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
deleteTempFile = true;
file = getSettings().getTempFile("suppression", "xml");
final URL url = new URL(suppressionFilePath);
Downloader downloader = new Downloader(getSettings());
final Downloader downloader = new Downloader(getSettings());
try {
downloader.fetchFile(url, file, false);
} catch (DownloadFailedException ex) {
@@ -177,7 +184,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
throw new SuppressionParseException(msg);
}
try {
rules.addAll(parser.parseSuppressionRules(file));
list.addAll(parser.parseSuppressionRules(file));
} catch (SuppressionParseException ex) {
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
LOGGER.warn(ex.getMessage());
@@ -197,6 +204,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
FileUtils.delete(file);
}
}
return list;
}
/**

View File

@@ -27,10 +27,10 @@ import org.owasp.dependencycheck.utils.Settings;
* <p>
* An interface that defines an Analyzer that is used to identify Dependencies.
* An analyzer will collect information about the dependency in the form of
* Evidence.<p>
* Evidence.</p>
* <p>
* When the {@link org.owasp.dependencycheck.Engine} executes it will load the
* analyzers and call the methods in the following order:
* analyzers and call the methods in the following order:</p>
* <ol>
* <li>{@link #initializeSettings(org.owasp.dependencycheck.utils.Settings)}</li>
* <li>{@link #initialize(org.owasp.dependencycheck.Engine)}</li>
@@ -75,7 +75,7 @@ public interface Analyzer {
*
* @param settings the configured settings
*/
public void initializeSettings(Settings settings);
void initializeSettings(Settings settings);
/**
* The initialize method is called (once) prior to the analyze method being

View File

@@ -24,13 +24,15 @@ import static java.util.Arrays.asList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import javax.annotation.concurrent.ThreadSafe;
/**
* The Analyzer Service Loader. This class loads all services that implement
* org.owasp.dependencycheck.analyzer.Analyzer.
* {@link org.owasp.dependencycheck.analyzer.Analyzer}.
*
* @author Jeremy Long
*/
@ThreadSafe
public class AnalyzerService {
/**

View File

@@ -111,7 +111,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
* Detects files with .zip extension.
*/
private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/**
* The name of the analyzer.
@@ -121,6 +121,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
* The phase that this analyzer is intended to run in.
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INITIAL;
/**
* Initializes the analyzer with the configured settings.
*
@@ -289,9 +290,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
}
if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
addDisguisedJarsToDependencies(dependency, engine);
engine.getDependencies().remove(dependency);
engine.removeDependency(dependency);
}
Collections.sort(engine.getDependencies());
engine.sortDependencies();
}
/**

View File

@@ -43,6 +43,7 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.ParserConfigurationException;
import org.owasp.dependencycheck.exception.InitializationException;
import org.apache.commons.lang3.SystemUtils;
@@ -55,6 +56,7 @@ import org.owasp.dependencycheck.utils.XmlUtils;
* @author colezlaw
*
*/
@ThreadSafe
public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
/**
@@ -111,20 +113,16 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
* @throws AnalysisException if anything goes sideways
*/
@Override
public void analyzeDependency(Dependency dependency, Engine engine)
throws AnalysisException {
public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
final File test = new File(dependency.getActualFilePath());
if (!test.isFile()) {
throw new AnalysisException(String.format("%s does not exist and cannot be analyzed by dependency-check",
dependency.getActualFilePath()));
}
if (grokAssemblyExe == null) {
LOGGER.warn("GrokAssembly didn't get deployed");
return;
}
final List<String> args = buildArgumentList();
if (args == null) {
LOGGER.warn("Assembly Analyzer was unable to execute");
@@ -199,8 +197,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
LOGGER.error("----------------------------------------------------");
throw new AnalysisException("Couldn't parse Assembly Analyzer results (GrokAssembly)", saxe);
}
// This shouldn't happen
}
/**

View File

@@ -176,7 +176,7 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
}
}
} else {
engine.getDependencies().remove(dependency);
engine.removeDependency(dependency);
}
}

View File

@@ -224,7 +224,7 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
}
final MessageDigest sha1 = getSha1MessageDigest();
currentDep.setSha1sum(Checksum.getHex(sha1.digest(path)));
engine.getDependencies().add(currentDep);
engine.addDependency(currentDep);
}
final String source = currentDep.getDisplayFileName();
currentDep.getProductEvidence().addEvidence(source, "Product",

View File

@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.lucene.analysis.util.CharArraySet;
import org.apache.lucene.document.Document;
@@ -63,6 +64,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public class CPEAnalyzer extends AbstractAnalyzer {
/**
@@ -92,6 +94,10 @@ public class CPEAnalyzer extends AbstractAnalyzer {
* data that will be written into the string.
*/
private static final int STRING_BUILDER_BUFFER = 20;
/**
* The URL to perform a search of the NVD CVE data at NIST.
*/
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
/**
* The CPE in memory index.
*/
@@ -101,11 +107,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
*/
private CveDB cve;
/**
* The URL to perform a search of the NVD CVE data at NIST.
*/
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
/**
* Returns the name of this analyzer.
*
@@ -126,18 +127,18 @@ public class CPEAnalyzer extends AbstractAnalyzer {
return AnalysisPhase.IDENTIFIER_ANALYSIS;
}
/**
* The default is to support parallel processing.
*
* @return false
*/
@Override
public boolean supportsParallelProcessing() {
return false;
}
// /**
// * The default is to support parallel processing.
// *
// * @return false
// */
// @Override
// public boolean supportsParallelProcessing() {
// return false;
// }
/**
* Creates the CPE Lucene Index.
*
* @param engine a reference to the dependency-check engine
* @throws InitializationException is thrown if there is an issue opening
* the index.
@@ -164,7 +165,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
* @throws DatabaseException when the database throws an exception. This
* usually occurs when the database is in use by another process.
*/
public void open(CveDB cve) throws IOException, DatabaseException {
public synchronized void open(CveDB cve) throws IOException, DatabaseException {
if (!isOpen()) {
this.cve = cve;
this.cpe = CpeMemoryIndex.getInstance();
@@ -185,10 +186,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
*/
@Override
public void closeAnalyzer() {
if (cve != null) {
cve.close();
cve = null;
}
if (cpe != null) {
cpe.close();
cpe = null;
@@ -490,7 +487,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
final String[] words = text.split("[\\s_-]");
final List<String> list = new ArrayList<>();
String tempWord = null;
CharArraySet stopWords = SearchFieldAnalyzer.getStopWords();
final CharArraySet stopWords = SearchFieldAnalyzer.getStopWords();
for (String word : words) {
if (stopWords.contains(word)) {
continue;

View File

@@ -36,6 +36,7 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
@@ -49,6 +50,7 @@ import org.owasp.dependencycheck.utils.Settings;
*
* @author colezlaw
*/
@ThreadSafe
public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
/**
@@ -232,7 +234,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
LOGGER.debug("Unable to delete temp file");
}
LOGGER.debug("Downloading {}", ma.getPomUrl());
Downloader downloader = new Downloader(getSettings());
final Downloader downloader = new Downloader(getSettings());
downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
PomUtils.analyzePOM(dependency, pomFile);

View File

@@ -23,6 +23,7 @@ import java.io.IOException;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
@@ -41,6 +42,7 @@ import org.owasp.dependencycheck.utils.Settings;
* @author Bianca Jiang (https://twitter.com/biancajiang)
*/
@Experimental
@ThreadSafe
public class CocoaPodsAnalyzer extends AbstractFileTypeAnalyzer {
/**

View File

@@ -117,7 +117,7 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
d.getProductEvidence().addEvidence(COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGHEST);
d.getVersionEvidence().addEvidence(COMPOSER_LOCK, "version", dep.getVersion(), Confidence.HIGHEST);
LOGGER.info("Adding dependency {}", d);
engine.getDependencies().add(d);
engine.addDependency(d);
}
} catch (IOException ex) {
LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());

View File

@@ -17,6 +17,7 @@
*/
package org.owasp.dependencycheck.analyzer;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.utils.Settings;
/**
@@ -26,6 +27,7 @@ import org.owasp.dependencycheck.utils.Settings;
*
* @author Jeremy Long
*/
@ThreadSafe
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
/**

View File

@@ -18,14 +18,11 @@
package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.utils.DependencyVersion;
@@ -47,37 +44,19 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
@ThreadSafe
public class DependencyBundlingAnalyzer extends AbstractDependencyComparingAnalyzer {
/**
* The Logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyBundlingAnalyzer.class);
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
/**
* 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 synchronized boolean getAnalyzed() {
return analyzed;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/**
* The name of the analyzer.
*/
@@ -106,19 +85,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</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;
}
/**
* <p>
@@ -132,65 +98,46 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
}
/**
* Analyzes a set of dependencies. If they have been found to have the same
* base path and the same set of identifiers they are likely related. The
* related dependencies are bundled into a single reportable item.
* Evaluates the dependencies
*
* @param ignore this analyzer ignores the dependency being analyzed
* @param engine the engine that is scanning the dependencies
* @throws AnalysisException is thrown if there is an error reading the JAR
* file.
* @param dependency a dependency to compare
* @param nextDependency a dependency to compare
* @param dependenciesToRemove a set of dependencies that will be removed
* @return true if a dependency is removed; otherwise false
*/
@Override
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
if (!analyzed) {
analyzed = true;
final Set<Dependency> dependenciesToRemove = new HashSet<>();
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
//for (Dependency nextDependency : engine.getDependencies()) {
while (mainIterator.hasNext()) {
final Dependency dependency = mainIterator.next();
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
while (subIterator.hasNext()) {
final Dependency nextDependency = subIterator.next();
if (hashesMatch(dependency, nextDependency)) {
if (!containedInWar(dependency.getFilePath())
&& !containedInWar(nextDependency.getFilePath())) {
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
} else if (isShadedJar(dependency, nextDependency)) {
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
nextDependency.getRelatedDependencies().remove(dependency);
break;
} else {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
dependency.getRelatedDependencies().remove(nextDependency);
}
} else if (cpeIdentifiersMatch(dependency, nextDependency)
&& hasSameBasePath(dependency, nextDependency)
&& vulnCountMatches(dependency, nextDependency)
&& fileNameMatch(dependency, nextDependency)) {
if (isCore(dependency, nextDependency)) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
}
protected boolean evaluateDependencies(final Dependency dependency, final Dependency nextDependency, final Set<Dependency> dependenciesToRemove) {
if (hashesMatch(dependency, nextDependency)) {
if (!containedInWar(dependency.getFilePath())
&& !containedInWar(nextDependency.getFilePath())) {
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
return true; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
// was difficult because of the inner iterator.
engine.getDependencies().removeAll(dependenciesToRemove);
} else if (isShadedJar(dependency, nextDependency)) {
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
nextDependency.getRelatedDependencies().remove(dependency);
return true;
} else {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
dependency.getRelatedDependencies().remove(nextDependency);
}
} else if (cpeIdentifiersMatch(dependency, nextDependency)
&& hasSameBasePath(dependency, nextDependency)
&& vulnCountMatches(dependency, nextDependency)
&& fileNameMatch(dependency, nextDependency)) {
if (isCore(dependency, nextDependency)) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
return true; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
return false;
}
/**

View File

@@ -18,12 +18,8 @@
package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
@@ -36,31 +32,12 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
public class DependencyMergingAnalyzer extends AbstractAnalyzer {
public class DependencyMergingAnalyzer extends AbstractDependencyComparingAnalyzer {
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
/**
* The Logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyMergingAnalyzer.class);
/**
* 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 synchronized boolean getAnalyzed() {
return analyzed;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/**
* The name of the analyzer.
*/
@@ -90,18 +67,6 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
return ANALYSIS_PHASE;
}
/**
* 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;
}
/**
* <p>
* Returns the setting key to determine if the analyzer is enabled.</p>
@@ -112,55 +77,34 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_DEPENDENCY_MERGING_ENABLED;
}
//</editor-fold>
/**
* Analyzes a set of dependencies. If they have been found to be the same
* dependency created by more multiple FileTypeAnalyzers (i.e. a gemspec
* dependency and a dependency from the Bundle Audit Analyzer. The
* dependencies are then merged into a single reportable item.
* Evaluates the dependencies
*
* @param ignore this analyzer ignores the dependency being analyzed
* @param engine the engine that is scanning the dependencies
* @throws AnalysisException is thrown if there is an error reading the JAR
* file.
* @param dependency a dependency to compare
* @param nextDependency a dependency to compare
* @param dependenciesToRemove a set of dependencies that will be removed
* @return true if a dependency is removed; otherwise false
*/
@Override
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
if (!analyzed) {
analyzed = true;
final Set<Dependency> dependenciesToRemove = new HashSet<>();
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
//for (Dependency nextDependency : engine.getDependencies()) {
while (mainIterator.hasNext()) {
final Dependency dependency = mainIterator.next();
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
while (subIterator.hasNext()) {
final Dependency nextDependency = subIterator.next();
Dependency main;
if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
if (main == dependency) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
} else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) {
if (main == dependency) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
}
}
protected boolean evaluateDependencies(final Dependency dependency, final Dependency nextDependency, final Set<Dependency> dependenciesToRemove) {
Dependency main;
if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
if (main == dependency) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
return true; //since we merged into the next dependency - skip forward to the next in mainIterator
}
} else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) {
if (main == dependency) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
return true; //since we merged into the next dependency - skip forward to the next in mainIterator
}
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
// was difficult because of the inner iterator.
engine.getDependencies().removeAll(dependenciesToRemove);
}
return false;
}
/**

View File

@@ -28,6 +28,7 @@ import java.util.ListIterator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
@@ -44,6 +45,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
/**
@@ -155,8 +157,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
}
}
}
if (mustContain
!= null) {
if (mustContain != null) {
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
while (itr.hasNext()) {
final Identifier i = itr.next();
@@ -444,7 +445,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
String parentPath = dependency.getFilePath().toLowerCase();
if (parentPath.contains(".jar")) {
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
final List<Dependency> dependencies = engine.getDependencies();
final Dependency[] dependencies = engine.getDependencies();
final Dependency parent = findDependency(parentPath, dependencies);
if (parent != null) {
boolean remove = false;
@@ -462,7 +463,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
}
}
if (remove) {
dependencies.remove(dependency);
engine.removeDependency(dependency);
}
}
}
@@ -474,10 +475,10 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
* dependencies.
*
* @param dependencyPath the path of the dependency to return
* @param dependencies the collection of dependencies to search
* @param dependencies the array of dependencies to search
* @return the dependency object for the given path, otherwise null
*/
private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) {
private Dependency findDependency(String dependencyPath, Dependency[] dependencies) {
for (Dependency d : dependencies) {
if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
return d;

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.analyzer;
import java.io.File;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.NameFileFilter;
@@ -30,11 +31,11 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* Takes a dependency and analyzes the filename and determines the hashes.
*
* @author Jeremy Long
*/
@ThreadSafe
public class FileNameAnalyzer extends AbstractAnalyzer {
/**
@@ -76,6 +77,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer {
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
/**
* <p>
* Returns the setting key to determine if the analyzer is enabled.</p>

View File

@@ -26,6 +26,8 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang.ArrayUtils;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
@@ -40,7 +42,6 @@ import org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule;
import org.owasp.dependencycheck.xml.hints.HintParseException;
import org.owasp.dependencycheck.xml.hints.HintParser;
import org.owasp.dependencycheck.xml.hints.HintRule;
import org.owasp.dependencycheck.xml.hints.Hints;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
@@ -51,6 +52,7 @@ import org.xml.sax.SAXException;
*
* @author Jeremy Long
*/
@ThreadSafe
public class HintAnalyzer extends AbstractAnalyzer {
/**
@@ -62,11 +64,14 @@ public class HintAnalyzer extends AbstractAnalyzer {
*/
private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
/**
* The collection of hints.
* The array of hint rules.
*/
private Hints hints;
private HintRule[] hints = null;
/**
* The array of vendor duplicating hint rules.
*/
private VendorDuplicatingHintRule[] vendorHints;
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/**
* The name of the analyzer.
*/
@@ -122,7 +127,6 @@ public class HintAnalyzer extends AbstractAnalyzer {
throw new InitializationException("Unable to parse the hint file", ex);
}
}
//</editor-fold>
/**
* The HintAnalyzer uses knowledge about a dependency to add additional
@@ -135,7 +139,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
*/
@Override
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
for (HintRule hint : hints.getHintRules()) {
for (HintRule hint : hints) {
boolean matchFound = false;
for (Evidence given : hint.getGivenVendor()) {
if (dependency.getVendorEvidence().getEvidence().contains(given)) {
@@ -199,7 +203,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
final List<Evidence> newEntries = new ArrayList<>();
while (itr.hasNext()) {
final Evidence e = itr.next();
for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
for (VendorDuplicatingHintRule dhr : vendorHints) {
if (dhr.getValue().equalsIgnoreCase(e.getValue(false))) {
newEntries.add(new Evidence(e.getSource() + " (hint)",
e.getName(), dhr.getDuplicate(), e.getConfidence()));
@@ -217,71 +221,79 @@ public class HintAnalyzer extends AbstractAnalyzer {
* @throws HintParseException thrown if the XML cannot be parsed.
*/
private void loadHintRules() throws HintParseException {
final HintParser parser = new HintParser();
File file = null;
try {
hints = parser.parseHints(FileUtils.getResourceAsStream(HINT_RULE_FILE_NAME));
} catch (HintParseException | SAXException ex) {
LOGGER.error("Unable to parse the base hint data file");
LOGGER.debug("Unable to parse the base hint data file", ex);
}
final String filePath = getSettings().getString(Settings.KEYS.HINTS_FILE);
if (filePath == null) {
return;
}
boolean deleteTempFile = false;
try {
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
if (uriRx.matcher(filePath).matches()) {
deleteTempFile = true;
file = getSettings().getTempFile("hint", "xml");
final URL url = new URL(filePath);
Downloader downloader = new Downloader(getSettings());
try {
downloader.fetchFile(url, file, false);
} catch (DownloadFailedException ex) {
downloader.fetchFile(url, file, true);
}
} else {
file = new File(filePath);
if (!file.exists()) {
try (InputStream fromClasspath = FileUtils.getResourceAsStream(filePath)) {
if (fromClasspath != null) {
deleteTempFile = true;
file = getSettings().getTempFile("hint", "xml");
try {
org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
} catch (IOException ex) {
throw new HintParseException("Unable to locate hints file in classpath", ex);
if (hints == null) {
final HintParser parser = new HintParser();
File file = null;
try {
parser.parseHints(FileUtils.getResourceAsStream(HINT_RULE_FILE_NAME));
hints = parser.getHintRules();
vendorHints = parser.getVendorDuplicatingHintRules();
} catch (HintParseException | SAXException ex) {
LOGGER.error("Unable to parse the base hint data file");
LOGGER.debug("Unable to parse the base hint data file", ex);
}
final String filePath = getSettings().getString(Settings.KEYS.HINTS_FILE);
if (filePath == null) {
return;
}
boolean deleteTempFile = false;
try {
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
if (uriRx.matcher(filePath).matches()) {
deleteTempFile = true;
file = getSettings().getTempFile("hint", "xml");
final URL url = new URL(filePath);
final Downloader downloader = new Downloader(getSettings());
try {
downloader.fetchFile(url, file, false);
} catch (DownloadFailedException ex) {
downloader.fetchFile(url, file, true);
}
} else {
file = new File(filePath);
if (!file.exists()) {
try (InputStream fromClasspath = FileUtils.getResourceAsStream(filePath)) {
if (fromClasspath != null) {
deleteTempFile = true;
file = getSettings().getTempFile("hint", "xml");
try {
org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
} catch (IOException ex) {
throw new HintParseException("Unable to locate hints file in classpath", ex);
}
}
}
}
}
}
if (file != null) {
try {
final Hints newHints = parser.parseHints(file);
hints.getHintRules().addAll(newHints.getHintRules());
hints.getVendorDuplicatingHintRules().addAll(newHints.getVendorDuplicatingHintRules());
LOGGER.debug("{} hint rules were loaded.", hints.getHintRules().size());
LOGGER.debug("{} duplicating hint rules were loaded.", hints.getVendorDuplicatingHintRules().size());
} catch (HintParseException ex) {
LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath());
LOGGER.warn(ex.getMessage());
LOGGER.debug("", ex);
throw ex;
if (file != null) {
try {
parser.parseHints(file);
if (parser.getHintRules() != null && parser.getHintRules().length > 0) {
hints = (HintRule[]) ArrayUtils.addAll(hints, parser.getHintRules());
}
if (parser.getVendorDuplicatingHintRules() != null && parser.getVendorDuplicatingHintRules().length > 0) {
vendorHints = (VendorDuplicatingHintRule[]) ArrayUtils.addAll(vendorHints, parser.getVendorDuplicatingHintRules());
}
LOGGER.debug("{} hint rules were loaded.", hints.length);
LOGGER.debug("{} duplicating hint rules were loaded.", vendorHints.length);
} catch (HintParseException ex) {
LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath());
LOGGER.warn(ex.getMessage());
LOGGER.debug("", ex);
throw ex;
}
}
} catch (DownloadFailedException ex) {
throw new HintParseException("Unable to fetch the configured hint file", ex);
} catch (MalformedURLException ex) {
throw new HintParseException("Configured hint file has an invalid URL", ex);
} catch (IOException ex) {
throw new HintParseException("Unable to create temp file for hints", ex);
} finally {
if (deleteTempFile && file != null) {
FileUtils.delete(file);
}
}
} catch (DownloadFailedException ex) {
throw new HintParseException("Unable to fetch the configured hint file", ex);
} catch (MalformedURLException ex) {
throw new HintParseException("Configured hint file has an invalid URL", ex);
} catch (IOException ex) {
throw new HintParseException("Unable to create temp file for hints", ex);
} finally {
if (deleteTempFile && file != null) {
FileUtils.delete(file);
}
}
}

View File

@@ -251,7 +251,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|| fileName.endsWith("-doc.jar")
|| isMacOSMetaDataFile(dependency, engine))
|| !isZipFile(dependency)) {
engine.getDependencies().remove(dependency);
engine.removeDependency(dependency);
return;
}
final boolean hasManifest = parseManifest(dependency, classNames);
@@ -289,7 +289,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
* @return whether or not the given dependencies contain a dependency with
* the given filename
*/
private boolean hasDependencyWithFilename(final List<Dependency> dependencies, final String fileName) {
private boolean hasDependencyWithFilename(final Dependency[] dependencies, final String fileName) {
for (final Dependency dependency : dependencies) {
if (Paths.get(dependency.getActualFilePath()).getFileName().toString().toLowerCase()
.equals(fileName.toLowerCase())) {
@@ -386,7 +386,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
newDependency.setFileName(displayName);
newDependency.setFilePath(displayPath);
setPomEvidence(newDependency, pom, null);
engine.getDependencies().add(newDependency);
engine.addDependency(newDependency);
} catch (AnalysisException ex) {
LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
LOGGER.trace("", ex);
@@ -700,6 +700,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
value = Jsoup.parse(value).text();
}
if (IGNORE_VALUES.contains(value)) {
//noinspection UnnecessaryContinue
continue;
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
foundSomething = true;
@@ -733,6 +734,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
foundSomething = true;
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
} else if (key.equalsIgnoreCase(Attributes.Name.MAIN_CLASS.toString())) {
//noinspection UnnecessaryContinue
continue;
//skipping main class as if this has important information to add it will be added during class name analysis...
} else {

View File

@@ -35,6 +35,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
@@ -59,6 +60,7 @@ import org.owasp.dependencycheck.utils.Settings;
*
* @author colezlaw
*/
@ThreadSafe
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
/**
@@ -251,7 +253,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
LOGGER.debug("Unable to delete temp file");
}
LOGGER.debug("Downloading {}", ma.getPomUrl());
Downloader downloader = new Downloader(getSettings());
final Downloader downloader = new Downloader(getSettings());
downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
PomUtils.analyzePOM(dependency, pomFile);
} catch (DownloadFailedException ex) {

View File

@@ -32,6 +32,7 @@ import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
import javax.json.Json;
import javax.json.JsonException;
import javax.json.JsonObject;
@@ -47,6 +48,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
* @author Dale Visser
*/
@Experimental
@ThreadSafe
public class NodePackageAnalyzer extends AbstractFileTypeAnalyzer {
/**

View File

@@ -37,11 +37,11 @@ import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonException;
@@ -59,6 +59,7 @@ import org.owasp.dependencycheck.utils.URLConnectionFailureException;
*
* @author Steve Springett
*/
@ThreadSafe
public class NspAnalyzer extends AbstractFileTypeAnalyzer {
/**
@@ -284,11 +285,11 @@ public class NspAnalyzer extends AbstractFileTypeAnalyzer {
* @param depType the dependency type
*/
private void processPackage(Dependency dependency, JsonArray jsonArray, String depType) {
JsonObjectBuilder builder = Json.createObjectBuilder();
final JsonObjectBuilder builder = Json.createObjectBuilder();
for (JsonString str : jsonArray.getValuesAs(JsonString.class)) {
builder.add(str.toString(), "");
}
JsonObject jsonObject = builder.build();
final JsonObject jsonObject = builder.build();
processPackage(dependency, jsonObject, depType);
}

View File

@@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException;
/**
@@ -40,6 +41,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
*
* @author colezlaw
*/
@ThreadSafe
public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
/**

View File

@@ -17,9 +17,8 @@
*/
package org.owasp.dependencycheck.analyzer;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -27,9 +26,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.LoggerFactory;
/**
* NvdCveAnalyzer is a utility class that takes a project dependency and
@@ -38,36 +35,13 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public class NvdCveAnalyzer extends AbstractAnalyzer {
/**
* The Logger for use throughout the class
*/
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class);
/**
* The CVE Index.
*/
private CveDB cveDB;
/**
* Closes the data source.
*/
@Override
public void closeAnalyzer() {
cveDB.close();
cveDB = null;
}
/**
* Returns the status of the data source - is the database open.
*
* @return true or false.
*/
public boolean isOpen() {
return cveDB != null;
}
//private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class);
/**
* Analyzes a dependency and attempts to determine if there are any CPE
* identifiers for this dependency.
@@ -79,6 +53,7 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
*/
@Override
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
final CveDB cveDB = engine.getDatabase();
for (Identifier id : dependency.getIdentifiers()) {
if ("cpe".equals(id.getType())) {
try {
@@ -133,16 +108,4 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_NVD_CVE_ENABLED;
}
/**
* Opens the database used to gather NVD CVE data.
*
* @param engine a reference the dependency-check engine
* @throws InitializationException is thrown if there is an issue opening
* the index.
*/
@Override
public void initializeAnalyzer(Engine engine) throws InitializationException {
this.cveDB = engine.getDatabase();
}
}

View File

@@ -31,6 +31,7 @@ import java.io.IOException;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException;
/**
@@ -38,6 +39,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
*
* @author Dale Visser
*/
@ThreadSafe
public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
/**
@@ -143,6 +145,16 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
return OPENSSLV_FILTER;
}
/**
* Returns the setting for the analyzer enabled setting key.
*
* @return the setting for the analyzer enabled setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
}
/**
* No-op initializer implementation.
*
@@ -182,7 +194,7 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
dependency.getVendorEvidence().addEvidence(OPENSSLV_H, "Vendor", "OpenSSL", Confidence.HIGHEST);
dependency.getProductEvidence().addEvidence(OPENSSLV_H, "Product", "OpenSSL", Confidence.HIGHEST);
} else {
engine.getDependencies().remove(dependency);
engine.removeDependency(dependency);
}
}
@@ -202,14 +214,4 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
"Problem occurred while reading dependency file.", e);
}
}
/**
* Returns the setting for the analyzer enabled setting key.
*
* @return the setting for the analyzer enabled setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
}
}

View File

@@ -46,6 +46,7 @@ import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.UrlStringUtils;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.concurrent.ThreadSafe;
/**
* Used to analyze a Wheel or egg distribution files, or their contents in
@@ -55,30 +56,26 @@ import java.util.concurrent.atomic.AtomicInteger;
* @author Dale Visser
*/
@Experimental
@ThreadSafe
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
/**
* Name of egg metadata files to analyze.
*/
private static final String PKG_INFO = "PKG-INFO";
/**
* Name of wheel metadata files to analyze.
*/
private static final String METADATA = "METADATA";
/**
* The logger.
*/
private static final Logger LOGGER = LoggerFactory
.getLogger(PythonDistributionAnalyzer.class);
private static final Logger LOGGER = LoggerFactory.getLogger(PythonDistributionAnalyzer.class);
/**
* The count of directories created during analysis. This is used for
* creating temporary directories.
*/
private static final AtomicInteger DIR_COUNT = new AtomicInteger(0);
/**
* The name of the analyzer.
*/
@@ -87,52 +84,39 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
* The phase that this analyzer is intended to run in.
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/**
* The set of file extensions supported by this analyzer.
*/
private static final String[] EXTENSIONS = {"whl", "egg", "zip"};
/**
* Used to match on egg archive candidate extensions.
*/
private static final FileFilter EGG_OR_ZIP = FileFilterBuilder.newInstance().addExtensions("egg", "zip").build();
/**
* Used to detect files with a .whl extension.
*/
private static final FileFilter WHL_FILTER = FileFilterBuilder.newInstance().addExtensions("whl").build();
/**
* The parent directory for the individual directories per archive.
*/
private File tempFileLocation;
/**
* Filter that detects *.dist-info files (but doesn't verify they are
* directories.
*/
private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter(
".dist-info");
private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter(".dist-info");
/**
* Filter that detects files named "METADATA".
*/
private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter(
"EGG-INFO");
private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter("EGG-INFO");
/**
* Filter that detects files named "METADATA".
*/
private static final NameFileFilter METADATA_FILTER = new NameFileFilter(
METADATA);
private static final NameFileFilter METADATA_FILTER = new NameFileFilter(METADATA);
/**
* Filter that detects files named "PKG-INFO".
*/
private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter(
PKG_INFO);
private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter(PKG_INFO);
/**
* The file filter used to determine which files this analyzer supports.
*/
@@ -311,8 +295,7 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
addPropertyToEvidence(headers, vendorEvidence, "Author", Confidence.LOW);
final String summary = headers.getHeader("Summary", null);
if (StringUtils.isNotBlank(summary)) {
JarAnalyzer
.addDescription(dependency, summary, METADATA, "summary");
JarAnalyzer.addDescription(dependency, summary, METADATA, "summary");
}
}

View File

@@ -35,6 +35,7 @@ import java.io.IOException;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException;
/**
@@ -44,13 +45,13 @@ import org.owasp.dependencycheck.exception.InitializationException;
* @author Dale Visser
*/
@Experimental
@ThreadSafe
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
/**
* Used when compiling file scanning regex patterns.
*/
private static final int REGEX_OPTIONS = Pattern.DOTALL
| Pattern.CASE_INSENSITIVE;
private static final int REGEX_OPTIONS = Pattern.DOTALL | Pattern.CASE_INSENSITIVE;
/**
* Filename extensions for files to be analyzed.
@@ -58,16 +59,14 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
private static final String EXTENSIONS = "py";
/**
* Pattern for matching the module docstring in a source file.
* Pattern for matching the module doc string in a source file.
*/
private static final Pattern MODULE_DOCSTRING = Pattern.compile(
"^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
private static final Pattern MODULE_DOCSTRING = Pattern.compile("^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
/**
* Matches assignments to version variables in Python source code.
*/
private static final Pattern VERSION_PATTERN = Pattern.compile(
"\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
private static final Pattern VERSION_PATTERN = Pattern.compile("\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
REGEX_OPTIONS);
/**
@@ -130,6 +129,16 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
return AnalysisPhase.INFORMATION_COLLECTION;
}
/**
* Returns the key name for the analyzers enabled setting.
*
* @return the key name for the analyzers enabled setting
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
}
/**
* Returns the FileFilter
*
@@ -192,7 +201,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
}
}
} else {
engine.getDependencies().remove(dependency);
engine.removeDependency(dependency);
}
}
@@ -212,8 +221,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
try {
contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim();
} catch (IOException e) {
throw new AnalysisException(
"Problem occurred while reading dependency file.", e);
throw new AnalysisException("Problem occurred while reading dependency file.", e);
}
boolean found = false;
if (!contents.isEmpty()) {
@@ -311,9 +319,4 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
}
return found;
}
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
}
}

View File

@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
@@ -50,6 +51,7 @@ import org.slf4j.LoggerFactory;
*
* @author Dale Visser
*/
@ThreadSafe
public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
/**
@@ -482,7 +484,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
dependency.setDisplayFileName(displayFileName);
dependency.setFileName(fileName);
dependency.setFilePath(filePath);
engine.getDependencies().add(dependency);
engine.addDependency(dependency);
return dependency;
}
}

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.io.FilenameFilter;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
@@ -47,6 +48,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
* @author Bianca Jiang (https://twitter.com/biancajiang)
*/
@Experimental
@ThreadSafe
public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer {
/**

View File

@@ -25,6 +25,7 @@ import java.nio.charset.Charset;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
@@ -46,6 +47,7 @@ import org.slf4j.LoggerFactory;
* @author Dale Visser
*/
@Experimental
@ThreadSafe
public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
/**
@@ -130,8 +132,7 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
private static final Pattern GEMSPEC_BLOCK_INIT = Pattern.compile("Gem::Specification\\.new\\s+?do\\s+?\\|(.+?)\\|");
@Override
protected void analyzeDependency(Dependency dependency, Engine engine)
throws AnalysisException {
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
String contents;
try {
contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset());

View File

@@ -23,6 +23,7 @@ import java.io.IOException;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
@@ -41,6 +42,7 @@ import org.owasp.dependencycheck.utils.Settings;
* @author Bianca Jiang (https://twitter.com/biancajiang)
*/
@Experimental
@ThreadSafe
public class SwiftPackageManagerAnalyzer extends AbstractFileTypeAnalyzer {
/**

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.analyzer;
import java.util.Iterator;
import java.util.Objects;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
@@ -37,8 +38,14 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public class VersionFilterAnalyzer extends AbstractAnalyzer {
/**
* The Logger for use throughout the class
*/
private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class);
//<editor-fold defaultstate="collapsed" desc="Constants">
/**
* Evidence source.
@@ -111,11 +118,6 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
}
//</editor-fold>
/**
* The Logger for use throughout the class
*/
private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class);
/**
* The HintAnalyzer uses knowledge about a dependency to add additional
* information to help in identification of identifiers or vulnerabilities.
@@ -126,7 +128,7 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
* the dependency.
*/
@Override
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
String fileVersion = null;
String pomVersion = null;
String manifestVersion = null;

View File

@@ -17,6 +17,7 @@
*/
package org.owasp.dependencycheck.analyzer;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.utils.Settings;
/**
@@ -26,6 +27,7 @@ import org.owasp.dependencycheck.utils.Settings;
*
* @author Jeremy Long
*/
@ThreadSafe
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
/**

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.analyzer.exception;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception thrown when the analysis of a dependency fails.
*
* @author Jeremy Long
*/
@ThreadSafe
public class AnalysisException extends Exception {
/**

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.analyzer.exception;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception thrown when files in an archive cannot be extracted.
*
* @author Jeremy Long
*/
@ThreadSafe
public class ArchiveExtractionException extends Exception {
/**

View File

@@ -21,9 +21,11 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
@@ -45,12 +47,13 @@ import org.xml.sax.SAXException;
*
* @author colezlaw
*/
@ThreadSafe
public class CentralSearch {
/**
* The URL for the Central service
*/
private final URL rootURL;
private final String rootURL;
/**
* Whether to use the Proxy when making requests
@@ -70,7 +73,7 @@ public class CentralSearch {
* Creates a NexusSearch for the given repository URL.
*
* @param settings the configured settings
* @throws java.net.MalformedURLException thrown if the configured URL is
* @throws MalformedURLException thrown if the configured URL is
* invalid
*/
public CentralSearch(Settings settings) throws MalformedURLException {
@@ -78,7 +81,10 @@ public class CentralSearch {
final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
LOGGER.debug("Central Search URL: {}", searchUrl);
this.rootURL = new URL(searchUrl);
if (isInvalidURL(searchUrl)) {
throw new MalformedURLException(String.format("The configured central analyzer URL is invalid: %s", searchUrl));
}
this.rootURL = searchUrl;
if (null != settings.getString(Settings.KEYS.PROXY_SERVER)) {
useProxy = true;
LOGGER.debug("Using proxy");
@@ -103,7 +109,7 @@ public class CentralSearch {
throw new IllegalArgumentException("Invalid SHA1 format");
}
List<MavenArtifact> result = null;
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1));
final URL url = new URL(String.format("%s?q=1:\"%s\"&wt=xml", rootURL, sha1));
LOGGER.debug("Searching Central url {}", url);
@@ -178,4 +184,21 @@ public class CentralSearch {
}
return result;
}
/**
* Tests to determine if the gien URL is <b>invalid</b>.
*
* @param url the url to evaluate
* @return true if the url is malformed; otherwise false
*/
private boolean isInvalidURL(String url) {
try {
final URL u = new URL(url);
u.toURI();
} catch (MalformedURLException | URISyntaxException e) {
LOGGER.trace("URL is invalid: {}", url);
return true;
}
return false;
}
}

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.data.composer;
import javax.annotation.concurrent.ThreadSafe;
/**
* Represents a dependency (GAV, right now) from a Composer dependency.
*
* @author colezlaw
*/
@ThreadSafe
public final class ComposerDependency {
/**

View File

@@ -17,11 +17,15 @@
*/
package org.owasp.dependencycheck.data.composer;
import javax.annotation.concurrent.ThreadSafe;
/**
* Represents an exception when handling a composer.json or composer.lock file. Generally used to wrap a downstream exception.
* Represents an exception when handling a composer.json or composer.lock file.
* Generally used to wrap a downstream exception.
*
* @author colezlaw
*/
@ThreadSafe
public class ComposerException extends RuntimeException {
/**

View File

@@ -29,12 +29,14 @@ import javax.json.stream.JsonParsingException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Parses a Composer.lock file from an input stream. In a separate class so it can hopefully be injected.
*
* @author colezlaw
*/
@NotThreadSafe
public class ComposerLockParser {
/**

View File

@@ -21,6 +21,8 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
@@ -47,21 +49,29 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>
* An in memory Lucene index that contains the vendor/product combinations from
* the CPE (application) identifiers within the NVD CVE data.
* the CPE (application) identifiers within the NVD CVE data.</p>
*
* This is the last remaining singleton in dependency-check-core; The use of
* this singleton - while it may not technically be thread-safe (one database
* used to build this index may not have the same entries as another) the risk
* of this is currently believed to be small. As this memory index consumes a
* large amount of memory we will remain using the singleton pattern for now.
*
* @author Jeremy Long
*/
@ThreadSafe
public final class CpeMemoryIndex implements AutoCloseable {
/**
* Singleton instance.
*/
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
/**
* The logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(CpeMemoryIndex.class);
/**
* singleton instance.
*/
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
/**
* The in memory Lucene index.
*/
@@ -82,19 +92,11 @@ public final class CpeMemoryIndex implements AutoCloseable {
* The Lucene QueryParser used for Searching.
*/
private QueryParser queryParser;
/**
* The search field analyzer for the product field.
*/
private SearchFieldAnalyzer productFieldAnalyzer;
/**
* The search field analyzer for the vendor field.
*/
private SearchFieldAnalyzer vendorFieldAnalyzer;
/**
* Track the number of current users of the Lucene index; used to track it
* it is okay to actually close the index.
*/
private int usageCount = 0;
private final AtomicInteger usageCount = new AtomicInteger(0);
/**
* private constructor for singleton.
@@ -118,8 +120,7 @@ public final class CpeMemoryIndex implements AutoCloseable {
* @throws IndexException thrown if there is an error creating the index
*/
public synchronized void open(CveDB cve) throws IndexException {
if (INSTANCE.usageCount <= 0) {
INSTANCE.usageCount = 0;
if (INSTANCE.usageCount.addAndGet(1) == 1) {
index = new RAMDirectory();
buildIndex(cve);
try {
@@ -131,7 +132,6 @@ public final class CpeMemoryIndex implements AutoCloseable {
searchingAnalyzer = createSearchingAnalyzer();
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
}
INSTANCE.usageCount += 1;
}
/**
@@ -140,7 +140,7 @@ public final class CpeMemoryIndex implements AutoCloseable {
* @return whether or not the index is open
*/
public synchronized boolean isOpen() {
return INSTANCE.usageCount > 0;
return INSTANCE.usageCount.get() > 0;
}
/**
@@ -151,8 +151,8 @@ public final class CpeMemoryIndex implements AutoCloseable {
private Analyzer createSearchingAnalyzer() {
final Map<String, Analyzer> fieldAnalyzers = new HashMap<>();
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
productFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
vendorFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
SearchFieldAnalyzer productFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
SearchFieldAnalyzer vendorFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
fieldAnalyzers.put(Fields.PRODUCT, productFieldAnalyzer);
fieldAnalyzers.put(Fields.VENDOR, vendorFieldAnalyzer);
@@ -164,8 +164,9 @@ public final class CpeMemoryIndex implements AutoCloseable {
*/
@Override
public synchronized void close() {
INSTANCE.usageCount -= 1;
if (INSTANCE.usageCount <= 0) {
final int count = INSTANCE.usageCount.get() - 1;
if (count <= 0) {
INSTANCE.usageCount.set(0);
if (searchingAnalyzer != null) {
searchingAnalyzer.close();
searchingAnalyzer = null;
@@ -218,8 +219,6 @@ public final class CpeMemoryIndex implements AutoCloseable {
} catch (DatabaseException ex) {
LOGGER.debug("", ex);
throw new IndexException("Error reading CPE data", ex);
} catch (CorruptIndexException ex) {
throw new IndexException("Unable to close an in-memory index", ex);
} catch (IOException ex) {
throw new IndexException("Unable to close an in-memory index", ex);
}

View File

@@ -17,11 +17,15 @@
*/
package org.owasp.dependencycheck.data.cpe;
import javax.annotation.concurrent.ThreadSafe;
/**
* Fields is a collection of field names used within the Lucene index for CPE entries.
* Fields is a collection of field names used within the Lucene index for CPE
* entries.
*
* @author Jeremy Long
*/
@ThreadSafe
public final class Fields {
/**
@@ -38,7 +42,8 @@ public final class Fields {
public static final String PRODUCT = "product";
/**
* Private constructor as this is more of an enumeration rather then a full class.
* Private constructor as this is more of an enumeration rather then a full
* class.
*/
private Fields() {
}

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.cpe;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.StringUtils;
/**
@@ -27,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
*
* @author Jeremy Long
*/
@ThreadSafe
public class IndexEntry implements Serializable {
/**

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.data.cpe;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception thrown when the there is an issue using the in-memory CPE Index.
*
* @author Jeremy Long
*/
@ThreadSafe
public class IndexException extends Exception {
/**

View File

@@ -26,11 +26,13 @@ import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
/**
*
* @author Jeremy Long
*/
@ThreadSafe
public final class CweDB {
/**
@@ -59,9 +61,7 @@ public final class CweDB {
final String filePath = "data/cwe.hashmap.serialized";
try (InputStream input = FileUtils.getResourceAsStream(filePath);
ObjectInputStream oin = new ObjectInputStream(input)) {
final Map<String, String> ret = (HashMap<String, String>) oin.readObject();
return ret;
return (HashMap<String, String>) oin.readObject();
} catch (ClassNotFoundException ex) {
LOGGER.warn("Unable to load CWE data. This should not be an issue.");
LOGGER.debug("", ex);
@@ -79,7 +79,7 @@ public final class CweDB {
* @param cweId the CWE ID
* @return the full name of the CWE
*/
public static String getCweName(String cweId) {
public static synchronized String getCweName(String cweId) {
if (cweId != null) {
return CWE.get(cweId);
}

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.data.cwe;
import java.util.HashMap;
import javax.annotation.concurrent.NotThreadSafe;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
@@ -27,6 +28,7 @@ import org.xml.sax.helpers.DefaultHandler;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class CweHandler extends DefaultHandler {
/**

View File

@@ -18,15 +18,18 @@
package org.owasp.dependencycheck.data.lucene;
import java.util.LinkedList;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
/**
* An abstract tokenizing filter that can be used as the base for a tokenizing filter.
* An abstract tokenizing filter that can be used as the base for a tokenizing
* filter.
*
* @author Jeremy Long
*/
@NotThreadSafe
public abstract class AbstractTokenizingFilter extends TokenFilter {
/**

View File

@@ -18,14 +18,17 @@
package org.owasp.dependencycheck.data.lucene;
import java.io.Reader;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.util.CharTokenizer;
import org.apache.lucene.util.Version;
/**
* Tokenizes the input breaking it into tokens when non-alpha/numeric characters are found.
* Tokenizes the input breaking it into tokens when non-alpha/numeric characters
* are found.
*
* @author Jeremy Long
*/
@NotThreadSafe
public class AlphaNumericTokenizer extends CharTokenizer {
/**

View File

@@ -17,12 +17,14 @@
*/
package org.owasp.dependencycheck.data.lucene;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.search.similarities.DefaultSimilarity;
/**
*
* @author Jeremy Long
*/
@NotThreadSafe
public class DependencySimilarity extends DefaultSimilarity {
/**

View File

@@ -18,19 +18,22 @@
package org.owasp.dependencycheck.data.lucene;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.lucene.util.Version;
/**
* <p>
* Lucene utils is a set of utilize written to make constructing Lucene queries simpler.</p>
* Lucene utils is a set of utilize written to make constructing Lucene queries
* simpler.</p>
*
* @author Jeremy Long
*/
@ThreadSafe
public final class LuceneUtils {
/**
* The current version of Lucene being used. Declaring this one place so an upgrade doesn't require hunting through the code
* base.
* The current version of Lucene being used. Declaring this one place so an
* upgrade doesn't require hunting through the code base.
*/
public static final Version CURRENT_VERSION = Version.LUCENE_47;
@@ -41,7 +44,8 @@ public final class LuceneUtils {
}
/**
* Appends the text to the supplied StringBuilder escaping Lucene control characters in the process.
* Appends the text to the supplied StringBuilder escaping Lucene control
* characters in the process.
*
* @param buf a StringBuilder to append the escaped text to
* @param text the data to be escaped
@@ -88,7 +92,8 @@ public final class LuceneUtils {
}
/**
* Escapes the text passed in so that it is treated as data instead of control characters.
* Escapes the text passed in so that it is treated as data instead of
* control characters.
*
* @param text data to be escaped
* @return the escaped text.

View File

@@ -18,8 +18,6 @@
package org.owasp.dependencycheck.data.lucene;
import java.io.Reader;
import java.util.Arrays;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
@@ -44,8 +42,8 @@ public class SearchFieldAnalyzer extends Analyzer {
/**
* The list of additional stop words to use.
*/
private static final List<String> ADDITIONAL_STOP_WORDS = Arrays.asList("software", "framework", "inc",
"com", "org", "net", "www", "consulting", "ltd", "foundation", "project");
private static final String[] ADDITIONAL_STOP_WORDS = {"software", "framework", "inc",
"com", "org", "net", "www", "consulting", "ltd", "foundation", "project"};
/**
* The set of stop words to use in the analyzer.
*/
@@ -57,8 +55,8 @@ public class SearchFieldAnalyzer extends Analyzer {
* @return the set of stop words being used
*/
public static CharArraySet getStopWords() {
CharArraySet words = new CharArraySet(LuceneUtils.CURRENT_VERSION, StopAnalyzer.ENGLISH_STOP_WORDS_SET, true);
words.addAll(ADDITIONAL_STOP_WORDS);
final CharArraySet words = StopFilter.makeStopSet(LuceneUtils.CURRENT_VERSION, ADDITIONAL_STOP_WORDS, true);
words.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);
return words;
}

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.data.lucene;
import java.io.IOException;
import java.util.LinkedList;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
@@ -33,6 +34,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
*
* @author Jeremy Long
*/
@NotThreadSafe
public final class TokenPairConcatenatingFilter extends TokenFilter {
/**

View File

@@ -21,6 +21,7 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.util.LinkedList;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.owasp.dependencycheck.utils.UrlStringUtils;
@@ -28,13 +29,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>
* Takes a TokenStream and splits or adds tokens to correctly index version numbers.</p>
* <p>
* <b>Example:</b> "3.0.0.RELEASE" -&gt; "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
*
* Takes a TokenStream, looks for URLs, and breaks them into separate tokens.
*
* @author Jeremy Long
*/
@NotThreadSafe
public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
/**
@@ -52,8 +52,9 @@ public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
}
/**
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by concatenating
* tokens with the previous token.
* Increments the underlying TokenStream and sets CharTermAttributes to
* construct an expanded set of tokens by concatenating tokens with the
* previous token.
*
* @return whether or not we have hit the end of the TokenStream
* @throws IOException is thrown when an IOException occurs

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.data.nexus;
import javax.annotation.concurrent.ThreadSafe;
/**
* Simple bean representing a Maven Artifact.
*
* @author colezlaw
*/
@ThreadSafe
public class MavenArtifact {
/**
@@ -45,7 +48,8 @@ public class MavenArtifact {
private String version;
/**
* The artifact url. This may change depending on which Nexus server the search took place.
* The artifact url. This may change depending on which Nexus server the
* search took place.
*/
private String artifactUrl;
/**
@@ -80,7 +84,8 @@ public class MavenArtifact {
* @param version the version
* @param jarAvailable if the jar file is available from central
* @param pomAvailable if the pom file is available from central
* @param secureDownload if the jar and pom files should be downloaded using HTTPS.
* @param secureDownload if the jar and pom files should be downloaded using
* HTTPS.
*/
public MavenArtifact(String groupId, String artifactId, String version, boolean jarAvailable, boolean pomAvailable, boolean secureDownload) {
this.groupId = groupId;
@@ -220,5 +225,3 @@ public class MavenArtifact {
}
}
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -22,6 +22,7 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
@@ -41,6 +42,7 @@ import org.xml.sax.SAXException;
*
* @author colezlaw
*/
@ThreadSafe
public class NexusSearch {
/**
@@ -66,16 +68,17 @@ public class NexusSearch {
*
* @param settings the configured settings
* @param useProxy flag indicating if the proxy settings should be used
* @throws java.net.MalformedURLException thrown if the configured URL is invalid
* @throws java.net.MalformedURLException thrown if the configured URL is
* invalid
*/
public NexusSearch(Settings settings, boolean useProxy) throws MalformedURLException {
this.settings = settings;
this.useProxy = useProxy;
final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
LOGGER.debug("Nexus Search URL: {}", searchUrl);
this.rootURL = new URL(searchUrl);
}
/**
@@ -103,7 +106,7 @@ public class NexusSearch {
// 2) Otherwise, don't use the proxy (either the proxy isn't configured,
// or proxy is specifically set to false
HttpURLConnection conn;
URLConnectionFactory factory = new URLConnectionFactory(settings);
final URLConnectionFactory factory = new URLConnectionFactory(settings);
conn = factory.createHttpURLConnection(url, useProxy);
conn.setDoOutput(true);
@@ -169,7 +172,7 @@ public class NexusSearch {
HttpURLConnection conn;
try {
final URL url = new URL(rootURL, "status");
URLConnectionFactory factory = new URLConnectionFactory(settings);
final URLConnectionFactory factory = new URLConnectionFactory(settings);
conn = factory.createHttpURLConnection(url, useProxy);
conn.addRequestProperty("Accept", "application/xml");
conn.connect();
@@ -187,9 +190,6 @@ public class NexusSearch {
} catch (IOException | ParserConfigurationException | SAXException e) {
return false;
}
return true;
}
}
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.data.nsp;
import java.util.Arrays;
import javax.annotation.concurrent.ThreadSafe;
/**
* The response from NSP check API will respond with 0 or more advisories. This
@@ -25,6 +26,7 @@ import java.util.Arrays;
*
* @author Steve Springett
*/
@ThreadSafe
public class Advisory {
/**

View File

@@ -28,6 +28,7 @@ import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.URLConnectionFactory;
@@ -45,6 +46,7 @@ import org.owasp.dependencycheck.utils.URLConnectionFailureException;
*
* @author Steve Springett
*/
@ThreadSafe
public class NspSearch {
/**

View File

@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
/**
* Class used to create a Sanitized version of package.json suitable for
@@ -32,6 +33,7 @@ import java.util.Map;
*
* @author Steve Springett
*/
@ThreadSafe
public final class SanitizePackage {
/**

View File

@@ -17,12 +17,16 @@
*/
package org.owasp.dependencycheck.data.nuget;
import javax.annotation.concurrent.ThreadSafe;
/**
* Represents the contents of a Nuspec manifest.
*
* @author colezlaw
*/
@ThreadSafe
public class NugetPackage {
/**
* The id.
*/
@@ -55,6 +59,7 @@ public class NugetPackage {
/**
* Sets the id.
*
* @param id the id
*/
public void setId(String id) {
@@ -63,6 +68,7 @@ public class NugetPackage {
/**
* Gets the id.
*
* @return the id
*/
public String getId() {
@@ -71,6 +77,7 @@ public class NugetPackage {
/**
* Sets the version.
*
* @param version the version
*/
public void setVersion(String version) {
@@ -79,6 +86,7 @@ public class NugetPackage {
/**
* Gets the version.
*
* @return the version
*/
public String getVersion() {
@@ -87,6 +95,7 @@ public class NugetPackage {
/**
* Sets the title.
*
* @param title the title
*/
public void setTitle(String title) {
@@ -95,6 +104,7 @@ public class NugetPackage {
/**
* Gets the title.
*
* @return the title
*/
public String getTitle() {
@@ -103,6 +113,7 @@ public class NugetPackage {
/**
* Sets the authors.
*
* @param authors the authors
*/
public void setAuthors(String authors) {
@@ -111,6 +122,7 @@ public class NugetPackage {
/**
* Gets the authors.
*
* @return the authors
*/
public String getAuthors() {
@@ -119,6 +131,7 @@ public class NugetPackage {
/**
* Sets the owners.
*
* @param owners the owners
*/
public void setOwners(String owners) {
@@ -127,6 +140,7 @@ public class NugetPackage {
/**
* Gets the owners.
*
* @return the owners
*/
public String getOwners() {
@@ -135,6 +149,7 @@ public class NugetPackage {
/**
* Sets the licenseUrl.
*
* @param licenseUrl the licenseUrl
*/
public void setLicenseUrl(String licenseUrl) {
@@ -143,6 +158,7 @@ public class NugetPackage {
/**
* Gets the licenseUrl.
*
* @return the licenseUrl
*/
public String getLicenseUrl() {

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.data.nuget;
import javax.annotation.concurrent.ThreadSafe;
/**
* Exception during the parsing of a Nuspec file.
*
* @author colezlaw
*/
@ThreadSafe
public class NuspecParseException extends Exception {
/**
@@ -32,19 +35,20 @@ public class NuspecParseException extends Exception {
/**
* Constructs a new exception with <code>null</code> as its detail message.
*
* The cause is not initialized, and may subsequently be initialized by a call to
* {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
*/
public NuspecParseException() {
super();
}
/**
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
* be initialized by a call to {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
* Constructs a new exception with the specified detail message. The cause
* is not initialized, and may subsequently be initialized by a call to
* {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
*
* @param message the detail message. The detail message is saved for later retrieval by the
* {@link java.lang.Throwable#getMessage()} method.
* @param message the detail message. The detail message is saved for later
* retrieval by the {@link java.lang.Throwable#getMessage()} method.
*/
public NuspecParseException(String message) {
super(message);
@@ -53,13 +57,16 @@ public class NuspecParseException extends Exception {
/**
* Constructs a new exception with the specified detail message and cause.
*
* Note that the detail message associated with <code>cause</code> is <em>not</em>
* Note that the detail message associated with <code>cause</code> is
* <em>not</em>
* automatically incorporated in this exception's detail message.
*
* @param message the detail message (which is saved for later retrieval by the
* {@link java.lang.Throwable#getMessage()} method.
* @param cause the cause (which is saved for later retrieval by the {@link java.lang.Throwable#getCause()} method).
* (A <code>null</code> value is permitted, and indicates that the cause is nonexistent or unknown).
* @param message the detail message (which is saved for later retrieval by
* the {@link java.lang.Throwable#getMessage()} method.
* @param cause the cause (which is saved for later retrieval by the
* {@link java.lang.Throwable#getCause()} method). (A <code>null</code>
* value is permitted, and indicates that the cause is nonexistent or
* unknown).
*/
public NuspecParseException(String message, Throwable cause) {
super(message, cause);

View File

@@ -26,6 +26,7 @@ import java.io.InputStream;
*
*/
public interface NuspecParser {
/**
* Parse an input stream and return the resulting {@link NugetPackage}.
*

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.data.nuget;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
@@ -35,6 +36,7 @@ import org.xml.sax.SAXException;
*
* @author colezlaw
*/
@ThreadSafe
public class XPathNuspecParser implements NuspecParser {
/**

View File

@@ -27,6 +27,7 @@ import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.IOUtils;
import org.owasp.dependencycheck.utils.DBUtils;
import org.owasp.dependencycheck.utils.DependencyVersion;
@@ -44,6 +45,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public final class ConnectionFactory {
/**
@@ -245,6 +247,7 @@ public final class ConnectionFactory {
public boolean h2DataFileExists() throws IOException {
return h2DataFileExists(settings);
}
/**
* Determines if the H2 database file exists. If it does not exist then the
* data structure will need to be created.

View File

@@ -17,11 +17,15 @@
*/
package org.owasp.dependencycheck.data.nvdcve;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception used to indicate the db4o database is corrupt. This could be due to invalid data or a complete failure of the db.
* An exception used to indicate the db4o database is corrupt. This could be due
* to invalid data or a complete failure of the db.
*
* @author Jeremy Long
*/
@ThreadSafe
public class CorruptDatabaseException extends DatabaseException {
/**

View File

@@ -17,7 +17,6 @@
*/
package org.owasp.dependencycheck.data.nvdcve;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
@@ -354,6 +353,7 @@ public final class CveDB implements AutoCloseable {
*
* @throws SQLException thrown if a SQL Exception occurs
*/
@SuppressWarnings("EmptyMethod")
public synchronized void commit() throws SQLException {
//temporary remove this as autocommit is on.
//if (isOpen()) {
@@ -514,7 +514,7 @@ public final class CveDB implements AutoCloseable {
*
* It should be also called when DB is closed.
*/
private void clearCache() {
private synchronized void clearCache() {
vulnerabilitiesForCpeCache.clear();
}

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.data.nvdcve;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception thrown if an operation against the database fails.
*
* @author Jeremy Long
*/
@ThreadSafe
public class DatabaseException extends RuntimeException {
/**

View File

@@ -97,7 +97,7 @@ public class DatabaseProperties {
*
* @return whether or not any properties are set
*/
public boolean isEmpty() {
public synchronized boolean isEmpty() {
return properties == null || properties.isEmpty();
}
@@ -107,7 +107,7 @@ public class DatabaseProperties {
* @param updatedValue the updated NVD CVE entry
* @throws UpdateException is thrown if there is an update exception
*/
public void save(NvdCveInfo updatedValue) throws UpdateException {
public synchronized void save(NvdCveInfo updatedValue) throws UpdateException {
if (updatedValue == null) {
return;
}
@@ -121,7 +121,7 @@ public class DatabaseProperties {
* @param value the property value
* @throws UpdateException is thrown if there is an update exception
*/
public void save(String key, String value) throws UpdateException {
public synchronized void save(String key, String value) throws UpdateException {
properties.put(key, value);
cveDB.saveProperty(key, value);
}
@@ -133,7 +133,7 @@ public class DatabaseProperties {
* @param key the property key
* @return the value of the property
*/
public String getProperty(String key) {
public synchronized String getProperty(String key) {
return properties.getProperty(key);
}
@@ -145,7 +145,7 @@ public class DatabaseProperties {
* @param defaultValue the default value
* @return the value of the property
*/
public String getProperty(String key, String defaultValue) {
public synchronized String getProperty(String key, String defaultValue) {
return properties.getProperty(key, defaultValue);
}
@@ -154,7 +154,7 @@ public class DatabaseProperties {
*
* @return the collection of Database Properties
*/
public Properties getProperties() {
public synchronized Properties getProperties() {
return properties;
}
@@ -165,7 +165,7 @@ public class DatabaseProperties {
*
* @return a map of the database meta data
*/
public Map<String, String> getMetaData() {
public synchronized Map<String, String> getMetaData() {
final Map<String, String> map = new TreeMap<>();
for (Entry<Object, Object> entry : properties.entrySet()) {
final String key = (String) entry.getKey();

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.data.nvdcve;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception thrown the database driver is unable to be loaded.
*
* @author Jeremy Long
*/
@ThreadSafe
public class DriverLoadException extends Exception {
/**

View File

@@ -31,12 +31,14 @@ import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
/**
* DriverLoader is a utility class that is used to load database drivers.
*
* @author Jeremy Long
*/
@ThreadSafe
public final class DriverLoader {
/**
@@ -148,8 +150,6 @@ public final class DriverLoader {
final Driver driver = (Driver) c.newInstance();
//TODO add usage count so we don't de-register a driver that is in use.
final Driver shim = new DriverShim(driver);
//using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
DriverManager.registerDriver(shim);

View File

@@ -28,16 +28,19 @@ import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import javax.annotation.concurrent.ThreadSafe;
/**
* <p>
* Driver shim to get around the class loader issue with the DriverManager. The following code is a nearly identical
* copy (with more comments and a few more methods implemented) of the DriverShim from:</p>
* Driver shim to get around the class loader issue with the DriverManager. The
* following code is a nearly identical copy (with more comments and a few more
* methods implemented) of the DriverShim from:</p>
* <blockquote>http://www.kfu.com/~nsayer/Java/dyn-jdbc.html</blockquote>
*
* @author Jeremy Long
* @see java.sql.Driver
*/
@ThreadSafe
class DriverShim implements Driver {
/**
@@ -59,12 +62,13 @@ class DriverShim implements Driver {
}
/**
* Wraps the underlying driver's call to acceptsURL. Returns whether or not the driver can open a connection to the
* given URL.
* Wraps the underlying driver's call to acceptsURL. Returns whether or not
* the driver can open a connection to the given URL.
*
* @param url the URL of the database
* @return true if the wrapped driver can connect to the specified URL
* @throws SQLException thrown if there is an error connecting to the database
* @throws SQLException thrown if there is an error connecting to the
* database
* @see java.sql.Driver#acceptsURL(java.lang.String)
*/
@Override
@@ -78,7 +82,8 @@ class DriverShim implements Driver {
* @param url the URL of the database
* @param info a collection of string/value pairs
* @return a Connection object
* @throws SQLException thrown if there is an error connecting to the database
* @throws SQLException thrown if there is an error connecting to the
* database
* @see java.sql.Driver#connect(java.lang.String, java.util.Properties)
*/
@Override
@@ -112,7 +117,8 @@ class DriverShim implements Driver {
* Wraps the call to the underlying driver's getParentLogger method.
*
* @return the parent's Logger
* @throws SQLFeatureNotSupportedException thrown if the feature is not supported
* @throws SQLFeatureNotSupportedException thrown if the feature is not
* supported
* @see java.sql.Driver#getParentLogger()
*/
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
@@ -140,7 +146,8 @@ class DriverShim implements Driver {
* @param info a collection of string/value pairs
* @return an array of DriverPropertyInfo objects
* @throws SQLException thrown if there is an error accessing the database
* @see java.sql.Driver#getPropertyInfo(java.lang.String, java.util.Properties)
* @see java.sql.Driver#getPropertyInfo(java.lang.String,
* java.util.Properties)
*/
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {

View File

@@ -21,6 +21,7 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.IOUtils;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -44,6 +45,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public class EngineVersionCheck implements CachedWebDataSource {
/**
@@ -115,7 +117,7 @@ public class EngineVersionCheck implements CachedWebDataSource {
public void update(Engine engine) throws UpdateException {
this.settings = engine.getSettings();
try {
CveDB db = engine.getDatabase();
final CveDB db = engine.getDatabase();
final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
final boolean enabled = settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true);
final String original = settings.getString(Settings.KEYS.CVE_ORIGINAL_MODIFIED_20_URL);
@@ -208,7 +210,7 @@ public class EngineVersionCheck implements CachedWebDataSource {
try {
final String str = settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt");
final URL url = new URL(str);
URLConnectionFactory factory = new URLConnectionFactory(settings);
final URLConnectionFactory factory = new URLConnectionFactory(settings);
conn = factory.createHttpURLConnection(url);
conn.connect();
if (conn.getResponseCode() != 200) {

View File

@@ -17,9 +17,6 @@
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.util.Calendar;
import java.util.HashMap;
@@ -27,8 +24,6 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.net.URL;
import java.nio.channels.FileLock;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -36,6 +31,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -63,6 +59,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public class NvdCveUpdater implements CachedWebDataSource {
/**
@@ -116,9 +113,12 @@ public class NvdCveUpdater implements CachedWebDataSource {
if (isUpdateConfiguredFalse()) {
return;
}
H2DBLock dbupdate = new H2DBLock(settings, ConnectionFactory.isH2Connection(settings));
H2DBLock dbupdate = null;
try {
dbupdate.lock();
if (ConnectionFactory.isH2Connection(settings)) {
dbupdate = new H2DBLock(settings);
dbupdate.lock();
}
initializeExecutorServices();
dbProperties = cveDb.getDatabaseProperties();
@@ -142,7 +142,9 @@ public class NvdCveUpdater implements CachedWebDataSource {
} catch (H2DBLockException ex) {
throw new UpdateException("Unable to obtain an exclusive lock on the H2 database to perform updates", ex);
} finally {
dbupdate.release();
if (dbupdate != null) {
dbupdate.release();
}
shutdownExecutorServices();
}
}
@@ -480,7 +482,7 @@ public class NvdCveUpdater implements CachedWebDataSource {
*
* @param settings the configured settings
*/
protected void setSettings(Settings settings) {
protected synchronized void setSettings(Settings settings) {
this.settings = settings;
}
@@ -513,7 +515,7 @@ public class NvdCveUpdater implements CachedWebDataSource {
public Long call() throws Exception {
LOGGER.debug("Checking for updates from: {}", url);
try {
Downloader downloader = new Downloader(settings);
final Downloader downloader = new Downloader(settings);
return downloader.getLastModified(new URL(url));
} finally {
settings.cleanup(false);

View File

@@ -19,13 +19,15 @@ package org.owasp.dependencycheck.data.update;
import java.util.Iterator;
import java.util.ServiceLoader;
import javax.annotation.concurrent.NotThreadSafe;
/**
* The CachedWebDataSource Service Loader. This class loads all services that implement
* org.owasp.dependencycheck.data.update.CachedWebDataSource.
* The CachedWebDataSource Service Loader. This class loads all services that
* implement {@link org.owasp.dependencycheck.data.update.CachedWebDataSource}.
*
* @author Jeremy Long
*/
@NotThreadSafe
public class UpdateService {
/**
@@ -36,14 +38,16 @@ public class UpdateService {
/**
* Creates a new instance of UpdateService.
*
* @param classLoader the ClassLoader to use when dynamically loading Analyzer and Update services
* @param classLoader the ClassLoader to use when dynamically loading
* Analyzer and Update services
*/
public UpdateService(ClassLoader classLoader) {
loader = ServiceLoader.load(CachedWebDataSource.class, classLoader);
}
/**
* Returns an Iterator for all instances of the CachedWebDataSource interface.
* Returns an Iterator for all instances of the CachedWebDataSource
* interface.
*
* @return an iterator of CachedWebDataSource.
*/

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.update.cpe;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.owasp.dependencycheck.data.update.NvdCveUpdater;
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
import org.owasp.dependencycheck.utils.Settings;
@@ -34,6 +35,7 @@ import org.xml.sax.helpers.DefaultHandler;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class CPEHandler extends DefaultHandler {
/**
@@ -62,6 +64,11 @@ public class CPEHandler extends DefaultHandler {
*/
private final List<Cpe> data = new ArrayList<>();
/**
* Constructs a new CPE Handler object with the configured settings.
*
* @param settings the configured settings
*/
public CPEHandler(Settings settings) {
cpeStartsWith = settings.getString(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER, "cpe:/a:");
}

View File

@@ -20,14 +20,30 @@ package org.owasp.dependencycheck.data.update.cpe;
import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
/**
*
* @author Jeremy Long
*/
@ThreadSafe
public class Cpe {
/**
* The CPE identifier string (cpe:/a:vendor:product:version).
*/
private String value;
/**
* The vendor portion of the identifier.
*/
private String vendor;
/**
* The product portion of the identifier.
*/
private String product;
/**
* Constructs a new Cpe Object by parsing the vendor and product from the CPE identifier value.
*
@@ -47,11 +63,6 @@ public class Cpe {
}
}
/**
* The CPE identifier string (cpe:/a:vendor:product:version).
*/
private String value;
/**
* Get the value of value.
*
@@ -69,10 +80,6 @@ public class Cpe {
public void setValue(String value) {
this.value = value;
}
/**
* The vendor portion of the identifier.
*/
private String vendor;
/**
* Get the value of vendor.
@@ -92,11 +99,6 @@ public class Cpe {
this.vendor = vendor;
}
/**
* The product portion of the identifier.
*/
private String product;
/**
* Get the value of product.
*

View File

@@ -17,11 +17,15 @@
*/
package org.owasp.dependencycheck.data.update.exception;
import javax.annotation.concurrent.ThreadSafe;
/**
* An InvalidDataDataException is a generic exception used when trying to load the NVD CVE meta data.
* An InvalidDataDataException is a generic exception used when trying to load
* the NVD CVE meta data.
*
* @author Jeremy Long
*/
@ThreadSafe
public class InvalidDataException extends Exception {
/**

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.data.update.exception;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception used when an error occurs reading a setting.
*
* @author Jeremy Long
*/
@ThreadSafe
public class UpdateException extends Exception {
/**

View File

@@ -25,6 +25,7 @@ import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
@@ -39,6 +40,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@ThreadSafe
public class DownloadTask implements Callable<Future<ProcessTask>> {
/**
@@ -128,15 +130,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
return first;
}
/**
* Set the value of first.
*
* @param first new value of first
*/
public void setFirst(File first) {
this.first = first;
}
/**
* Get the value of second.
*
@@ -146,15 +139,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
return second;
}
/**
* Set the value of second.
*
* @param second new value of second
*/
public void setSecond(File second) {
this.second = second;
}
@Override
public Future<ProcessTask> call() throws Exception {
try {
@@ -163,7 +147,7 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
LOGGER.info("Download Started for NVD CVE - {}", nvdCveInfo.getId());
final long startDownload = System.currentTimeMillis();
try {
Downloader downloader = new Downloader(settings);
final Downloader downloader = new Downloader(settings);
downloader.fetchFile(url1, first);
downloader.fetchFile(url2, second);
} catch (DownloadFailedException ex) {

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.NotThreadSafe;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -34,6 +35,7 @@ import org.xml.sax.helpers.DefaultHandler;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class NvdCve12Handler extends DefaultHandler {
/**

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.update.nvd;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.index.CorruptIndexException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
@@ -40,6 +41,7 @@ import static org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler.Attribut
*
* @author Jeremy Long
*/
@NotThreadSafe
public class NvdCve20Handler extends DefaultHandler {
/**
@@ -184,9 +186,7 @@ public class NvdCve20Handler extends DefaultHandler {
totalNumberOfApplicationEntries += 1;
try {
saveEntry(vulnerability);
} catch (DatabaseException | CorruptIndexException ex) {
throw new SAXException(ex);
} catch (IOException ex) {
} catch (DatabaseException | IOException ex) {
throw new SAXException(ex);
}
}

View File

@@ -17,17 +17,36 @@
*/
package org.owasp.dependencycheck.data.update.nvd;
import javax.annotation.concurrent.ThreadSafe;
/**
* A pojo that contains the Url and timestamp of the current NvdCve XML files.
*
* @author Jeremy Long
*/
@ThreadSafe
public class NvdCveInfo {
/**
* an id.
*/
private String id;
/**
* a url.
*/
private String url;
/**
* The 1.2 schema URL.
*/
private String oldSchemaVersionUrl;
/**
* a timestamp - epoch time.
*/
private long timestamp;
/**
* indicates whether or not this item should be updated.
*/
private boolean needsUpdate = true;
/**
* Get the value of id.
@@ -46,10 +65,6 @@ public class NvdCveInfo {
public void setId(String id) {
this.id = id;
}
/**
* a url.
*/
private String url;
/**
* Get the value of url.
@@ -68,10 +83,6 @@ public class NvdCveInfo {
public void setUrl(String url) {
this.url = url;
}
/**
* The 1.2 schema URL.
*/
private String oldSchemaVersionUrl;
/**
* Get the value of oldSchemaVersionUrl.
@@ -90,10 +101,6 @@ public class NvdCveInfo {
public void setOldSchemaVersionUrl(String oldSchemaVersionUrl) {
this.oldSchemaVersionUrl = oldSchemaVersionUrl;
}
/**
* a timestamp - epoch time.
*/
private long timestamp;
/**
* Get the value of timestamp - epoch time.
@@ -112,10 +119,6 @@ public class NvdCveInfo {
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* indicates whether or not this item should be updated.
*/
private boolean needsUpdate = true;
/**
* Get the value of needsUpdate.

View File

@@ -23,6 +23,7 @@ import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -42,6 +43,7 @@ import org.xml.sax.SAXException;
*
* @author Jeremy Long
*/
@ThreadSafe
public class ProcessTask implements Callable<ProcessTask> {
/**

View File

@@ -21,13 +21,15 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Contains a collection of updateable NvdCveInfo objects. This is used to determine which files need to be downloaded and
* processed.
* Contains a collection of updateable NvdCveInfo objects. This is used to
* determine which files need to be downloaded and processed.
*
* @author Jeremy Long
*/
@NotThreadSafe
public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
/**
@@ -36,7 +38,13 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
private final Map<String, NvdCveInfo> collection = new TreeMap<>();
/**
* Returns the collection of NvdCveInfo objects. This method is mainly used for testing.
* An internal iterator used to implement iterable.
*/
private Iterator<Entry<String, NvdCveInfo>> iterableContent = null;
/**
* Returns the collection of NvdCveInfo objects. This method is mainly used
* for testing.
*
* @return the collection of NvdCveInfo objects
*/
@@ -63,7 +71,8 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
*
* @param id the key for the item to be added
* @param url the URL to download the item
* @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need).
* @param oldUrl the URL for the old version of the item (the NVD CVE old
* schema still contains useful data we need).
* @param timestamp the last modified date of the downloaded item
* @param needsUpdate whether or not the data needs to be updated
*/
@@ -93,10 +102,6 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
public long getTimeStamp(String key) {
return collection.get(key).getTimestamp();
}
/**
* An internal iterator used to implement iterable.
*/
private Iterator<Entry<String, NvdCveInfo>> iterableContent = null;
/**
* <p>
@@ -118,7 +123,8 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
* <p>
* <b>This method is not thread safe.</b></p>
*
* @return true or false depending on whether or not another item exists in the collection
* @return true or false depending on whether or not another item exists in
* the collection
*/
@Override
public boolean hasNext() {

View File

@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -43,6 +44,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class Dependency implements Serializable, Comparable<Dependency> {
/**

View File

@@ -22,12 +22,14 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.io.Serializable;
import javax.annotation.concurrent.ThreadSafe;
/**
* Evidence is a piece of information about a Dependency.
*
* @author Jeremy Long
*/
@ThreadSafe
public class Evidence implements Serializable, Comparable<Evidence> {
/**
@@ -44,6 +46,31 @@ public class Evidence implements Serializable, Comparable<Evidence> {
*/
private static final int MAGIC_HASH_MULTIPLIER = 67;
/**
* The name of the evidence.
*/
private String name;
/**
* The source of the evidence.
*/
private String source;
/**
* The value of the evidence.
*/
private String value;
/**
* A value indicating if the Evidence has been "used" (aka read).
*/
private boolean used;
/**
* The confidence level for the evidence.
*/
private Confidence confidence;
/**
* Creates a new Evidence object.
*/
@@ -65,11 +92,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.confidence = confidence;
}
/**
* The name of the evidence.
*/
private String name;
/**
* Get the value of name.
*
@@ -88,11 +110,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.name = name;
}
/**
* The source of the evidence.
*/
private String source;
/**
* Get the value of source.
*
@@ -111,11 +128,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.source = source;
}
/**
* The value of the evidence.
*/
private String value;
/**
* Get the value of value.
*
@@ -148,11 +160,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.value = value;
}
/**
* A value indicating if the Evidence has been "used" (aka read).
*/
private boolean used;
/**
* Get the value of used.
*
@@ -171,11 +178,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.used = used;
}
/**
* The confidence level for the evidence.
*/
private Confidence confidence;
/**
* Get the value of confidence.
*

View File

@@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.commons.lang3.StringUtils;
import org.owasp.dependencycheck.utils.DependencyVersion;
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
@@ -37,6 +38,7 @@ import org.slf4j.LoggerFactory;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class EvidenceCollection implements Serializable, Iterable<Evidence> {
/**

View File

@@ -18,12 +18,14 @@
package org.owasp.dependencycheck.dependency;
import java.io.Serializable;
import javax.annotation.concurrent.ThreadSafe;
/**
* In identifier such as a CPE or dependency coordinates (i.e. GAV).
*
* @author Jeremy Long
*/
@ThreadSafe
public class Identifier implements Serializable, Comparable<Identifier> {
//<editor-fold defaultstate="collapsed" desc="fields">

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.dependency;
import java.io.Serializable;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.builder.CompareToBuilder;
/**
@@ -26,6 +27,7 @@ import org.apache.commons.lang3.builder.CompareToBuilder;
*
* @author Jeremy Long
*/
@ThreadSafe
public class Reference implements Serializable, Comparable<Reference> {
/**

View File

@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.commons.lang3.builder.CompareToBuilder;
/**
@@ -30,6 +31,7 @@ import org.apache.commons.lang3.builder.CompareToBuilder;
*
* @author Jeremy Long
*/
@NotThreadSafe
public class Vulnerability implements Serializable, Comparable<Vulnerability> {
/**

View File

@@ -19,12 +19,14 @@ package org.owasp.dependencycheck.dependency;
import java.io.Serializable;
import java.util.Comparator;
import javax.annotation.concurrent.ThreadSafe;
/**
* Comparator for Vulnerability objects.
*
* @author Jeremy Long
*/
@ThreadSafe
public class VulnerabilityComparator implements Comparator<Vulnerability>, Serializable {
/**

View File

@@ -20,16 +20,19 @@ package org.owasp.dependencycheck.dependency;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.StringUtils;
import org.owasp.dependencycheck.data.cpe.IndexEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A record containing information about vulnerable software. This is referenced from a vulnerability.
* A record containing information about vulnerable software. This is referenced
* from a vulnerability.
*
* @author Jeremy Long
*/
@ThreadSafe
public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> {
/**
@@ -41,6 +44,26 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
*/
private static final long serialVersionUID = 307319490326651052L;
/**
* If present, indicates that previous version are vulnerable.
*/
private String previousVersion;
/**
* The name of the cpe.
*/
private String name;
/**
* The product version number.
*/
private String version;
/**
* The product update version.
*/
private String update;
/**
* Parse a CPE entry from the cpe string representation.
*
@@ -58,7 +81,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
/**
* <p>
* Parses a name attribute value, from the cpe.xml, into its corresponding parts: vendor, product, version, update.</p>
* Parses a name attribute value, from the cpe.xml, into its corresponding
* parts: vendor, product, version, update.</p>
* <p>
* Example:</p>
* <code>&nbsp;&nbsp;&nbsp;cpe:/a:apache:struts:1.1:rc2</code>
@@ -93,10 +117,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
}
}
/**
* If present, indicates that previous version are vulnerable.
*/
private String previousVersion;
/**
* Indicates if previous versions of this software are vulnerable.
@@ -126,7 +146,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
/**
* Standard equals implementation to compare this VulnerableSoftware to another object.
* Standard equals implementation to compare this VulnerableSoftware to
* another object.
*
* @param obj the object to compare
* @return whether or not the objects are equal
@@ -156,7 +177,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
/**
* Standard toString() implementation display the name and whether or not previous versions are also affected.
* Standard toString() implementation display the name and whether or not
* previous versions are also affected.
*
* @return a string representation of the object
*/
@@ -224,10 +246,9 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
/**
* Determines if the string passed in is a positive integer.
* To be counted as a positive integer, the string must only contain 0-9
* and must not have any leading zeros (though "0" is a valid positive
* integer).
* Determines if the string passed in is a positive integer. To be counted
* as a positive integer, the string must only contain 0-9 and must not have
* any leading zeros (though "0" is a valid positive integer).
*
* @param str the string to test
* @return true if the string only contains 0-9, otherwise false.
@@ -251,10 +272,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
return true;
}
/**
* The name of the cpe.
*/
private String name;
/**
* Get the value of name.
@@ -273,10 +290,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
public void setName(String name) {
this.name = name;
}
/**
* The product version number.
*/
private String version;
/**
* Get the value of version.
@@ -295,10 +308,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
public void setVersion(String version) {
this.version = version;
}
/**
* The product update version.
*/
private String update;
/**
* Get the value of update.
@@ -341,7 +350,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
/**
* Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default.
* Replaces '+' with '%2B' and then URL Decodes the string attempting first
* UTF-8, then ASCII, then default.
*
* @param string the string to URL Decode
* @return the URL Decoded string
@@ -362,7 +372,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
/**
* Call {@link java.net.URLDecoder#decode(String)} to URL decode using the default encoding.
* Call {@link java.net.URLDecoder#decode(String)} to URL decode using the
* default encoding.
*
* @param text www-form-encoded URL to decode
* @return the newly decoded String

View File

@@ -17,11 +17,14 @@
*/
package org.owasp.dependencycheck.exception;
import javax.annotation.concurrent.ThreadSafe;
/**
* An exception used when a dependency could not be found.
*
* @author Jeremy Long
*/
@ThreadSafe
public class DependencyNotFoundException extends Exception {
/**

View File

@@ -21,12 +21,14 @@ import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/**
* A collection of several exceptions.
*
* @author Jeremy Long
*/
@NotThreadSafe
public class ExceptionCollection extends Exception {
/**
* The serial version uid.

Some files were not shown because too many files have changed in this diff Show More