Java tutorial
/* * This file is part of dependency-check-cli. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (c) 2012 Jeremy Long. All Rights Reserved. */ package org.owasp.dependencycheck; import java.io.File; import java.io.FileNotFoundException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionGroup; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.owasp.dependencycheck.reporting.ReportGenerator.Format; import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A utility to parse command line arguments for the DependencyCheck. * * @author Jeremy Long */ public final class CliParser { /** * The logger. */ private static final Logger LOGGER = LoggerFactory.getLogger(CliParser.class); /** * The command line. */ private CommandLine line; /** * Indicates whether the arguments are valid. */ private boolean isValid = true; /** * Parses the arguments passed in and captures the results for later use. * * @param args the command line arguments * @throws FileNotFoundException is thrown when a 'file' argument does not * point to a file that exists. * @throws ParseException is thrown when a Parse Exception occurs. */ public void parse(String[] args) throws FileNotFoundException, ParseException { line = parseArgs(args); if (line != null) { validateArgs(); } } /** * Parses the command line arguments. * * @param args the command line arguments * @return the results of parsing the command line arguments * @throws ParseException if the arguments are invalid */ private CommandLine parseArgs(String[] args) throws ParseException { final CommandLineParser parser = new DefaultParser(); final Options options = createCommandLineOptions(); return parser.parse(options, args); } /** * Validates that the command line arguments are valid. * * @throws FileNotFoundException if there is a file specified by either the * SCAN or CPE command line arguments that does not exist. * @throws ParseException is thrown if there is an exception parsing the * command line. */ private void validateArgs() throws FileNotFoundException, ParseException { if (isUpdateOnly() || isRunScan()) { final String value = line.getOptionValue(ARGUMENT.CVE_VALID_FOR_HOURS); if (value != null) { try { final int i = Integer.parseInt(value); if (i < 0) { throw new ParseException( "Invalid Setting: cveValidForHours must be a number greater than or equal to 0."); } } catch (NumberFormatException ex) { throw new ParseException( "Invalid Setting: cveValidForHours must be a number greater than or equal to 0."); } } } if (isRunScan()) { validatePathExists(getScanFiles(), ARGUMENT.SCAN); validatePathExists(getReportDirectory(), ARGUMENT.OUT); if (getPathToMono() != null) { validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO); } if (!line.hasOption(ARGUMENT.APP_NAME) && !line.hasOption(ARGUMENT.PROJECT)) { throw new ParseException("Missing '" + ARGUMENT.PROJECT + "' argument; the scan cannot be run without the an project name."); } if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) { final String format = line.getOptionValue(ARGUMENT.OUTPUT_FORMAT); try { Format.valueOf(format); } catch (IllegalArgumentException ex) { final String msg = String.format("An invalid 'format' of '%s' was specified. " + "Supported output formats are XML, HTML, VULN, or ALL", format); throw new ParseException(msg); } } if ((getBaseCve12Url() != null || getBaseCve20Url() != null || getModifiedCve12Url() != null || getModifiedCve20Url() != null) && (getBaseCve12Url() == null || getBaseCve20Url() == null || getModifiedCve12Url() == null || getModifiedCve20Url() == null)) { final String msg = "If one of the CVE URLs is specified they must all be specified; please add the missing CVE URL."; throw new ParseException(msg); } if (line.hasOption((ARGUMENT.SYM_LINK_DEPTH))) { try { final int i = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH)); if (i < 0) { throw new ParseException("Symbolic Link Depth (symLink) must be greater than zero."); } } catch (NumberFormatException ex) { throw new ParseException("Symbolic Link Depth (symLink) is not a number."); } } } } /** * Validates whether or not the path(s) points at a file that exists; if the * path(s) does not point to an existing file a FileNotFoundException is * thrown. * * @param paths the paths to validate if they exists * @param optType the option being validated (e.g. scan, out, etc.) * @throws FileNotFoundException is thrown if one of the paths being * validated does not exist. */ private void validatePathExists(String[] paths, String optType) throws FileNotFoundException { for (String path : paths) { validatePathExists(path, optType); } } /** * Validates whether or not the path points at a file that exists; if the * path does not point to an existing file a FileNotFoundException is * thrown. * * @param path the paths to validate if they exists * @param argumentName the argument being validated (e.g. scan, out, etc.) * @throws FileNotFoundException is thrown if the path being validated does * not exist. */ private void validatePathExists(String path, String argumentName) throws FileNotFoundException { if (path == null) { isValid = false; final String msg = String.format("Invalid '%s' argument: null", argumentName); throw new FileNotFoundException(msg); } else if (!path.contains("*") && !path.contains("?")) { File f = new File(path); if ("o".equalsIgnoreCase(argumentName.substring(0, 1)) && !"ALL".equalsIgnoreCase(this.getReportFormat())) { final String checkPath = path.toLowerCase(); if (checkPath.endsWith(".html") || checkPath.endsWith(".xml") || checkPath.endsWith(".htm")) { if (f.getParentFile() == null) { f = new File(".", path); } if (!f.getParentFile().isDirectory()) { isValid = false; final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path); throw new FileNotFoundException(msg); } } } else if (!f.exists()) { isValid = false; final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path); throw new FileNotFoundException(msg); } } else if (path.startsWith("//") || path.startsWith("\\\\")) { isValid = false; final String msg = String.format( "Invalid '%s' argument: '%s'%nUnable to scan paths that start with '//'.", argumentName, path); throw new FileNotFoundException(msg); } } /** * Generates an Options collection that is used to parse the command line * and to display the help message. * * @return the command line options used for parsing the command line */ @SuppressWarnings("static-access") private Options createCommandLineOptions() { final Options options = new Options(); addStandardOptions(options); addAdvancedOptions(options); addDeprecatedOptions(options); return options; } /** * Adds the standard command line options to the given options collection. * * @param options a collection of command line arguments * @throws IllegalArgumentException thrown if there is an exception */ @SuppressWarnings("static-access") private void addStandardOptions(final Options options) throws IllegalArgumentException { final Option help = new Option(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, false, "Print this message."); final Option advancedHelp = Option.builder().longOpt(ARGUMENT.ADVANCED_HELP) .desc("Print the advanced help message.").build(); final Option version = new Option(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION, false, "Print the version information."); final Option noUpdate = new Option(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE, false, "Disables the automatic updating of the CPE data."); final Option projectName = Option.builder().hasArg().argName("name").longOpt(ARGUMENT.PROJECT) .desc("The name of the project being scanned. This is a required argument.").build(); final Option path = Option.builder(ARGUMENT.SCAN_SHORT).argName("path").hasArg().longOpt(ARGUMENT.SCAN) .desc("The path to scan - this option can be specified multiple times. Ant style" + " paths are supported (e.g. path/**/*.jar).") .build(); final Option excludes = Option.builder().argName("pattern").hasArg().longOpt(ARGUMENT.EXCLUDE) .desc("Specify and exclusion pattern. This option can be specified multiple times" + " and it accepts Ant style excludsions.") .build(); final Option props = Option.builder(ARGUMENT.PROP_SHORT).argName("file").hasArg().longOpt(ARGUMENT.PROP) .desc("A property file to load.").build(); final Option out = Option.builder(ARGUMENT.OUT_SHORT).argName("path").hasArg().longOpt(ARGUMENT.OUT) .desc("The folder to write reports to. This defaults to the current directory. " + "It is possible to set this to a specific file name if the format argument is not set to ALL.") .build(); final Option outputFormat = Option.builder(ARGUMENT.OUTPUT_FORMAT_SHORT).argName("format").hasArg() .longOpt(ARGUMENT.OUTPUT_FORMAT) .desc("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.").build(); final Option verboseLog = Option.builder(ARGUMENT.VERBOSE_LOG_SHORT).argName("file").hasArg() .longOpt(ARGUMENT.VERBOSE_LOG).desc("The file path to write verbose logging information.").build(); final Option symLinkDepth = Option.builder().argName("depth").hasArg().longOpt(ARGUMENT.SYM_LINK_DEPTH) .desc("Sets how deep nested symbolic links will be followed; 0 indicates symbolic links will not be followed.") .build(); final Option suppressionFile = Option.builder().argName("file").hasArg().longOpt(ARGUMENT.SUPPRESSION_FILE) .desc("The file path to the suppression XML file.").build(); final Option cveValidForHours = Option.builder().argName("hours").hasArg() .longOpt(ARGUMENT.CVE_VALID_FOR_HOURS) .desc("The number of hours to wait before checking for new updates from the NVD.").build(); final Option experimentalEnabled = Option.builder().longOpt(ARGUMENT.EXPERIMENTAL) .desc("Enables the experimental analzers.").build(); //This is an option group because it can be specified more then once. final OptionGroup og = new OptionGroup(); og.addOption(path); final OptionGroup exog = new OptionGroup(); exog.addOption(excludes); options.addOptionGroup(og).addOptionGroup(exog).addOption(projectName).addOption(out) .addOption(outputFormat).addOption(version).addOption(help).addOption(advancedHelp) .addOption(noUpdate).addOption(symLinkDepth).addOption(props).addOption(verboseLog) .addOption(suppressionFile).addOption(cveValidForHours).addOption(experimentalEnabled); } /** * Adds the advanced command line options to the given options collection. * These are split out for purposes of being able to display two different * help messages. * * @param options a collection of command line arguments * @throws IllegalArgumentException thrown if there is an exception */ @SuppressWarnings("static-access") private void addAdvancedOptions(final Options options) throws IllegalArgumentException { final Option cve12Base = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_BASE_12) .desc("Base URL for each years CVE 1.2, the %d will be replaced with the year. ").build(); final Option cve20Base = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_BASE_20) .desc("Base URL for each years CVE 2.0, the %d will be replaced with the year.").build(); final Option cve12Modified = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_MOD_12) .desc("URL for the modified CVE 1.2.").build(); final Option cve20Modified = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_MOD_20) .desc("URL for the modified CVE 2.0.").build(); final Option updateOnly = Option.builder().longOpt(ARGUMENT.UPDATE_ONLY) .desc("Only update the local NVD data cache; no scan will be executed.").build(); final Option data = Option.builder(ARGUMENT.DATA_DIRECTORY_SHORT).argName("path").hasArg() .longOpt(ARGUMENT.DATA_DIRECTORY) .desc("The location of the H2 Database file. This option should generally not be set.").build(); final Option nexusUrl = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.NEXUS_URL) .desc("The url to the Nexus Server's REST API Endpoint (http://domain/nexus/service/local). " + "If not set the Nexus Analyzer will be disabled.") .build(); final Option nexusUsesProxy = Option.builder().argName("true/false").hasArg() .longOpt(ARGUMENT.NEXUS_USES_PROXY) .desc("Whether or not the configured proxy should be used when connecting to Nexus.").build(); final Option additionalZipExtensions = Option.builder().argName("extensions").hasArg() .longOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS) .desc("A comma separated list of additional extensions to be scanned as ZIP files " + "(ZIP, EAR, WAR are already treated as zip files)") .build(); final Option pathToMono = Option.builder().argName("path").hasArg().longOpt(ARGUMENT.PATH_TO_MONO) .desc("The path to Mono for .NET Assembly analysis on non-windows systems.").build(); final Option pathToBundleAudit = Option.builder().argName("path").hasArg() .longOpt(ARGUMENT.PATH_TO_BUNDLE_AUDIT).desc("The path to bundle-audit for Gem bundle analysis.") .build(); final Option connectionTimeout = Option.builder(ARGUMENT.CONNECTION_TIMEOUT_SHORT).argName("timeout") .hasArg().longOpt(ARGUMENT.CONNECTION_TIMEOUT) .desc("The connection timeout (in milliseconds) to use when downloading resources.").build(); final Option proxyServer = Option.builder().argName("server").hasArg().longOpt(ARGUMENT.PROXY_SERVER) .desc("The proxy server to use when downloading resources.").build(); final Option proxyPort = Option.builder().argName("port").hasArg().longOpt(ARGUMENT.PROXY_PORT) .desc("The proxy port to use when downloading resources.").build(); final Option proxyUsername = Option.builder().argName("user").hasArg().longOpt(ARGUMENT.PROXY_USERNAME) .desc("The proxy username to use when downloading resources.").build(); final Option proxyPassword = Option.builder().argName("pass").hasArg().longOpt(ARGUMENT.PROXY_PASSWORD) .desc("The proxy password to use when downloading resources.").build(); final Option connectionString = Option.builder().argName("connStr").hasArg() .longOpt(ARGUMENT.CONNECTION_STRING).desc("The connection string to the database.").build(); final Option dbUser = Option.builder().argName("user").hasArg().longOpt(ARGUMENT.DB_NAME) .desc("The username used to connect to the database.").build(); final Option dbPassword = Option.builder().argName("password").hasArg().longOpt(ARGUMENT.DB_PASSWORD) .desc("The password for connecting to the database.").build(); final Option dbDriver = Option.builder().argName("driver").hasArg().longOpt(ARGUMENT.DB_DRIVER) .desc("The database driver name.").build(); final Option dbDriverPath = Option.builder().argName("path").hasArg().longOpt(ARGUMENT.DB_DRIVER_PATH).desc( "The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.") .build(); final Option disableJarAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_JAR) .desc("Disable the Jar Analyzer.").build(); final Option disableArchiveAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_ARCHIVE) .desc("Disable the Archive Analyzer.").build(); final Option disableNuspecAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_NUSPEC) .desc("Disable the Nuspec Analyzer.").build(); final Option disableAssemblyAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_ASSEMBLY) .desc("Disable the .NET Assembly Analyzer.").build(); final Option disablePythonDistributionAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_PY_DIST) .desc("Disable the Python Distribution Analyzer.").build(); final Option disablePythonPackageAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_PY_PKG) .desc("Disable the Python Package Analyzer.").build(); final Option disableComposerAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_COMPOSER) .desc("Disable the PHP Composer Analyzer.").build(); final Option disableAutoconfAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_AUTOCONF) .desc("Disable the Autoconf Analyzer.").build(); final Option disableOpenSSLAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_OPENSSL) .desc("Disable the OpenSSL Analyzer.").build(); final Option disableCmakeAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_CMAKE) .desc("Disable the Cmake Analyzer.").build(); final Option disableCentralAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_CENTRAL).desc( "Disable the Central Analyzer. If this analyzer is disabled it is likely you also want to disable " + "the Nexus Analyzer.") .build(); final Option disableNexusAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_NEXUS) .desc("Disable the Nexus Analyzer.").build(); final Option purge = Option.builder().longOpt(ARGUMENT.PURGE_NVD).desc("Purges the local NVD data cache") .build(); options.addOption(updateOnly).addOption(cve12Base).addOption(cve20Base).addOption(cve12Modified) .addOption(cve20Modified).addOption(proxyPort).addOption(proxyServer).addOption(proxyUsername) .addOption(proxyPassword).addOption(connectionTimeout).addOption(connectionString).addOption(dbUser) .addOption(data).addOption(dbPassword).addOption(dbDriver).addOption(dbDriverPath) .addOption(disableJarAnalyzer).addOption(disableArchiveAnalyzer).addOption(disableAssemblyAnalyzer) .addOption(pathToBundleAudit).addOption(disablePythonDistributionAnalyzer) .addOption(disableCmakeAnalyzer).addOption(disablePythonPackageAnalyzer) .addOption(Option.builder().longOpt(ARGUMENT.DISABLE_RUBYGEMS) .desc("Disable the Ruby Gemspec Analyzer.").build()) .addOption(Option.builder().longOpt(ARGUMENT.DISABLE_BUNDLE_AUDIT) .desc("Disable the Ruby Bundler-Audit Analyzer.").build()) .addOption(disableAutoconfAnalyzer).addOption(disableComposerAnalyzer) .addOption(disableOpenSSLAnalyzer).addOption(disableNuspecAnalyzer) .addOption(disableCentralAnalyzer).addOption(disableNexusAnalyzer) .addOption(Option.builder().longOpt(ARGUMENT.DISABLE_NODE_JS) .desc("Disable the Node.js Package Analyzer.").build()) .addOption(nexusUrl).addOption(nexusUsesProxy).addOption(additionalZipExtensions) .addOption(pathToMono).addOption(pathToBundleAudit).addOption(purge); } /** * Adds the deprecated command line options to the given options collection. * These are split out for purposes of not including them in the help * message. We need to add the deprecated options so as not to break * existing scripts. * * @param options a collection of command line arguments * @throws IllegalArgumentException thrown if there is an exception */ @SuppressWarnings({ "static-access", "deprecation" }) private void addDeprecatedOptions(final Options options) throws IllegalArgumentException { final Option proxyServer = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.PROXY_URL) .desc("The proxy url argument is deprecated, use proxyserver instead.").build(); final Option appName = Option.builder(ARGUMENT.APP_NAME_SHORT).argName("name").hasArg() .longOpt(ARGUMENT.APP_NAME).desc("The name of the project being scanned.").build(); options.addOption(proxyServer); options.addOption(appName); } /** * Determines if the 'version' command line argument was passed in. * * @return whether or not the 'version' command line argument was passed in */ public boolean isGetVersion() { return (line != null) && line.hasOption(ARGUMENT.VERSION); } /** * Determines if the 'help' command line argument was passed in. * * @return whether or not the 'help' command line argument was passed in */ public boolean isGetHelp() { return (line != null) && line.hasOption(ARGUMENT.HELP); } /** * Determines if the 'scan' command line argument was passed in. * * @return whether or not the 'scan' command line argument was passed in */ public boolean isRunScan() { return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN); } /** * Returns the symbolic link depth (how deeply symbolic links will be * followed). * * @return the symbolic link depth */ public int getSymLinkDepth() { int value = 0; try { value = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH, "0")); if (value < 0) { value = 0; } } catch (NumberFormatException ex) { LOGGER.debug("Symbolic link was not a number"); } return value; } /** * Returns true if the disableJar command line argument was specified. * * @return true if the disableJar command line argument was specified; * otherwise false */ public boolean isJarDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR); } /** * Returns true if the disableArchive command line argument was specified. * * @return true if the disableArchive command line argument was specified; * otherwise false */ public boolean isArchiveDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE); } /** * Returns true if the disableNuspec command line argument was specified. * * @return true if the disableNuspec command line argument was specified; * otherwise false */ public boolean isNuspecDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC); } /** * Returns true if the disableAssembly command line argument was specified. * * @return true if the disableAssembly command line argument was specified; * otherwise false */ public boolean isAssemblyDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY); } /** * Returns true if the disableBundleAudit command line argument was * specified. * * @return true if the disableBundleAudit command line argument was * specified; otherwise false */ public boolean isBundleAuditDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_BUNDLE_AUDIT); } /** * Returns true if the disablePyDist command line argument was specified. * * @return true if the disablePyDist command line argument was specified; * otherwise false */ public boolean isPythonDistributionDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_DIST); } /** * Returns true if the disablePyPkg command line argument was specified. * * @return true if the disablePyPkg command line argument was specified; * otherwise false */ public boolean isPythonPackageDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_PKG); } /** * Returns whether the Ruby gemspec analyzer is disabled. * * @return true if the {@link ARGUMENT#DISABLE_RUBYGEMS} command line * argument was specified; otherwise false */ public boolean isRubyGemspecDisabled() { return (null != line) && line.hasOption(ARGUMENT.DISABLE_RUBYGEMS); } /** * Returns true if the disableCmake command line argument was specified. * * @return true if the disableCmake command line argument was specified; * otherwise false */ public boolean isCmakeDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_CMAKE); } /** * Returns true if the disableAutoconf command line argument was specified. * * @return true if the disableAutoconf command line argument was specified; * otherwise false */ public boolean isAutoconfDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_AUTOCONF); } /** * Returns true if the disableComposer command line argument was specified. * * @return true if the disableComposer command line argument was specified; * otherwise false */ public boolean isComposerDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_COMPOSER); } /** * Returns true if the disableNexus command line argument was specified. * * @return true if the disableNexus command line argument was specified; * otherwise false */ public boolean isNexusDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS); } /** * Returns true if the disableOpenSSL command line argument was specified. * * @return true if the disableOpenSSL command line argument was specified; * otherwise false */ public boolean isOpenSSLDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_OPENSSL); } /** * Returns true if the disableNodeJS command line argument was specified. * * @return true if the disableNodeJS command line argument was specified; * otherwise false */ public boolean isNodeJsDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_NODE_JS); } /** * Returns true if the disableCentral command line argument was specified. * * @return true if the disableCentral command line argument was specified; * otherwise false */ public boolean isCentralDisabled() { return (line != null) && line.hasOption(ARGUMENT.DISABLE_CENTRAL); } /** * Returns the url to the nexus server if one was specified. * * @return the url to the nexus server; if none was specified this will * return null; */ public String getNexusUrl() { if (line == null || !line.hasOption(ARGUMENT.NEXUS_URL)) { return null; } else { return line.getOptionValue(ARGUMENT.NEXUS_URL); } } /** * Returns true if the Nexus Analyzer should use the configured proxy to * connect to Nexus; otherwise false is returned. * * @return true if the Nexus Analyzer should use the configured proxy to * connect to Nexus; otherwise false */ public boolean isNexusUsesProxy() { // If they didn't specify whether Nexus needs to use the proxy, we should // still honor the property if it's set. if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) { try { return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY); } catch (InvalidSettingException ise) { return true; } } else { return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY)); } } /** * Displays the command line help message to the standard output. */ public void printHelp() { final HelpFormatter formatter = new HelpFormatter(); final Options options = new Options(); addStandardOptions(options); if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) { addAdvancedOptions(options); } final String helpMsg = String.format("%n%s" + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. " + "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n", Settings.getString("application.name", "DependencyCheck"), Settings.getString("application.name", "DependencyCheck")); formatter.printHelp(Settings.getString("application.name", "DependencyCheck"), helpMsg, options, "", true); } /** * Retrieves the file command line parameter(s) specified for the 'scan' * argument. * * @return the file paths specified on the command line for scan */ public String[] getScanFiles() { 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. * * @return the path to the reports directory. */ public String getReportDirectory() { return line.getOptionValue(ARGUMENT.OUT, "."); } /** * Returns the path to Mono for .NET Assembly analysis on non-windows * systems. * * @return the path to Mono */ public String getPathToMono() { return line.getOptionValue(ARGUMENT.PATH_TO_MONO); } /** * Returns the path to bundle-audit for Ruby bundle analysis. * * @return the path to Mono */ public String getPathToBundleAudit() { return line.getOptionValue(ARGUMENT.PATH_TO_BUNDLE_AUDIT); } /** * Returns the output format specified on the command line. Defaults to HTML * if no format was specified. * * @return the output format name. */ public String getReportFormat() { return line.getOptionValue(ARGUMENT.OUTPUT_FORMAT, "HTML"); } /** * Returns the application name specified on the command line. * * @return the application name. */ public String getProjectName() { final String appName = line.getOptionValue(ARGUMENT.APP_NAME); String name = line.getOptionValue(ARGUMENT.PROJECT); if (name == null && appName != null) { name = appName; LOGGER.warn("The '" + ARGUMENT.APP_NAME + "' argument should no longer be used; use '" + ARGUMENT.PROJECT + "' instead."); } return name; } /** * Returns the base URL for the CVE 1.2 XMl file. * * @return the URL to the CVE 1.2 XML file. */ public String getBaseCve12Url() { return line.getOptionValue(ARGUMENT.CVE_BASE_12); } /** * Returns the base URL for the CVE 2.0 XMl file. * * @return the URL to the CVE 2.0 XML file. */ public String getBaseCve20Url() { return line.getOptionValue(ARGUMENT.CVE_BASE_20); } /** * Returns the URL for the modified CVE 1.2 XMl file. * * @return the URL to the modified CVE 1.2 XML file. */ public String getModifiedCve12Url() { return line.getOptionValue(ARGUMENT.CVE_MOD_12); } /** * Returns the URL for the modified CVE 2.0 XMl file. * * @return the URL to the modified CVE 2.0 XML file. */ public String getModifiedCve20Url() { return line.getOptionValue(ARGUMENT.CVE_MOD_20); } /** * Returns the connection timeout. * * @return the connection timeout */ public String getConnectionTimeout() { return line.getOptionValue(ARGUMENT.CONNECTION_TIMEOUT); } /** * Returns the proxy server. * * @return the proxy server */ @SuppressWarnings("deprecation") public String getProxyServer() { String server = line.getOptionValue(ARGUMENT.PROXY_SERVER); if (server == null) { server = line.getOptionValue(ARGUMENT.PROXY_URL); if (server != null) { LOGGER.warn("An old command line argument 'proxyurl' was detected; use proxyserver instead"); } } return server; } /** * Returns the proxy port. * * @return the proxy port */ public String getProxyPort() { return line.getOptionValue(ARGUMENT.PROXY_PORT); } /** * Returns the proxy username. * * @return the proxy username */ public String getProxyUsername() { return line.getOptionValue(ARGUMENT.PROXY_USERNAME); } /** * Returns the proxy password. * * @return the proxy password */ public String getProxyPassword() { return line.getOptionValue(ARGUMENT.PROXY_PASSWORD); } /** * Get the value of dataDirectory. * * @return the value of dataDirectory */ public String getDataDirectory() { return line.getOptionValue(ARGUMENT.DATA_DIRECTORY); } /** * Returns the properties file specified on the command line. * * @return the properties file specified on the command line */ public File getPropertiesFile() { final String path = line.getOptionValue(ARGUMENT.PROP); if (path != null) { return new File(path); } return null; } /** * Returns the path to the verbose log file. * * @return the path to the verbose log file */ public String getVerboseLog() { return line.getOptionValue(ARGUMENT.VERBOSE_LOG); } /** * Returns the path to the suppression file. * * @return the path to the suppression file */ public String getSuppressionFile() { return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE); } /** * <p> * Prints the manifest information to standard output.</p> * <ul><li>Implementation-Title: ${pom.name}</li> * <li>Implementation-Version: ${pom.version}</li></ul> */ public void printVersionInfo() { final String version = String.format("%s version %s", Settings.getString(Settings.KEYS.APPLICATION_VAME, "dependency-check"), Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown")); System.out.println(version); } /** * Checks if the auto update feature has been disabled. If it has been * disabled via the command line this will return false. * * @return <code>true</code> if auto-update is allowed; otherwise * <code>false</code> */ public boolean isAutoUpdate() { return line != null && !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE); } /** * Checks if the update only flag has been set. * * @return <code>true</code> if the update only flag has been set; otherwise * <code>false</code>. */ public boolean isUpdateOnly() { return line != null && line.hasOption(ARGUMENT.UPDATE_ONLY); } /** * Checks if the purge NVD flag has been set. * * @return <code>true</code> if the purge nvd flag has been set; otherwise * <code>false</code>. */ public boolean isPurge() { return line != null && line.hasOption(ARGUMENT.PURGE_NVD); } /** * Returns the database driver name if specified; otherwise null is * returned. * * @return the database driver name if specified; otherwise null is returned */ public String getDatabaseDriverName() { return line.getOptionValue(ARGUMENT.DB_DRIVER); } /** * Returns the database driver path if specified; otherwise null is * returned. * * @return the database driver name if specified; otherwise null is returned */ public String getDatabaseDriverPath() { return line.getOptionValue(ARGUMENT.DB_DRIVER_PATH); } /** * Returns the database connection string if specified; otherwise null is * returned. * * @return the database connection string if specified; otherwise null is * returned */ public String getConnectionString() { return line.getOptionValue(ARGUMENT.CONNECTION_STRING); } /** * Returns the database database user name if specified; otherwise null is * returned. * * @return the database database user name if specified; otherwise null is * returned */ public String getDatabaseUser() { return line.getOptionValue(ARGUMENT.DB_NAME); } /** * Returns the database database password if specified; otherwise null is * returned. * * @return the database database password if specified; otherwise null is * returned */ public String getDatabasePassword() { return line.getOptionValue(ARGUMENT.DB_PASSWORD); } /** * Returns the additional Extensions if specified; otherwise null is * returned. * * @return the additional Extensions; otherwise null is returned */ public String getAdditionalZipExtensions() { return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS); } /** * Get the value of cveValidForHours. * * @return the value of cveValidForHours */ public Integer getCveValidForHours() { final String v = line.getOptionValue(ARGUMENT.CVE_VALID_FOR_HOURS); if (v != null) { return Integer.parseInt(v); } return null; } /** * Returns true if the experimental analyzers are enabled. * * @return true if the experimental analyzers are enabled; otherwise false */ public boolean isExperimentalEnabled() { return line.hasOption(ARGUMENT.EXPERIMENTAL); } /** * A collection of static final strings that represent the possible command * line arguments. */ public static class ARGUMENT { /** * The long CLI argument name specifying the directory/file to scan. */ public static final String SCAN = "scan"; /** * The short CLI argument name specifying the directory/file to scan. */ public static final String SCAN_SHORT = "s"; /** * The long CLI argument name specifying that the CPE/CVE/etc. data * should not be automatically updated. */ public static final String DISABLE_AUTO_UPDATE = "noupdate"; /** * The short CLI argument name specifying that the CPE/CVE/etc. data * should not be automatically updated. */ public static final String DISABLE_AUTO_UPDATE_SHORT = "n"; /** * The long CLI argument name specifying that only the update phase * should be executed; no scan should be run. */ public static final String UPDATE_ONLY = "updateonly"; /** * The long CLI argument name specifying that only the update phase * should be executed; no scan should be run. */ public static final String PURGE_NVD = "purge"; /** * The long CLI argument name specifying the directory to write the * reports to. */ public static final String OUT = "out"; /** * The short CLI argument name specifying the directory to write the * reports to. */ public static final String OUT_SHORT = "o"; /** * The long CLI argument name specifying the output format to write the * reports to. */ public static final String OUTPUT_FORMAT = "format"; /** * The short CLI argument name specifying the output format to write the * reports to. */ public static final String OUTPUT_FORMAT_SHORT = "f"; /** * The long CLI argument name specifying the name of the project to be * scanned. */ public static final String PROJECT = "project"; /** * The long CLI argument name specifying the name of the application to * be scanned. * * @deprecated project should be used instead */ @Deprecated public static final String APP_NAME = "app"; /** * The short CLI argument name specifying the name of the application to * be scanned. * * @deprecated project should be used instead */ @Deprecated public static final String APP_NAME_SHORT = "a"; /** * The long CLI argument name asking for help. */ public static final String HELP = "help"; /** * The long CLI argument name asking for advanced help. */ public static final String ADVANCED_HELP = "advancedHelp"; /** * The short CLI argument name asking for help. */ public static final String HELP_SHORT = "h"; /** * The long CLI argument name asking for the version. */ public static final String VERSION_SHORT = "v"; /** * The short CLI argument name asking for the version. */ public static final String VERSION = "version"; /** * The CLI argument name indicating the proxy port. */ public static final String PROXY_PORT = "proxyport"; /** * The CLI argument name indicating the proxy server. */ public static final String PROXY_SERVER = "proxyserver"; /** * The CLI argument name indicating the proxy url. * * @deprecated use {@link #PROXY_SERVER} instead */ @Deprecated public static final String PROXY_URL = "proxyurl"; /** * The CLI argument name indicating the proxy username. */ public static final String PROXY_USERNAME = "proxyuser"; /** * The CLI argument name indicating the proxy password. */ public static final String PROXY_PASSWORD = "proxypass"; /** * The short CLI argument name indicating the connection timeout. */ public static final String CONNECTION_TIMEOUT_SHORT = "c"; /** * The CLI argument name indicating the connection timeout. */ public static final String CONNECTION_TIMEOUT = "connectiontimeout"; /** * The short CLI argument name for setting the location of an additional * properties file. */ public static final String PROP_SHORT = "P"; /** * The CLI argument name for setting the location of an additional * properties file. */ public static final String PROP = "propertyfile"; /** * The CLI argument name for setting the location of the data directory. */ public static final String DATA_DIRECTORY = "data"; /** * The CLI argument name for setting the URL for the CVE Data Files. */ public static final String CVE_MOD_12 = "cveUrl12Modified"; /** * The CLI argument name for setting the URL for the CVE Data Files. */ public static final String CVE_MOD_20 = "cveUrl20Modified"; /** * The CLI argument name for setting the URL for the CVE Data Files. */ public static final String CVE_BASE_12 = "cveUrl12Base"; /** * The CLI argument name for setting the URL for the CVE Data Files. */ public static final String CVE_BASE_20 = "cveUrl20Base"; /** * The short CLI argument name for setting the location of the data * directory. */ public static final String DATA_DIRECTORY_SHORT = "d"; /** * The CLI argument name for setting the location of the data directory. */ public static final String VERBOSE_LOG = "log"; /** * The short CLI argument name for setting the location of the data * directory. */ public static final String VERBOSE_LOG_SHORT = "l"; /** * The CLI argument name for setting the depth of symbolic links that * will be followed. */ public static final String SYM_LINK_DEPTH = "symLink"; /** * The CLI argument name for setting the location of the suppression * file. */ public static final String SUPPRESSION_FILE = "suppression"; /** * The CLI argument name for setting the location of the suppression * file. */ public static final String CVE_VALID_FOR_HOURS = "cveValidForHours"; /** * Disables the Jar Analyzer. */ public static final String DISABLE_JAR = "disableJar"; /** * Disables the Archive Analyzer. */ public static final String DISABLE_ARCHIVE = "disableArchive"; /** * Disables the Python Distribution Analyzer. */ public static final String DISABLE_PY_DIST = "disablePyDist"; /** * Disables the Python Package Analyzer. */ public static final String DISABLE_PY_PKG = "disablePyPkg"; /** * Disables the Python Package Analyzer. */ public static final String DISABLE_COMPOSER = "disableComposer"; /** * Disables the Ruby Gemspec Analyzer. */ public static final String DISABLE_RUBYGEMS = "disableRubygems"; /** * Disables the Autoconf Analyzer. */ public static final String DISABLE_AUTOCONF = "disableAutoconf"; /** * Disables the Cmake Analyzer. */ public static final String DISABLE_CMAKE = "disableCmake"; /** * Disables the Assembly Analyzer. */ public static final String DISABLE_ASSEMBLY = "disableAssembly"; /** * Disables the Ruby Bundler Audit Analyzer. */ public static final String DISABLE_BUNDLE_AUDIT = "disableBundleAudit"; /** * Disables the Nuspec Analyzer. */ public static final String DISABLE_NUSPEC = "disableNuspec"; /** * Disables the Central Analyzer. */ public static final String DISABLE_CENTRAL = "disableCentral"; /** * Disables the Nexus Analyzer. */ public static final String DISABLE_NEXUS = "disableNexus"; /** * Disables the OpenSSL Analyzer. */ public static final String DISABLE_OPENSSL = "disableOpenSSL"; /** * Disables the Node.js Package Analyzer. */ public static final String DISABLE_NODE_JS = "disableNodeJS"; /** * The URL of the nexus server. */ public static final String NEXUS_URL = "nexus"; /** * Whether or not the defined proxy should be used when connecting to * Nexus. */ public static final String NEXUS_USES_PROXY = "nexusUsesProxy"; /** * The CLI argument name for setting the connection string. */ public static final String CONNECTION_STRING = "connectionString"; /** * The CLI argument name for setting the database user name. */ public static final String DB_NAME = "dbUser"; /** * The CLI argument name for setting the database password. */ public static final String DB_PASSWORD = "dbPassword"; /** * The CLI argument name for setting the database driver name. */ public static final String DB_DRIVER = "dbDriverName"; /** * The CLI argument name for setting the path to the database driver; in * case it is not on the class path. */ public static final String DB_DRIVER_PATH = "dbDriverPath"; /** * The CLI argument name for setting the path to mono for .NET Assembly * analysis on non-windows systems. */ public static final String PATH_TO_MONO = "mono"; /** * 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"; /** * The CLI argument name for setting the path to bundle-audit for Ruby * bundle analysis. */ public static final String PATH_TO_BUNDLE_AUDIT = "bundleAudit"; /** * The CLI argument to enable the experimental analyzers. */ private static final String EXPERIMENTAL = "enableExperimental"; } }