View Javadoc
1   /*
2    * This file is part of dependency-check-cli.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck;
19  
20  import java.io.File;
21  import java.io.FileNotFoundException;
22  
23  import org.apache.commons.cli.CommandLine;
24  import org.apache.commons.cli.CommandLineParser;
25  import org.apache.commons.cli.HelpFormatter;
26  import org.apache.commons.cli.Option;
27  import org.apache.commons.cli.OptionBuilder;
28  import org.apache.commons.cli.OptionGroup;
29  import org.apache.commons.cli.Options;
30  import org.apache.commons.cli.ParseException;
31  import org.apache.commons.cli.PosixParser;
32  import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
33  import org.owasp.dependencycheck.utils.InvalidSettingException;
34  import org.owasp.dependencycheck.utils.Settings;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  /**
39   * A utility to parse command line arguments for the DependencyCheck.
40   *
41   * @author Jeremy Long
42   */
43  public final class CliParser {
44  
45      /**
46       * The logger.
47       */
48      private static final Logger LOGGER = LoggerFactory.getLogger(CliParser.class);
49      /**
50       * The command line.
51       */
52      private CommandLine line;
53      /**
54       * Indicates whether the arguments are valid.
55       */
56      private boolean isValid = true;
57  
58      /**
59       * Parses the arguments passed in and captures the results for later use.
60       *
61       * @param args the command line arguments
62       * @throws FileNotFoundException is thrown when a 'file' argument does not point to a file that exists.
63       * @throws ParseException is thrown when a Parse Exception occurs.
64       */
65      public void parse(String[] args) throws FileNotFoundException, ParseException {
66          line = parseArgs(args);
67  
68          if (line != null) {
69              validateArgs();
70          }
71      }
72  
73      /**
74       * Parses the command line arguments.
75       *
76       * @param args the command line arguments
77       * @return the results of parsing the command line arguments
78       * @throws ParseException if the arguments are invalid
79       */
80      private CommandLine parseArgs(String[] args) throws ParseException {
81          final CommandLineParser parser = new PosixParser();
82          final Options options = createCommandLineOptions();
83          return parser.parse(options, args);
84      }
85  
86      /**
87       * Validates that the command line arguments are valid.
88       *
89       * @throws FileNotFoundException if there is a file specified by either the SCAN or CPE command line arguments that does not
90       * exist.
91       * @throws ParseException is thrown if there is an exception parsing the command line.
92       */
93      private void validateArgs() throws FileNotFoundException, ParseException {
94          if (isRunScan()) {
95              validatePathExists(getScanFiles(), ARGUMENT.SCAN);
96              validatePathExists(getReportDirectory(), ARGUMENT.OUT);
97              if (getPathToMono() != null) {
98                  validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO);
99              }
100             if (!line.hasOption(ARGUMENT.APP_NAME)) {
101                 throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
102             }
103             if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
104                 final String format = line.getOptionValue(ARGUMENT.OUTPUT_FORMAT);
105                 try {
106                     Format.valueOf(format);
107                 } catch (IllegalArgumentException ex) {
108                     final String msg = String.format("An invalid 'format' of '%s' was specified. "
109                             + "Supported output formats are XML, HTML, VULN, or ALL", format);
110                     throw new ParseException(msg);
111                 }
112             }
113             if ((getBaseCve12Url() != null || getBaseCve20Url() != null || getModifiedCve12Url() != null || getModifiedCve20Url() != null)
114                     && (getBaseCve12Url() == null || getBaseCve20Url() == null || getModifiedCve12Url() == null || getModifiedCve20Url() == null)) {
115                 final String msg = "If one of the CVE URLs is specified they must all be specified; please add the missing CVE URL.";
116                 throw new ParseException(msg);
117             }
118             if (line.hasOption((ARGUMENT.SYM_LINK_DEPTH))) {
119                 try {
120                     final int i = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH));
121                     if (i < 0) {
122                         throw new ParseException("Symbolic Link Depth (symLink) must be greater than zero.");
123                     }
124                 } catch (NumberFormatException ex) {
125                     throw new ParseException("Symbolic Link Depth (symLink) is not a number.");
126                 }
127             }
128         }
129     }
130 
131     /**
132      * 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
133      * FileNotFoundException is thrown.
134      *
135      * @param paths the paths to validate if they exists
136      * @param optType the option being validated (e.g. scan, out, etc.)
137      * @throws FileNotFoundException is thrown if one of the paths being validated does not exist.
138      */
139     private void validatePathExists(String[] paths, String optType) throws FileNotFoundException {
140         for (String path : paths) {
141             validatePathExists(path, optType);
142         }
143     }
144 
145     /**
146      * Validates whether or not the path points at a file that exists; if the path does not point to an existing file a
147      * FileNotFoundException is thrown.
148      *
149      * @param path the paths to validate if they exists
150      * @param argumentName the argument being validated (e.g. scan, out, etc.)
151      * @throws FileNotFoundException is thrown if the path being validated does not exist.
152      */
153     private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
154         if (path == null) {
155             isValid = false;
156             final String msg = String.format("Invalid '%s' argument: null", argumentName);
157             throw new FileNotFoundException(msg);
158         } else if (!path.contains("*") && !path.contains("?")) {
159             File f = new File(path);
160             if ("o".equalsIgnoreCase(argumentName.substring(0, 1)) && !"ALL".equalsIgnoreCase(this.getReportFormat())) {
161                 final String checkPath = path.toLowerCase();
162                 if (checkPath.endsWith(".html") || checkPath.endsWith(".xml") || checkPath.endsWith(".htm")) {
163                     if (f.getParentFile() == null) {
164                         f = new File(".", path);
165                     }
166                     if (!f.getParentFile().isDirectory()) {
167                         isValid = false;
168                         final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
169                         throw new FileNotFoundException(msg);
170                     }
171                 }
172             } else {
173                 if (!f.exists()) {
174                     isValid = false;
175                     final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
176                     throw new FileNotFoundException(msg);
177                 }
178             }
179         } else if (path.startsWith("//") || path.startsWith("\\\\")) {
180             isValid = false;
181             final String msg = String.format("Invalid '%s' argument: '%s'%nUnable to scan paths that start with '//'.", argumentName, path);
182             throw new FileNotFoundException(msg);
183         }
184     }
185 
186     /**
187      * Generates an Options collection that is used to parse the command line and to display the help message.
188      *
189      * @return the command line options used for parsing the command line
190      */
191     @SuppressWarnings("static-access")
192     private Options createCommandLineOptions() {
193         final Options options = new Options();
194         addStandardOptions(options);
195         addAdvancedOptions(options);
196         addDeprecatedOptions(options);
197         return options;
198     }
199 
200     /**
201      * Adds the standard command line options to the given options collection.
202      *
203      * @param options a collection of command line arguments
204      * @throws IllegalArgumentException thrown if there is an exception
205      */
206     @SuppressWarnings("static-access")
207     private void addStandardOptions(final Options options) throws IllegalArgumentException {
208         final Option help = new Option(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, false,
209                 "Print this message.");
210 
211         final Option advancedHelp = OptionBuilder.withLongOpt(ARGUMENT.ADVANCED_HELP)
212                 .withDescription("Print the advanced help message.").create();
213 
214         final Option version = new Option(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION,
215                 false, "Print the version information.");
216 
217         final Option noUpdate = new Option(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE,
218                 false, "Disables the automatic updating of the CPE data.");
219 
220         final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ARGUMENT.APP_NAME)
221                 .withDescription("The name of the application being scanned. This is a required argument.")
222                 .create(ARGUMENT.APP_NAME_SHORT);
223 
224         final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
225                 .withDescription("The path to scan - this option can be specified multiple times. Ant style"
226                         + " paths are supported (e.g. path/**/*.jar).")
227                 .create(ARGUMENT.SCAN_SHORT);
228 
229         final Option excludes = OptionBuilder.withArgName("pattern").hasArg().withLongOpt(ARGUMENT.EXCLUDE)
230                 .withDescription("Specify and exclusion pattern. This option can be specified multiple times"
231                         + " and it accepts Ant style excludsions.")
232                 .create();
233 
234         final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
235                 .withDescription("A property file to load.")
236                 .create(ARGUMENT.PROP_SHORT);
237 
238         final Option out = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.OUT)
239                 .withDescription("The folder to write reports to. This defaults to the current directory. "
240                         + "It is possible to set this to a specific file name if the format argument is not set to ALL.")
241                 .create(ARGUMENT.OUT_SHORT);
242 
243         final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
244                 .withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
245                 .create(ARGUMENT.OUTPUT_FORMAT_SHORT);
246 
247         final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.VERBOSE_LOG)
248                 .withDescription("The file path to write verbose logging information.")
249                 .create(ARGUMENT.VERBOSE_LOG_SHORT);
250 
251         final Option symLinkDepth = OptionBuilder.withArgName("depth").hasArg().withLongOpt(ARGUMENT.SYM_LINK_DEPTH)
252                 .withDescription("Sets how deep nested symbolic links will be followed; 0 indicates symbolic links will not be followed.")
253                 .create();
254 
255         final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
256                 .withDescription("The file path to the suppression XML file.")
257                 .create();
258 
259         //This is an option group because it can be specified more then once.
260         final OptionGroup og = new OptionGroup();
261         og.addOption(path);
262 
263         final OptionGroup exog = new OptionGroup();
264         exog.addOption(excludes);
265 
266         options.addOptionGroup(og)
267                 .addOptionGroup(exog)
268                 .addOption(out)
269                 .addOption(outputFormat)
270                 .addOption(appName)
271                 .addOption(version)
272                 .addOption(help)
273                 .addOption(advancedHelp)
274                 .addOption(noUpdate)
275                 .addOption(symLinkDepth)
276                 .addOption(props)
277                 .addOption(verboseLog)
278                 .addOption(suppressionFile);
279     }
280 
281     /**
282      * Adds the advanced command line options to the given options collection. These are split out for purposes of being able to
283      * display two different help messages.
284      *
285      * @param options a collection of command line arguments
286      * @throws IllegalArgumentException thrown if there is an exception
287      */
288     @SuppressWarnings("static-access")
289     private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
290 
291         final Option cve12Base = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_BASE_12)
292                 .withDescription("Base URL for each year’s CVE 1.2, the %d will be replaced with the year. ")
293                 .create();
294 
295         final Option cve20Base = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_BASE_20)
296                 .withDescription("Base URL for each year’s CVE 2.0, the %d will be replaced with the year.")
297                 .create();
298 
299         final Option cve12Modified = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_MOD_12)
300                 .withDescription("URL for the modified CVE 1.2.")
301                 .create();
302 
303         final Option cve20Modified = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_MOD_20)
304                 .withDescription("URL for the modified CVE 2.0.")
305                 .create();
306 
307         final Option updateOnly = OptionBuilder.withLongOpt(ARGUMENT.UPDATE_ONLY)
308                 .withDescription("Only update the local NVD data cache; no scan will be executed.").create();
309 
310         final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DATA_DIRECTORY)
311                 .withDescription("The location of the H2 Database file. This option should generally not be set.")
312                 .create(ARGUMENT.DATA_DIRECTORY_SHORT);
313 
314         final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
315                 .withDescription("The url to the Nexus Server's REST API Endpoint (http://domain/nexus/service/local). "
316                         + "If not set the Nexus Analyzer will be disabled.").create();
317 
318         final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.NEXUS_USES_PROXY)
319                 .withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
320                 .create();
321 
322         final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
323                 .withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
324                 .withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
325                         + "(ZIP, EAR, WAR are already treated as zip files)").create();
326 
327         final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.PATH_TO_MONO)
328                 .withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
329                 .create();
330 
331         final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
332                 .withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
333                 .create(ARGUMENT.CONNECTION_TIMEOUT_SHORT);
334 
335         final Option proxyServer = OptionBuilder.withArgName("server").hasArg().withLongOpt(ARGUMENT.PROXY_SERVER)
336                 .withDescription("The proxy server to use when downloading resources.").create();
337 
338         final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ARGUMENT.PROXY_PORT)
339                 .withDescription("The proxy port to use when downloading resources.").create();
340 
341         final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.PROXY_USERNAME)
342                 .withDescription("The proxy username to use when downloading resources.").create();
343 
344         final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ARGUMENT.PROXY_PASSWORD)
345                 .withDescription("The proxy password to use when downloading resources.").create();
346 
347         final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ARGUMENT.CONNECTION_STRING)
348                 .withDescription("The connection string to the database.").create();
349 
350         final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.DB_NAME)
351                 .withDescription("The username used to connect to the database.").create();
352 
353         final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ARGUMENT.DB_PASSWORD)
354                 .withDescription("The password for connecting to the database.").create();
355 
356         final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ARGUMENT.DB_DRIVER)
357                 .withDescription("The database driver name.").create();
358 
359         final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DB_DRIVER_PATH)
360                 .withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
361                 .create();
362 
363         final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
364                 .withDescription("Disable the Jar Analyzer.").create();
365 
366         final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
367                 .withDescription("Disable the Archive Analyzer.").create();
368 
369         final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
370                 .withDescription("Disable the Nuspec Analyzer.").create();
371 
372         final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
373                 .withDescription("Disable the .NET Assembly Analyzer.").create();
374 
375         final Option disablePythonDistributionAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_PY_DIST)
376                 .withDescription("Disable the Python Distribution Analyzer.").create();
377 
378         final Option disablePythonPackageAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_PY_PKG)
379                 .withDescription("Disable the Python Package Analyzer.").create();
380 
381         final Option disableAutoconfAnalyzer = OptionBuilder
382                 .withLongOpt(ARGUMENT.DISABLE_AUTOCONF)
383                 .withDescription("Disable the Autoconf Analyzer.").create();
384 
385         final Option disableOpenSSLAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_OPENSSL)
386                 .withDescription("Disable the OpenSSL Analyzer.").create();
387         final Option disableCmakeAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_CMAKE).
388                 withDescription("Disable the Cmake Analyzer.").create();
389 
390         final Option disableCentralAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_CENTRAL)
391                 .withDescription("Disable the Central Analyzer. If this analyzer is disabled it is likely you also want to disable "
392                         + "the Nexus Analyzer.").create();
393 
394         final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
395                 .withDescription("Disable the Nexus Analyzer.").create();
396 
397         options.addOption(updateOnly)
398                 .addOption(cve12Base)
399                 .addOption(cve20Base)
400                 .addOption(cve12Modified)
401                 .addOption(cve20Modified)
402                 .addOption(proxyPort)
403                 .addOption(proxyServer)
404                 .addOption(proxyUsername)
405                 .addOption(proxyPassword)
406                 .addOption(connectionTimeout)
407                 .addOption(connectionString)
408                 .addOption(dbUser)
409                 .addOption(data)
410                 .addOption(dbPassword)
411                 .addOption(dbDriver)
412                 .addOption(dbDriverPath)
413                 .addOption(disableJarAnalyzer)
414                 .addOption(disableArchiveAnalyzer)
415                 .addOption(disableAssemblyAnalyzer)
416                 .addOption(disablePythonDistributionAnalyzer)
417                 .addOption(disableCmakeAnalyzer)
418                 .addOption(disablePythonPackageAnalyzer)
419                 .addOption(disableAutoconfAnalyzer)
420                 .addOption(disableOpenSSLAnalyzer)
421                 .addOption(disableNuspecAnalyzer)
422                 .addOption(disableCentralAnalyzer)
423                 .addOption(disableNexusAnalyzer)
424                 .addOption(nexusUrl)
425                 .addOption(nexusUsesProxy)
426                 .addOption(additionalZipExtensions)
427                 .addOption(pathToMono);
428     }
429 
430     /**
431      * Adds the deprecated command line options to the given options collection. These are split out for purposes of not including
432      * them in the help message. We need to add the deprecated options so as not to break existing scripts.
433      *
434      * @param options a collection of command line arguments
435      * @throws IllegalArgumentException thrown if there is an exception
436      */
437     @SuppressWarnings({"static-access", "deprecation"})
438     private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
439 
440         final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
441                 .withDescription("The proxy url argument is deprecated, use proxyserver instead.")
442                 .create();
443 
444         options.addOption(proxyServer);
445     }
446 
447     /**
448      * Determines if the 'version' command line argument was passed in.
449      *
450      * @return whether or not the 'version' command line argument was passed in
451      */
452     public boolean isGetVersion() {
453         return (line != null) && line.hasOption(ARGUMENT.VERSION);
454     }
455 
456     /**
457      * Determines if the 'help' command line argument was passed in.
458      *
459      * @return whether or not the 'help' command line argument was passed in
460      */
461     public boolean isGetHelp() {
462         return (line != null) && line.hasOption(ARGUMENT.HELP);
463     }
464 
465     /**
466      * Determines if the 'scan' command line argument was passed in.
467      *
468      * @return whether or not the 'scan' command line argument was passed in
469      */
470     public boolean isRunScan() {
471         return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
472     }
473 
474     /**
475      * Returns the symbolic link depth (how deeply symbolic links will be followed).
476      *
477      * @return the symbolic link depth
478      */
479     public int getSymLinkDepth() {
480         int value = 0;
481         try {
482             value = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH, "0"));
483             if (value < 0) {
484                 value = 0;
485             }
486         } catch (NumberFormatException ex) {
487             LOGGER.debug("Symbolic link was not a number");
488         }
489         return value;
490     }
491 
492     /**
493      * Returns true if the disableJar command line argument was specified.
494      *
495      * @return true if the disableJar command line argument was specified; otherwise false
496      */
497     public boolean isJarDisabled() {
498         return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
499     }
500 
501     /**
502      * Returns true if the disableArchive command line argument was specified.
503      *
504      * @return true if the disableArchive command line argument was specified; otherwise false
505      */
506     public boolean isArchiveDisabled() {
507         return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
508     }
509 
510     /**
511      * Returns true if the disableNuspec command line argument was specified.
512      *
513      * @return true if the disableNuspec command line argument was specified; otherwise false
514      */
515     public boolean isNuspecDisabled() {
516         return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
517     }
518 
519     /**
520      * Returns true if the disableAssembly command line argument was specified.
521      *
522      * @return true if the disableAssembly command line argument was specified; otherwise false
523      */
524     public boolean isAssemblyDisabled() {
525         return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
526     }
527 
528     /**
529      * Returns true if the disablePyDist command line argument was specified.
530      *
531      * @return true if the disablePyDist command line argument was specified; otherwise false
532      */
533     public boolean isPythonDistributionDisabled() {
534         return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_DIST);
535     }
536 
537     /**
538      * Returns true if the disablePyPkg command line argument was specified.
539      *
540      * @return true if the disablePyPkg command line argument was specified; otherwise false
541      */
542     public boolean isPythonPackageDisabled() {
543         return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_PKG);
544     }
545 
546     /**
547      * Returns true if the disableCmake command line argument was specified.
548      *
549      * @return true if the disableCmake command line argument was specified; otherwise false
550      */
551     public boolean isCmakeDisabled() {
552         return (line != null) && line.hasOption(ARGUMENT.DISABLE_CMAKE);
553     }
554 
555     /**
556      * Returns true if the disableAutoconf command line argument was specified.
557      *
558      * @return true if the disableAutoconf command line argument was specified; otherwise false
559      */
560     public boolean isAutoconfDisabled() {
561         return (line != null) && line.hasOption(ARGUMENT.DISABLE_AUTOCONF);
562     }
563 
564     /**
565      * Returns true if the disableNexus command line argument was specified.
566      *
567      * @return true if the disableNexus command line argument was specified; otherwise false
568      */
569     public boolean isNexusDisabled() {
570         return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
571     }
572 
573     /**
574      * Returns true if the disableOpenSSL command line argument was specified.
575      *
576      * @return true if the disableOpenSSL command line argument was specified; otherwise false
577      */
578     public boolean isOpenSSLDisabled() {
579         return (line != null) && line.hasOption(ARGUMENT.DISABLE_OPENSSL);
580     }
581 
582     /**
583      * Returns true if the disableCentral command line argument was specified.
584      *
585      * @return true if the disableCentral command line argument was specified; otherwise false
586      */
587     public boolean isCentralDisabled() {
588         return (line != null) && line.hasOption(ARGUMENT.DISABLE_CENTRAL);
589     }
590 
591     /**
592      * Returns the url to the nexus server if one was specified.
593      *
594      * @return the url to the nexus server; if none was specified this will return null;
595      */
596     public String getNexusUrl() {
597         if (line == null || !line.hasOption(ARGUMENT.NEXUS_URL)) {
598             return null;
599         } else {
600             return line.getOptionValue(ARGUMENT.NEXUS_URL);
601         }
602     }
603 
604     /**
605      * Returns true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false is returned.
606      *
607      * @return true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false
608      */
609     public boolean isNexusUsesProxy() {
610         // If they didn't specify whether Nexus needs to use the proxy, we should
611         // still honor the property if it's set.
612         if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
613             try {
614                 return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
615             } catch (InvalidSettingException ise) {
616                 return true;
617             }
618         } else {
619             return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY));
620         }
621     }
622 
623     /**
624      * Displays the command line help message to the standard output.
625      */
626     public void printHelp() {
627         final HelpFormatter formatter = new HelpFormatter();
628         final Options options = new Options();
629         addStandardOptions(options);
630         if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) {
631             addAdvancedOptions(options);
632         }
633         final String helpMsg = String.format("%n%s"
634                 + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. "
635                 + "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n",
636                 Settings.getString("application.name", "DependencyCheck"),
637                 Settings.getString("application.name", "DependencyCheck"));
638 
639         formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
640                 helpMsg,
641                 options,
642                 "",
643                 true);
644     }
645 
646     /**
647      * Retrieves the file command line parameter(s) specified for the 'scan' argument.
648      *
649      * @return the file paths specified on the command line for scan
650      */
651     public String[] getScanFiles() {
652         return line.getOptionValues(ARGUMENT.SCAN);
653     }
654 
655     /**
656      * Retrieves the list of excluded file patterns specified by the 'exclude' argument.
657      *
658      * @return the excluded file patterns
659      */
660     public String[] getExcludeList() {
661         return line.getOptionValues(ARGUMENT.EXCLUDE);
662     }
663 
664     /**
665      * Returns the directory to write the reports to specified on the command line.
666      *
667      * @return the path to the reports directory.
668      */
669     public String getReportDirectory() {
670         return line.getOptionValue(ARGUMENT.OUT, ".");
671     }
672 
673     /**
674      * Returns the path to Mono for .NET Assembly analysis on non-windows systems.
675      *
676      * @return the path to Mono
677      */
678     public String getPathToMono() {
679         return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
680     }
681 
682     /**
683      * Returns the output format specified on the command line. Defaults to HTML if no format was specified.
684      *
685      * @return the output format name.
686      */
687     public String getReportFormat() {
688         return line.getOptionValue(ARGUMENT.OUTPUT_FORMAT, "HTML");
689     }
690 
691     /**
692      * Returns the application name specified on the command line.
693      *
694      * @return the application name.
695      */
696     public String getApplicationName() {
697         return line.getOptionValue(ARGUMENT.APP_NAME);
698     }
699 
700     /**
701      * Returns the base URL for the CVE 1.2 XMl file.
702      *
703      * @return the URL to the CVE 1.2 XML file.
704      */
705     public String getBaseCve12Url() {
706         return line.getOptionValue(ARGUMENT.CVE_BASE_12);
707     }
708 
709     /**
710      * Returns the base URL for the CVE 2.0 XMl file.
711      *
712      * @return the URL to the CVE 2.0 XML file.
713      */
714     public String getBaseCve20Url() {
715         return line.getOptionValue(ARGUMENT.CVE_BASE_20);
716     }
717 
718     /**
719      * Returns the URL for the modified CVE 1.2 XMl file.
720      *
721      * @return the URL to the modified CVE 1.2 XML file.
722      */
723     public String getModifiedCve12Url() {
724         return line.getOptionValue(ARGUMENT.CVE_MOD_12);
725     }
726 
727     /**
728      * Returns the URL for the modified CVE 2.0 XMl file.
729      *
730      * @return the URL to the modified CVE 2.0 XML file.
731      */
732     public String getModifiedCve20Url() {
733         return line.getOptionValue(ARGUMENT.CVE_MOD_20);
734     }
735 
736     /**
737      * Returns the connection timeout.
738      *
739      * @return the connection timeout
740      */
741     public String getConnectionTimeout() {
742         return line.getOptionValue(ARGUMENT.CONNECTION_TIMEOUT);
743     }
744 
745     /**
746      * Returns the proxy server.
747      *
748      * @return the proxy server
749      */
750     @SuppressWarnings("deprecation")
751     public String getProxyServer() {
752 
753         String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
754         if (server == null) {
755             server = line.getOptionValue(ARGUMENT.PROXY_URL);
756             if (server != null) {
757                 LOGGER.warn("An old command line argument 'proxyurl' was detected; use proxyserver instead");
758             }
759         }
760         return server;
761     }
762 
763     /**
764      * Returns the proxy port.
765      *
766      * @return the proxy port
767      */
768     public String getProxyPort() {
769         return line.getOptionValue(ARGUMENT.PROXY_PORT);
770     }
771 
772     /**
773      * Returns the proxy username.
774      *
775      * @return the proxy username
776      */
777     public String getProxyUsername() {
778         return line.getOptionValue(ARGUMENT.PROXY_USERNAME);
779     }
780 
781     /**
782      * Returns the proxy password.
783      *
784      * @return the proxy password
785      */
786     public String getProxyPassword() {
787         return line.getOptionValue(ARGUMENT.PROXY_PASSWORD);
788     }
789 
790     /**
791      * Get the value of dataDirectory.
792      *
793      * @return the value of dataDirectory
794      */
795     public String getDataDirectory() {
796         return line.getOptionValue(ARGUMENT.DATA_DIRECTORY);
797     }
798 
799     /**
800      * Returns the properties file specified on the command line.
801      *
802      * @return the properties file specified on the command line
803      */
804     public File getPropertiesFile() {
805         final String path = line.getOptionValue(ARGUMENT.PROP);
806         if (path != null) {
807             return new File(path);
808         }
809         return null;
810     }
811 
812     /**
813      * Returns the path to the verbose log file.
814      *
815      * @return the path to the verbose log file
816      */
817     public String getVerboseLog() {
818         return line.getOptionValue(ARGUMENT.VERBOSE_LOG);
819     }
820 
821     /**
822      * Returns the path to the suppression file.
823      *
824      * @return the path to the suppression file
825      */
826     public String getSuppressionFile() {
827         return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
828     }
829 
830     /**
831      * <p>
832      * Prints the manifest information to standard output.</p>
833      * <ul><li>Implementation-Title: ${pom.name}</li>
834      * <li>Implementation-Version: ${pom.version}</li></ul>
835      */
836     public void printVersionInfo() {
837         final String version = String.format("%s version %s",
838                 Settings.getString(Settings.KEYS.APPLICATION_VAME, "dependency-check"),
839                 Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
840         System.out.println(version);
841     }
842 
843     /**
844      * Checks if the auto update feature has been disabled. If it has been disabled via the command line this will return false.
845      *
846      * @return <code>true</code> if auto-update is allowed; otherwise <code>false</code>
847      */
848     public boolean isAutoUpdate() {
849         return (line == null) || !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
850     }
851 
852     /**
853      * Checks if the update only flag has been set.
854      *
855      * @return <code>true</code> if the update only flag has been set; otherwise <code>false</code>.
856      */
857     public boolean isUpdateOnly() {
858         return (line == null) || line.hasOption(ARGUMENT.UPDATE_ONLY);
859     }
860 
861     /**
862      * Returns the database driver name if specified; otherwise null is returned.
863      *
864      * @return the database driver name if specified; otherwise null is returned
865      */
866     public String getDatabaseDriverName() {
867         return line.getOptionValue(ARGUMENT.DB_DRIVER);
868     }
869 
870     /**
871      * Returns the database driver path if specified; otherwise null is returned.
872      *
873      * @return the database driver name if specified; otherwise null is returned
874      */
875     public String getDatabaseDriverPath() {
876         return line.getOptionValue(ARGUMENT.DB_DRIVER_PATH);
877     }
878 
879     /**
880      * Returns the database connection string if specified; otherwise null is returned.
881      *
882      * @return the database connection string if specified; otherwise null is returned
883      */
884     public String getConnectionString() {
885         return line.getOptionValue(ARGUMENT.CONNECTION_STRING);
886     }
887 
888     /**
889      * Returns the database database user name if specified; otherwise null is returned.
890      *
891      * @return the database database user name if specified; otherwise null is returned
892      */
893     public String getDatabaseUser() {
894         return line.getOptionValue(ARGUMENT.DB_NAME);
895     }
896 
897     /**
898      * Returns the database database password if specified; otherwise null is returned.
899      *
900      * @return the database database password if specified; otherwise null is returned
901      */
902     public String getDatabasePassword() {
903         return line.getOptionValue(ARGUMENT.DB_PASSWORD);
904     }
905 
906     /**
907      * Returns the additional Extensions if specified; otherwise null is returned.
908      *
909      * @return the additional Extensions; otherwise null is returned
910      */
911     public String getAdditionalZipExtensions() {
912         return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS);
913     }
914 
915     /**
916      * A collection of static final strings that represent the possible command line arguments.
917      */
918     public static class ARGUMENT {
919 
920         /**
921          * The long CLI argument name specifying the directory/file to scan.
922          */
923         public static final String SCAN = "scan";
924         /**
925          * The short CLI argument name specifying the directory/file to scan.
926          */
927         public static final String SCAN_SHORT = "s";
928         /**
929          * The long CLI argument name specifying that the CPE/CVE/etc. data should not be automatically updated.
930          */
931         public static final String DISABLE_AUTO_UPDATE = "noupdate";
932         /**
933          * The short CLI argument name specifying that the CPE/CVE/etc. data should not be automatically updated.
934          */
935         public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
936         /**
937          * The long CLI argument name specifying that only the update phase should be executed; no scan should be run.
938          */
939         public static final String UPDATE_ONLY = "updateonly";
940         /**
941          * The long CLI argument name specifying the directory to write the reports to.
942          */
943         public static final String OUT = "out";
944         /**
945          * The short CLI argument name specifying the directory to write the reports to.
946          */
947         public static final String OUT_SHORT = "o";
948         /**
949          * The long CLI argument name specifying the output format to write the reports to.
950          */
951         public static final String OUTPUT_FORMAT = "format";
952         /**
953          * The short CLI argument name specifying the output format to write the reports to.
954          */
955         public static final String OUTPUT_FORMAT_SHORT = "f";
956         /**
957          * The long CLI argument name specifying the name of the application to be scanned.
958          */
959         public static final String APP_NAME = "app";
960         /**
961          * The short CLI argument name specifying the name of the application to be scanned.
962          */
963         public static final String APP_NAME_SHORT = "a";
964         /**
965          * The long CLI argument name asking for help.
966          */
967         public static final String HELP = "help";
968         /**
969          * The long CLI argument name asking for advanced help.
970          */
971         public static final String ADVANCED_HELP = "advancedHelp";
972         /**
973          * The short CLI argument name asking for help.
974          */
975         public static final String HELP_SHORT = "h";
976         /**
977          * The long CLI argument name asking for the version.
978          */
979         public static final String VERSION_SHORT = "v";
980         /**
981          * The short CLI argument name asking for the version.
982          */
983         public static final String VERSION = "version";
984         /**
985          * The CLI argument name indicating the proxy port.
986          */
987         public static final String PROXY_PORT = "proxyport";
988         /**
989          * The CLI argument name indicating the proxy server.
990          */
991         public static final String PROXY_SERVER = "proxyserver";
992         /**
993          * The CLI argument name indicating the proxy url.
994          *
995          * @deprecated use {@link #PROXY_SERVER} instead
996          */
997         @Deprecated
998         public static final String PROXY_URL = "proxyurl";
999         /**
1000          * The CLI argument name indicating the proxy username.
1001          */
1002         public static final String PROXY_USERNAME = "proxyuser";
1003         /**
1004          * The CLI argument name indicating the proxy password.
1005          */
1006         public static final String PROXY_PASSWORD = "proxypass";
1007         /**
1008          * The short CLI argument name indicating the connection timeout.
1009          */
1010         public static final String CONNECTION_TIMEOUT_SHORT = "c";
1011         /**
1012          * The CLI argument name indicating the connection timeout.
1013          */
1014         public static final String CONNECTION_TIMEOUT = "connectiontimeout";
1015         /**
1016          * The short CLI argument name for setting the location of an additional properties file.
1017          */
1018         public static final String PROP_SHORT = "P";
1019         /**
1020          * The CLI argument name for setting the location of an additional properties file.
1021          */
1022         public static final String PROP = "propertyfile";
1023         /**
1024          * The CLI argument name for setting the location of the data directory.
1025          */
1026         public static final String DATA_DIRECTORY = "data";
1027         /**
1028          * The CLI argument name for setting the URL for the CVE Data Files.
1029          */
1030         public static final String CVE_MOD_12 = "cveUrl12Modified";
1031         /**
1032          * The CLI argument name for setting the URL for the CVE Data Files.
1033          */
1034         public static final String CVE_MOD_20 = "cveUrl20Modified";
1035         /**
1036          * The CLI argument name for setting the URL for the CVE Data Files.
1037          */
1038         public static final String CVE_BASE_12 = "cveUrl12Base";
1039         /**
1040          * The CLI argument name for setting the URL for the CVE Data Files.
1041          */
1042         public static final String CVE_BASE_20 = "cveUrl20Base";
1043         /**
1044          * The short CLI argument name for setting the location of the data directory.
1045          */
1046         public static final String DATA_DIRECTORY_SHORT = "d";
1047         /**
1048          * The CLI argument name for setting the location of the data directory.
1049          */
1050         public static final String VERBOSE_LOG = "log";
1051         /**
1052          * The short CLI argument name for setting the location of the data directory.
1053          */
1054         public static final String VERBOSE_LOG_SHORT = "l";
1055 
1056         /**
1057          * The CLI argument name for setting the depth of symbolic links that will be followed.
1058          */
1059         public static final String SYM_LINK_DEPTH = "symLink";
1060         /**
1061          * The CLI argument name for setting the location of the suppression file.
1062          */
1063         public static final String SUPPRESSION_FILE = "suppression";
1064         /**
1065          * Disables the Jar Analyzer.
1066          */
1067         public static final String DISABLE_JAR = "disableJar";
1068         /**
1069          * Disables the Archive Analyzer.
1070          */
1071         public static final String DISABLE_ARCHIVE = "disableArchive";
1072         /**
1073          * Disables the Python Distribution Analyzer.
1074          */
1075         public static final String DISABLE_PY_DIST = "disablePyDist";
1076         /**
1077          * Disables the Python Package Analyzer.
1078          */
1079         public static final String DISABLE_PY_PKG = "disablePyPkg";
1080         /**
1081          * Disables the Autoconf Analyzer.
1082          */
1083         public static final String DISABLE_AUTOCONF = "disableAutoconf";
1084         /**
1085          * Disables the Cmake Analyzer.
1086          */
1087         public static final String DISABLE_CMAKE = "disableCmake";
1088         /**
1089          * Disables the Assembly Analyzer.
1090          */
1091         public static final String DISABLE_ASSEMBLY = "disableAssembly";
1092         /**
1093          * Disables the Nuspec Analyzer.
1094          */
1095         public static final String DISABLE_NUSPEC = "disableNuspec";
1096         /**
1097          * Disables the Central Analyzer.
1098          */
1099         public static final String DISABLE_CENTRAL = "disableCentral";
1100         /**
1101          * Disables the Nexus Analyzer.
1102          */
1103         public static final String DISABLE_NEXUS = "disableNexus";
1104         /**
1105          * Disables the OpenSSL Analyzer.
1106          */
1107         public static final String DISABLE_OPENSSL = "disableOpenSSL";
1108         /**
1109          * The URL of the nexus server.
1110          */
1111         public static final String NEXUS_URL = "nexus";
1112         /**
1113          * Whether or not the defined proxy should be used when connecting to Nexus.
1114          */
1115         public static final String NEXUS_USES_PROXY = "nexusUsesProxy";
1116         /**
1117          * The CLI argument name for setting the connection string.
1118          */
1119         public static final String CONNECTION_STRING = "connectionString";
1120         /**
1121          * The CLI argument name for setting the database user name.
1122          */
1123         public static final String DB_NAME = "dbUser";
1124         /**
1125          * The CLI argument name for setting the database password.
1126          */
1127         public static final String DB_PASSWORD = "dbPassword";
1128         /**
1129          * The CLI argument name for setting the database driver name.
1130          */
1131         public static final String DB_DRIVER = "dbDriverName";
1132         /**
1133          * The CLI argument name for setting the path to the database driver; in case it is not on the class path.
1134          */
1135         public static final String DB_DRIVER_PATH = "dbDriverPath";
1136         /**
1137          * The CLI argument name for setting the path to mono for .NET Assembly analysis on non-windows systems.
1138          */
1139         public static final String PATH_TO_MONO = "mono";
1140         /**
1141          * The CLI argument name for setting extra extensions.
1142          */
1143         public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
1144         /**
1145          * Exclude path argument.
1146          */
1147         public static final String EXCLUDE = "exclude";
1148     }
1149 }