1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.owasp.dependencycheck.cli;
20
21 import java.io.File;
22 import java.io.FileNotFoundException;
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.Settings;
34
35
36
37
38
39
40 public final class CliParser {
41
42
43
44
45 private CommandLine line;
46
47
48
49 private final Options options = createCommandLineOptions();
50
51
52
53 private boolean isValid = true;
54
55
56
57
58
59
60
61
62
63 public void parse(String[] args) throws FileNotFoundException, ParseException {
64 line = parseArgs(args);
65
66 if (line != null) {
67 validateArgs();
68 }
69 }
70
71
72
73
74
75
76
77
78 private CommandLine parseArgs(String[] args) throws ParseException {
79 final CommandLineParser parser = new PosixParser();
80 return parser.parse(options, args);
81 }
82
83
84
85
86
87
88
89
90
91 private void validateArgs() throws FileNotFoundException, ParseException {
92 if (isRunScan()) {
93 validatePathExists(getScanFiles(), "scan");
94 validatePathExists(getReportDirectory(), "out");
95 if (!line.hasOption(ArgumentName.APP_NAME)) {
96 throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
97 }
98 if (line.hasOption(ArgumentName.OUTPUT_FORMAT)) {
99 final String format = line.getOptionValue(ArgumentName.OUTPUT_FORMAT);
100 try {
101 Format.valueOf(format);
102 } catch (IllegalArgumentException ex) {
103 final String msg = String.format("An invalid 'format' of '%s' was specified. Supported output formats are XML, HTML, VULN, or ALL", format);
104 throw new ParseException(msg);
105 }
106 }
107 }
108 }
109
110
111
112
113
114
115
116
117
118
119
120 private void validatePathExists(String[] paths, String optType) throws FileNotFoundException {
121 for (String path : paths) {
122 validatePathExists(path, optType);
123 }
124 }
125
126
127
128
129
130
131
132
133
134
135
136 private void validatePathExists(String path, String optType) throws FileNotFoundException {
137 final File f = new File(path);
138 if (!f.exists()) {
139 isValid = false;
140 final String msg = String.format("Invalid '%s' argument: '%s'", optType, path);
141 throw new FileNotFoundException(msg);
142 }
143 }
144
145
146
147
148
149
150
151 @SuppressWarnings("static-access")
152 private Options createCommandLineOptions() {
153 final Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
154 "Print this message.");
155
156 final Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
157 false, "Print the version information.");
158
159 final Option noUpdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
160 false, "Disables the automatic updating of the CPE data.");
161
162 final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APP_NAME)
163 .withDescription("The name of the application being scanned. This is a required argument.")
164 .create(ArgumentName.APP_NAME_SHORT);
165
166 final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ArgumentName.CONNECTION_TIMEOUT)
167 .withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
168 .create(ArgumentName.CONNECTION_TIMEOUT_SHORT);
169
170 final Option proxyUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.PROXY_URL)
171 .withDescription("The proxy url to use when downloading resources.")
172 .create(ArgumentName.PROXY_URL_SHORT);
173
174 final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ArgumentName.PROXY_PORT)
175 .withDescription("The proxy port to use when downloading resources.")
176 .create(ArgumentName.PROXY_PORT_SHORT);
177
178 final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.PROXY_USERNAME)
179 .withDescription("The proxy username to use when downloading resources.")
180 .create(ArgumentName.PROXY_USERNAME_SHORT);
181
182 final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ArgumentName.PROXY_PASSWORD)
183 .withDescription("The proxy password to use when downloading resources.")
184 .create(ArgumentName.PROXY_PASSWORD_SHORT);
185
186 final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
187 .withDescription("The path to scan - this option can be specified multiple times.")
188 .create(ArgumentName.SCAN_SHORT);
189
190 final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
191 .withDescription("A property file to load.")
192 .create(ArgumentName.PROP_SHORT);
193
194 final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DATA_DIRECTORY)
195 .withDescription("The location of the data directory used to store persistent data. This option should generally not be set.")
196 .create(ArgumentName.DATA_DIRECTORY_SHORT);
197
198 final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
199 .withDescription("The folder to write reports to. This defaults to the current directory.")
200 .create(ArgumentName.OUT_SHORT);
201
202 final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
203 .withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
204 .create(ArgumentName.OUTPUT_FORMAT_SHORT);
205
206 final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.VERBOSE_LOG)
207 .withDescription("The file path to write verbose logging information.")
208 .create(ArgumentName.VERBOSE_LOG_SHORT);
209
210 final OptionGroup og = new OptionGroup();
211 og.addOption(path);
212
213 final Options opts = new Options();
214 opts.addOptionGroup(og);
215 opts.addOption(out);
216 opts.addOption(outputFormat);
217 opts.addOption(appName);
218 opts.addOption(version);
219 opts.addOption(help);
220 opts.addOption(noUpdate);
221 opts.addOption(props);
222 opts.addOption(data);
223 opts.addOption(verboseLog);
224 opts.addOption(proxyPort);
225 opts.addOption(proxyUrl);
226 opts.addOption(proxyUsername);
227 opts.addOption(proxyPassword);
228 opts.addOption(connectionTimeout);
229
230 return opts;
231 }
232
233
234
235
236
237
238 public boolean isGetVersion() {
239 return (line != null) && line.hasOption(ArgumentName.VERSION);
240 }
241
242
243
244
245
246
247 public boolean isGetHelp() {
248 return (line != null) && line.hasOption(ArgumentName.HELP);
249 }
250
251
252
253
254
255
256 public boolean isRunScan() {
257 return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
258 }
259
260
261
262
263 public void printHelp() {
264 final HelpFormatter formatter = new HelpFormatter();
265 final String nl = System.getProperty("line.separator");
266
267 formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
268 nl + Settings.getString("application.name", "DependencyCheck")
269 + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. "
270 + Settings.getString("application.name", "DependencyCheck")
271 + " will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov." + nl + nl,
272 options,
273 "",
274 true);
275 }
276
277
278
279
280
281
282
283 public String[] getScanFiles() {
284 return line.getOptionValues(ArgumentName.SCAN);
285 }
286
287
288
289
290
291
292
293 public String getReportDirectory() {
294 return line.getOptionValue(ArgumentName.OUT, ".");
295 }
296
297
298
299
300
301
302
303 public String getReportFormat() {
304 return line.getOptionValue(ArgumentName.OUTPUT_FORMAT, "HTML");
305 }
306
307
308
309
310
311
312 public String getApplicationName() {
313 return line.getOptionValue(ArgumentName.APP_NAME);
314 }
315
316
317
318
319
320
321 public String getConnectionTimeout() {
322 return line.getOptionValue(ArgumentName.CONNECTION_TIMEOUT);
323 }
324
325
326
327
328
329
330 public String getProxyUrl() {
331 return line.getOptionValue(ArgumentName.PROXY_URL);
332 }
333
334
335
336
337
338
339 public String getProxyPort() {
340 return line.getOptionValue(ArgumentName.PROXY_PORT);
341 }
342
343
344
345
346
347
348 public String getProxyUsername() {
349 return line.getOptionValue(ArgumentName.PROXY_USERNAME);
350 }
351
352
353
354
355
356
357 public String getProxyPassword() {
358 return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
359 }
360
361
362
363
364
365
366 public String getDataDirectory() {
367 return line.getOptionValue(ArgumentName.DATA_DIRECTORY);
368 }
369
370
371
372
373
374
375 public File getPropertiesFile() {
376 final String path = line.getOptionValue(ArgumentName.PROP);
377 if (path != null) {
378 return new File(path);
379 }
380 return null;
381 }
382
383
384
385
386
387
388 public String getVerboseLog() {
389 return line.getOptionValue(ArgumentName.VERBOSE_LOG);
390 }
391
392
393
394
395
396
397 public void printVersionInfo() {
398 final String version = String.format("%s version %s",
399 Settings.getString("application.name", "DependencyCheck"),
400 Settings.getString("application.version", "Unknown"));
401 System.out.println(version);
402 }
403
404
405
406
407
408
409
410 public boolean isAutoUpdate() {
411 return (line == null) || !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE);
412 }
413
414
415
416
417
418 public static class ArgumentName {
419
420
421
422
423 public static final String SCAN = "scan";
424
425
426
427 public static final String SCAN_SHORT = "s";
428
429
430
431
432 public static final String DISABLE_AUTO_UPDATE = "noupdate";
433
434
435
436
437 public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
438
439
440
441
442 public static final String OUT = "out";
443
444
445
446
447 public static final String OUT_SHORT = "o";
448
449
450
451
452 public static final String OUTPUT_FORMAT = "format";
453
454
455
456
457 public static final String OUTPUT_FORMAT_SHORT = "f";
458
459
460
461
462 public static final String APP_NAME = "app";
463
464
465
466
467 public static final String APP_NAME_SHORT = "a";
468
469
470
471 public static final String HELP = "help";
472
473
474
475 public static final String HELP_SHORT = "h";
476
477
478
479 public static final String VERSION_SHORT = "v";
480
481
482
483 public static final String VERSION = "version";
484
485
486
487 public static final String PROXY_PORT_SHORT = "p";
488
489
490
491 public static final String PROXY_PORT = "proxyport";
492
493
494
495 public static final String PROXY_URL_SHORT = "u";
496
497
498
499 public static final String PROXY_URL = "proxyurl";
500
501
502
503 public static final String PROXY_USERNAME_SHORT = "pu";
504
505
506
507 public static final String PROXY_USERNAME = "proxyuser";
508
509
510
511 public static final String PROXY_PASSWORD_SHORT = "pp";
512
513
514
515 public static final String PROXY_PASSWORD = "proxypass";
516
517
518
519 public static final String CONNECTION_TIMEOUT_SHORT = "c";
520
521
522
523 public static final String CONNECTION_TIMEOUT = "connectiontimeout";
524
525
526
527
528 public static final String PROP_SHORT = "p";
529
530
531
532
533 public static final String PROP = "propertyfile";
534
535
536
537 public static final String DATA_DIRECTORY = "data";
538
539
540
541
542 public static final String DATA_DIRECTORY_SHORT = "d";
543
544
545
546 public static final String VERBOSE_LOG = "log";
547
548
549
550
551 public static final String VERBOSE_LOG_SHORT = "l";
552 }
553 }