From da77727673230c7e28357c4c52a32a747d3f1ff8 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 5 Nov 2014 06:20:15 -0500 Subject: [PATCH] changes to support Ant style paths to resolve issue #153 Former-commit-id: b1666d6652891c4b012457fd5de7f8230938fb45 --- .../java/org/owasp/dependencycheck/App.java | 84 ++++++++++++++++--- .../org/owasp/dependencycheck/CliParser.java | 30 +++++-- 2 files changed, 97 insertions(+), 17 deletions(-) diff --git a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java index 5122bf88f..f4e0690e7 100644 --- a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java +++ b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java @@ -21,7 +21,11 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.cli.ParseException; @@ -29,6 +33,7 @@ import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.org.apache.tools.ant.DirectoryScanner; import org.owasp.dependencycheck.reporting.ReportGenerator; import org.owasp.dependencycheck.utils.LogUtils; import org.owasp.dependencycheck.utils.Settings; @@ -92,7 +97,11 @@ public class App { cli.printVersionInfo(); } else if (cli.isRunScan()) { populateSettings(cli); - runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles()); + try { + runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles(), cli.getExcludeList()); + } catch (InvalidScanPathException ex) { + Logger.getLogger(App.class.getName()).log(Level.SEVERE, "An invalid scan path was detected; unable to scan '//*' paths"); + } } else { cli.printHelp(); } @@ -105,18 +114,69 @@ public class App { * @param outputFormat the output format of the report * @param applicationName the application name for the report * @param files the files/directories to scan + * @param files the patterns for files/directories to exclude */ - private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files) { - Engine scanner = null; + private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files, + String[] excludes) throws InvalidScanPathException { + Engine engine = null; try { - scanner = new Engine(); - - for (String file : files) { - scanner.scan(file); + engine = new Engine(); + List antStylePaths = new ArrayList(); + if (excludes == null || excludes.length == 0) { + for (String file : files) { + if (file.contains("*") || file.contains("?")) { + antStylePaths.add(file); + } else { + engine.scan(file); + } + } + } else { + antStylePaths = Arrays.asList(files); } - scanner.analyzeDependencies(); - final List dependencies = scanner.getDependencies(); + Set paths = new HashSet(); + for (String file : antStylePaths) { + DirectoryScanner scanner = new DirectoryScanner(); + String include = file.replace('\\', '/'); + File baseDir; + + if (include.startsWith("//")) { + throw new InvalidScanPathException("Unable to scan paths specified by //"); + } else if (include.startsWith("./")) { + baseDir = new File("."); + include = include.substring(2); + } else if (include.startsWith("/")) { + baseDir = new File("/"); + include = include.substring(1); + } else if (include.contains("/")) { + final int pos = include.indexOf('/'); + String tmp = include.substring(0, pos); + if (tmp.contains("*") || tmp.contains("?")) { + baseDir = new File("."); + } else { + baseDir = new File(tmp); + include = include.substring(pos + 1); + } + } else { //no path info - must just be a file in the working directory + baseDir = new File("."); + } + scanner.setBasedir(baseDir); + scanner.setIncludes(include); + if (excludes != null && excludes.length > 0) { + scanner.addExcludes(excludes); + } + scanner.scan(); + if (scanner.getIncludedFilesCount() > 0) { + for (String s : scanner.getIncludedFiles()) { + File f = new File(baseDir, s); + paths.add(f); + } + } + } + engine.scan(paths); + + engine.analyzeDependencies(); + final List dependencies = engine.getDependencies(); DatabaseProperties prop = null; CveDB cve = null; try { @@ -130,7 +190,7 @@ public class App { cve.close(); } } - final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop); + final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop); try { report.generateReports(reportDirectory, outputFormat); } catch (IOException ex) { @@ -144,8 +204,8 @@ public class App { LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped"); LOGGER.log(Level.FINE, "", ex); } finally { - if (scanner != null) { - scanner.cleanup(); + if (engine != null) { + engine.cleanup(); } } } diff --git a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java index 5092e9eb5..d26e427b2 100644 --- a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java +++ b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java @@ -134,7 +134,7 @@ public final class CliParser { * @throws FileNotFoundException is thrown if the path being validated does not exist. */ private void validatePathExists(String path, String argumentName) throws FileNotFoundException { - if (!path.contains("*.")) { + if (!path.contains("*") && !path.contains("?")) { final File f = new File(path); if (!f.exists()) { isValid = false; @@ -151,7 +151,6 @@ public final class CliParser { */ @SuppressWarnings("static-access") private Options createCommandLineOptions() { - final Options options = new Options(); addStandardOptions(options); addAdvancedOptions(options); @@ -184,10 +183,15 @@ public final class CliParser { .create(ARGUMENT.APP_NAME_SHORT); final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN) - .withDescription("The path to scan - this option can be specified multiple times. To limit the scan" - + " to specific file types *.[ext] can be added to the end of the path.") + .withDescription("The path to scan - this option can be specified multiple times. Ant style" + + " paths are supported (e.g. path/**/*.jar).") .create(ARGUMENT.SCAN_SHORT); + final Option excludes = OptionBuilder.withArgName("pattern").hasArg().withLongOpt(ARGUMENT.EXCLUDE) + .withDescription("Specify and exclusion pattern. This option can be specified multiple times" + + " and it accepts Ant style excludsions.") + .create(); + final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP) .withDescription("A property file to load.") .create(ARGUMENT.PROP_SHORT); @@ -212,7 +216,11 @@ public final class CliParser { final OptionGroup og = new OptionGroup(); og.addOption(path); + final OptionGroup exog = new OptionGroup(); + exog.addOption(excludes); + options.addOptionGroup(og) + .addOptionGroup(exog) .addOption(out) .addOption(outputFormat) .addOption(appName) @@ -479,7 +487,6 @@ public final class CliParser { options, "", true); - } /** @@ -491,6 +498,15 @@ public final class CliParser { return line.getOptionValues(ARGUMENT.SCAN); } + /** + * Retrieves the list of excluded file patterns specified by the 'exclude' argument. + * + * @return the excluded file patterns + */ + public String[] getExcludeList() { + return line.getOptionValues(ARGUMENT.EXCLUDE); + } + /** * Returns the directory to write the reports to specified on the command line. * @@ -877,5 +893,9 @@ public final class CliParser { * The CLI argument name for setting extra extensions. */ public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions"; + /** + * Exclude path argument + */ + public static final String EXCLUDE = "exclude"; } }