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 path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
179 .withDescription("The path to scan - this option can be specified multiple times.")
180 .create(ArgumentName.SCAN_SHORT);
181
182 final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
183 .withDescription("A property file to load.")
184 .create(ArgumentName.PROP_SHORT);
185
186 final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DATA_DIRECTORY)
187 .withDescription("The location of the data directory used to store persistent data. This option should generally not be set.")
188 .create(ArgumentName.DATA_DIRECTORY_SHORT);
189
190 final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
191 .withDescription("The folder to write reports to. This defaults to the current directory.")
192 .create(ArgumentName.OUT_SHORT);
193
194 final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
195 .withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
196 .create(ArgumentName.OUTPUT_FORMAT_SHORT);
197
198 final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.VERBOSE_LOG)
199 .withDescription("The file path to write verbose logging information.")
200 .create(ArgumentName.VERBOSE_LOG_SHORT);
201
202 final OptionGroup og = new OptionGroup();
203 og.addOption(path);
204
205 final Options opts = new Options();
206 opts.addOptionGroup(og);
207 opts.addOption(out);
208 opts.addOption(outputFormat);
209 opts.addOption(appName);
210 opts.addOption(version);
211 opts.addOption(help);
212 opts.addOption(noUpdate);
213 opts.addOption(props);
214 opts.addOption(data);
215 opts.addOption(verboseLog);
216 opts.addOption(proxyPort);
217 opts.addOption(proxyUrl);
218 opts.addOption(connectionTimeout);
219
220 return opts;
221 }
222
223
224
225
226
227
228 public boolean isGetVersion() {
229 return (line != null) && line.hasOption(ArgumentName.VERSION);
230 }
231
232
233
234
235
236
237 public boolean isGetHelp() {
238 return (line != null) && line.hasOption(ArgumentName.HELP);
239 }
240
241
242
243
244
245
246 public boolean isRunScan() {
247 return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
248 }
249
250
251
252
253 public void printHelp() {
254 final HelpFormatter formatter = new HelpFormatter();
255 final String nl = System.getProperty("line.separator");
256
257 formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
258 nl + Settings.getString("application.name", "DependencyCheck")
259 + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. "
260 + Settings.getString("application.name", "DependencyCheck")
261 + " will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov." + nl + nl,
262 options,
263 "",
264 true);
265 }
266
267
268
269
270
271
272
273 public String[] getScanFiles() {
274 return line.getOptionValues(ArgumentName.SCAN);
275 }
276
277
278
279
280
281
282
283 public String getReportDirectory() {
284 return line.getOptionValue(ArgumentName.OUT, ".");
285 }
286
287
288
289
290
291
292
293 public String getReportFormat() {
294 return line.getOptionValue(ArgumentName.OUTPUT_FORMAT, "HTML");
295 }
296
297
298
299
300
301
302 public String getApplicationName() {
303 return line.getOptionValue(ArgumentName.APP_NAME);
304 }
305
306
307
308
309
310
311 public String getConnectionTimeout() {
312 return line.getOptionValue(ArgumentName.CONNECTION_TIMEOUT);
313 }
314
315
316
317
318
319
320 public String getProxyUrl() {
321 return line.getOptionValue(ArgumentName.PROXY_URL);
322 }
323
324
325
326
327
328
329 public String getProxyPort() {
330 return line.getOptionValue(ArgumentName.PROXY_PORT);
331 }
332
333
334
335
336
337
338 public String getDataDirectory() {
339 return line.getOptionValue(ArgumentName.DATA_DIRECTORY);
340 }
341
342
343
344
345
346
347 public File getPropertiesFile() {
348 final String path = line.getOptionValue(ArgumentName.PROP);
349 if (path != null) {
350 return new File(path);
351 }
352 return null;
353 }
354
355
356
357
358
359
360 public String getVerboseLog() {
361 return line.getOptionValue(ArgumentName.VERBOSE_LOG);
362 }
363
364
365
366
367
368
369 public void printVersionInfo() {
370 final String version = String.format("%s version %s",
371 Settings.getString("application.name", "DependencyCheck"),
372 Settings.getString("application.version", "Unknown"));
373 System.out.println(version);
374 }
375
376
377
378
379
380
381
382 public boolean isAutoUpdate() {
383 return (line == null) || !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE);
384 }
385
386
387
388
389
390 public static class ArgumentName {
391
392
393
394
395 public static final String SCAN = "scan";
396
397
398
399 public static final String SCAN_SHORT = "s";
400
401
402
403
404 public static final String DISABLE_AUTO_UPDATE = "noupdate";
405
406
407
408
409 public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
410
411
412
413
414 public static final String OUT = "out";
415
416
417
418
419 public static final String OUT_SHORT = "o";
420
421
422
423
424 public static final String OUTPUT_FORMAT = "format";
425
426
427
428
429 public static final String OUTPUT_FORMAT_SHORT = "f";
430
431
432
433
434 public static final String APP_NAME = "app";
435
436
437
438
439 public static final String APP_NAME_SHORT = "a";
440
441
442
443 public static final String HELP = "help";
444
445
446
447 public static final String HELP_SHORT = "h";
448
449
450
451 public static final String VERSION_SHORT = "v";
452
453
454
455 public static final String VERSION = "version";
456
457
458
459 public static final String PROXY_PORT_SHORT = "p";
460
461
462
463 public static final String PROXY_PORT = "proxyport";
464
465
466
467 public static final String PROXY_URL_SHORT = "u";
468
469
470
471 public static final String PROXY_URL = "proxyurl";
472
473
474
475 public static final String CONNECTION_TIMEOUT_SHORT = "c";
476
477
478
479 public static final String CONNECTION_TIMEOUT = "connectiontimeout";
480
481
482
483
484 public static final String PROP_SHORT = "p";
485
486
487
488
489 public static final String PROP = "propertyfile";
490
491
492
493 public static final String DATA_DIRECTORY = "data";
494
495
496
497
498 public static final String DATA_DIRECTORY_SHORT = "d";
499
500
501
502 public static final String VERBOSE_LOG = "log";
503
504
505
506
507 public static final String VERBOSE_LOG_SHORT = "l";
508 }
509 }