1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.cli;
19
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import org.apache.commons.cli.CommandLine;
23 import org.apache.commons.cli.CommandLineParser;
24 import org.apache.commons.cli.HelpFormatter;
25 import org.apache.commons.cli.Option;
26 import org.apache.commons.cli.OptionBuilder;
27 import org.apache.commons.cli.OptionGroup;
28 import org.apache.commons.cli.Options;
29 import org.apache.commons.cli.ParseException;
30 import org.apache.commons.cli.PosixParser;
31 import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
32 import org.owasp.dependencycheck.utils.Settings;
33
34
35
36
37
38
39 public final class CliParser {
40
41
42
43
44 private CommandLine line;
45
46
47
48 private boolean isValid = true;
49
50
51
52
53
54
55
56
57 public void parse(String[] args) throws FileNotFoundException, ParseException {
58 line = parseArgs(args);
59
60 if (line != null) {
61 validateArgs();
62 }
63 }
64
65
66
67
68
69
70
71
72 private CommandLine parseArgs(String[] args) throws ParseException {
73 final CommandLineParser parser = new PosixParser();
74 final Options options = createCommandLineOptions();
75 return parser.parse(options, args);
76 }
77
78
79
80
81
82
83
84
85 private void validateArgs() throws FileNotFoundException, ParseException {
86 if (isRunScan()) {
87 validatePathExists(getScanFiles(), "scan");
88 validatePathExists(getReportDirectory(), "out");
89 if (!line.hasOption(ArgumentName.APP_NAME)) {
90 throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
91 }
92 if (line.hasOption(ArgumentName.OUTPUT_FORMAT)) {
93 final String format = line.getOptionValue(ArgumentName.OUTPUT_FORMAT);
94 try {
95 Format.valueOf(format);
96 } catch (IllegalArgumentException ex) {
97 final String msg = String.format("An invalid 'format' of '%s' was specified. "
98 + "Supported output formats are XML, HTML, VULN, or ALL", format);
99 throw new ParseException(msg);
100 }
101 }
102 }
103 }
104
105
106
107
108
109
110
111
112
113 private void validatePathExists(String[] paths, String optType) throws FileNotFoundException {
114 for (String path : paths) {
115 validatePathExists(path, optType);
116 }
117 }
118
119
120
121
122
123
124
125
126
127 private void validatePathExists(String path, String optType) throws FileNotFoundException {
128 final File f = new File(path);
129 if (!f.exists()) {
130 isValid = false;
131 final String msg = String.format("Invalid '%s' argument: '%s'", optType, path);
132 throw new FileNotFoundException(msg);
133 }
134 }
135
136
137
138
139
140
141 @SuppressWarnings("static-access")
142 private Options createCommandLineOptions() {
143
144 final Options options = new Options();
145 addStandardOptions(options);
146 addAdvancedOptions(options);
147
148 return options;
149 }
150
151
152
153
154
155
156
157 @SuppressWarnings("static-access")
158 private void addStandardOptions(final Options options) throws IllegalArgumentException {
159 final Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
160 "Print this message.");
161
162 final Option advancedHelp = OptionBuilder.withLongOpt(ArgumentName.ADVANCED_HELP)
163 .withDescription("Print the advanced help message.").create();
164
165 final Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
166 false, "Print the version information.");
167
168 final Option noUpdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
169 false, "Disables the automatic updating of the CPE data.");
170
171 final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APP_NAME)
172 .withDescription("The name of the application being scanned. This is a required argument.")
173 .create(ArgumentName.APP_NAME_SHORT);
174
175 final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
176 .withDescription("The path to scan - this option can be specified multiple times.")
177 .create(ArgumentName.SCAN_SHORT);
178
179 final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
180 .withDescription("A property file to load.")
181 .create(ArgumentName.PROP_SHORT);
182
183 final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
184 .withDescription("The folder to write reports to. This defaults to the current directory.")
185 .create(ArgumentName.OUT_SHORT);
186
187 final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
188 .withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
189 .create(ArgumentName.OUTPUT_FORMAT_SHORT);
190
191 final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.VERBOSE_LOG)
192 .withDescription("The file path to write verbose logging information.")
193 .create(ArgumentName.VERBOSE_LOG_SHORT);
194
195 final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.SUPPRESION_FILE)
196 .withDescription("The file path to the suppression XML file.")
197 .create();
198
199 final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NEXUS)
200 .withDescription("Disable the Nexus Analyzer.")
201 .create();
202
203 final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.NEXUS_URL)
204 .withDescription("The url to the Nexus Server.")
205 .create();
206
207 final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ArgumentName.NEXUS_USES_PROXY)
208 .withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
209 .create();
210
211 final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
212 .withLongOpt(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS)
213 .withDescription("A comma seperated list of additional extensions to be scanned as ZIP files "
214 + "(ZIP, EAR, WAR are already treated as zip files)")
215 .create();
216
217
218 final OptionGroup og = new OptionGroup();
219 og.addOption(path);
220
221 options.addOptionGroup(og)
222 .addOption(out)
223 .addOption(outputFormat)
224 .addOption(appName)
225 .addOption(version)
226 .addOption(help)
227 .addOption(advancedHelp)
228 .addOption(noUpdate)
229 .addOption(props)
230 .addOption(verboseLog)
231 .addOption(suppressionFile)
232 .addOption(disableNexusAnalyzer)
233 .addOption(nexusUrl)
234 .addOption(nexusUsesProxy)
235 .addOption(additionalZipExtensions);
236 }
237
238
239
240
241
242
243
244
245 @SuppressWarnings("static-access")
246 private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
247
248 final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DATA_DIRECTORY)
249 .withDescription("The location of the H2 Database file. This option should generally not be set.")
250 .create(ArgumentName.DATA_DIRECTORY_SHORT);
251
252 final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ArgumentName.CONNECTION_TIMEOUT)
253 .withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
254 .create(ArgumentName.CONNECTION_TIMEOUT_SHORT);
255
256 final Option proxyUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.PROXY_URL)
257 .withDescription("The proxy url to use when downloading resources.")
258 .create(ArgumentName.PROXY_URL_SHORT);
259
260 final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ArgumentName.PROXY_PORT)
261 .withDescription("The proxy port to use when downloading resources.")
262 .create(ArgumentName.PROXY_PORT_SHORT);
263
264 final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.PROXY_USERNAME)
265 .withDescription("The proxy username to use when downloading resources.")
266 .create();
267
268 final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ArgumentName.PROXY_PASSWORD)
269 .withDescription("The proxy password to use when downloading resources.")
270 .create();
271
272 final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ArgumentName.CONNECTION_STRING)
273 .withDescription("The connection string to the database.")
274 .create();
275 final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.DB_NAME)
276 .withDescription("The username used to connect to the database.")
277 .create();
278 final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ArgumentName.DB_PASSWORD)
279 .withDescription("The password for connecting to the database.")
280 .create();
281 final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ArgumentName.DB_DRIVER)
282 .withDescription("The database driver name.")
283 .create();
284 final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DB_DRIVER_PATH)
285 .withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
286 .create();
287
288 options.addOption(proxyPort)
289 .addOption(proxyUrl)
290 .addOption(proxyUsername)
291 .addOption(proxyPassword)
292 .addOption(connectionTimeout)
293 .addOption(connectionString)
294 .addOption(dbUser)
295 .addOption(data)
296 .addOption(dbPassword)
297 .addOption(dbDriver)
298 .addOption(dbDriverPath);
299 }
300
301
302
303
304
305
306 public boolean isGetVersion() {
307 return (line != null) && line.hasOption(ArgumentName.VERSION);
308 }
309
310
311
312
313
314
315 public boolean isGetHelp() {
316 return (line != null) && line.hasOption(ArgumentName.HELP);
317 }
318
319
320
321
322
323
324 public boolean isRunScan() {
325 return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
326 }
327
328
329
330
331
332
333 public boolean isNexusDisabled() {
334 return (line != null) && line.hasOption(ArgumentName.DISABLE_NEXUS);
335 }
336
337
338
339
340
341
342 public String getNexusUrl() {
343 if (line == null || !line.hasOption(ArgumentName.NEXUS_URL)) {
344 return null;
345 } else {
346 return line.getOptionValue(ArgumentName.NEXUS_URL);
347 }
348 }
349
350
351
352
353
354
355
356 public boolean isNexusUsesProxy() {
357 if (line == null || !line.hasOption(ArgumentName.NEXUS_USES_PROXY)) {
358 return true;
359 } else {
360 return Boolean.parseBoolean(line.getOptionValue(ArgumentName.NEXUS_USES_PROXY));
361 }
362 }
363
364
365
366
367 public void printHelp() {
368 final HelpFormatter formatter = new HelpFormatter();
369 final Options options = new Options();
370 addStandardOptions(options);
371 if (line != null && line.hasOption(ArgumentName.ADVANCED_HELP)) {
372 addAdvancedOptions(options);
373 }
374 final String helpMsg = String.format("%n%s"
375 + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. "
376 + "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n",
377 Settings.getString("application.name", "DependencyCheck"),
378 Settings.getString("application.name", "DependencyCheck"));
379
380 formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
381 helpMsg,
382 options,
383 "",
384 true);
385
386 }
387
388
389
390
391
392
393 public String[] getScanFiles() {
394 return line.getOptionValues(ArgumentName.SCAN);
395 }
396
397
398
399
400
401
402 public String getReportDirectory() {
403 return line.getOptionValue(ArgumentName.OUT, ".");
404 }
405
406
407
408
409
410
411 public String getReportFormat() {
412 return line.getOptionValue(ArgumentName.OUTPUT_FORMAT, "HTML");
413 }
414
415
416
417
418
419
420 public String getApplicationName() {
421 return line.getOptionValue(ArgumentName.APP_NAME);
422 }
423
424
425
426
427
428
429 public String getConnectionTimeout() {
430 return line.getOptionValue(ArgumentName.CONNECTION_TIMEOUT);
431 }
432
433
434
435
436
437
438 public String getProxyUrl() {
439 return line.getOptionValue(ArgumentName.PROXY_URL);
440 }
441
442
443
444
445
446
447 public String getProxyPort() {
448 return line.getOptionValue(ArgumentName.PROXY_PORT);
449 }
450
451
452
453
454
455
456 public String getProxyUsername() {
457 return line.getOptionValue(ArgumentName.PROXY_USERNAME);
458 }
459
460
461
462
463
464
465 public String getProxyPassword() {
466 return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
467 }
468
469
470
471
472
473
474 public String getDataDirectory() {
475 return line.getOptionValue(ArgumentName.DATA_DIRECTORY);
476 }
477
478
479
480
481
482
483 public File getPropertiesFile() {
484 final String path = line.getOptionValue(ArgumentName.PROP);
485 if (path != null) {
486 return new File(path);
487 }
488 return null;
489 }
490
491
492
493
494
495
496 public String getVerboseLog() {
497 return line.getOptionValue(ArgumentName.VERBOSE_LOG);
498 }
499
500
501
502
503
504
505 public String getSuppressionFile() {
506 return line.getOptionValue(ArgumentName.SUPPRESION_FILE);
507 }
508
509
510
511
512
513
514
515 public void printVersionInfo() {
516 final String version = String.format("%s version %s",
517 Settings.getString("application.name", "DependencyCheck"),
518 Settings.getString("application.version", "Unknown"));
519 System.out.println(version);
520 }
521
522
523
524
525
526
527
528 public boolean isAutoUpdate() {
529 return (line == null) || !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE);
530 }
531
532
533
534
535
536
537 public String getDatabaseDriverName() {
538 return line.getOptionValue(ArgumentName.DB_DRIVER);
539 }
540
541
542
543
544
545
546 public String getDatabaseDriverPath() {
547 return line.getOptionValue(ArgumentName.DB_DRIVER_PATH);
548 }
549
550
551
552
553
554
555 public String getConnectionString() {
556 return line.getOptionValue(ArgumentName.CONNECTION_STRING);
557 }
558
559
560
561
562
563
564 public String getDatabaseUser() {
565 return line.getOptionValue(ArgumentName.DB_NAME);
566 }
567
568
569
570
571
572
573 public String getDatabasePassword() {
574 return line.getOptionValue(ArgumentName.DB_PASSWORD);
575 }
576
577
578
579
580
581
582 public String getAdditionalZipExtensions() {
583 return line.getOptionValue(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS);
584 }
585
586
587
588
589 public static class ArgumentName {
590
591
592
593
594 public static final String SCAN = "scan";
595
596
597
598 public static final String SCAN_SHORT = "s";
599
600
601
602 public static final String DISABLE_AUTO_UPDATE = "noupdate";
603
604
605
606 public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
607
608
609
610 public static final String OUT = "out";
611
612
613
614 public static final String OUT_SHORT = "o";
615
616
617
618 public static final String OUTPUT_FORMAT = "format";
619
620
621
622 public static final String OUTPUT_FORMAT_SHORT = "f";
623
624
625
626 public static final String APP_NAME = "app";
627
628
629
630 public static final String APP_NAME_SHORT = "a";
631
632
633
634 public static final String HELP = "help";
635
636
637
638 public static final String ADVANCED_HELP = "advancedHelp";
639
640
641
642 public static final String HELP_SHORT = "h";
643
644
645
646 public static final String VERSION_SHORT = "v";
647
648
649
650 public static final String VERSION = "version";
651
652
653
654 public static final String PROXY_PORT_SHORT = "p";
655
656
657
658 public static final String PROXY_PORT = "proxyport";
659
660
661
662 public static final String PROXY_URL_SHORT = "u";
663
664
665
666 public static final String PROXY_URL = "proxyurl";
667
668
669
670 public static final String PROXY_USERNAME = "proxyuser";
671
672
673
674 public static final String PROXY_PASSWORD = "proxypass";
675
676
677
678 public static final String CONNECTION_TIMEOUT_SHORT = "c";
679
680
681
682 public static final String CONNECTION_TIMEOUT = "connectiontimeout";
683
684
685
686 public static final String PROP_SHORT = "p";
687
688
689
690 public static final String PROP = "propertyfile";
691
692
693
694 public static final String DATA_DIRECTORY = "data";
695
696
697
698 public static final String DATA_DIRECTORY_SHORT = "d";
699
700
701
702 public static final String VERBOSE_LOG = "log";
703
704
705
706 public static final String VERBOSE_LOG_SHORT = "l";
707
708
709
710 public static final String SUPPRESION_FILE = "suppression";
711
712
713
714 public static final String DISABLE_NEXUS = "disableNexus";
715
716
717
718 public static final String NEXUS_URL = "nexus";
719
720
721
722 public static final String NEXUS_USES_PROXY = "nexusUsesProxy";
723
724
725
726 public static final String CONNECTION_STRING = "connectionString";
727
728
729
730 public static final String DB_NAME = "dbUser";
731
732
733
734 public static final String DB_PASSWORD = "dbPassword";
735
736
737
738 public static final String DB_DRIVER = "dbDriverName";
739
740
741
742 public static final String DB_DRIVER_PATH = "dbDriverPath";
743
744
745
746 public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
747 }
748 }