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
208 final OptionGroup og = new OptionGroup();
209 og.addOption(path);
210
211 options.addOptionGroup(og)
212 .addOption(out)
213 .addOption(outputFormat)
214 .addOption(appName)
215 .addOption(version)
216 .addOption(help)
217 .addOption(advancedHelp)
218 .addOption(noUpdate)
219 .addOption(props)
220 .addOption(verboseLog)
221 .addOption(suppressionFile)
222 .addOption(disableNexusAnalyzer)
223 .addOption(nexusUrl);
224 }
225
226
227
228
229
230
231
232
233 @SuppressWarnings("static-access")
234 private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
235
236 final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DATA_DIRECTORY)
237 .withDescription("The location of the H2 Database file. This option should generally not be set.")
238 .create(ArgumentName.DATA_DIRECTORY_SHORT);
239
240 final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ArgumentName.CONNECTION_TIMEOUT)
241 .withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
242 .create(ArgumentName.CONNECTION_TIMEOUT_SHORT);
243
244 final Option proxyUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.PROXY_URL)
245 .withDescription("The proxy url to use when downloading resources.")
246 .create(ArgumentName.PROXY_URL_SHORT);
247
248 final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ArgumentName.PROXY_PORT)
249 .withDescription("The proxy port to use when downloading resources.")
250 .create(ArgumentName.PROXY_PORT_SHORT);
251
252 final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.PROXY_USERNAME)
253 .withDescription("The proxy username to use when downloading resources.")
254 .create();
255
256 final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ArgumentName.PROXY_PASSWORD)
257 .withDescription("The proxy password to use when downloading resources.")
258 .create();
259
260 final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ArgumentName.CONNECTION_STRING)
261 .withDescription("The connection string to the database.")
262 .create();
263 final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.DB_NAME)
264 .withDescription("The username used to connect to the database.")
265 .create();
266 final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ArgumentName.DB_PASSWORD)
267 .withDescription("The password for connecting to the database.")
268 .create();
269 final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ArgumentName.DB_DRIVER)
270 .withDescription("The database driver name.")
271 .create();
272 final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DB_DRIVER_PATH)
273 .withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
274 .create();
275
276 options.addOption(proxyPort)
277 .addOption(proxyUrl)
278 .addOption(proxyUsername)
279 .addOption(proxyPassword)
280 .addOption(connectionTimeout)
281 .addOption(connectionString)
282 .addOption(dbUser)
283 .addOption(data)
284 .addOption(dbPassword)
285 .addOption(dbDriver)
286 .addOption(dbDriverPath);
287 }
288
289
290
291
292
293
294 public boolean isGetVersion() {
295 return (line != null) && line.hasOption(ArgumentName.VERSION);
296 }
297
298
299
300
301
302
303 public boolean isGetHelp() {
304 return (line != null) && line.hasOption(ArgumentName.HELP);
305 }
306
307
308
309
310
311
312 public boolean isRunScan() {
313 return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
314 }
315
316
317
318
319
320
321 public boolean isNexusDisabled() {
322 return (line != null) && line.hasOption(ArgumentName.DISABLE_NEXUS);
323 }
324
325
326
327
328
329
330 public String getNexusUrl() {
331 if (line == null || !line.hasOption(ArgumentName.NEXUS_URL)) {
332 return null;
333 } else {
334 return line.getOptionValue(ArgumentName.NEXUS_URL);
335 }
336 }
337
338
339
340
341 public void printHelp() {
342 final HelpFormatter formatter = new HelpFormatter();
343 final Options options = new Options();
344 addStandardOptions(options);
345 if (line != null && line.hasOption(ArgumentName.ADVANCED_HELP)) {
346 addAdvancedOptions(options);
347 }
348 final String helpMsg = String.format("%n%s"
349 + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. "
350 + "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n",
351 Settings.getString("application.name", "DependencyCheck"),
352 Settings.getString("application.name", "DependencyCheck"));
353
354 formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
355 helpMsg,
356 options,
357 "",
358 true);
359
360 }
361
362
363
364
365
366
367 public String[] getScanFiles() {
368 return line.getOptionValues(ArgumentName.SCAN);
369 }
370
371
372
373
374
375
376 public String getReportDirectory() {
377 return line.getOptionValue(ArgumentName.OUT, ".");
378 }
379
380
381
382
383
384
385 public String getReportFormat() {
386 return line.getOptionValue(ArgumentName.OUTPUT_FORMAT, "HTML");
387 }
388
389
390
391
392
393
394 public String getApplicationName() {
395 return line.getOptionValue(ArgumentName.APP_NAME);
396 }
397
398
399
400
401
402
403 public String getConnectionTimeout() {
404 return line.getOptionValue(ArgumentName.CONNECTION_TIMEOUT);
405 }
406
407
408
409
410
411
412 public String getProxyUrl() {
413 return line.getOptionValue(ArgumentName.PROXY_URL);
414 }
415
416
417
418
419
420
421 public String getProxyPort() {
422 return line.getOptionValue(ArgumentName.PROXY_PORT);
423 }
424
425
426
427
428
429
430 public String getProxyUsername() {
431 return line.getOptionValue(ArgumentName.PROXY_USERNAME);
432 }
433
434
435
436
437
438
439 public String getProxyPassword() {
440 return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
441 }
442
443
444
445
446
447
448 public String getDataDirectory() {
449 return line.getOptionValue(ArgumentName.DATA_DIRECTORY);
450 }
451
452
453
454
455
456
457 public File getPropertiesFile() {
458 final String path = line.getOptionValue(ArgumentName.PROP);
459 if (path != null) {
460 return new File(path);
461 }
462 return null;
463 }
464
465
466
467
468
469
470 public String getVerboseLog() {
471 return line.getOptionValue(ArgumentName.VERBOSE_LOG);
472 }
473
474
475
476
477
478
479 public String getSuppressionFile() {
480 return line.getOptionValue(ArgumentName.SUPPRESION_FILE);
481 }
482
483
484
485
486
487
488
489 public void printVersionInfo() {
490 final String version = String.format("%s version %s",
491 Settings.getString("application.name", "DependencyCheck"),
492 Settings.getString("application.version", "Unknown"));
493 System.out.println(version);
494 }
495
496
497
498
499
500
501
502 public boolean isAutoUpdate() {
503 return (line == null) || !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE);
504 }
505
506
507
508
509
510
511 public String getDatabaseDriverName() {
512 return line.getOptionValue(ArgumentName.DB_DRIVER);
513 }
514
515
516
517
518
519
520 public String getDatabaseDriverPath() {
521 return line.getOptionValue(ArgumentName.DB_DRIVER_PATH);
522 }
523
524
525
526
527
528
529 public String getConnectionString() {
530 return line.getOptionValue(ArgumentName.CONNECTION_STRING);
531 }
532
533
534
535
536
537
538 public String getDatabaseUser() {
539 return line.getOptionValue(ArgumentName.DB_NAME);
540 }
541
542
543
544
545
546
547 public String getDatabasePassword() {
548 return line.getOptionValue(ArgumentName.DB_PASSWORD);
549 }
550
551
552
553
554 public static class ArgumentName {
555
556
557
558
559 public static final String SCAN = "scan";
560
561
562
563 public static final String SCAN_SHORT = "s";
564
565
566
567 public static final String DISABLE_AUTO_UPDATE = "noupdate";
568
569
570
571 public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
572
573
574
575 public static final String OUT = "out";
576
577
578
579 public static final String OUT_SHORT = "o";
580
581
582
583 public static final String OUTPUT_FORMAT = "format";
584
585
586
587 public static final String OUTPUT_FORMAT_SHORT = "f";
588
589
590
591 public static final String APP_NAME = "app";
592
593
594
595 public static final String APP_NAME_SHORT = "a";
596
597
598
599 public static final String HELP = "help";
600
601
602
603 public static final String ADVANCED_HELP = "advancedHelp";
604
605
606
607 public static final String HELP_SHORT = "h";
608
609
610
611 public static final String VERSION_SHORT = "v";
612
613
614
615 public static final String VERSION = "version";
616
617
618
619 public static final String PROXY_PORT_SHORT = "p";
620
621
622
623 public static final String PROXY_PORT = "proxyport";
624
625
626
627 public static final String PROXY_URL_SHORT = "u";
628
629
630
631 public static final String PROXY_URL = "proxyurl";
632
633
634
635 public static final String PROXY_USERNAME = "proxyuser";
636
637
638
639 public static final String PROXY_PASSWORD = "proxypass";
640
641
642
643 public static final String CONNECTION_TIMEOUT_SHORT = "c";
644
645
646
647 public static final String CONNECTION_TIMEOUT = "connectiontimeout";
648
649
650
651 public static final String PROP_SHORT = "p";
652
653
654
655 public static final String PROP = "propertyfile";
656
657
658
659 public static final String DATA_DIRECTORY = "data";
660
661
662
663 public static final String DATA_DIRECTORY_SHORT = "d";
664
665
666
667 public static final String VERBOSE_LOG = "log";
668
669
670
671 public static final String VERBOSE_LOG_SHORT = "l";
672
673
674
675 public static final String SUPPRESION_FILE = "suppression";
676
677
678
679 public static final String DISABLE_NEXUS = "disableNexus";
680
681
682
683 public static final String NEXUS_URL = "nexus";
684
685
686
687 public static final String CONNECTION_STRING = "connectionString";
688
689
690
691 public static final String DB_NAME = "dbUser";
692
693
694
695 public static final String DB_PASSWORD = "dbPassword";
696
697
698
699 public static final String DB_DRIVER = "dbDriverName";
700
701
702
703 public static final String DB_DRIVER_PATH = "dbDriverPath";
704 }
705 }