1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  package org.owasp.dependencycheck;
19  
20  import java.io.File;
21  import java.io.FileNotFoundException;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Set;
26  
27  import java.util.stream.Collectors;
28  import java.util.stream.Stream;
29  import org.apache.commons.cli.ParseException;
30  import org.apache.tools.ant.DirectoryScanner;
31  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
32  import org.owasp.dependencycheck.dependency.Dependency;
33  import org.owasp.dependencycheck.dependency.Vulnerability;
34  import org.apache.tools.ant.types.LogLevel;
35  import org.owasp.dependencycheck.data.update.exception.UpdateException;
36  import org.owasp.dependencycheck.dependency.naming.Identifier;
37  import org.owasp.dependencycheck.exception.ExceptionCollection;
38  import org.owasp.dependencycheck.exception.ReportException;
39  import org.owasp.dependencycheck.utils.Downloader;
40  import org.owasp.dependencycheck.utils.InvalidSettingException;
41  import org.owasp.dependencycheck.utils.Settings;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  import ch.qos.logback.core.FileAppender;
46  import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
47  import ch.qos.logback.classic.filter.ThresholdFilter;
48  import ch.qos.logback.classic.spi.ILoggingEvent;
49  import ch.qos.logback.classic.Level;
50  import ch.qos.logback.classic.LoggerContext;
51  import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter;
52  import java.util.TreeSet;
53  import org.owasp.dependencycheck.utils.SeverityUtil;
54  
55  
56  
57  
58  
59  
60  @SuppressWarnings("squid:S106")
61  public class App {
62  
63      
64  
65  
66      private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
67      
68  
69  
70      private static final String ERROR_LOADING_PROPERTIES_FILE = "Error loading properties file";
71      
72  
73  
74      private static final String NEW_LINE = System.getProperty("line.separator", "\n");
75      
76  
77  
78      private final Settings settings;
79  
80      
81  
82  
83  
84  
85      @SuppressWarnings("squid:S4823")
86      public static void main(String[] args) {
87          System.setProperty("jcs.logSystem", "slf4j");
88          if (!LOGGER.isDebugEnabled()) {
89              Slf4jAdapter.muteLogging(true);
90          }
91          final int exitCode;
92          final App app = new App();
93          exitCode = app.run(args);
94          LOGGER.debug("Exit code: {}", exitCode);
95          System.exit(exitCode);
96      }
97  
98      
99  
100 
101     public App() {
102         settings = new Settings();
103     }
104 
105     
106 
107 
108 
109 
110     protected App(Settings settings) {
111         this.settings = settings;
112     }
113 
114     
115 
116 
117 
118 
119 
120     public int run(String[] args) {
121         int exitCode = 0;
122         final CliParser cli = new CliParser(settings);
123 
124         try {
125             cli.parse(args);
126         } catch (FileNotFoundException ex) {
127             System.err.println(ex.getMessage());
128             cli.printHelp();
129             return 1;
130         } catch (ParseException ex) {
131             System.err.println(ex.getMessage());
132             cli.printHelp();
133             return 2;
134         }
135         final String verboseLog = cli.getStringArgument(CliParser.ARGUMENT.VERBOSE_LOG);
136         if (verboseLog != null) {
137             prepareLogger(verboseLog);
138         }
139 
140         if (cli.isPurge()) {
141             final String connStr = cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_STRING);
142             if (connStr != null) {
143                 LOGGER.error("Unable to purge the database when using a non-default connection string");
144                 exitCode = 3;
145             } else {
146                 try {
147                     populateSettings(cli);
148                     Downloader.getInstance().configure(settings);
149                 } catch (InvalidSettingException ex) {
150                     LOGGER.error(ex.getMessage());
151                     LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex);
152                     exitCode = 4;
153                     return exitCode;
154                 }
155                 try (Engine engine = new Engine(Engine.Mode.EVIDENCE_PROCESSING, settings)) {
156                     if (!engine.purge()) {
157                         exitCode = 7;
158                         return exitCode;
159                     }
160                 } finally {
161                     settings.cleanup();
162                 }
163             }
164         } else if (cli.isGetVersion()) {
165             cli.printVersionInfo();
166         } else if (cli.isUpdateOnly()) {
167             try {
168                 populateSettings(cli);
169                 settings.setBoolean(Settings.KEYS.AUTO_UPDATE, true);
170                 Downloader.getInstance().configure(settings);
171             } catch (InvalidSettingException ex) {
172                 LOGGER.error(ex.getMessage());
173                 LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex);
174                 exitCode = 4;
175                 return exitCode;
176             }
177             try {
178                 runUpdateOnly();
179             } catch (UpdateException ex) {
180                 LOGGER.error(ex.getMessage(), ex);
181                 exitCode = 8;
182             } catch (DatabaseException ex) {
183                 LOGGER.error(ex.getMessage(), ex);
184                 exitCode = 9;
185             } finally {
186                 settings.cleanup();
187             }
188         } else if (cli.isRunScan()) {
189             try {
190                 populateSettings(cli);
191                 Downloader.getInstance().configure(settings);
192             } catch (InvalidSettingException ex) {
193                 LOGGER.error(ex.getMessage(), ex);
194                 LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex);
195                 exitCode = 4;
196                 return exitCode;
197             }
198             try {
199                 final String[] scanFiles = cli.getScanFiles();
200                 if (scanFiles != null) {
201                     exitCode = runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), scanFiles,
202                             cli.getExcludeList(), cli.getSymLinkDepth(), cli.getFailOnCVSS());
203                 } else {
204                     LOGGER.error("No scan files configured");
205                 }
206             } catch (DatabaseException ex) {
207                 LOGGER.error(ex.getMessage());
208                 LOGGER.debug("database exception", ex);
209                 exitCode = 11;
210             } catch (ReportException ex) {
211                 LOGGER.error(ex.getMessage());
212                 LOGGER.debug("report exception", ex);
213                 exitCode = 12;
214             } catch (ExceptionCollection ex) {
215                 if (ex.isFatal()) {
216                     exitCode = 13;
217                     LOGGER.error("One or more fatal errors occurred");
218                 } else {
219                     exitCode = 14;
220                 }
221                 for (Throwable e : ex.getExceptions()) {
222                     if (e.getMessage() != null) {
223                         LOGGER.error(e.getMessage());
224                         LOGGER.debug("unexpected error", e);
225                     }
226                 }
227             } finally {
228                 settings.cleanup();
229             }
230         } else {
231             cli.printHelp();
232         }
233         return exitCode;
234     }
235 
236     
237 
238 
239 
240 
241 
242 
243 
244 
245 
246 
247 
248 
249 
250 
251 
252 
253 
254 
255 
256     private int runScan(String reportDirectory, String[] outputFormats, String applicationName, String[] files,
257             String[] excludes, int symLinkDepth, float cvssFailScore) throws DatabaseException,
258             ExceptionCollection, ReportException {
259         Engine engine = null;
260         try {
261             final List<String> antStylePaths = getPaths(files);
262             final Set<File> paths = scanAntStylePaths(antStylePaths, symLinkDepth, excludes);
263 
264             engine = new Engine(settings);
265             engine.scan(paths);
266 
267             ExceptionCollection exCol = null;
268             try {
269                 engine.analyzeDependencies();
270             } catch (ExceptionCollection ex) {
271                 if (ex.isFatal()) {
272                     throw ex;
273                 }
274                 exCol = ex;
275             }
276 
277             try {
278                 for (String outputFormat : outputFormats) {
279                     engine.writeReports(applicationName, new File(reportDirectory), outputFormat, exCol);
280                 }
281             } catch (ReportException ex) {
282                 if (exCol != null) {
283                     exCol.addException(ex);
284                     throw exCol;
285                 } else {
286                     throw ex;
287                 }
288             }
289             if (exCol != null && !exCol.getExceptions().isEmpty()) {
290                 throw exCol;
291             }
292             return determineReturnCode(engine, cvssFailScore);
293         } finally {
294             if (engine != null) {
295                 engine.close();
296             }
297         }
298     }
299 
300     
301 
302 
303 
304 
305 
306 
307 
308 
309     private int determineReturnCode(Engine engine, float cvssFailScore) {
310         int retCode = 0;
311         
312         final StringBuilder ids = new StringBuilder();
313         for (Dependency d : engine.getDependencies()) {
314             boolean addName = true;
315             for (Vulnerability v : d.getVulnerabilities()) {
316                 final Double cvssV2 = v.getCvssV2() != null && v.getCvssV2().getCvssData() != null
317                         && v.getCvssV2().getCvssData().getBaseScore() != null ? v.getCvssV2().getCvssData().getBaseScore() : -1;
318                 final Double cvssV3 = v.getCvssV3() != null && v.getCvssV3().getCvssData() != null
319                         && v.getCvssV3().getCvssData().getBaseScore() != null ? v.getCvssV3().getCvssData().getBaseScore() : -1;
320                 final Double cvssV4 = v.getCvssV4() != null && v.getCvssV4().getCvssData() != null
321                         && v.getCvssV4().getCvssData().getBaseScore() != null ? v.getCvssV4().getCvssData().getBaseScore() : -1;
322                 final Double unscoredCvss = v.getUnscoredSeverity() != null ? SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) : -1;
323 
324                 if (cvssV2 >= cvssFailScore
325                         || cvssV3 >= cvssFailScore
326                         || cvssV4 >= cvssFailScore
327                         || unscoredCvss >= cvssFailScore
328                         
329                         || (cvssFailScore <= 0.0f)) {
330                     double score = 0.0;
331                     if (cvssV4 >= 0.0) {
332                         score = cvssV4;
333                     } else if (cvssV3 >= 0.0) {
334                         score = cvssV3;
335                     } else if (cvssV2 >= 0.0) {
336                         score = cvssV2;
337                     } else if (unscoredCvss >= 0.0) {
338                         score = unscoredCvss;
339                     }
340                     if (addName) {
341                         addName = false;
342                         ids.append(NEW_LINE).append(d.getFileName()).append(" (")
343                            .append(Stream.concat(d.getSoftwareIdentifiers().stream(), d.getVulnerableSoftwareIdentifiers().stream())
344                                          .map(Identifier::getValue)
345                                          .collect(Collectors.joining(", ")))
346                            .append("): ");
347                         ids.append(v.getName()).append('(').append(score).append(')');
348                     } else {
349                         ids.append(", ").append(v.getName()).append('(').append(score).append(')');
350                     }
351                 }
352             }
353         }
354         if (ids.length() > 0) {
355             LOGGER.error(
356                     String.format("%n%nOne or more dependencies were identified with vulnerabilities that have a CVSS score greater than or "
357                             + "equal to '%.1f': %n%s%n%nSee the dependency-check report for more details.%n%n", cvssFailScore, ids)
358             );
359 
360             retCode = 15;
361         }
362 
363         return retCode;
364     }
365 
366     
367 
368 
369 
370 
371 
372 
373 
374     private Set<File> scanAntStylePaths(List<String> antStylePaths, int symLinkDepth, String[] excludes) {
375         final Set<File> paths = new TreeSet<>();
376         for (String file : antStylePaths) {
377             LOGGER.debug("Scanning {}", file);
378             final DirectoryScanner scanner = new DirectoryScanner();
379             String include = file.replace('\\', '/');
380             final File baseDir;
381             final int pos = getLastFileSeparator(include);
382             final String tmpBase = include.substring(0, pos);
383             final String tmpInclude = include.substring(pos + 1);
384             if (tmpInclude.indexOf('*') >= 0 || tmpInclude.indexOf('?') >= 0
385                     || new File(include).isFile()) {
386                 baseDir = new File(tmpBase);
387                 include = tmpInclude;
388             } else {
389                 baseDir = new File(tmpBase, tmpInclude);
390                 include = "**/*";
391             }
392             LOGGER.debug("BaseDir: " + baseDir);
393             LOGGER.debug("Include: " + include);
394             scanner.setBasedir(baseDir);
395             final String[] includes = {include};
396             scanner.setIncludes(includes);
397             scanner.setMaxLevelsOfSymlinks(symLinkDepth);
398             if (symLinkDepth <= 0) {
399                 scanner.setFollowSymlinks(false);
400             }
401             if (excludes != null && excludes.length > 0) {
402                 for (String e : excludes) {
403                     LOGGER.debug("Exclude: " + e);
404                 }
405                 scanner.addExcludes(excludes);
406             }
407             scanner.scan();
408             if (scanner.getIncludedFilesCount() > 0) {
409                 for (String s : scanner.getIncludedFiles()) {
410                     final File f = new File(baseDir, s);
411                     LOGGER.debug("Found file {}", f);
412                     paths.add(f);
413                 }
414             }
415         }
416         return paths;
417     }
418 
419     
420 
421 
422 
423 
424 
425     private List<String> getPaths(String[] files) {
426         final List<String> antStylePaths = new ArrayList<>();
427         for (String file : files) {
428             final String antPath = ensureCanonicalPath(file);
429             antStylePaths.add(antPath);
430         }
431         return antStylePaths;
432     }
433 
434     
435 
436 
437 
438 
439 
440 
441     private void runUpdateOnly() throws UpdateException, DatabaseException {
442         try (Engine engine = new Engine(settings)) {
443             engine.doUpdates();
444         }
445     }
446 
447     
448     
449 
450 
451 
452 
453 
454 
455 
456     protected void populateSettings(CliParser cli) throws InvalidSettingException {
457         final File propertiesFile = cli.getFileArgument(CliParser.ARGUMENT.PROP);
458         if (propertiesFile != null) {
459             try {
460                 settings.mergeProperties(propertiesFile);
461             } catch (FileNotFoundException ex) {
462                 throw new InvalidSettingException("Unable to find properties file '" + propertiesFile.getPath() + "'", ex);
463             } catch (IOException ex) {
464                 throw new InvalidSettingException("Error reading properties file '" + propertiesFile.getPath() + "'", ex);
465             }
466         }
467         final String dataDirectory = cli.getStringArgument(CliParser.ARGUMENT.DATA_DIRECTORY);
468         if (dataDirectory != null) {
469             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
470         } else if (System.getProperty("basedir") != null) {
471             final File dataDir = new File(System.getProperty("basedir"), "data");
472             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
473         } else {
474             final File jarPath = new File(App.class
475                     .getProtectionDomain().getCodeSource().getLocation().getPath());
476             final File base = jarPath.getParentFile();
477             final String sub = settings.getString(Settings.KEYS.DATA_DIRECTORY);
478             final File dataDir = new File(base, sub);
479             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
480         }
481         final Boolean autoUpdate = cli.hasOption(CliParser.ARGUMENT.DISABLE_AUTO_UPDATE) != null ? false : null;
482         settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
483         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER,
484                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_SERVER));
485         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT,
486                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_PORT));
487         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME,
488                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_USERNAME));
489         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD,
490                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_PASSWORD, Settings.KEYS.PROXY_PASSWORD));
491         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_NON_PROXY_HOSTS,
492                 cli.getStringArgument(CliParser.ARGUMENT.NON_PROXY_HOSTS));
493         settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT,
494                 cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_TIMEOUT));
495         settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_READ_TIMEOUT,
496                 cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_READ_TIMEOUT));
497         settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE,
498                 cli.getStringArgument(CliParser.ARGUMENT.HINTS_FILE));
499         settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE,
500                 cli.getStringArguments(CliParser.ARGUMENT.SUPPRESSION_FILES));
501         settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_USER,
502                 cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_USER));
503         settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_PASSWORD,
504                 cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_PASSWORD));
505         settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_BEARER_TOKEN,
506                 cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_BEARER_TOKEN));
507         
508         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED,
509                 cli.hasOption(CliParser.ARGUMENT.EXPERIMENTAL));
510         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIRED_ENABLED,
511                 cli.hasOption(CliParser.ARGUMENT.RETIRED));
512         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_GOLANG_PATH,
513                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_GO));
514         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_YARN_PATH,
515                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_YARN));
516         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_PNPM_PATH,
517                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_PNPM));
518         settings.setBooleanIfNotNull(Settings.KEYS.PRETTY_PRINT,
519                 cli.hasOption(CliParser.ARGUMENT.PRETTY_PRINT));
520         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL,
521                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL));
522         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_USER,
523                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_USER));
524         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_PASSWORD,
525                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_PASSWORD));
526         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_BEARER_TOKEN,
527                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_BEARER_TOKEN));
528         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE,
529                 cli.hasOption(CliParser.ARGUMENT.RETIRE_JS_FORCEUPDATE));
530         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FILTERS,
531                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_FILTERS));
532         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FILTER_NON_VULNERABLE,
533                 cli.hasOption(CliParser.ARGUMENT.RETIREJS_FILTER_NON_VULNERABLE));
534         settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED,
535                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_JAR, Settings.KEYS.ANALYZER_JAR_ENABLED));
536         settings.setBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED,
537                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_VERSION_CHECK, Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED));
538         settings.setBoolean(Settings.KEYS.ANALYZER_MSBUILD_PROJECT_ENABLED,
539                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_MSBUILD, Settings.KEYS.ANALYZER_MSBUILD_PROJECT_ENABLED));
540         settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED,
541                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_ARCHIVE, Settings.KEYS.ANALYZER_ARCHIVE_ENABLED));
542         settings.setBoolean(Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED,
543                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_KEV, Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED));
544         settings.setStringIfNotNull(Settings.KEYS.KEV_URL,
545                 cli.getStringArgument(CliParser.ARGUMENT.KEV_URL));
546         settings.setStringIfNotNull(Settings.KEYS.KEV_USER,
547                 cli.getStringArgument(CliParser.ARGUMENT.KEV_USER));
548         settings.setStringIfNotNull(Settings.KEYS.KEV_PASSWORD,
549                 cli.getStringArgument(CliParser.ARGUMENT.KEV_PASSWORD));
550         settings.setStringIfNotNull(Settings.KEYS.KEV_BEARER_TOKEN,
551                 cli.getStringArgument(CliParser.ARGUMENT.KEV_BEARER_TOKEN));
552         settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED,
553                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PY_DIST, Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED));
554         settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED,
555                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PY_PKG, Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED));
556         settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED,
557                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_AUTOCONF, Settings.KEYS.ANALYZER_AUTOCONF_ENABLED));
558         settings.setBoolean(Settings.KEYS.ANALYZER_MAVEN_INSTALL_ENABLED,
559                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_MAVEN_INSTALL, Settings.KEYS.ANALYZER_MAVEN_INSTALL_ENABLED));
560         settings.setBoolean(Settings.KEYS.ANALYZER_PIP_ENABLED,
561                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PIP, Settings.KEYS.ANALYZER_PIP_ENABLED));
562         settings.setBoolean(Settings.KEYS.ANALYZER_PIPFILE_ENABLED,
563                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PIPFILE, Settings.KEYS.ANALYZER_PIPFILE_ENABLED));
564         settings.setBoolean(Settings.KEYS.ANALYZER_POETRY_ENABLED,
565                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_POETRY, Settings.KEYS.ANALYZER_POETRY_ENABLED));
566         settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED,
567                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CMAKE, Settings.KEYS.ANALYZER_CMAKE_ENABLED));
568         settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED,
569                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NUSPEC, Settings.KEYS.ANALYZER_NUSPEC_ENABLED));
570         settings.setBoolean(Settings.KEYS.ANALYZER_NUGETCONF_ENABLED,
571                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NUGETCONF, Settings.KEYS.ANALYZER_NUGETCONF_ENABLED));
572         settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED,
573                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_ASSEMBLY, Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED));
574         settings.setBoolean(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED,
575                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_BUNDLE_AUDIT, Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED));
576         settings.setBoolean(Settings.KEYS.ANALYZER_FILE_NAME_ENABLED,
577                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_FILENAME, Settings.KEYS.ANALYZER_FILE_NAME_ENABLED));
578         settings.setBoolean(Settings.KEYS.ANALYZER_MIX_AUDIT_ENABLED,
579                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_MIX_AUDIT, Settings.KEYS.ANALYZER_MIX_AUDIT_ENABLED));
580         settings.setBoolean(Settings.KEYS.ANALYZER_OPENSSL_ENABLED,
581                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_OPENSSL, Settings.KEYS.ANALYZER_OPENSSL_ENABLED));
582         settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED,
583                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_COMPOSER, Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED));
584         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_SKIP_DEV,
585                 cli.hasOption(CliParser.ARGUMENT.COMPOSER_LOCK_SKIP_DEV));
586         settings.setBoolean(Settings.KEYS.ANALYZER_CPANFILE_ENABLED,
587                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CPAN, Settings.KEYS.ANALYZER_CPANFILE_ENABLED));
588         settings.setBoolean(Settings.KEYS.ANALYZER_GOLANG_DEP_ENABLED,
589                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_GO_DEP, Settings.KEYS.ANALYZER_GOLANG_DEP_ENABLED));
590         settings.setBoolean(Settings.KEYS.ANALYZER_GOLANG_MOD_ENABLED,
591                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_GOLANG_MOD, Settings.KEYS.ANALYZER_GOLANG_MOD_ENABLED));
592         settings.setBoolean(Settings.KEYS.ANALYZER_DART_ENABLED,
593                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_DART, Settings.KEYS.ANALYZER_DART_ENABLED));
594         settings.setBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED,
595                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NODE_JS, Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED));
596         settings.setBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED,
597                 !cli.isNodeAuditDisabled());
598         settings.setBoolean(Settings.KEYS.ANALYZER_YARN_AUDIT_ENABLED,
599                 !cli.isYarnAuditDisabled());
600         settings.setBoolean(Settings.KEYS.ANALYZER_PNPM_AUDIT_ENABLED,
601                 !cli.isPnpmAuditDisabled());
602         settings.setBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_USE_CACHE,
603                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NODE_AUDIT_CACHE, Settings.KEYS.ANALYZER_NODE_AUDIT_USE_CACHE));
604         settings.setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED,
605                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_RETIRE_JS, Settings.KEYS.ANALYZER_RETIREJS_ENABLED));
606         settings.setBoolean(Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED,
607                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_SWIFT, Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED));
608         settings.setBoolean(Settings.KEYS.ANALYZER_SWIFT_PACKAGE_RESOLVED_ENABLED,
609                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_SWIFT_RESOLVED, Settings.KEYS.ANALYZER_SWIFT_PACKAGE_RESOLVED_ENABLED));
610         settings.setBoolean(Settings.KEYS.ANALYZER_COCOAPODS_ENABLED,
611                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_COCOAPODS, Settings.KEYS.ANALYZER_COCOAPODS_ENABLED));
612         settings.setBoolean(Settings.KEYS.ANALYZER_CARTHAGE_ENABLED,
613                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CARTHAGE, Settings.KEYS.ANALYZER_CARTHAGE_ENABLED));
614         settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED,
615                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_RUBYGEMS, Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED));
616         settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED,
617                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CENTRAL, Settings.KEYS.ANALYZER_CENTRAL_ENABLED));
618         settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_USE_CACHE,
619                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CENTRAL_CACHE, Settings.KEYS.ANALYZER_CENTRAL_USE_CACHE));
620         settings.setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_ENABLED,
621                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_OSSINDEX, Settings.KEYS.ANALYZER_OSSINDEX_ENABLED));
622         settings.setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_USE_CACHE,
623                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_OSSINDEX_CACHE, Settings.KEYS.ANALYZER_OSSINDEX_USE_CACHE));
624 
625         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_SKIPDEV,
626                 cli.hasOption(CliParser.ARGUMENT.NODE_PACKAGE_SKIP_DEV_DEPENDENCIES));
627         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_AUDIT_SKIPDEV,
628                 cli.hasOption(CliParser.ARGUMENT.DISABLE_NODE_AUDIT_SKIPDEV));
629         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED,
630                 cli.hasOption(CliParser.ARGUMENT.ENABLE_NEXUS));
631         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL,
632                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_URL));
633         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_USER,
634                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_USERNAME));
635         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_PASSWORD,
636                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_PASSWORD));
637         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_BEARER_TOKEN,
638                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_BEARER_TOKEN));
639         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_URL,
640                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_URL));
641         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_USER,
642                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_USERNAME));
643         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_PASSWORD,
644                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_PASSWORD, Settings.KEYS.ANALYZER_OSSINDEX_PASSWORD));
645         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS,
646                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS,
647                         Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS));
648         settings.setFloat(Settings.KEYS.JUNIT_FAIL_ON_CVSS,
649                 cli.getFloatArgument(CliParser.ARGUMENT.FAIL_JUNIT_ON_CVSS, 0));
650         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_ENABLED,
651                 cli.hasOption(CliParser.ARGUMENT.ARTIFACTORY_ENABLED));
652         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_PARALLEL_ANALYSIS,
653                 cli.getBooleanArgument(CliParser.ARGUMENT.ARTIFACTORY_PARALLEL_ANALYSIS));
654         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_USES_PROXY,
655                 cli.getBooleanArgument(CliParser.ARGUMENT.ARTIFACTORY_USES_PROXY));
656         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_URL,
657                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_URL));
658         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_API_USERNAME,
659                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_USERNAME));
660         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_API_TOKEN,
661                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_API_TOKEN));
662         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_BEARER_TOKEN,
663                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_BEARER_TOKEN));
664         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_MIX_AUDIT_PATH,
665                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_MIX_AUDIT));
666         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH,
667                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_BUNDLE_AUDIT));
668         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_WORKING_DIRECTORY,
669                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_BUNDLE_AUDIT_WORKING_DIRECTORY));
670         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL,
671                 cli.getStringArgument(CliParser.ARGUMENT.NEXUS_URL));
672         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_USER,
673                 cli.getStringArgument(CliParser.ARGUMENT.NEXUS_USERNAME));
674         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_PASSWORD,
675                 cli.getStringArgument(CliParser.ARGUMENT.NEXUS_PASSWORD, Settings.KEYS.ANALYZER_NEXUS_PASSWORD));
676         
677         final boolean nexusUsesProxy = cli.isNexusUsesProxy();
678         settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
679         settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME,
680                 cli.getStringArgument(CliParser.ARGUMENT.DB_DRIVER));
681         settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH,
682                 cli.getStringArgument(CliParser.ARGUMENT.DB_DRIVER_PATH));
683         settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING,
684                 cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_STRING));
685         settings.setStringIfNotEmpty(Settings.KEYS.DB_USER,
686                 cli.getStringArgument(CliParser.ARGUMENT.DB_NAME));
687         settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD,
688                 cli.getStringArgument(CliParser.ARGUMENT.DB_PASSWORD, Settings.KEYS.DB_PASSWORD));
689         settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS,
690                 cli.getStringArgument(CliParser.ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS));
691         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_DOTNET_PATH,
692                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_CORE));
693 
694         String key = cli.getStringArgument(CliParser.ARGUMENT.NVD_API_KEY);
695         if (key != null) {
696             if ((key.startsWith("\"") && key.endsWith("\"") || (key.startsWith("'") && key.endsWith("'")))) {
697                 key = key.substring(1, key.length() - 1);
698             }
699             settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, key);
700         }
701         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_ENDPOINT,
702                 cli.getStringArgument(CliParser.ARGUMENT.NVD_API_ENDPOINT));
703         settings.setIntIfNotNull(Settings.KEYS.NVD_API_DELAY, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_DELAY));
704         settings.setIntIfNotNull(Settings.KEYS.NVD_API_RESULTS_PER_PAGE, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_RESULTS_PER_PAGE));
705         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_URL, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_URL));
706         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_USER, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_USER));
707         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_PASSWORD, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_PASSWORD));
708         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_BEARER_TOKEN, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_BEARER_TOKEN));
709         settings.setIntIfNotNull(Settings.KEYS.NVD_API_MAX_RETRY_COUNT, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_MAX_RETRY_COUNT));
710         settings.setIntIfNotNull(Settings.KEYS.NVD_API_VALID_FOR_HOURS, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_VALID_FOR_HOURS));
711 
712         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_URL,
713                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_URL));
714         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_USER,
715                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_USER));
716         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_PASSWORD,
717                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_PASSWORD));
718         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_BEARER_TOKEN,
719                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_BEARER_TOKEN));
720         settings.setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED,
721                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_HOSTED_SUPPRESSIONS, Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED));
722         settings.setBooleanIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE,
723                 cli.hasOption(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_FORCEUPDATE));
724         settings.setIntIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS,
725                 cli.getIntegerValue(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS));
726     }
727 
728     
729     
730 
731 
732 
733 
734     private void prepareLogger(String verboseLog) {
735         final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
736         final PatternLayoutEncoder encoder = new PatternLayoutEncoder();
737         encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
738         encoder.setContext(context);
739         encoder.start();
740         final FileAppender<ILoggingEvent> fa = new FileAppender<>();
741         fa.setAppend(true);
742         fa.setEncoder(encoder);
743         fa.setContext(context);
744         fa.setFile(verboseLog);
745         final File f = new File(verboseLog);
746         String name = f.getName();
747         final int i = name.lastIndexOf('.');
748         if (i > 1) {
749             name = name.substring(0, i);
750         }
751         fa.setName(name);
752         fa.start();
753         final ch.qos.logback.classic.Logger rootLogger = context.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
754         rootLogger.setLevel(Level.DEBUG);
755         final ThresholdFilter filter = new ThresholdFilter();
756         filter.setLevel(LogLevel.INFO.getValue());
757         filter.setContext(context);
758         filter.start();
759         rootLogger.iteratorForAppenders().forEachRemaining(action -> action.addFilter(filter));
760         rootLogger.addAppender(fa);
761     }
762 
763     
764 
765 
766 
767 
768 
769 
770 
771 
772     protected String ensureCanonicalPath(String path) {
773         final String basePath;
774         String wildCards = null;
775         final String file = path.replace('\\', '/');
776         if (file.contains("*") || file.contains("?")) {
777 
778             int pos = getLastFileSeparator(file);
779             if (pos < 0) {
780                 return file;
781             }
782             pos += 1;
783             basePath = file.substring(0, pos);
784             wildCards = file.substring(pos);
785         } else {
786             basePath = file;
787         }
788 
789         File f = new File(basePath);
790         try {
791             f = f.getCanonicalFile();
792             if (wildCards != null) {
793                 f = new File(f, wildCards);
794             }
795         } catch (IOException ex) {
796             LOGGER.warn("Invalid path '{}' was provided.", path);
797             LOGGER.debug("Invalid path provided", ex);
798         }
799         return f.getAbsolutePath().replace('\\', '/');
800     }
801 
802     
803 
804 
805 
806 
807 
808     @SuppressWarnings("ManualMinMaxCalculation")
809     private int getLastFileSeparator(String file) {
810         if (file.contains("*") || file.contains("?")) {
811             int p1 = file.indexOf('*');
812             int p2 = file.indexOf('?');
813             p1 = p1 > 0 ? p1 : file.length();
814             p2 = p2 > 0 ? p2 : file.length();
815             int pos = p1 < p2 ? p1 : p2;
816             pos = file.lastIndexOf('/', pos);
817             return pos;
818         } else {
819             return file.lastIndexOf('/');
820         }
821     }
822 }