checkstyle/findbugs corrections

This commit is contained in:
Jeremy Long
2016-05-25 17:21:46 -04:00
parent c0384bb0ee
commit 6a807bc002
11 changed files with 368 additions and 258 deletions

View File

@@ -73,7 +73,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
public static String REQUESTED_API_VERSION = "1.7.12"; // final
//CSON: VisibilityModifier
//CSON: StaticVariableName
/**
* The logger factory class string.
*/

View File

@@ -35,11 +35,14 @@ 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>
* 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>
* Note, this grouping only works on dependencies with identified CVE
* entries</p>
*
* @author Jeremy Long
*/
@@ -92,12 +95,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
//</editor-fold>
/**
* 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.
* 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.
* @throws AnalysisException is thrown if there is an error reading the JAR
* file.
*/
@Override
public void analyze(Dependency ignore, Engine engine) throws AnalysisException {
@@ -138,11 +143,11 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
} else if ( isSameRubyGem(dependency, nextDependency) ) {
Dependency main = getMainGemspecDependency(dependency, nextDependency);
if (main == dependency) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
} else if (isSameRubyGem(dependency, nextDependency)) {
final Dependency main = getMainGemspecDependency(dependency, nextDependency);
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
}
@@ -160,10 +165,11 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
* Adds the relatedDependency to the dependency's related dependencies.
*
* @param dependency the main dependency
* @param relatedDependency a collection of dependencies to be removed from the main analysis loop, this is the source of
* dependencies to remove
* @param dependenciesToRemove a collection of dependencies that will be removed from the main analysis loop, this function
* adds to this collection
* @param relatedDependency a collection of dependencies to be removed from
* the main analysis loop, this is the source of dependencies to remove
* @param dependenciesToRemove a collection of dependencies that will be
* removed from the main analysis loop, this function adds to this
* collection
*/
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
dependency.addRelatedDependency(relatedDependency);
@@ -179,7 +185,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
/**
* Attempts to trim a maven repo to a common base path. This is typically [drive]\[repo_location]\repository\[path1]\[path2].
* Attempts to trim a maven repo to a common base path. This is typically
* [drive]\[repo_location]\repository\[path1]\[path2].
*
* @param path the path to trim
* @return a string representing the base path.
@@ -204,11 +211,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
/**
* Returns true if the file names (and version if it exists) of the two dependencies are sufficiently similar.
* Returns true if the file names (and version if it exists) of the two
* dependencies are sufficiently similar.
*
* @param dependency1 a dependency2 to compare
* @param dependency2 a dependency2 to compare
* @return true if the identifiers in the two supplied dependencies are equal
* @return true if the identifiers in the two supplied dependencies are
* equal
*/
private boolean fileNameMatch(Dependency dependency1, Dependency dependency2) {
if (dependency1 == null || dependency1.getFileName() == null
@@ -236,11 +245,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
/**
* Returns true if the CPE identifiers in the two supplied dependencies are equal.
* Returns true if the CPE identifiers in the two supplied dependencies are
* equal.
*
* @param dependency1 a dependency2 to compare
* @param dependency2 a dependency2 to compare
* @return true if the identifiers in the two supplied dependencies are equal
* @return true if the identifiers in the two supplied dependencies are
* equal
*/
private boolean cpeIdentifiersMatch(Dependency dependency1, Dependency dependency2) {
if (dependency1 == null || dependency1.getIdentifiers() == null
@@ -310,37 +321,53 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
return false;
}
/**
* Bundling Ruby gems that are identified from different .gemspec files but denote the same package path.
* This happens when Ruby bundler installs an app's dependencies by running "bundle install".
* Bundling Ruby gems that are identified from different .gemspec files but
* denote the same package path. This happens when Ruby bundler installs an
* application's dependencies by running "bundle install".
*
* @param dependency1 dependency to compare
* @param dependency2 dependency to compare
* @return true if the the dependencies being analyzed appear to be the
* same; otherwise false
*/
private boolean isSameRubyGem(Dependency dependency1, Dependency dependency2) {
if (dependency1 == null || dependency2 == null ||
!dependency1.getFileName().endsWith(".gemspec") ||
!dependency2.getFileName().endsWith(".gemspec") ||
dependency1.getPackagePath() == null ||
dependency2.getPackagePath() == null) {
if (dependency1 == null || dependency2 == null
|| !dependency1.getFileName().endsWith(".gemspec")
|| !dependency2.getFileName().endsWith(".gemspec")
|| dependency1.getPackagePath() == null
|| dependency2.getPackagePath() == null) {
return false;
}
if (dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath()))
return true;
if (dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath())) {
return true;
}
return false;
return false;
}
/**
* Ruby gems installed by "bundle install" can have zero or more *.gemspec files, all of which have the same packagePath and should be grouped.
* If one of these gemspec is from <parent>/specifications/*.gemspec, because it is a stub with fully resolved gem meta-data
* created by Ruby bundler, this dependency should be the main one. Otherwise, use dependency2 as main.
*
* This method returns null if any dependency is not from *.gemspec, or the two do not have the same packagePath.
* In this case, they should not be grouped.
* Ruby gems installed by "bundle install" can have zero or more *.gemspec
* files, all of which have the same packagePath and should be grouped. If
* one of these gemspec is from <parent>/specifications/*.gemspec, because
* it is a stub with fully resolved gem meta-data created by Ruby bundler,
* this dependency should be the main one. Otherwise, use dependency2 as
* main.
*
* This method returns null if any dependency is not from *.gemspec, or the
* two do not have the same packagePath. In this case, they should not be
* grouped.
*
* @param dependency1 dependency to compare
* @param dependency2 dependency to compare
* @return the main dependency; or null if a gemspec is not included in the
* analysis
*/
private Dependency getMainGemspecDependency(Dependency dependency1, Dependency dependency2) {
if (isSameRubyGem(dependency1, dependency2)) {
final File lFile = dependency1.getActualFile();
File left = lFile.getParentFile();
if (isSameRubyGem(dependency1, dependency2)) {
final File lFile = dependency1.getActualFile();
final File left = lFile.getParentFile();
if (left != null && left.getName().equalsIgnoreCase("specifications")) {
return dependency1;
}
@@ -350,12 +377,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
/**
* This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison to the
* 'right' library.
* This is likely a very broken attempt at determining if the 'left'
* dependency is the 'core' library in comparison to the 'right' library.
*
* @param left the dependency to test
* @param right the dependency to test against
* @return a boolean indicating whether or not the left dependency should be considered the "core" version.
* @return a boolean indicating whether or not the left dependency should be
* considered the "core" version.
*/
boolean isCore(Dependency left, Dependency right) {
final String leftName = left.getFileName().toLowerCase();
@@ -391,11 +419,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
/**
* Compares the SHA1 hashes of two dependencies to determine if they are equal.
* Compares the SHA1 hashes of two dependencies to determine if they are
* equal.
*
* @param dependency1 a dependency object to compare
* @param dependency2 a dependency object to compare
* @return true if the sha1 hashes of the two dependencies match; otherwise false
* @return true if the sha1 hashes of the two dependencies match; otherwise
* false
*/
private boolean hashesMatch(Dependency dependency1, Dependency dependency2) {
if (dependency1 == null || dependency2 == null || dependency1.getSha1sum() == null || dependency2.getSha1sum() == null) {
@@ -405,12 +435,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
/**
* Determines if the jar is shaded and the created pom.xml identified the same CPE as the jar - if so, the pom.xml dependency
* should be removed.
* Determines if the jar is shaded and the created pom.xml identified the
* same CPE as the jar - if so, the pom.xml dependency should be removed.
*
* @param dependency a dependency to check
* @param nextDependency another dependency to check
* @return true if on of the dependencies is a pom.xml and the identifiers between the two collections match; otherwise false
* @return true if on of the dependencies is a pom.xml and the identifiers
* between the two collections match; otherwise false
*/
private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
final String mainName = dependency.getFileName().toLowerCase();
@@ -424,12 +455,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
/**
* Determines which path is shortest; if path lengths are equal then we use compareTo of the string method to determine if the
* first path is smaller.
* Determines which path is shortest; if path lengths are equal then we use
* compareTo of the string method to determine if the first path is smaller.
*
* @param left the first path to compare
* @param right the second path to compare
* @return <code>true</code> if the leftPath is the shortest; otherwise <code>false</code>
* @return <code>true</code> if the leftPath is the shortest; otherwise
* <code>false</code>
*/
protected boolean firstPathIsShortest(String left, String right) {
final String leftPath = left.replace('\\', '/');

View File

@@ -70,7 +70,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* Python init files
*/
private static final NameFileFilter IGNORED_FILES = new NameFileFilter(new String[] {
private static final NameFileFilter IGNORED_FILES = new NameFileFilter(new String[]{
"__init__.py",
"__init__.pyc",
"__init__.pyo",
@@ -81,7 +81,8 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
*
* @param dependency the dependency to analyze.
* @param engine the engine that is scanning the dependencies
* @throws AnalysisException is thrown if there is an error reading the JAR file.
* @throws AnalysisException is thrown if there is an error reading the JAR
* file.
*/
@Override
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
@@ -107,13 +108,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
fileName, Confidence.MEDIUM);
}
//add as vendor and product evidence
// if (fileName.contains("-")) {
// dependency.getProductEvidence().addEvidence("file", "name",
// fileName, Confidence.HIGHEST);
// dependency.getVendorEvidence().addEvidence("file", "name",
// fileName, Confidence.HIGHEST);
// } else
if (!IGNORED_FILES.accept(f)) {
dependency.getProductEvidence().addEvidence("file", "name",
fileName, Confidence.HIGH);

View File

@@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -578,7 +577,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
}
String projectURL = pom.getProjectURL();
final String projectURL = pom.getProjectURL();
if (projectURL != null && !projectURL.trim().isEmpty()) {
dependency.getVendorEvidence().addEvidence("pom", "url", projectURL, Confidence.HIGHEST);
}

View File

@@ -39,7 +39,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Used to analyze a Python package, and collect information that can be used to determine the associated CPE.
* Used to analyze a Python package, and collect information that can be used to
* determine the associated CPE.
*
* @author Dale Visser
*/
@@ -166,7 +167,8 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
*
* @param dependency the dependency being analyzed
* @param engine the engine being used to perform the scan
* @throws AnalysisException thrown if there is an unrecoverable error analyzing the dependency
* @throws AnalysisException thrown if there is an unrecoverable error
* analyzing the dependency
*/
@Override
protected void analyzeFileType(Dependency dependency, Engine engine)
@@ -175,21 +177,20 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
final File parent = file.getParentFile();
final String parentName = parent.getName();
if (INIT_PY_FILTER.accept(file)) {
//by definition, the containing folder of __init__.py is considered the package, even the file is empty:
//"The __init__.py files are required to make Python treat the directories as containing packages"
//see section "6.4 Packages" from https://docs.python.org/2/tutorial/modules.html;
//by definition, the containing folder of __init__.py is considered the package, even the file is empty:
//"The __init__.py files are required to make Python treat the directories as containing packages"
//see section "6.4 Packages" from https://docs.python.org/2/tutorial/modules.html;
dependency.setDisplayFileName(parentName + "/__init__.py");
dependency.getProductEvidence().addEvidence(file.getName(),
"PackageName", parentName, Confidence.HIGHEST);
final File[] fileList = parent.listFiles(PY_FILTER);
if (fileList != null) {
for (final File sourceFile : fileList) {
analyzeFileContents(dependency, sourceFile);
}
}
}
else {
} else {
// copy, alter and set in case some other thread is iterating over
final List<Dependency> dependencies = new ArrayList<Dependency>(
engine.getDependencies());
@@ -199,8 +200,9 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
* This should gather information from leading docstrings, file comments, and assignments to __version__, __title__,
* __summary__, __uri__, __url__, __home*page__, __author__, and their all caps equivalents.
* This should gather information from leading docstrings, file comments,
* and assignments to __version__, __title__, __summary__, __uri__, __url__,
* __home*page__, __author__, and their all caps equivalents.
*
* @param dependency the dependency being analyzed
* @param file the file name to analyze
@@ -291,7 +293,8 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
* Gather evidence from a Python source file using the given string assignment regex pattern.
* Gather evidence from a Python source file using the given string
* assignment regex pattern.
*
* @param pattern to scan contents with
* @param contents of Python source file

View File

@@ -61,8 +61,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_INFORMATION_COLLECTION;
private static final FileFilter FILTER
= FileFilterBuilder.newInstance().addFilenames("Gemfile.lock").build();
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames("Gemfile.lock").build();
public static final String NAME = "Name: ";
public static final String VERSION = "Version: ";
public static final String ADVISORY = "Advisory: ";
@@ -81,7 +80,9 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
/**
* Launch bundle-audit.
*
* @param folder directory that contains bundle audit
* @return a handle to the process
* @throws AnalysisException thrown when there is an issue launching bundle audit
*/
private Process launchBundleAudit(File folder) throws AnalysisException {
if (!folder.isDirectory()) {
@@ -131,7 +132,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
throw ae;
}
int exitValue = process.waitFor();
final int exitValue = process.waitFor();
if (0 == exitValue) {
LOGGER.warn("Unexpected exit code from bundle-audit process. Disabling {}: {}", ANALYZER_NAME, exitValue);
setEnabled(false);
@@ -236,7 +237,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
try {
errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
while (errReader.ready()) {
String error = errReader.readLine();
final String error = errReader.readLine();
LOGGER.warn(error);
}
rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
@@ -284,7 +285,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
dependency = map.get(gem);
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
} else if (nextLine.startsWith(VERSION)) {
vulnerability = createVulnerability(parentName, dependency, vulnerability, gem, nextLine);
vulnerability = createVulnerability(parentName, dependency, gem, nextLine);
} else if (nextLine.startsWith(ADVISORY)) {
setVulnerabilityName(parentName, dependency, vulnerability, nextLine);
} else if (nextLine.startsWith(CRITICALITY)) {
@@ -318,7 +319,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
private void addReferenceToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
final String url = nextLine.substring(("URL: ").length());
if (null != vulnerability) {
Reference ref = new Reference();
final Reference ref = new Reference();
ref.setName(vulnerability.getName());
ref.setSource("bundle-audit");
ref.setUrl(url);
@@ -351,7 +352,8 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
}
private Vulnerability createVulnerability(String parentName, Dependency dependency, Vulnerability vulnerability, String gem, String nextLine) {
private Vulnerability createVulnerability(String parentName, Dependency dependency, String gem, String nextLine) {
Vulnerability vulnerability = null;
if (null != dependency) {
final String version = nextLine.substring(VERSION.length());
dependency.getVersionEvidence().addEvidence(

View File

@@ -25,20 +25,23 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
/**
* This analyzer accepts the fully resolved .gemspec created by the Ruby bundler (http://bundler.io)
* for better evidence results. It also tries to resolve the dependency packagePath
* to where the gem is actually installed. Then during {@link AnalysisPhase.PRE_FINDING_ANALYSIS}
* {@link DependencyBundlingAnalyzer} will merge two .gemspec dependencies together if
* <code>Dependency.getPackagePath()</code> are the same.
*
* Ruby bundler creates new .gemspec files under a folder called "specifications" at deploy time,
* in addition to the original .gemspec files from source. The bundler generated
* .gemspec files always contain fully resolved attributes thus provide more accurate
* evidences, whereas the original .gemspec from source often contain variables for attributes
* that can't be used for evidences.
*
* Note this analyzer share the same {@link Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED} as
* {@link RubyGemspecAnalyzer}, so it will enabled/disabled with {@link RubyGemspecAnalyzer}.
* This analyzer accepts the fully resolved .gemspec created by the Ruby bundler
* (http://bundler.io) for better evidence results. It also tries to resolve the
* dependency packagePath to where the gem is actually installed. Then during {@link AnalysisPhase.PRE_FINDING_ANALYSIS}
* {@link DependencyBundlingAnalyzer} will merge two .gemspec dependencies
* together if <code>Dependency.getPackagePath()</code> are the same.
*
* Ruby bundler creates new .gemspec files under a folder called
* "specifications" at deploy time, in addition to the original .gemspec files
* from source. The bundler generated .gemspec files always contain fully
* resolved attributes thus provide more accurate evidences, whereas the
* original .gemspec from source often contain variables for attributes that
* can't be used for evidences.
*
* Note this analyzer share the same
* {@link Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED} as
* {@link RubyGemspecAnalyzer}, so it will enabled/disabled with
* {@link RubyGemspecAnalyzer}.
*
* @author Bianca Jiang (biancajiang@gmail.com)
*/
@@ -48,12 +51,16 @@ public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer {
* The name of the analyzer.
*/
private static final String ANALYZER_NAME = "Ruby Bundler Analyzer";
//Folder name that contains .gemspec files created by "bundle install"
private static final String SPECIFICATIONS = "specifications";
//Folder name that contains the gems by "bundle install"
private static final String GEMS = "gems";
/**
* Folder name that contains .gemspec files created by "bundle install"
*/
private static final String SPECIFICATIONS = "specifications";
/**
* Folder name that contains the gems by "bundle install"
*/
private static final String GEMS = "gems";
/**
* Returns the name of the analyzer.
@@ -66,61 +73,66 @@ public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer {
}
/**
* Only accept *.gemspec files generated by "bundle install --deployment" under "specifications" folder.
* Only accept *.gemspec files generated by "bundle install --deployment"
* under "specifications" folder.
*
* @param pathname the path name to test
* @return true if the analyzer can process the given file; otherwise false
*/
@Override
@Override
public boolean accept(File pathname) {
boolean accepted = super.accept(pathname);
if(accepted == true) {
File parentDir = pathname.getParentFile();
accepted = parentDir != null && parentDir.getName().equals(SPECIFICATIONS);
if (accepted) {
final File parentDir = pathname.getParentFile();
accepted = parentDir != null && parentDir.getName().equals(SPECIFICATIONS);
}
return accepted;
}
@Override
@Override
protected void analyzeFileType(Dependency dependency, Engine engine)
throws AnalysisException {
super.analyzeFileType(dependency, engine);
//find the corresponding gem folder for this .gemspec stub by "bundle install --deployment"
File gemspecFile = dependency.getActualFile();
String gemFileName = gemspecFile.getName();
final File gemspecFile = dependency.getActualFile();
final String gemFileName = gemspecFile.getName();
final String gemName = gemFileName.substring(0, gemFileName.lastIndexOf(".gemspec"));
File specificationsDir = gemspecFile.getParentFile();
if(specificationsDir != null && specificationsDir.getName().equals(SPECIFICATIONS) && specificationsDir.exists()) {
File parentDir = specificationsDir.getParentFile();
if(parentDir != null && parentDir.exists()) {
File gemsDir = new File(parentDir, GEMS);
if(gemsDir != null && gemsDir.exists()) {
File[] matchingFiles = gemsDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.equals(gemName);
}
});
if(matchingFiles.length > 0) {
String gemPath = matchingFiles[0].getAbsolutePath();
if(dependency.getActualFilePath().equals(dependency.getFilePath())) {
if(gemPath != null)
dependency.setPackagePath(gemPath);
} else {
//.gemspec's actualFilePath and filePath are different when it's from a compressed file
//in which case actualFilePath is the temp directory used by decompression.
//packagePath should use the filePath of the identified gem file in "gems" folder
File gemspecStub = new File(dependency.getFilePath());
File specDir = gemspecStub.getParentFile();
if(specDir != null && specDir.getName().equals(SPECIFICATIONS)) {
File gemsDir2 = new File(specDir.getParentFile(), GEMS);
File packageDir = new File(gemsDir2, gemName);
dependency.setPackagePath(packageDir.getAbsolutePath());
}
}
}
}
}
}
}
final File specificationsDir = gemspecFile.getParentFile();
if (specificationsDir != null && specificationsDir.getName().equals(SPECIFICATIONS) && specificationsDir.exists()) {
final File parentDir = specificationsDir.getParentFile();
if (parentDir != null && parentDir.exists()) {
final File gemsDir = new File(parentDir, GEMS);
if (gemsDir.exists()) {
final File[] matchingFiles = gemsDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.equals(gemName);
}
});
if (matchingFiles != null && matchingFiles.length > 0) {
final String gemPath = matchingFiles[0].getAbsolutePath();
if (dependency.getActualFilePath().equals(dependency.getFilePath())) {
if (gemPath != null) {
dependency.setPackagePath(gemPath);
}
} else {
//.gemspec's actualFilePath and filePath are different when it's from a compressed file
//in which case actualFilePath is the temp directory used by decompression.
//packagePath should use the filePath of the identified gem file in "gems" folder
final File gemspecStub = new File(dependency.getFilePath());
final File specDir = gemspecStub.getParentFile();
if (specDir != null && specDir.getName().equals(SPECIFICATIONS)) {
final File gemsDir2 = new File(specDir.getParentFile(), GEMS);
final File packageDir = new File(gemsDir2, gemName);
dependency.setPackagePath(packageDir.getAbsolutePath());
}
}
}
}
}
}
}
}

View File

@@ -34,15 +34,22 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.EvidenceCollection;
import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Used to analyze Ruby Gem specifications and collect information that can be used to determine the associated CPE. Regular
* expressions are used to parse the well-defined Ruby syntax that forms the specification.
* Used to analyze Ruby Gem specifications and collect information that can be
* used to determine the associated CPE. Regular expressions are used to parse
* the well-defined Ruby syntax that forms the specification.
*
* @author Dale Visser
*/
public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(RubyGemspecAnalyzer.class);
/**
* The name of the analyzer.
*/
@@ -53,13 +60,22 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/**
* The gemspec file extension.
*/
private static final String GEMSPEC = "gemspec";
private static final FileFilter FILTER
= FileFilterBuilder.newInstance().addExtensions(GEMSPEC).build();
//TODO: support Rakefile
//= FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build();
/**
* The file filter containing the list of file extensions that can be
* analyzed.
*/
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(GEMSPEC).build();
//TODO: support Rakefile
//= FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build();
/**
* The name of the version file.
*/
private static final String VERSION_FILE_NAME = "VERSION";
/**
@@ -96,7 +112,8 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
* Returns the key used in the properties file to reference the analyzer's
* enabled property.
*
* @return the analyzer's enabled property setting key
*/
@@ -108,8 +125,7 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The capture group #1 is the block variable.
*/
private static final Pattern GEMSPEC_BLOCK_INIT
= Pattern.compile("Gem::Specification\\.new\\s+?do\\s+?\\|(.+?)\\|");
private static final Pattern GEMSPEC_BLOCK_INIT = Pattern.compile("Gem::Specification\\.new\\s+?do\\s+?\\|(.+?)\\|");
@Override
protected void analyzeFileType(Dependency dependency, Engine engine)
@@ -125,7 +141,7 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
if (matcher.find()) {
contents = contents.substring(matcher.end());
final String blockVariable = matcher.group(1);
final EvidenceCollection vendor = dependency.getVendorEvidence();
final EvidenceCollection product = dependency.getProductEvidence();
final String name = addStringEvidence(product, contents, blockVariable, "name", "name", Confidence.HIGHEST);
@@ -138,71 +154,90 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
addStringEvidence(vendor, contents, blockVariable, "email", "emails?", Confidence.MEDIUM);
addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST);
addStringEvidence(vendor, contents, blockVariable, "license", "licen[cs]es?", Confidence.HIGHEST);
String value = addStringEvidence(dependency.getVersionEvidence(), contents, blockVariable, "version", "version", Confidence.HIGHEST);
if(value.length() < 1)
addEvidenceFromVersionFile(dependency.getActualFile(), dependency.getVersionEvidence());
final String value = addStringEvidence(dependency.getVersionEvidence(), contents,
blockVariable, "version", "version", Confidence.HIGHEST);
if (value.length() < 1) {
addEvidenceFromVersionFile(dependency.getActualFile(), dependency.getVersionEvidence());
}
}
setPackagePath(dependency);
}
/**
* Adds the specified evidence to the given evidence collection.
*
* @param evidences the collection to add the evidence to
* @param contents the evidence contents
* @param blockVariable the variable
* @param field the field
* @param fieldPattern the field pattern
* @param confidence the confidence of the evidence
* @return the evidence string value added
*/
private String addStringEvidence(EvidenceCollection evidences, String contents,
String blockVariable, String field, String fieldPattern, Confidence confidence) {
String value = "";
//capture array value between [ ]
final Matcher arrayMatcher = Pattern.compile(
//capture array value between [ ]
final Matcher arrayMatcher = Pattern.compile(
String.format("\\s*?%s\\.%s\\s*?=\\s*?\\[(.*?)\\]", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents);
if(arrayMatcher.find()) {
String arrayValue = arrayMatcher.group(1);
value = arrayValue.replaceAll("['\"]", "").trim(); //strip quotes
}
//capture single value between quotes
else {
final Matcher matcher = Pattern.compile(
String.format("\\s*?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents);
if (matcher.find()) {
value = matcher.group(2);
}
}
if(value.length() > 0)
evidences.addEvidence(GEMSPEC, field, value, confidence);
if (arrayMatcher.find()) {
final String arrayValue = arrayMatcher.group(1);
value = arrayValue.replaceAll("['\"]", "").trim(); //strip quotes
} else { //capture single value between quotes
final Matcher matcher = Pattern.compile(
String.format("\\s*?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents);
if (matcher.find()) {
value = matcher.group(2);
}
}
if (value.length() > 0) {
evidences.addEvidence(GEMSPEC, field, value, confidence);
}
return value;
}
private String addEvidenceFromVersionFile(File dependencyFile, EvidenceCollection versionEvidences) {
String value = null;
File parentDir = dependencyFile.getParentFile();
if(parentDir != null) {
File[] matchingFiles = parentDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.contains(VERSION_FILE_NAME);
}
});
for(int i = 0; i < matchingFiles.length; i++) {
try {
List<String> lines = FileUtils.readLines(matchingFiles[i]);
if(lines.size() == 1) { //TODO other checking?
value = lines.get(0).trim();
versionEvidences.addEvidence(GEMSPEC, "version", value, Confidence.HIGH);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return value;
/**
* Adds evidence from the version file.
*
* @param dependencyFile the dependency being analyzed
* @param versionEvidences the version evidence
*/
private void addEvidenceFromVersionFile(File dependencyFile, EvidenceCollection versionEvidences) {
final File parentDir = dependencyFile.getParentFile();
if (parentDir != null) {
final File[] matchingFiles = parentDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.contains(VERSION_FILE_NAME);
}
});
for (File f : matchingFiles) {
try {
final List<String> lines = FileUtils.readLines(f, Charset.defaultCharset());
if (lines.size() == 1) { //TODO other checking?
final String value = lines.get(0).trim();
versionEvidences.addEvidence(GEMSPEC, "version", value, Confidence.HIGH);
}
} catch (IOException e) {
LOGGER.debug("Error reading gemspec", e);
}
}
}
}
/**
* Sets the package path on the dependency.
*
* @param dep the dependency to alter
*/
private void setPackagePath(Dependency dep) {
File file = new File(dep.getFilePath());
String parent = file.getParent();
if(parent != null)
dep.setPackagePath(parent);
final File file = new File(dep.getFilePath());
final String parent = file.getParent();
if (parent != null) {
dep.setPackagePath(parent);
}
}
}

View File

@@ -36,9 +36,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A program dependency. This object is one of the core components within DependencyCheck. It is used to collect information about
* the dependency in the form of evidence. The Evidence is then used to determine if there are any known, published,
* vulnerabilities associated with the program dependency.
* A program dependency. This object is one of the core components within
* DependencyCheck. It is used to collect information about the dependency in
* the form of evidence. The Evidence is then used to determine if there are any
* known, published, vulnerabilities associated with the program dependency.
*
* @author Jeremy Long
*/
@@ -72,17 +73,31 @@ public class Dependency implements Serializable, Comparable<Dependency> {
* The file name of the dependency.
*/
private String fileName;
/**
* The package path.
*/
private String packagePath;
/**
* Returns the package path.
*
* @return the package path
*/
public String getPackagePath() {
return packagePath;
}
return packagePath;
}
public void setPackagePath(String packagePath) {
this.packagePath = packagePath;
}
/**
* Sets the package path.
*
* @param packagePath the package path
*/
public void setPackagePath(String packagePath) {
this.packagePath = packagePath;
}
/**
/**
* The md5 hash of the dependency.
*/
private String md5sum;
@@ -144,10 +159,12 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Returns the file name of the dependency with the backslash escaped for use in JavaScript. This is a complete hack as I
* could not get the replace to work in the template itself.
* Returns the file name of the dependency with the backslash escaped for
* use in JavaScript. This is a complete hack as I could not get the replace
* to work in the template itself.
*
* @return the file name of the dependency with the backslash escaped for use in JavaScript
* @return the file name of the dependency with the backslash escaped for
* use in JavaScript
*/
public String getFileNameForJavaScript() {
return this.fileName.replace("\\", "\\\\");
@@ -199,9 +216,9 @@ public class Dependency implements Serializable, Comparable<Dependency> {
* @param filePath the file path of the dependency
*/
public void setFilePath(String filePath) {
if(this.packagePath == null || this.packagePath.equals(this.filePath))
this.packagePath = filePath;
if (this.packagePath == null || this.packagePath.equals(this.filePath)) {
this.packagePath = filePath;
}
this.filePath = filePath;
}
@@ -220,7 +237,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Returns the file name to display in reports; if no display file name has been set it will default to the actual file name.
* Returns the file name to display in reports; if no display file name has
* been set it will default to the actual file name.
*
* @return the file name to display
*/
@@ -235,8 +253,9 @@ public class Dependency implements Serializable, Comparable<Dependency> {
* <p>
* Gets the file path of the dependency.</p>
* <p>
* <b>NOTE:</b> This may not be the actual path of the file on disk. The actual path of the file on disk can be obtained via
* the getActualFilePath().</p>
* <b>NOTE:</b> This may not be the actual path of the file on disk. The
* actual path of the file on disk can be obtained via the
* getActualFilePath().</p>
*
* @return the file path of the dependency
*/
@@ -299,7 +318,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Adds an entry to the list of detected Identifiers for the dependency file.
* Adds an entry to the list of detected Identifiers for the dependency
* file.
*
* @param type the type of identifier (such as CPE)
* @param value the value of the identifier
@@ -311,7 +331,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Adds an entry to the list of detected Identifiers for the dependency file.
* Adds an entry to the list of detected Identifiers for the dependency
* file.
*
* @param type the type of identifier (such as CPE)
* @param value the value of the identifier
@@ -362,7 +383,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Adds an entry to the list of detected Identifiers for the dependency file.
* Adds an entry to the list of detected Identifiers for the dependency
* file.
*
* @param identifier the identifier to add
*/
@@ -594,8 +616,9 @@ public class Dependency implements Serializable, Comparable<Dependency> {
private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
/**
* Get the value of {@link #relatedDependencies}. This field is used to collect other dependencies which really represent the
* same dependency, and may be presented as one item in reports.
* Get the value of {@link #relatedDependencies}. This field is used to
* collect other dependencies which really represent the same dependency,
* and may be presented as one item in reports.
*
* @return the value of relatedDependencies
*/
@@ -654,9 +677,11 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Adds a related dependency. The internal collection is normally a {@link java.util.TreeSet}, which relies on
* {@link #compareTo(Dependency)}. A consequence of this is that if you attempt to add a dependency with the same file path
* (modulo character case) as one that is already in the collection, it won't get added.
* Adds a related dependency. The internal collection is normally a
* {@link java.util.TreeSet}, which relies on
* {@link #compareTo(Dependency)}. A consequence of this is that if you
* attempt to add a dependency with the same file path (modulo character
* case) as one that is already in the collection, it won't get added.
*
* @param dependency a reference to the related dependency
*/
@@ -706,7 +731,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Implementation of the Comparable&lt;Dependency&gt; interface. The comparison is solely based on the file path.
* Implementation of the Comparable&lt;Dependency&gt; interface. The
* comparison is solely based on the file path.
*
* @param o a dependency to compare
* @return an integer representing the natural ordering
@@ -776,12 +802,14 @@ public class Dependency implements Serializable, Comparable<Dependency> {
}
/**
* Standard toString() implementation showing the filename, actualFilePath, and filePath.
* Standard toString() implementation showing the filename, actualFilePath,
* and filePath.
*
* @return the string representation of the file
*/
@Override
public String toString() {
return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath + "', filePath='" + filePath + "', packagePath='" + packagePath + "'}";
return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath
+ "', filePath='" + filePath + "', packagePath='" + packagePath + "'}";
}
}

View File

@@ -260,7 +260,7 @@ public class Model {
public void addLicense(License license) {
licenses.add(license);
}
/**
* The project URL.
*/
@@ -272,17 +272,17 @@ public class Model {
* @return the value of projectURL
*/
public String getProjectURL() {
return projectURL;
}
return projectURL;
}
/**
* Set the value of projectURL.
*
* @param parentVersion new value of projectURL
* @param projectURL new value of projectURL
*/
public void setProjectURL(String projectURL) {
this.projectURL = projectURL;
}
public void setProjectURL(String projectURL) {
this.projectURL = projectURL;
}
/**
* Process the Maven properties file and interpolate all properties.
@@ -308,11 +308,14 @@ public class Model {
/**
* <p>
* A utility function that will interpolate strings based on values given in the properties file. It will also interpolate the
* strings contained within the properties file so that properties can reference other properties.</p>
* A utility function that will interpolate strings based on values given in
* the properties file. It will also interpolate the strings contained
* within the properties file so that properties can reference other
* properties.</p>
* <p>
* <b>Note:</b> if there is no property found the reference will be removed. In other words, if the interpolated string will
* be replaced with an empty string.
* <b>Note:</b> if there is no property found the reference will be removed.
* In other words, if the interpolated string will be replaced with an empty
* string.
* </p>
* <p>
* Example:</p>
@@ -329,7 +332,8 @@ public class Model {
* </code>
*
* @param text the string that contains references to properties.
* @param properties a collection of properties that may be referenced within the text.
* @param properties a collection of properties that may be referenced
* within the text.
* @return the interpolated text.
*/
public static String interpolateString(String text, Properties properties) {
@@ -340,8 +344,9 @@ public class Model {
return substitutor.replace(text);
}
/**
* Utility class that can provide values from a Properties object to a StrSubstitutor.
/**
* Utility class that can provide values from a Properties object to a
* StrSubstitutor.
*/
private static class PropertyLookup extends StrLookup {

View File

@@ -13,6 +13,6 @@
^ \* See the License for the specific language governing permissions and\s*$
^ \* limitations under the License\.\s*$
^ \*\s*$
^ \* Copyright \(c\) 201[0-9] (Jeremy Long|Steve Springett|The OWASP Foundation|Institute for Defense Analyses)\. All Rights Reserved\.\s*$
^ \* Copyright \(c\) 201[0-9] (Jeremy Long|Steve Springett|Bianca Jiang|The OWASP Foundation|Institute for Defense Analyses)\. All Rights Reserved\.\s*$
^ \*/\s*$
^package