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