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