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