View Javadoc
1   /*
2    * This file is part of dependency-check-utils.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.utils;
19  
20  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  
24  import com.fasterxml.jackson.core.JsonProcessingException;
25  import com.fasterxml.jackson.databind.ObjectMapper;
26  
27  import org.jetbrains.annotations.NotNull;
28  import org.jetbrains.annotations.Nullable;
29  
30  import java.io.File;
31  import java.io.FileInputStream;
32  import java.io.FileNotFoundException;
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.io.PrintWriter;
36  import java.io.StringWriter;
37  import java.io.UnsupportedEncodingException;
38  import java.net.URLDecoder;
39  import java.nio.charset.StandardCharsets;
40  import java.security.ProtectionDomain;
41  import java.util.ArrayList;
42  import java.util.Arrays;
43  import java.util.Enumeration;
44  import java.util.List;
45  import java.util.Properties;
46  import java.util.UUID;
47  import java.util.function.Predicate;
48  import java.util.regex.Pattern;
49  import java.util.stream.Collectors;
50  
51  /**
52   * A simple settings container that wraps the dependencycheck.properties file.
53   *
54   * @author Jeremy Long
55   * @version $Id: $Id
56   */
57  public final class Settings {
58  
59      /**
60       * The logger.
61       */
62      private static final Logger LOGGER = LoggerFactory.getLogger(Settings.class);
63      /**
64       * The properties file location.
65       */
66      private static final String PROPERTIES_FILE = "dependencycheck.properties";
67      /**
68       * Array separator.
69       */
70      private static final String ARRAY_SEP = ",";
71      /**
72       * The properties.
73       */
74      private Properties props = null;
75      /**
76       * The collection of properties that should be masked when logged.
77       */
78      private List<Predicate<String>> maskedKeys;
79      /**
80       * A reference to the temporary directory; used in case it needs to be
81       * deleted during cleanup.
82       */
83      private File tempDirectory = null;
84  
85      /**
86       * Reference to a utility class used to convert objects to json.
87       */
88      private final ObjectMapper objectMapper = new ObjectMapper();
89  
90      //<editor-fold defaultstate="collapsed" desc="KEYS used to access settings">
91      /**
92       * The collection of keys used within the properties file.
93       */
94      //suppress hard-coded password rule
95      @SuppressWarnings("squid:S2068")
96      public static final class KEYS {
97  
98          /**
99           * The key to obtain the application name.
100          */
101         public static final String APPLICATION_NAME = "odc.application.name";
102         /**
103          * The key to obtain the application version.
104          */
105         public static final String APPLICATION_VERSION = "odc.application.version";
106         /**
107          * The key to obtain the URL to retrieve the current release version
108          * from.
109          */
110         public static final String ENGINE_VERSION_CHECK_URL = "engine.version.url";
111         /**
112          * The properties key indicating whether or not the cached data sources
113          * should be updated.
114          */
115         public static final String AUTO_UPDATE = "odc.autoupdate";
116         /**
117          * The database driver class name. If this is not in the properties file
118          * the embedded database is used.
119          */
120         public static final String DB_DRIVER_NAME = "data.driver_name";
121         /**
122          * The database driver class name. If this is not in the properties file
123          * the embedded database is used.
124          */
125         public static final String DB_DRIVER_PATH = "data.driver_path";
126         /**
127          * The database connection string. If this is not in the properties file
128          * the embedded database is used.
129          */
130         public static final String DB_CONNECTION_STRING = "data.connection_string";
131         /**
132          * The username to use when connecting to the database.
133          */
134         public static final String DB_USER = "data.user";
135         /**
136          * The password to authenticate to the database.
137          */
138         public static final String DB_PASSWORD = "data.password";
139         /**
140          * The base path to use for the data directory (for embedded db and
141          * other cached resources from the Internet).
142          */
143         public static final String DATA_DIRECTORY = "data.directory";
144         /**
145          * The base path to use for the H2 data directory (for embedded db).
146          */
147         public static final String H2_DATA_DIRECTORY = "data.h2.directory";
148         /**
149          * The database file name.
150          */
151         public static final String DB_FILE_NAME = "data.file_name";
152         /**
153          * The database schema version.
154          */
155         public static final String DB_VERSION = "data.version";
156         /**
157          * The starts with filter used to exclude CVE entries from the database.
158          * By default this is set to 'cpe:2.3:a:' which limits the CVEs imported
159          * to just those that are related to applications. If this were set to
160          * just 'cpe:2.3:' the OS, hardware, and application related CVEs would
161          * be imported.
162          */
163         public static final String CVE_CPE_STARTS_WITH_FILTER = "cve.cpe.startswith.filter";
164         /**
165          * The NVD API Endpoint.
166          */
167         public static final String NVD_API_ENDPOINT = "nvd.api.endpoint";
168         /**
169          * API Key for the NVD API.
170          */
171         public static final String NVD_API_KEY = "nvd.api.key";
172         /**
173          * The delay between requests for the NVD API.
174          */
175         public static final String NVD_API_DELAY = "nvd.api.delay";
176         /**
177          * The maximum number of retry requests for a single call to the NVD
178          * API.
179          */
180         public static final String NVD_API_MAX_RETRY_COUNT = "nvd.api.max.retry.count";
181         /**
182          * The properties key to control the skipping of the check for NVD
183          * updates.
184          */
185         public static final String NVD_API_VALID_FOR_HOURS = "nvd.api.check.validforhours";
186         /**
187          * The properties key to control the results per page lower than NVD's default of 2000
188          * See #6863 for the rationale on allowing lower configurations.
189          */
190         public static final String NVD_API_RESULTS_PER_PAGE = "nvd.api.results.per.page";
191         /**
192          * The properties key that indicates how often the NVD API data feed
193          * needs to be updated before a full refresh is evaluated.
194          */
195         public static final String NVD_API_DATAFEED_VALID_FOR_DAYS = "nvd.api.datafeed.validfordays";
196         /**
197          * The URL for the NVD API Data Feed.
198          */
199         public static final String NVD_API_DATAFEED_URL = "nvd.api.datafeed.url";
200         /**
201          * The username to use when connecting to the NVD Data feed.
202          */
203         public static final String NVD_API_DATAFEED_USER = "nvd.api.datafeed.user";
204         /**
205          * The password to authenticate to the NVD Data feed.
206          */
207         public static final String NVD_API_DATAFEED_PASSWORD = "nvd.api.datafeed.password";
208         /**
209          * The starting year for the NVD CVE Data feed cache.
210          */
211         public static final String NVD_API_DATAFEED_START_YEAR = "nvd.api.datafeed.startyear";
212         //END NEW
213         /**
214          * The key to determine if the NVD CVE analyzer is enabled.
215          */
216         public static final String ANALYZER_NVD_CVE_ENABLED = "analyzer.nvdcve.enabled";
217         /**
218          * The properties key that indicates how often the CPE data needs to be
219          * updated.
220          */
221         public static final String CPE_MODIFIED_VALID_FOR_DAYS = "cpe.validfordays";
222         /**
223          * The properties key for the URL to retrieve the CPE.
224          */
225         public static final String CPE_URL = "cpe.url";
226         /**
227          * The properties key for the URL to retrieve the Known Exploited
228          * Vulnerabilities..
229          */
230         public static final String KEV_URL = "kev.url";
231 
232         /**
233          * The properties key for the hosted suppressions username.
234          * For use when hosted suppressions are mirrored locally on a site requiring authentication
235          */
236         public static final String KEV_USER = "kev.user";
237 
238         /**
239          * The properties key for the hosted suppressions password.
240          * For use when hosted suppressions are mirrored locally on a site requiring authentication
241          */
242         public static final String KEV_PASSWORD = "kev.password";
243 
244         /**
245          * The properties key to control the skipping of the check for Known
246          * Exploited Vulnerabilities updates.
247          */
248         public static final String KEV_CHECK_VALID_FOR_HOURS = "kev.check.validforhours";
249         /**
250          * Whether or not if using basic auth with a proxy the system setting
251          * 'jdk.http.auth.tunneling.disabledSchemes' should be set to an empty
252          * string.
253          */
254         public static final String PROXY_DISABLE_SCHEMAS = "proxy.disableSchemas";
255         /**
256          * The properties key for the proxy server.
257          */
258         public static final String PROXY_SERVER = "proxy.server";
259         /**
260          * The properties key for the proxy port - this must be an integer
261          * value.
262          */
263         public static final String PROXY_PORT = "proxy.port";
264         /**
265          * The properties key for the proxy username.
266          */
267         public static final String PROXY_USERNAME = "proxy.username";
268         /**
269          * The properties key for the proxy password.
270          */
271         public static final String PROXY_PASSWORD = "proxy.password";
272         /**
273          * The properties key for the non proxy hosts.
274          */
275         public static final String PROXY_NON_PROXY_HOSTS = "proxy.nonproxyhosts";
276         /**
277          * The properties key for the connection timeout.
278          */
279         public static final String CONNECTION_TIMEOUT = "connection.timeout";
280         /**
281          * The properties key for the connection read timeout.
282          */
283         public static final String CONNECTION_READ_TIMEOUT = "connection.read.timeout";
284         /**
285          * The location of the temporary directory.
286          */
287         public static final String TEMP_DIRECTORY = "temp.directory";
288         /**
289          * The maximum number of threads to allocate when downloading files.
290          */
291         public static final String MAX_DOWNLOAD_THREAD_POOL_SIZE = "max.download.threads";
292         /**
293          * The properties key for the analysis timeout.
294          */
295         public static final String ANALYSIS_TIMEOUT = "odc.analysis.timeout";
296         /**
297          * The key for the suppression file.
298          */
299         public static final String SUPPRESSION_FILE = "suppression.file";
300         /**
301          * The username used when connecting to the suppressionFiles.
302          */
303         public static final String SUPPRESSION_FILE_USER = "suppression.file.user";
304         /**
305          * The password used when connecting to the suppressionFiles.
306          */
307         public static final String SUPPRESSION_FILE_PASSWORD = "suppression.file.password";
308         /**
309          * The key for the whether the hosted suppressions file datasource is
310          * enabled.
311          */
312         public static final String HOSTED_SUPPRESSIONS_ENABLED = "hosted.suppressions.enabled";
313         /**
314          * The key for the hosted suppressions file URL.
315          */
316         public static final String HOSTED_SUPPRESSIONS_URL = "hosted.suppressions.url";
317 
318         /**
319          * The properties key for the hosted suppressions username.
320          * For use when hosted suppressions are mirrored locally on a site requiring authentication
321          */
322         public static final String HOSTED_SUPPRESSIONS_USER = "hosted.suppressions.user";
323 
324         /**
325          * The properties key for the hosted suppressions password.
326          * For use when hosted suppressions are mirrored locally on a site requiring authentication
327          */
328         public static final String HOSTED_SUPPRESSIONS_PASSWORD = "hosted.suppressions.password";
329 
330         /**
331          * The properties key for defining whether the hosted suppressions file
332          * will be updated regardless of the autoupdate settings.
333          */
334         public static final String HOSTED_SUPPRESSIONS_FORCEUPDATE = "hosted.suppressions.forceupdate";
335 
336         /**
337          * The properties key to control the skipping of the check for hosted
338          * suppressions file updates.
339          */
340         public static final String HOSTED_SUPPRESSIONS_VALID_FOR_HOURS = "hosted.suppressions.validforhours";
341 
342         /**
343          * The key for the hint file.
344          */
345         public static final String HINTS_FILE = "hints.file";
346         /**
347          * The key for the property that controls what CVSS scores are
348          * considered failing test cases for the JUNIT repor.
349          */
350         public static final String JUNIT_FAIL_ON_CVSS = "junit.fail.on.cvss";
351 
352         /**
353          * The properties key for whether the Jar Analyzer is enabled.
354          */
355         public static final String ANALYZER_JAR_ENABLED = "analyzer.jar.enabled";
356 
357         /**
358          * The properties key for whether the Known Exploited Vulnerability
359          * Analyzer is enabled.
360          */
361         public static final String ANALYZER_KNOWN_EXPLOITED_ENABLED = "analyzer.knownexploited.enabled";
362 
363         /**
364          * The properties key for whether experimental analyzers are loaded.
365          */
366         public static final String ANALYZER_EXPERIMENTAL_ENABLED = "analyzer.experimental.enabled";
367         /**
368          * The properties key for whether experimental analyzers are loaded.
369          */
370         public static final String ANALYZER_RETIRED_ENABLED = "analyzer.retired.enabled";
371         /**
372          * The properties key for whether the Archive analyzer is enabled.
373          */
374         public static final String ANALYZER_ARCHIVE_ENABLED = "analyzer.archive.enabled";
375         /**
376          * The properties key for whether the node.js package analyzer is
377          * enabled.
378          */
379         public static final String ANALYZER_NODE_PACKAGE_ENABLED = "analyzer.node.package.enabled";
380         /**
381          * The properties key for configure whether the Node Package analyzer
382          * should skip devDependencies.
383          */
384         public static final String ANALYZER_NODE_PACKAGE_SKIPDEV = "analyzer.node.package.skipdev";
385         /**
386          * The properties key for whether the Node Audit analyzer is enabled.
387          */
388         public static final String ANALYZER_NODE_AUDIT_ENABLED = "analyzer.node.audit.enabled";
389         /**
390          * The properties key for whether the Yarn Audit analyzer is enabled.
391          */
392         public static final String ANALYZER_YARN_AUDIT_ENABLED = "analyzer.yarn.audit.enabled";
393         /**
394          * The properties key for whether the Pnpm Audit analyzer is enabled.
395          */
396         public static final String ANALYZER_PNPM_AUDIT_ENABLED = "analyzer.pnpm.audit.enabled";
397         /**
398          * The properties key for supplying the URL to the Node Audit API.
399          */
400         public static final String ANALYZER_NODE_AUDIT_URL = "analyzer.node.audit.url";
401         /**
402          * The properties key for configure whether the Node Audit analyzer
403          * should skip devDependencies.
404          */
405         public static final String ANALYZER_NODE_AUDIT_SKIPDEV = "analyzer.node.audit.skipdev";
406         /**
407          * The properties key for whether node audit analyzer results will be
408          * cached.
409          */
410         public static final String ANALYZER_NODE_AUDIT_USE_CACHE = "analyzer.node.audit.use.cache";
411         /**
412          * The properties key for whether the RetireJS analyzer is enabled.
413          */
414         public static final String ANALYZER_RETIREJS_ENABLED = "analyzer.retirejs.enabled";
415         /**
416          * The properties key for whether the RetireJS analyzer file content
417          * filters.
418          */
419         public static final String ANALYZER_RETIREJS_FILTERS = "analyzer.retirejs.filters";
420         /**
421          * The properties key for whether the RetireJS analyzer should filter
422          * out non-vulnerable dependencies.
423          */
424         public static final String ANALYZER_RETIREJS_FILTER_NON_VULNERABLE = "analyzer.retirejs.filternonvulnerable";
425         /**
426          * The properties key for defining the URL to the RetireJS repository.
427          */
428         public static final String ANALYZER_RETIREJS_REPO_JS_URL = "analyzer.retirejs.repo.js.url";
429         /**
430          * The properties key for the Nexus search credentials username.
431          */
432         public static final String ANALYZER_RETIREJS_REPO_JS_USER = "analyzer.retirejs.repo.js.username";
433         /**
434          * The properties key for the Nexus search credentials password.
435          */
436         public static final String ANALYZER_RETIREJS_REPO_JS_PASSWORD = "analyzer.retirejs.repo.js.password";
437         /**
438          * The properties key for defining whether the RetireJS repository will
439          * be updated regardless of the autoupdate settings.
440          */
441         public static final String ANALYZER_RETIREJS_FORCEUPDATE = "analyzer.retirejs.forceupdate";
442         /**
443          * The properties key to control the skipping of the check for CVE
444          * updates.
445          */
446         public static final String ANALYZER_RETIREJS_REPO_VALID_FOR_HOURS = "analyzer.retirejs.repo.validforhours";
447         /**
448          * The properties key for whether the PHP composer lock file analyzer is
449          * enabled.
450          */
451         public static final String ANALYZER_COMPOSER_LOCK_ENABLED = "analyzer.composer.lock.enabled";
452         /**
453          * The properties key for whether the PHP composer lock file analyzer 
454          * should skip dev packages.
455          */
456         public static final String ANALYZER_COMPOSER_LOCK_SKIP_DEV = "analyzer.composer.lock.skipdev";
457         /**
458          * The properties key for whether the Perl CPAN file file analyzer is
459          * enabled.
460          */
461         public static final String ANALYZER_CPANFILE_ENABLED = "analyzer.cpanfile.enabled";
462         /**
463          * The properties key for whether the Python Distribution analyzer is
464          * enabled.
465          */
466         public static final String ANALYZER_PYTHON_DISTRIBUTION_ENABLED = "analyzer.python.distribution.enabled";
467         /**
468          * The properties key for whether the Python Package analyzer is
469          * enabled.
470          */
471         public static final String ANALYZER_PYTHON_PACKAGE_ENABLED = "analyzer.python.package.enabled";
472         /**
473          * The properties key for whether the Elixir mix audit analyzer is
474          * enabled.
475          */
476         public static final String ANALYZER_MIX_AUDIT_ENABLED = "analyzer.mix.audit.enabled";
477         /**
478          * The path to mix_audit, if available.
479          */
480         public static final String ANALYZER_MIX_AUDIT_PATH = "analyzer.mix.audit.path";
481         /**
482          * The properties key for whether the Golang Mod analyzer is enabled.
483          */
484         public static final String ANALYZER_GOLANG_MOD_ENABLED = "analyzer.golang.mod.enabled";
485         /**
486          * The path to go, if available.
487          */
488         public static final String ANALYZER_GOLANG_PATH = "analyzer.golang.path";
489         /**
490          * The path to go, if available.
491          */
492         public static final String ANALYZER_YARN_PATH = "analyzer.yarn.path";
493         /**
494          * The path to pnpm, if available.
495          */
496         public static final String ANALYZER_PNPM_PATH = "analyzer.pnpm.path";
497         /**
498          * The properties key for whether the Golang Dep analyzer is enabled.
499          */
500         public static final String ANALYZER_GOLANG_DEP_ENABLED = "analyzer.golang.dep.enabled";
501         /**
502          * The properties key for whether the Ruby Gemspec Analyzer is enabled.
503          */
504         public static final String ANALYZER_RUBY_GEMSPEC_ENABLED = "analyzer.ruby.gemspec.enabled";
505         /**
506          * The properties key for whether the Autoconf analyzer is enabled.
507          */
508         public static final String ANALYZER_AUTOCONF_ENABLED = "analyzer.autoconf.enabled";
509         /**
510          * The properties key for whether the maven_install.json analyzer is
511          * enabled.
512          */
513         public static final String ANALYZER_MAVEN_INSTALL_ENABLED = "analyzer.maveninstall.enabled";
514         /**
515          * The properties key for whether the pip analyzer is enabled.
516          */
517         public static final String ANALYZER_PIP_ENABLED = "analyzer.pip.enabled";
518         /**
519          * The properties key for whether the pipfile analyzer is enabled.
520          */
521         public static final String ANALYZER_PIPFILE_ENABLED = "analyzer.pipfile.enabled";
522         /**
523          * The properties key for whether the Poetry analyzer is enabled.
524          */
525         public static final String ANALYZER_POETRY_ENABLED = "analyzer.poetry.enabled";
526         /**
527          * The properties key for whether the CMake analyzer is enabled.
528          */
529         public static final String ANALYZER_CMAKE_ENABLED = "analyzer.cmake.enabled";
530         /**
531          * The properties key for whether the Ruby Bundler Audit analyzer is
532          * enabled.
533          */
534         public static final String ANALYZER_BUNDLE_AUDIT_ENABLED = "analyzer.bundle.audit.enabled";
535         /**
536          * The properties key for whether the .NET Assembly analyzer is enabled.
537          */
538         public static final String ANALYZER_ASSEMBLY_ENABLED = "analyzer.assembly.enabled";
539         /**
540          * The properties key for whether the .NET Nuspec analyzer is enabled.
541          */
542         public static final String ANALYZER_NUSPEC_ENABLED = "analyzer.nuspec.enabled";
543         /**
544          * The properties key for whether the .NET Nuget packages.config
545          * analyzer is enabled.
546          */
547         public static final String ANALYZER_NUGETCONF_ENABLED = "analyzer.nugetconf.enabled";
548         /**
549          * The properties key for whether the Libman analyzer is enabled.
550          */
551         public static final String ANALYZER_LIBMAN_ENABLED = "analyzer.libman.enabled";
552         /**
553          * The properties key for whether the .NET MSBuild Project analyzer is
554          * enabled.
555          */
556         public static final String ANALYZER_MSBUILD_PROJECT_ENABLED = "analyzer.msbuildproject.enabled";
557         /**
558          * The properties key for whether the Nexus analyzer is enabled.
559          */
560         public static final String ANALYZER_NEXUS_ENABLED = "analyzer.nexus.enabled";
561         /**
562          * The properties key for the Nexus search URL.
563          */
564         public static final String ANALYZER_NEXUS_URL = "analyzer.nexus.url";
565         /**
566          * The properties key for the Nexus search credentials username.
567          */
568         public static final String ANALYZER_NEXUS_USER = "analyzer.nexus.username";
569         /**
570          * The properties key for the Nexus search credentials password.
571          */
572         public static final String ANALYZER_NEXUS_PASSWORD = "analyzer.nexus.password";
573         /**
574          * The properties key for using the proxy to reach Nexus.
575          */
576         public static final String ANALYZER_NEXUS_USES_PROXY = "analyzer.nexus.proxy";
577         /**
578          * The properties key for whether the Artifactory analyzer is enabled.
579          */
580         public static final String ANALYZER_ARTIFACTORY_ENABLED = "analyzer.artifactory.enabled";
581         /**
582          * The properties key for the Artifactory search URL.
583          */
584         public static final String ANALYZER_ARTIFACTORY_URL = "analyzer.artifactory.url";
585         /**
586          * The properties key for the Artifactory username.
587          */
588         public static final String ANALYZER_ARTIFACTORY_API_USERNAME = "analyzer.artifactory.api.username";
589         /**
590          * The properties key for the Artifactory API token.
591          */
592         public static final String ANALYZER_ARTIFACTORY_API_TOKEN = "analyzer.artifactory.api.token";
593         /**
594          * The properties key for the Artifactory bearer token
595          * (https://www.jfrog.com/confluence/display/RTF/Access+Tokens). It can
596          * be generated using:
597          * <pre>curl -u yourUserName -X POST \
598          *    "https://artifactory.techno.ingenico.com/artifactory/api/security/token" \
599          *    -d "username=yourUserName"</pre>.
600          */
601         public static final String ANALYZER_ARTIFACTORY_BEARER_TOKEN = "analyzer.artifactory.bearer.token";
602         /**
603          * The properties key for using the proxy to reach Artifactory.
604          */
605         public static final String ANALYZER_ARTIFACTORY_USES_PROXY = "analyzer.artifactory.proxy";
606         /**
607          * The properties key for whether the Artifactory analyzer should use
608          * parallel processing.
609          */
610         public static final String ANALYZER_ARTIFACTORY_PARALLEL_ANALYSIS = "analyzer.artifactory.parallel.analysis";
611         /**
612          * The properties key for whether the Central analyzer is enabled.
613          */
614         public static final String ANALYZER_CENTRAL_ENABLED = "analyzer.central.enabled";
615         /**
616          * Key for the path to the local Maven repository.
617          */
618         public static final String MAVEN_LOCAL_REPO = "odc.maven.local.repo";
619         /**
620          * Key for the URL to obtain content from Maven Central.
621          */
622         public static final String CENTRAL_CONTENT_URL = "central.content.url";
623         /**
624          * The properties key for whether the Central analyzer should use
625          * parallel processing.
626          */
627         public static final String ANALYZER_CENTRAL_PARALLEL_ANALYSIS = "analyzer.central.parallel.analysis";
628         /**
629          * The properties key for whether the Central analyzer should use
630          * parallel processing.
631          */
632         public static final String ANALYZER_CENTRAL_RETRY_COUNT = "analyzer.central.retry.count";
633         /**
634          * The properties key for whether the OpenSSL analyzer is enabled.
635          */
636         public static final String ANALYZER_OPENSSL_ENABLED = "analyzer.openssl.enabled";
637         /**
638          * The properties key for whether the cocoapods analyzer is enabled.
639          */
640         public static final String ANALYZER_COCOAPODS_ENABLED = "analyzer.cocoapods.enabled";
641         /**
642          * The properties key for whether the carthage analyzer is enabled.
643          */
644         public static final String ANALYZER_CARTHAGE_ENABLED = "analyzer.carthage.enabled";
645         /**
646          * The properties key for whether the SWIFT package manager analyzer is
647          * enabled.
648          */
649         public static final String ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED = "analyzer.swift.package.manager.enabled";
650         /**
651          * The properties key for whether the SWIFT package resolved analyzer is
652          * enabled.
653          */
654         public static final String ANALYZER_SWIFT_PACKAGE_RESOLVED_ENABLED = "analyzer.swift.package.resolved.enabled";
655         /**
656          * The properties key for the Central search URL.
657          */
658         public static final String ANALYZER_CENTRAL_URL = "analyzer.central.url";
659         /**
660          * The properties key for the Central search query.
661          */
662         public static final String ANALYZER_CENTRAL_QUERY = "analyzer.central.query";
663         /**
664          * The properties key for whether Central search results will be cached.
665          */
666         public static final String ANALYZER_CENTRAL_USE_CACHE = "analyzer.central.use.cache";
667         /**
668          * The path to dotnet core, if available.
669          */
670         public static final String ANALYZER_ASSEMBLY_DOTNET_PATH = "analyzer.assembly.dotnet.path";
671         /**
672          * The path to bundle-audit, if available.
673          */
674         public static final String ANALYZER_BUNDLE_AUDIT_PATH = "analyzer.bundle.audit.path";
675         /**
676          * The path to bundle-audit, if available.
677          */
678         public static final String ANALYZER_BUNDLE_AUDIT_WORKING_DIRECTORY = "analyzer.bundle.audit.working.directory";
679         /**
680          * The additional configured zip file extensions, if available.
681          */
682         public static final String ADDITIONAL_ZIP_EXTENSIONS = "extensions.zip";
683         /**
684          * The key to obtain the path to the VFEED data file.
685          */
686         public static final String VFEED_DATA_FILE = "vfeed.data_file";
687         /**
688          * The key to obtain the VFEED connection string.
689          */
690         public static final String VFEED_CONNECTION_STRING = "vfeed.connection_string";
691         /**
692          * The key to obtain the base download URL for the VFeed data file.
693          */
694         public static final String VFEED_DOWNLOAD_URL = "vfeed.download_url";
695         /**
696          * The key to obtain the download file name for the VFeed data.
697          */
698         public static final String VFEED_DOWNLOAD_FILE = "vfeed.download_file";
699         /**
700          * The key to obtain the VFeed update status.
701          */
702         public static final String VFEED_UPDATE_STATUS = "vfeed.update_status";
703         /**
704          * The key to the HTTP request method for query last modified date.
705          */
706         public static final String DOWNLOADER_QUICK_QUERY_TIMESTAMP = "downloader.quick.query.timestamp";
707         /**
708          * The key to HTTP protocol list to use.
709          */
710         public static final String DOWNLOADER_TLS_PROTOCOL_LIST = "downloader.tls.protocols";
711         /**
712          * The key to determine if the CPE analyzer is enabled.
713          */
714         public static final String ANALYZER_CPE_ENABLED = "analyzer.cpe.enabled";
715         /**
716          * The key to determine if the NPM CPE analyzer is enabled.
717          */
718         public static final String ANALYZER_NPM_CPE_ENABLED = "analyzer.npm.cpe.enabled";
719         /**
720          * The key to determine if the CPE Suppression analyzer is enabled.
721          */
722         public static final String ANALYZER_CPE_SUPPRESSION_ENABLED = "analyzer.cpesuppression.enabled";
723         /**
724          * The key to determine if the Dependency Bundling analyzer is enabled.
725          */
726         public static final String ANALYZER_DEPENDENCY_BUNDLING_ENABLED = "analyzer.dependencybundling.enabled";
727         /**
728          * The key to determine if the Dependency Merging analyzer is enabled.
729          */
730         public static final String ANALYZER_DEPENDENCY_MERGING_ENABLED = "analyzer.dependencymerging.enabled";
731         /**
732          * The key to determine if the False Positive analyzer is enabled.
733          */
734         public static final String ANALYZER_FALSE_POSITIVE_ENABLED = "analyzer.falsepositive.enabled";
735         /**
736          * The key to determine if the File Name analyzer is enabled.
737          */
738         public static final String ANALYZER_FILE_NAME_ENABLED = "analyzer.filename.enabled";
739         /**
740          * The key to determine if the File Version analyzer is enabled.
741          */
742         public static final String ANALYZER_PE_ENABLED = "analyzer.pe.enabled";
743         /**
744          * The key to determine if the Hint analyzer is enabled.
745          */
746         public static final String ANALYZER_HINT_ENABLED = "analyzer.hint.enabled";
747         /**
748          * The key to determine if the Version Filter analyzer is enabled.
749          */
750         public static final String ANALYZER_VERSION_FILTER_ENABLED = "analyzer.versionfilter.enabled";
751         /**
752          * The key to determine if the Vulnerability Suppression analyzer is
753          * enabled.
754          */
755         public static final String ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED = "analyzer.vulnerabilitysuppression.enabled";
756         /**
757          * The key to determine if the NVD CVE updater should be enabled.
758          */
759         public static final String UPDATE_NVDCVE_ENABLED = "updater.nvdcve.enabled";
760         /**
761          * The key to determine if dependency-check should check if there is a
762          * new version available.
763          */
764         public static final String UPDATE_VERSION_CHECK_ENABLED = "updater.versioncheck.enabled";
765         /**
766          * The key to determine which ecosystems should skip the CPE analysis.
767          */
768         public static final String ECOSYSTEM_SKIP_CPEANALYZER = "ecosystem.skip.cpeanalyzer";
769         /**
770          * Adds capabilities to batch insert. Tested on PostgreSQL and H2.
771          */
772         public static final String ENABLE_BATCH_UPDATES = "database.batchinsert.enabled";
773         /**
774          * Size of database batch inserts.
775          */
776         public static final String MAX_BATCH_SIZE = "database.batchinsert.maxsize";
777         /**
778          * The key that specifies the class name of the Write Lock shutdown
779          * hook.
780          */
781         public static final String WRITELOCK_SHUTDOWN_HOOK = "data.writelock.shutdownhook";
782         /**
783          * The properties key for whether the Sonatype OSS Index analyzer is
784          * enabled.
785          */
786         public static final String ANALYZER_OSSINDEX_ENABLED = "analyzer.ossindex.enabled";
787         /**
788          * The properties key for whether the Sonatype OSS Index should use a
789          * local cache.
790          */
791         public static final String ANALYZER_OSSINDEX_USE_CACHE = "analyzer.ossindex.use.cache";
792         /**
793          * The properties key for the Sonatype OSS Index URL.
794          */
795         public static final String ANALYZER_OSSINDEX_URL = "analyzer.ossindex.url";
796         /**
797          * The properties key for the Sonatype OSS Index user.
798          */
799         public static final String ANALYZER_OSSINDEX_USER = "analyzer.ossindex.user";
800         /**
801          * The properties key for the Sonatype OSS Index password.
802          */
803         public static final String ANALYZER_OSSINDEX_PASSWORD = "analyzer.ossindex.password";
804         /**
805          * The properties key for the Sonatype OSS batch-size.
806          */
807         public static final String ANALYZER_OSSINDEX_BATCH_SIZE = "analyzer.ossindex.batch.size";
808         /**
809          * The properties key for the Sonatype OSS Request Delay. Amount of time
810          * in seconds to wait before executing a request against the Sonatype
811          * OSS Rest API
812          */
813         public static final String ANALYZER_OSSINDEX_REQUEST_DELAY = "analyzer.ossindex.request.delay";
814         /**
815          * The properties key for only warning about Sonatype OSS Index remote
816          * errors instead of failing the request.
817          */
818         public static final String ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS = "analyzer.ossindex.remote-error.warn-only";
819         /**
820          * The properties key setting whether or not the JSON and XML reports
821          * will be pretty printed.
822          */
823 
824         /**
825          * The properties key for whether the Dart analyzer is enabled.
826          */
827         public static final String ANALYZER_DART_ENABLED = "analyzer.dart.enabled";
828 
829         /**
830          * The properties key for whether to pretty print the XML/JSON reports.
831          */
832         public static final String PRETTY_PRINT = "odc.reports.pretty.print";
833         /**
834          * The properties key setting which other keys should be considered
835          * sensitive and subsequently masked when logged.
836          */
837         public static final String MASKED_PROPERTIES = "odc.settings.mask";
838         /**
839          * The properties key for the default max query size for Lucene query
840          * results.
841          */
842         public static final String MAX_QUERY_SIZE_DEFAULT = "odc.ecosystem.maxquerylimit.default";
843         /**
844          * The properties key prefix for the default max query size for Lucene
845          * query results; append the ecosystem to obtain the default query size.
846          */
847         public static final String MAX_QUERY_SIZE_PREFIX = "odc.ecosystem.maxquerylimit.";
848 
849         /**
850          * private constructor because this is a "utility" class containing
851          * constants
852          */
853         private KEYS() {
854             //do nothing
855         }
856     }
857     //</editor-fold>
858 
859     /**
860      * Initialize the settings object.
861      */
862     public Settings() {
863         initialize(PROPERTIES_FILE);
864     }
865 
866     /**
867      * Initialize the settings object using the given properties.
868      *
869      * @param properties the properties to be used with this Settings instance
870      * @since 4.0.3
871      */
872     public Settings(final Properties properties) {
873         props = properties;
874         logProperties("Properties loaded", props);
875     }
876 
877     /**
878      * Initialize the settings object using the given properties file.
879      *
880      * @param propertiesFilePath the path to the base properties file to load
881      */
882     public Settings(@NotNull final String propertiesFilePath) {
883         initialize(propertiesFilePath);
884     }
885 
886     /**
887      * Initializes the settings object from the given file.
888      *
889      * @param propertiesFilePath the path to the settings property file
890      */
891     private void initialize(@NotNull final String propertiesFilePath) {
892         props = new Properties();
893         try (InputStream in = FileUtils.getResourceAsStream(propertiesFilePath)) {
894             props.load(in);
895         } catch (NullPointerException ex) {
896             LOGGER.error("Did not find settings file '{}'.", propertiesFilePath);
897             LOGGER.debug("", ex);
898         } catch (IOException ex) {
899             LOGGER.error("Unable to load settings from '{}'.", propertiesFilePath);
900             LOGGER.debug("", ex);
901         }
902         logProperties("Properties loaded", props);
903     }
904 
905     /**
906      * Cleans up resources to prevent memory leaks.
907      */
908     public void cleanup() {
909         cleanup(true);
910     }
911 
912     /**
913      * Cleans up resources to prevent memory leaks.
914      *
915      * @param deleteTemporary flag indicating whether any temporary directories
916      * generated should be removed
917      */
918     public synchronized void cleanup(boolean deleteTemporary) {
919         if (deleteTemporary && tempDirectory != null && tempDirectory.exists()) {
920             LOGGER.debug("Deleting ALL temporary files from `{}`", tempDirectory.toString());
921             FileUtils.delete(tempDirectory);
922             tempDirectory = null;
923         }
924     }
925 
926     /**
927      * Check if a given key is considered to have a value with sensitive data.
928      *
929      * @param key the key to determine if the property should be masked
930      * @return <code>true</code> if the key is for a sensitive property value;
931      * otherwise <code>false</code>
932      */
933     private boolean isKeyMasked(@NotNull String key) {
934         if (maskedKeys == null || maskedKeys.isEmpty()) {
935             initMaskedKeys();
936         }
937         return maskedKeys.stream().anyMatch(maskExp -> maskExp.test(key));
938     }
939 
940     /**
941      * Obtains the printable/loggable value for a given key/value pair. This
942      * will mask some values so as to not leak sensitive information.
943      *
944      * @param key the property key
945      * @param value the property value
946      * @return the printable value
947      */
948     String getPrintableValue(@NotNull String key, String value) {
949         String printableValue = null;
950         if (value != null) {
951             printableValue = isKeyMasked(key) ? "********" : value;
952         }
953         return printableValue;
954     }
955 
956     /**
957      * Initializes the masked keys collection. This is done outside of the
958      * {@link #initialize(java.lang.String)} method because a caller may use the
959      * {@link #mergeProperties(java.io.File)} to add additional properties after
960      * the call to initialize.
961      */
962     void initMaskedKeys() {
963         final String[] masked = getArray(Settings.KEYS.MASKED_PROPERTIES);
964         if (masked == null) {
965             maskedKeys = new ArrayList<>();
966         } else {
967             maskedKeys = Arrays.stream(masked)
968                     .map(v -> Pattern.compile(v).asPredicate())
969                     .collect(Collectors.toList());
970         }
971     }
972 
973     /**
974      * Logs the properties. This will not log any properties that contain
975      * 'password' in the key.
976      *
977      * @param header the header to print with the log message
978      * @param properties the properties to log
979      */
980     private void logProperties(@NotNull final String header, @NotNull final Properties properties) {
981         if (LOGGER.isDebugEnabled()) {
982             initMaskedKeys();
983             final StringWriter sw = new StringWriter();
984             try (PrintWriter pw = new PrintWriter(sw)) {
985                 pw.format("%s:%n%n", header);
986                 final Enumeration<?> e = properties.propertyNames();
987                 while (e.hasMoreElements()) {
988                     final String key = (String) e.nextElement();
989                     final String value = getPrintableValue(key, properties.getProperty(key));
990                     if (value != null) {
991                         pw.format("%s='%s'%n", key, value);
992                     }
993                 }
994                 pw.flush();
995                 LOGGER.debug(sw.toString());
996             }
997         }
998     }
999 
1000     /**
1001      * Sets a property value.
1002      *
1003      * @param key the key for the property
1004      * @param value the value for the property
1005      */
1006     public void setString(@NotNull final String key, @NotNull final String value) {
1007         props.setProperty(key, value);
1008         LOGGER.debug("Setting: {}='{}'", key, getPrintableValue(key, value));
1009     }
1010 
1011     /**
1012      * Sets a property value only if the value is not null.
1013      *
1014      * @param key the key for the property
1015      * @param value the value for the property
1016      */
1017     public void setStringIfNotNull(@NotNull final String key, @Nullable final String value) {
1018         if (null != value) {
1019             setString(key, value);
1020         }
1021     }
1022 
1023     /**
1024      * Sets a property value only if the value is not null and not empty.
1025      *
1026      * @param key the key for the property
1027      * @param value the value for the property
1028      */
1029     public void setStringIfNotEmpty(@NotNull final String key, @Nullable final String value) {
1030         if (null != value && !value.isEmpty()) {
1031             setString(key, value);
1032         }
1033     }
1034 
1035     /**
1036      * Sets a property value only if the array value is not null and not empty.
1037      *
1038      * @param key the key for the property
1039      * @param value the value for the property
1040      */
1041     public void setArrayIfNotEmpty(@NotNull final String key, @Nullable final String[] value) {
1042         if (null != value && value.length > 0) {
1043             try {
1044                 setString(key, objectMapper.writeValueAsString(value));
1045             } catch (JsonProcessingException e) {
1046                 throw new IllegalArgumentException();
1047             }
1048         }
1049     }
1050 
1051     /**
1052      * Sets a property value only if the array value is not null and not empty.
1053      *
1054      * @param key the key for the property
1055      * @param value the value for the property
1056      */
1057     public void setArrayIfNotEmpty(@NotNull final String key, @Nullable final List<String> value) {
1058         if (null != value && !value.isEmpty()) {
1059             try {
1060                 setString(key, objectMapper.writeValueAsString(value));
1061             } catch (JsonProcessingException e) {
1062                 throw new IllegalArgumentException();
1063             }
1064         }
1065     }
1066 
1067     /**
1068      * Sets a property value.
1069      *
1070      * @param key the key for the property
1071      * @param value the value for the property
1072      */
1073     public void setBoolean(@NotNull final String key, boolean value) {
1074         setString(key, Boolean.toString(value));
1075     }
1076 
1077     /**
1078      * Sets a property value only if the value is not null.
1079      *
1080      * @param key the key for the property
1081      * @param value the value for the property
1082      */
1083     public void setBooleanIfNotNull(@NotNull final String key, @Nullable final Boolean value) {
1084         if (null != value) {
1085             setBoolean(key, value);
1086         }
1087     }
1088 
1089     /**
1090      * Sets a float property value.
1091      *
1092      * @param key the key for the property
1093      * @param value the value for the property
1094      */
1095     public void setFloat(@NotNull final String key, final float value) {
1096         setString(key, Float.toString(value));
1097     }
1098 
1099     /**
1100      * Sets a property value.
1101      *
1102      * @param key the key for the property
1103      * @param value the value for the property
1104      */
1105     public void setInt(@NotNull final String key, final int value) {
1106         props.setProperty(key, String.valueOf(value));
1107         LOGGER.debug("Setting: {}='{}'", key, value);
1108     }
1109 
1110     /**
1111      * Sets a property value only if the value is not null.
1112      *
1113      * @param key the key for the property
1114      * @param value the value for the property
1115      */
1116     public void setIntIfNotNull(@NotNull final String key, @Nullable final Integer value) {
1117         if (null != value) {
1118             setInt(key, value);
1119         }
1120     }
1121 
1122     /**
1123      * Merges a new properties file into the current properties. This method
1124      * allows for the loading of a user provided properties file.<br><br>
1125      * <b>Note</b>: even if using this method - system properties will be loaded
1126      * before properties loaded from files.
1127      *
1128      * @param filePath the path to the properties file to merge.
1129      * @throws java.io.FileNotFoundException is thrown when the filePath points
1130      * to a non-existent file
1131      * @throws java.io.IOException is thrown when there is an exception
1132      * loading/merging the properties
1133      */
1134     @SuppressFBWarnings(justification = "try with resource will clenaup the resources", value = {"OBL_UNSATISFIED_OBLIGATION"})
1135     public void mergeProperties(@NotNull final File filePath) throws FileNotFoundException, IOException {
1136         try (FileInputStream fis = new FileInputStream(filePath)) {
1137             mergeProperties(fis);
1138         }
1139     }
1140 
1141     /**
1142      * Merges a new properties file into the current properties. This method
1143      * allows for the loading of a user provided properties file.<br><br>
1144      * Note: even if using this method - system properties will be loaded before
1145      * properties loaded from files.
1146      *
1147      * @param filePath the path to the properties file to merge.
1148      * @throws java.io.FileNotFoundException is thrown when the filePath points
1149      * to a non-existent file
1150      * @throws java.io.IOException is thrown when there is an exception
1151      * loading/merging the properties
1152      */
1153     @SuppressFBWarnings(justification = "try with resource will clenaup the resources", value = {"OBL_UNSATISFIED_OBLIGATION"})
1154     public void mergeProperties(@NotNull final String filePath) throws FileNotFoundException, IOException {
1155         try (FileInputStream fis = new FileInputStream(filePath)) {
1156             mergeProperties(fis);
1157         }
1158     }
1159 
1160     /**
1161      * Merges a new properties file into the current properties. This method
1162      * allows for the loading of a user provided properties file.<br><br>
1163      * <b>Note</b>: even if using this method - system properties will be loaded
1164      * before properties loaded from files.
1165      *
1166      * @param stream an Input Stream pointing at a properties file to merge
1167      * @throws java.io.IOException is thrown when there is an exception
1168      * loading/merging the properties
1169      */
1170     public void mergeProperties(@NotNull final InputStream stream) throws IOException {
1171         props.load(stream);
1172         logProperties("Properties updated via merge", props);
1173     }
1174 
1175     /**
1176      * Returns a value from the properties file as a File object. If the value
1177      * was specified as a system property or passed in via the -Dprop=value
1178      * argument - this method will return the value from the system properties
1179      * before the values in the contained configuration file.
1180      *
1181      * @param key the key to lookup within the properties file
1182      * @return the property from the properties file converted to a File object
1183      */
1184     @Nullable
1185     public File getFile(@NotNull final String key) {
1186         final String file = getString(key);
1187         if (file == null) {
1188             return null;
1189         }
1190         return new File(file);
1191     }
1192 
1193     /**
1194      * Returns a value from the properties file as a File object. If the value
1195      * was specified as a system property or passed in via the -Dprop=value
1196      * argument - this method will return the value from the system properties
1197      * before the values in the contained configuration file.
1198      * <p>
1199      * This method will check the configured base directory and will use this as
1200      * the base of the file path. Additionally, if the base directory begins
1201      * with a leading "[JAR]\" sequence with the path to the folder containing
1202      * the JAR file containing this class.
1203      *
1204      * @param key the key to lookup within the properties file
1205      * @return the property from the properties file converted to a File object
1206      */
1207     File getDataFile(@NotNull final String key) {
1208         final String file = getString(key);
1209         LOGGER.debug("Settings.getDataFile() - file: '{}'", file);
1210         if (file == null) {
1211             return null;
1212         }
1213         if (file.startsWith("[JAR]")) {
1214             LOGGER.debug("Settings.getDataFile() - transforming filename");
1215             final File jarPath = getJarPath();
1216             LOGGER.debug("Settings.getDataFile() - jar file: '{}'", jarPath.toString());
1217             final File retVal = new File(jarPath, file.substring(6));
1218             LOGGER.debug("Settings.getDataFile() - returning: '{}'", retVal);
1219             return retVal;
1220         }
1221         return new File(file);
1222     }
1223 
1224     /**
1225      * Attempts to retrieve the folder containing the Jar file containing the
1226      * Settings class.
1227      *
1228      * @return a File object
1229      */
1230     private File getJarPath() {
1231         String decodedPath = ".";
1232         String jarPath = "";
1233         final ProtectionDomain domain = Settings.class.getProtectionDomain();
1234         if (domain != null && domain.getCodeSource() != null && domain.getCodeSource().getLocation() != null) {
1235             jarPath = Settings.class.getProtectionDomain().getCodeSource().getLocation().getPath();
1236         }
1237         try {
1238             decodedPath = URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name());
1239         } catch (UnsupportedEncodingException ex) {
1240             LOGGER.trace("", ex);
1241         }
1242 
1243         final File path = new File(decodedPath);
1244         if (path.getName().toLowerCase().endsWith(".jar")) {
1245             return path.getParentFile();
1246         } else {
1247             return new File(".");
1248         }
1249     }
1250 
1251     /**
1252      * Returns a value from the properties file. If the value was specified as a
1253      * system property or passed in via the -Dprop=value argument - this method
1254      * will return the value from the system properties before the values in the
1255      * contained configuration file.
1256      *
1257      * @param key the key to lookup within the properties file
1258      * @param defaultValue the default value for the requested property
1259      * @return the property from the properties file
1260      */
1261     public String getString(@NotNull final String key, @Nullable final String defaultValue) {
1262         return System.getProperty(key, props.getProperty(key, defaultValue));
1263     }
1264 
1265     /**
1266      * Returns the temporary directory.
1267      *
1268      * @return the temporary directory
1269      * @throws java.io.IOException if any.
1270      */
1271     public synchronized File getTempDirectory() throws IOException {
1272         if (tempDirectory == null) {
1273             final File baseTemp = new File(getString(Settings.KEYS.TEMP_DIRECTORY, System.getProperty("java.io.tmpdir")));
1274             tempDirectory = FileUtils.createTempDirectory(baseTemp);
1275         }
1276         return tempDirectory;
1277     }
1278 
1279     /**
1280      * Returns a value from the properties file. If the value was specified as a
1281      * system property or passed in via the -Dprop=value argument - this method
1282      * will return the value from the system properties before the values in the
1283      * contained configuration file.
1284      *
1285      * @param key the key to lookup within the properties file
1286      * @return the property from the properties file
1287      */
1288     public String getString(@NotNull final String key) {
1289         return System.getProperty(key, props.getProperty(key));
1290     }
1291 
1292     /**
1293      * Returns a list with the given key.
1294      * <p>
1295      * If the property is not set then {@code null} will be returned.
1296      *
1297      * @param key the key to get from this
1298      * {@link org.owasp.dependencycheck.utils.Settings}.
1299      * @return the list or {@code null} if the key wasn't present.
1300      */
1301     public String[] getArray(@NotNull final String key) {
1302         final String string = getString(key);
1303         if (string != null) {
1304             if (string.charAt(0) == '{' || string.charAt(0) == '[') {
1305                 try {
1306                     return objectMapper.readValue(string, String[].class);
1307                 } catch (JsonProcessingException e) {
1308                     throw new IllegalStateException("Unable to read value '" + string + "' as an array");
1309                 }
1310             } else {
1311                 return string.split(ARRAY_SEP);
1312             }
1313         }
1314         return null;
1315     }
1316 
1317     /**
1318      * Removes a property from the local properties collection. This is mainly
1319      * used in test cases.
1320      *
1321      * @param key the property key to remove
1322      */
1323     public void removeProperty(@NotNull final String key) {
1324         props.remove(key);
1325     }
1326 
1327     /**
1328      * Returns an int value from the properties file. If the value was specified
1329      * as a system property or passed in via the -Dprop=value argument - this
1330      * method will return the value from the system properties before the values
1331      * in the contained configuration file.
1332      *
1333      * @param key the key to lookup within the properties file
1334      * @return the property from the properties file
1335      * @throws org.owasp.dependencycheck.utils.InvalidSettingException is thrown
1336      * if there is an error retrieving the setting
1337      */
1338     public int getInt(@NotNull final String key) throws InvalidSettingException {
1339         try {
1340             return Integer.parseInt(getString(key));
1341         } catch (NumberFormatException ex) {
1342             throw new InvalidSettingException("Could not convert property '" + key + "' to an int.", ex);
1343         }
1344     }
1345 
1346     /**
1347      * Returns an int value from the properties file. If the value was specified
1348      * as a system property or passed in via the -Dprop=value argument - this
1349      * method will return the value from the system properties before the values
1350      * in the contained configuration file.
1351      *
1352      * @param key the key to lookup within the properties file
1353      * @param defaultValue the default value to return
1354      * @return the property from the properties file or the defaultValue if the
1355      * property does not exist or cannot be converted to an integer
1356      */
1357     public int getInt(@NotNull final String key, int defaultValue) {
1358         int value;
1359         try {
1360             value = Integer.parseInt(getString(key));
1361         } catch (NumberFormatException ex) {
1362             if (!getString(key, "").isEmpty()) {
1363                 LOGGER.debug("Could not convert property '{}={}' to an int; using {} instead.",
1364                         key, getPrintableValue(key, getString(key)), defaultValue);
1365             }
1366             value = defaultValue;
1367         }
1368         return value;
1369     }
1370 
1371     /**
1372      * Returns a long value from the properties file. If the value was specified
1373      * as a system property or passed in via the -Dprop=value argument - this
1374      * method will return the value from the system properties before the values
1375      * in the contained configuration file.
1376      *
1377      * @param key the key to lookup within the properties file
1378      * @return the property from the properties file
1379      * @throws org.owasp.dependencycheck.utils.InvalidSettingException is thrown
1380      * if there is an error retrieving the setting
1381      */
1382     public long getLong(@NotNull final String key) throws InvalidSettingException {
1383         try {
1384             return Long.parseLong(getString(key));
1385         } catch (NumberFormatException ex) {
1386             throw new InvalidSettingException("Could not convert property '" + key + "' to a long.", ex);
1387         }
1388     }
1389 
1390     /**
1391      * Returns a boolean value from the properties file. If the value was
1392      * specified as a system property or passed in via the
1393      * <code>-Dprop=value</code> argument this method will return the value from
1394      * the system properties before the values in the contained configuration
1395      * file.
1396      *
1397      * @param key the key to lookup within the properties file
1398      * @return the property from the properties file
1399      * @throws org.owasp.dependencycheck.utils.InvalidSettingException is thrown
1400      * if there is an error retrieving the setting
1401      */
1402     public boolean getBoolean(@NotNull final String key) throws InvalidSettingException {
1403         return Boolean.parseBoolean(getString(key));
1404     }
1405 
1406     /**
1407      * Returns a boolean value from the properties file. If the value was
1408      * specified as a system property or passed in via the
1409      * <code>-Dprop=value</code> argument this method will return the value from
1410      * the system properties before the values in the contained configuration
1411      * file.
1412      *
1413      * @param key the key to lookup within the properties file
1414      * @param defaultValue the default value to return if the setting does not
1415      * exist
1416      * @return the property from the properties file
1417      */
1418     public boolean getBoolean(@NotNull final String key, boolean defaultValue) {
1419         return Boolean.parseBoolean(getString(key, Boolean.toString(defaultValue)));
1420     }
1421 
1422     /**
1423      * Returns a float value from the properties file. If the value was
1424      * specified as a system property or passed in via the
1425      * <code>-Dprop=value</code> argument this method will return the value from
1426      * the system properties before the values in the contained configuration
1427      * file.
1428      *
1429      * @param key the key to lookup within the properties file
1430      * @param defaultValue the default value to return if the setting does not
1431      * exist
1432      * @return the property from the properties file
1433      */
1434     public float getFloat(@NotNull final String key, float defaultValue) {
1435         float retValue = defaultValue;
1436         try {
1437             retValue = Float.parseFloat(getString(key));
1438         } catch (Throwable ex) {
1439             LOGGER.trace("ignore", ex);
1440         }
1441         return retValue;
1442     }
1443 
1444     /**
1445      * Returns a connection string from the configured properties. If the
1446      * connection string contains a %s, this method will determine the 'data'
1447      * directory and replace the %s with the path to the data directory. If the
1448      * data directory does not exist it will be created.
1449      *
1450      * @param connectionStringKey the property file key for the connection
1451      * string
1452      * @param dbFileNameKey the settings key for the db filename
1453      * @return the connection string
1454      * @throws IOException thrown the data directory cannot be created
1455      * @throws InvalidSettingException thrown if there is an invalid setting
1456      */
1457     public String getConnectionString(String connectionStringKey, String dbFileNameKey)
1458             throws IOException, InvalidSettingException {
1459         final String connStr = getString(connectionStringKey);
1460         if (connStr == null) {
1461             final String msg = String.format("Invalid properties file; %s is missing.", connectionStringKey);
1462             throw new InvalidSettingException(msg);
1463         }
1464         if (connStr.contains("%s")) {
1465             final File directory = getH2DataDirectory();
1466             LOGGER.debug("Data directory: {}", directory);
1467             String fileName = null;
1468             if (dbFileNameKey != null) {
1469                 fileName = getString(dbFileNameKey);
1470             }
1471             if (fileName == null) {
1472                 final String msg = String.format("Invalid properties file to get a file based connection string; '%s' must be defined.",
1473                         dbFileNameKey);
1474                 throw new InvalidSettingException(msg);
1475             }
1476             if (connStr.startsWith("jdbc:h2:file:") && fileName.endsWith(".mv.db")) {
1477                 fileName = fileName.substring(0, fileName.length() - 6);
1478             }
1479             // yes, for H2 this path won't actually exists - but this is sufficient to get the value needed
1480             final File dbFile = new File(directory, fileName);
1481             final String cString = String.format(connStr, dbFile.getCanonicalPath());
1482             LOGGER.debug("Connection String: '{}'", cString);
1483             return cString;
1484         }
1485         return connStr;
1486     }
1487 
1488     /**
1489      * Retrieves the primary data directory that is used for caching web
1490      * content.
1491      *
1492      * @return the data directory to store data files
1493      * @throws java.io.IOException is thrown if an java.io.IOException occurs of
1494      * course...
1495      */
1496     public File getDataDirectory() throws IOException {
1497         final File path = getDataFile(Settings.KEYS.DATA_DIRECTORY);
1498         if (path != null && (path.exists() || path.mkdirs())) {
1499             return path;
1500         }
1501         throw new IOException(String.format("Unable to create the data directory '%s'",
1502                 (path == null) ? "unknown" : path.getAbsolutePath()));
1503     }
1504 
1505     /**
1506      * Retrieves the H2 data directory - if the database has been moved to the
1507      * temp directory this method will return the temp directory.
1508      *
1509      * @return the data directory to store data files
1510      * @throws java.io.IOException is thrown if an java.io.IOException occurs of
1511      * course...
1512      */
1513     public File getH2DataDirectory() throws IOException {
1514         final String h2Test = getString(Settings.KEYS.H2_DATA_DIRECTORY);
1515         final File path;
1516         if (h2Test != null && !h2Test.isEmpty()) {
1517             path = getDataFile(Settings.KEYS.H2_DATA_DIRECTORY);
1518         } else {
1519             path = getDataFile(Settings.KEYS.DATA_DIRECTORY);
1520         }
1521         if (path != null && (path.exists() || path.mkdirs())) {
1522             return path;
1523         }
1524         throw new IOException(String.format("Unable to create the h2 data directory '%s'",
1525                 (path == null) ? "unknown" : path.getAbsolutePath()));
1526     }
1527 
1528     /**
1529      * Generates a new temporary file name that is guaranteed to be unique.
1530      *
1531      * @param prefix the prefix for the file name to generate
1532      * @param extension the extension of the generated file name
1533      * @return a temporary File
1534      * @throws java.io.IOException if any.
1535      */
1536     public File getTempFile(@NotNull final String prefix, @NotNull final String extension) throws IOException {
1537         final File dir = getTempDirectory();
1538         final String tempFileName = String.format("%s%s.%s", prefix, UUID.randomUUID(), extension);
1539         final File tempFile = new File(dir, tempFileName);
1540         if (tempFile.exists()) {
1541             return getTempFile(prefix, extension);
1542         }
1543         return tempFile;
1544     }
1545 }