mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
217 Commits
v1.4.5
...
reportGene
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e4d012a69 | ||
|
|
dccbd659ed | ||
|
|
1b84095c0e | ||
|
|
c96ef88222 | ||
|
|
0540474e0c | ||
|
|
2dbfba9ac5 | ||
|
|
8eff628303 | ||
|
|
519167bf0f | ||
|
|
e8e06d12c7 | ||
|
|
006224b52c | ||
|
|
6007be1b5f | ||
|
|
6b5cfe1560 | ||
|
|
f584be7f44 | ||
|
|
b6a7d0ee9b | ||
|
|
1402b20a6b | ||
|
|
898412eaea | ||
|
|
7753b6f3c1 | ||
|
|
ea93f315d5 | ||
|
|
7f9cf5bb14 | ||
|
|
c4fe921670 | ||
|
|
693c08cfd3 | ||
|
|
9776f38b97 | ||
|
|
ff91d7cda7 | ||
|
|
e218b8ad70 | ||
|
|
555b1dc1cc | ||
|
|
523eed9319 | ||
|
|
9c7f6daf75 | ||
|
|
f2037b3fab | ||
|
|
c545285f7f | ||
|
|
290cd0507e | ||
|
|
ee72f172d2 | ||
|
|
e721dac389 | ||
|
|
4c15993a44 | ||
|
|
8fc42078c7 | ||
|
|
06d6fe4bd6 | ||
|
|
96cda322a3 | ||
|
|
0c991af58d | ||
|
|
3677b5f429 | ||
|
|
fd0abd9066 | ||
|
|
abb10600f7 | ||
|
|
c9a6bb4b16 | ||
|
|
9ff0042527 | ||
|
|
0504f9c4cc | ||
|
|
7b7861206b | ||
|
|
6f9207fe25 | ||
|
|
de6cd3621b | ||
|
|
04b506662f | ||
|
|
c1250fc53e | ||
|
|
c2f521f528 | ||
|
|
5fde08b001 | ||
|
|
69d621b981 | ||
|
|
4134fb3fef | ||
|
|
81b2b966ba | ||
|
|
ae65ebe687 | ||
|
|
03f84fa77e | ||
|
|
ff6b3dbd4f | ||
|
|
bf7b8ccce8 | ||
|
|
57b1895b5e | ||
|
|
8edf65186f | ||
|
|
13d781d2b1 | ||
|
|
7c1c99f5f9 | ||
|
|
0a02f43b8c | ||
|
|
d4e50d9560 | ||
|
|
5681e0bfdf | ||
|
|
55bfe4cad8 | ||
|
|
d726792be6 | ||
|
|
5c21451760 | ||
|
|
b3736ac13a | ||
|
|
a4899de956 | ||
|
|
e3ca70ba0d | ||
|
|
bdace1b1b7 | ||
|
|
567022a9b7 | ||
|
|
83262afd13 | ||
|
|
3ff838a2cc | ||
|
|
40b5c45ef6 | ||
|
|
d2a8645dd4 | ||
|
|
4543835a0d | ||
|
|
c0f41c461b | ||
|
|
116ef264e1 | ||
|
|
1371dacdaa | ||
|
|
d252d0f29f | ||
|
|
3786f6ebc7 | ||
|
|
6813427867 | ||
|
|
f94cf106a6 | ||
|
|
a67e421a5d | ||
|
|
865db1b6c3 | ||
|
|
31d7379a39 | ||
|
|
f473e63a61 | ||
|
|
c9ee55863f | ||
|
|
238a96184a | ||
|
|
44ddad8101 | ||
|
|
afa47f7dfc | ||
|
|
f289bcd285 | ||
|
|
c7adb1bb65 | ||
|
|
4bbc5e27b5 | ||
|
|
c877ade004 | ||
|
|
ebd8996ad5 | ||
|
|
f31313d021 | ||
|
|
6936dac9b4 | ||
|
|
4b2f6832fe | ||
|
|
c622ff2b19 | ||
|
|
35d0f21c47 | ||
|
|
3066d286c5 | ||
|
|
18564e8e86 | ||
|
|
832cbabc7d | ||
|
|
8b764d5e17 | ||
|
|
e2a1a59543 | ||
|
|
cedb8d3db1 | ||
|
|
539bd754df | ||
|
|
109f5c22e9 | ||
|
|
a23d127c62 | ||
|
|
6825304100 | ||
|
|
947499726a | ||
|
|
97b2e1a4da | ||
|
|
2b04c6a7dd | ||
|
|
3bb6553111 | ||
|
|
371dba948d | ||
|
|
675349c06f | ||
|
|
7a88981aa4 | ||
|
|
626f6c3de2 | ||
|
|
5540397456 | ||
|
|
69c6dd40a1 | ||
|
|
5ed6e838fc | ||
|
|
1d32a6012a | ||
|
|
b157049a7e | ||
|
|
8ea6b08a0a | ||
|
|
8856ff04ec | ||
|
|
8bfbd11a51 | ||
|
|
abd843d281 | ||
|
|
c54f9b1144 | ||
|
|
318f3e14dd | ||
|
|
46f227e92e | ||
|
|
a7b6f37503 | ||
|
|
a61bba2f72 | ||
|
|
dfc6d952bd | ||
|
|
046f4605f9 | ||
|
|
32590ab7ff | ||
|
|
efeb084e57 | ||
|
|
03ec3142c3 | ||
|
|
679df936e7 | ||
|
|
5ed5764ab5 | ||
|
|
d588092727 | ||
|
|
295ba0679d | ||
|
|
bcdf26c88d | ||
|
|
d6e092bfa2 | ||
|
|
388c1b5af1 | ||
|
|
717aea9a03 | ||
|
|
4951ee5a62 | ||
|
|
666150cf7f | ||
|
|
d8290c0c45 | ||
|
|
e363e8109b | ||
|
|
b228d08843 | ||
|
|
3e08437808 | ||
|
|
e0d5651b75 | ||
|
|
59e29b7afe | ||
|
|
d180208e34 | ||
|
|
0ce1ef596c | ||
|
|
5f7486f851 | ||
|
|
03559fd106 | ||
|
|
d08357a1c2 | ||
|
|
c1cb87ebde | ||
|
|
82fd1cf4d7 | ||
|
|
a87391e609 | ||
|
|
3071cfd7be | ||
|
|
583c2d34d3 | ||
|
|
c9640fbf04 | ||
|
|
192d1de944 | ||
|
|
aa0314c840 | ||
|
|
0171b859c6 | ||
|
|
d267e14b73 | ||
|
|
79e63f4067 | ||
|
|
72d7af5291 | ||
|
|
0e313d1910 | ||
|
|
6841f9a009 | ||
|
|
caeec68999 | ||
|
|
541915a5a7 | ||
|
|
cb75ab8cca | ||
|
|
0f3845b16d | ||
|
|
dd7128095e | ||
|
|
1367be510c | ||
|
|
2ea0eb3c64 | ||
|
|
a5990ea6f3 | ||
|
|
67921f5f3d | ||
|
|
d31e0453bd | ||
|
|
ae21424a30 | ||
|
|
3577949425 | ||
|
|
0d72471502 | ||
|
|
17590a6d38 | ||
|
|
d9dcc8cc2d | ||
|
|
df1ee5e8c6 | ||
|
|
3c68ebece7 | ||
|
|
c9e8e6cf0e | ||
|
|
36945fb84d | ||
|
|
960a2e27ab | ||
|
|
71724461a9 | ||
|
|
ae5a95bfb3 | ||
|
|
d6c9fea354 | ||
|
|
d6f1351f6b | ||
|
|
373488adb4 | ||
|
|
59401cc9f8 | ||
|
|
eca0e7a852 | ||
|
|
563dc24854 | ||
|
|
3a70e25983 | ||
|
|
a9fc6bf02c | ||
|
|
cd4f09dc86 | ||
|
|
4193718571 | ||
|
|
0464626e2b | ||
|
|
a0198e34e7 | ||
|
|
0b329bd40e | ||
|
|
3d33f24f09 | ||
|
|
886c02fad2 | ||
|
|
3a11504153 | ||
|
|
3a082ae00a | ||
|
|
780201845b | ||
|
|
0e0a4bb0b4 | ||
|
|
5333083a78 | ||
|
|
b8c6c86330 |
34
.github/contributing.md
vendored
Normal file
34
.github/contributing.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Contributing to OWASP dependency-check
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
- Ensure you're running the latest version of dependency-check.
|
||||
- Ensure the bug has not [already been reported](https://github.com/jeremylong/DependencyCheck/issues).
|
||||
- If you're unable to find an open issue addressing the problem, please [submit a new issue](https://github.com/jeremylong/DependencyCheck/issues/new).
|
||||
- Please fill out the appropriate section of the bug report template provided. Please delete any sections not needed in the template.
|
||||
|
||||
## Reporting Vulnerabilities
|
||||
|
||||
- If you believe you have found a vulnerability in dependency-check itself (not that dependency-check found a vulnerability); please email jeremy.long@owasp.org.
|
||||
|
||||
## Asking Questions
|
||||
|
||||
- Your question may be answered by taking a look at the [documentataion](https://jeremylong.github.io/DependencyCheck/).
|
||||
- If you still have a question consider:
|
||||
- posting to the [Google Group](https://groups.google.com/forum/#!forum/dependency-check)
|
||||
- opening a [new issue](https://github.com/jeremylong/DependencyCheck/issues/new)
|
||||
|
||||
## Enhancement Requests
|
||||
|
||||
- Suggest changes by [submitting a new issue](https://github.com/jeremylong/DependencyCheck/issues/new) and begin coding.
|
||||
|
||||
## Contributing Code
|
||||
|
||||
- If you have written a new feature or have fixed a bug please open a new pull request with the patch.
|
||||
- Ensure the PR description clearly describes the problem and solution. Include any related issue number(s) if applicable.
|
||||
- Please ensure the PR passes the automated checks performed (travis-ci, codacy, etc.)
|
||||
- Please consider adding test cases for any new functionality
|
||||
|
||||
## Thank you for your contributions
|
||||
|
||||
OWASP dependency-check team
|
||||
2
.github/issue_template.md
vendored
2
.github/issue_template.md
vendored
@@ -1,3 +1,5 @@
|
||||
Please delete any un-needed section from the following issue template:
|
||||
|
||||
### Reporting Bugs/Errors
|
||||
When reporting errors, 99% of the time log file output is required. Please post the log file as a [gist](https://gist.github.com/) and provide a link in the new issue.
|
||||
|
||||
|
||||
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
## Fixes Issue #
|
||||
|
||||
## Description of Change
|
||||
|
||||
*Please add a description of the proposed change*
|
||||
|
||||
## Have test cases been added to cover the new functionality?
|
||||
|
||||
*yes/no*
|
||||
10
.travis.yml
10
.travis.yml
@@ -1,3 +1,13 @@
|
||||
language: java
|
||||
jdk: oraclejdk7
|
||||
script: mvn install -DreleaseTesting
|
||||
env:
|
||||
global:
|
||||
secure: ZUzhWfpXJw/oAeDlUkDFkEJMT0T7kCN3d7ah8urkL2B0KFfKOqQagkbXkgvDa1SYud8VdcnoGa69LfkEr5IrdqW7R4bEYZAiN5swm4Z0iO8t53szVspm2f+O9jQ44O/sfOfpfLxWUUuhdc7Vbrszp+tSszxdPmssWL+f5a/mfWs=
|
||||
|
||||
before_install:
|
||||
- sudo apt-get install jq
|
||||
- wget -O ~/codacy-coverage-reporter-assembly-latest.jar $(curl https://api.github.com/repos/codacy/codacy-coverage-reporter/releases/latest | jq -r .assets[0].browser_download_url)
|
||||
|
||||
after_success:
|
||||
- java -cp ~/codacy-coverage-reporter-assembly-latest.jar com.codacy.CodacyCoverageReporter -l Java -r build-reporting/target/site/jacoco-aggregate/jacoco.xml
|
||||
|
||||
25
Dockerfile
25
Dockerfile
@@ -2,13 +2,28 @@ FROM java:8
|
||||
|
||||
MAINTAINER Timo Pagel <dependencycheckmaintainer@timo-pagel.de>
|
||||
|
||||
RUN wget -O /tmp/current.txt http://jeremylong.github.io/DependencyCheck/current.txt && current=$(cat /tmp/current.txt) && wget https://dl.bintray.com/jeremy-long/owasp/dependency-check-$current-release.zip && unzip dependency-check-$current-release.zip && mv dependency-check /usr/share/
|
||||
ENV user=dependencycheck
|
||||
ENV version_url=https://jeremylong.github.io/DependencyCheck/current.txt
|
||||
ENV download_url=https://dl.bintray.com/jeremy-long/owasp
|
||||
|
||||
RUN useradd -ms /bin/bash dockeruser && chown -R dockeruser:dockeruser /usr/share/dependency-check && mkdir /report && chown -R dockeruser:dockeruser /report
|
||||
USER dockeruser
|
||||
RUN wget -O /tmp/current.txt ${version_url} && \
|
||||
version=$(cat /tmp/current.txt) && \
|
||||
file="dependency-check-${version}-release.zip" && \
|
||||
wget "$download_url/$file" && \
|
||||
unzip ${file} && \
|
||||
rm ${file} && \
|
||||
mv dependency-check /usr/share/
|
||||
|
||||
VOLUME "/src /usr/share/dependency-check/data /report"
|
||||
RUN useradd -ms /bin/bash ${user} && \
|
||||
chown -R ${user}:${user} /usr/share/dependency-check && \
|
||||
mkdir /report && \
|
||||
chown -R ${user}:${user} /report
|
||||
|
||||
USER ${user}
|
||||
|
||||
VOLUME ["/src" "/usr/share/dependency-check/data" "/report"]
|
||||
|
||||
WORKDIR /report
|
||||
|
||||
ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh", "--scan", "/src"]
|
||||
CMD ["--help"]
|
||||
ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh"]
|
||||
|
||||
62
README.md
62
README.md
@@ -1,4 +1,6 @@
|
||||
[](https://travis-ci.org/jeremylong/DependencyCheck) [](https://www.apache.org/licenses/LICENSE-2.0.txt) [](https://scan.coverity.com/projects/dependencycheck)
|
||||
[](https://travis-ci.org/jeremylong/DependencyCheck) [](https://scan.coverity.com/projects/dependencycheck) [](https://www.codacy.com/app/jeremylong/DependencyCheck?utm_source=github.com&utm_medium=referral&utm_content=jeremylong/DependencyCheck&utm_campaign=Badge_Grade) [](https://www.apache.org/licenses/LICENSE-2.0.txt)
|
||||
|
||||
[](https://www.toolswatch.org/2015/06/black-hat-arsenal-usa-2015-speakers-lineup/) [](https://www.toolswatch.org/2014/06/black-hat-usa-2014-arsenal-tools-speaker-list/) [](https://www.toolswatch.org/2013/06/announcement-blackhat-arsenal-usa-2013-selected-tools/)
|
||||
|
||||
Dependency-Check
|
||||
================
|
||||
@@ -27,8 +29,8 @@ $ ./bin/dependency-check.sh --project Testing --out . --scan [path to jar files
|
||||
```
|
||||
On Windows
|
||||
```
|
||||
> bin/dependency-check.bat -h
|
||||
> bin/dependency-check.bat --project Testing --out . --scan [path to jar files to be scanned]
|
||||
> .\bin\dependency-check.bat -h
|
||||
> .\bin\dependency-check.bat --project Testing --out . --scan [path to jar files to be scanned]
|
||||
```
|
||||
On Mac with [Homebrew](http://brew.sh)
|
||||
```
|
||||
@@ -91,40 +93,46 @@ $ ./dependency-check-cli/target/release/bin/dependency-check.sh --project Testin
|
||||
On Windows
|
||||
```
|
||||
> mvn install
|
||||
> dependency-check-cli/target/release/bin/dependency-check.bat -h
|
||||
> dependency-check-cli/target/release/bin/dependency-check.bat --project Testing --out . --scan ./src/test/resources
|
||||
> .\dependency-check-cli\target\release\bin\dependency-check.bat -h
|
||||
> .\dependency-check-cli\target\release\bin\dependency-check.bat --project Testing --out . --scan ./src/test/resources
|
||||
```
|
||||
|
||||
Then load the resulting 'DependencyCheck-Report.html' into your favorite browser.
|
||||
|
||||
### Docker
|
||||
|
||||
In the following example it is assumed that the source to be checked is in the actual directory. A persistent data directory and a persistent report directory is used so that the container can be destroyed after running it to make sure that you use the newst version, always.
|
||||
```
|
||||
# After the first run, feel free to change the owner of the directories to the owner of the creted files and the permissions to 744
|
||||
DATA_DIRECTORY=$HOME/OWASP-Dependency-Check/data
|
||||
REPORT_DIRECTORY=/$HOME/OWASP-Dependency-Check/reports
|
||||
In the following example it is assumed that the source to be checked is in the current working directory. Persistent data and report directories are used, allowing you to destroy the container after running.
|
||||
|
||||
if [ ! -d $DATA_DIRECTORY ]; then
|
||||
echo "Initially creating persistent directories"
|
||||
mkdir -p $DATA_DIRECTORY
|
||||
chmod -R 777 $DATA_DIRECTORY
|
||||
|
||||
mkdir -p $REPORT_DIRECTORY
|
||||
chmod -R 777 $REPORT_DIRECTORY
|
||||
```
|
||||
#!/bin/sh
|
||||
|
||||
OWASPDC_DIRECTORY=$HOME/OWASP-Dependency-Check
|
||||
DATA_DIRECTORY="$OWASPDC_DIRECTORY/data"
|
||||
REPORT_DIRECTORY="$OWASPDC_DIRECTORY/reports"
|
||||
|
||||
if [ ! -d "$DATA_DIRECTORY" ]; then
|
||||
echo "Initially creating persistent directories"
|
||||
mkdir -p "$DATA_DIRECTORY"
|
||||
chmod -R 777 "$DATA_DIRECTORY"
|
||||
|
||||
mkdir -p "$REPORT_DIRECTORY"
|
||||
chmod -R 777 "$REPORT_DIRECTORY"
|
||||
fi
|
||||
|
||||
docker pull owasp/dependency-check # Make sure it is the actual version
|
||||
# Make sure we are using the latest version
|
||||
docker pull owasp/dependency-check
|
||||
|
||||
docker run --rm \
|
||||
--volume $(pwd):/src \
|
||||
--volume $DATA_DIRECTORY:/usr/share/dependency-check/data \
|
||||
--volume $REPORT_DIRECTORY:/report \
|
||||
--name dependency-check \
|
||||
dc \
|
||||
--suppression "/src/security/dependency-check-suppression.xml"\
|
||||
--format "ALL" \
|
||||
--project "My OWASP Dependency Check Projekt" \
|
||||
--volume $(pwd):/src \
|
||||
--volume "$DATA_DIRECTORY":/usr/share/dependency-check/data \
|
||||
--volume "$REPORT_DIRECTORY":/report \
|
||||
owasp/dependency-check \
|
||||
--scan /src \
|
||||
--format "ALL" \
|
||||
--project "My OWASP Dependency Check Project"
|
||||
# Use suppression like this: (/src == $pwd)
|
||||
# --suppression "/src/security/dependency-check-suppression.xml"
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -144,7 +152,7 @@ Dependency-Check is Copyright (c) 2012-2016 Jeremy Long. All Rights Reserved.
|
||||
|
||||
Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://raw.githubusercontent.com/jeremylong/DependencyCheck/master/LICENSE.txt) file for the full license.
|
||||
|
||||
Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt] [notices] file for more information.
|
||||
Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt][notices] file for more information.
|
||||
|
||||
|
||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||
|
||||
80
build-reporting/pom.xml
Normal file
80
build-reporting/pom.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<!--
|
||||
This file is part of dependency-check build-reporting.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Copyright (c) 2017 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>build-reporting</artifactId>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/build-reporting</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>report-aggregate</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>report-aggregate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
5
build-reporting/src/site/markdown/index.md
Normal file
5
build-reporting/src/site/markdown/index.md
Normal file
@@ -0,0 +1,5 @@
|
||||
About
|
||||
=====
|
||||
OWASP dependency-check build reporting is used to aggregate jacoco test coverage results
|
||||
so that they can be posted to [Codacy](https://www.codacy.com/app/OWASP_Reviews/DependencyCheck/dashboard)
|
||||
to track code coverage.
|
||||
32
build-reporting/src/site/site.xml
Normal file
32
build-reporting/src/site/site.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!--
|
||||
This file is part of dependency-check build reporting.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Copyright (c) 2017 Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
<project name="dependency-check-build-reporting">
|
||||
<bannerLeft>
|
||||
<name>OWASP dependency-check build reporting</name>
|
||||
<alt>OWASP dependency-check build reporting</alt>
|
||||
<src>../images/dc.svg</src>
|
||||
</bannerLeft>
|
||||
<body>
|
||||
<breadcrumbs>
|
||||
<item name="dependency-check" href="../index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu ref="Project Documentation" />
|
||||
<menu ref="reports" />
|
||||
</body>
|
||||
</project>
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.5</version>
|
||||
<version>1.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
@@ -223,48 +223,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
<haltOnFailure>false</haltOnFailure>
|
||||
<totalBranchRate>85</totalBranchRate>
|
||||
<totalLineRate>85</totalLineRate>
|
||||
<packageLineRate>85</packageLineRate>
|
||||
<packageBranchRate>85</packageBranchRate>
|
||||
<regexes>
|
||||
<regex>
|
||||
<pattern>.*\$.*</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
</regexes>
|
||||
</check>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>clean</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/dependency-check-data</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
@@ -288,7 +246,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<version>${reporting.pmd-plugin.version}</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<linkXRef>true</linkXRef>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
|
||||
@@ -53,16 +53,157 @@ public class Check extends Update {
|
||||
* System specific new line character.
|
||||
*/
|
||||
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
|
||||
/**
|
||||
* Whether the ruby gemspec analyzer should be enabled.
|
||||
*/
|
||||
private Boolean rubygemsAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the Node.js Analyzer is enabled.
|
||||
*/
|
||||
private Boolean nodeAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the Ruby Bundle Audit Analyzer is enabled.
|
||||
*/
|
||||
private Boolean bundleAuditAnalyzerEnabled;
|
||||
/**
|
||||
* Whether the CMake analyzer should be enabled.
|
||||
*/
|
||||
private Boolean cmakeAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the Open SSL analyzer is enabled.
|
||||
*/
|
||||
private Boolean opensslAnalyzerEnabled;
|
||||
/**
|
||||
* Whether the python package analyzer should be enabled.
|
||||
*/
|
||||
private Boolean pyPackageAnalyzerEnabled;
|
||||
/**
|
||||
* Whether the python distribution analyzer should be enabled.
|
||||
*/
|
||||
private Boolean pyDistributionAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the central analyzer is enabled.
|
||||
*/
|
||||
private Boolean centralAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the nexus analyzer is enabled.
|
||||
*/
|
||||
private Boolean nexusAnalyzerEnabled;
|
||||
/**
|
||||
* The URL of a Nexus server's REST API end point
|
||||
* (http://domain/nexus/service/local).
|
||||
*/
|
||||
private String nexusUrl;
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
private Boolean nexusUsesProxy;
|
||||
/**
|
||||
* Additional ZIP File extensions to add analyze. This should be a
|
||||
* comma-separated list of file extensions to treat like ZIP files.
|
||||
*/
|
||||
private String zipExtensions;
|
||||
/**
|
||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
||||
*/
|
||||
private String pathToMono;
|
||||
|
||||
/**
|
||||
* Construct a new DependencyCheckTask.
|
||||
* The application name for the report.
|
||||
*
|
||||
* @deprecated use projectName instead.
|
||||
*/
|
||||
public Check() {
|
||||
super();
|
||||
// Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
|
||||
// core end up coming through this tasks logger
|
||||
StaticLoggerBinder.getSingleton().setTask(this);
|
||||
}
|
||||
@Deprecated
|
||||
private String applicationName = null;
|
||||
/**
|
||||
* The name of the project being analyzed.
|
||||
*/
|
||||
private String projectName = "dependency-check";
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check
|
||||
* report.
|
||||
*/
|
||||
private String reportOutputDirectory = ".";
|
||||
/**
|
||||
* Specifies if the build should be failed if a CVSS score above a specified
|
||||
* level is identified. The default is 11 which means since the CVSS scores
|
||||
* are 0-10, by default the build will never fail and the CVSS score is set
|
||||
* to 11. The valid range for the fail build on CVSS is 0 to 11, where
|
||||
* anything above 10 will not cause the build to fail.
|
||||
*/
|
||||
private float failBuildOnCVSS = 11;
|
||||
/**
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
|
||||
* recommended that this be turned to false. Default is true.
|
||||
*/
|
||||
private Boolean autoUpdate;
|
||||
/**
|
||||
* Whether only the update phase should be executed.
|
||||
*
|
||||
* @deprecated Use the update task instead
|
||||
*/
|
||||
@Deprecated
|
||||
private boolean updateOnly = false;
|
||||
|
||||
/**
|
||||
* The report format to be generated (HTML, XML, VULN, CSV, JSON, ALL). Default is
|
||||
* HTML.
|
||||
*/
|
||||
private String reportFormat = "HTML";
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
private String suppressionFile;
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
private String hintsFile;
|
||||
/**
|
||||
* flag indicating whether or not to show a summary of findings.
|
||||
*/
|
||||
private boolean showSummary = true;
|
||||
/**
|
||||
* Whether experimental analyzers are enabled.
|
||||
*/
|
||||
private Boolean enableExperimental;
|
||||
/**
|
||||
* Whether or not the Jar Analyzer is enabled.
|
||||
*/
|
||||
private Boolean jarAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the Archive Analyzer is enabled.
|
||||
*/
|
||||
private Boolean archiveAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the .NET Nuspec Analyzer is enabled.
|
||||
*/
|
||||
private Boolean nuspecAnalyzerEnabled;
|
||||
/**
|
||||
* Whether or not the PHP Composer Analyzer is enabled.
|
||||
*/
|
||||
private Boolean composerAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Whether or not the .NET Assembly Analyzer is enabled.
|
||||
*/
|
||||
private Boolean assemblyAnalyzerEnabled;
|
||||
/**
|
||||
* Whether the autoconf analyzer should be enabled.
|
||||
*/
|
||||
private Boolean autoconfAnalyzerEnabled;
|
||||
/**
|
||||
* Sets the path for the bundle-audit binary.
|
||||
*/
|
||||
private String bundleAuditPath;
|
||||
/**
|
||||
* Whether or not the CocoaPods Analyzer is enabled.
|
||||
*/
|
||||
private Boolean cocoapodsAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Whether or not the Swift package Analyzer is enabled.
|
||||
*/
|
||||
private Boolean swiftPackageManagerAnalyzerEnabled;
|
||||
//The following code was copied Apache Ant PathConvert
|
||||
//BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert
|
||||
/**
|
||||
@@ -70,9 +211,9 @@ public class Check extends Update {
|
||||
*/
|
||||
private Resources path = null;
|
||||
/**
|
||||
* Reference to path/fileset to convert
|
||||
* Reference to path/file set to convert
|
||||
*/
|
||||
private Reference refid = null;
|
||||
private Reference refId = null;
|
||||
|
||||
/**
|
||||
* Add an arbitrary ResourceCollection.
|
||||
@@ -82,7 +223,7 @@ public class Check extends Update {
|
||||
*/
|
||||
public void add(ResourceCollection rc) {
|
||||
if (isReference()) {
|
||||
throw new BuildException("Nested elements are not allowed when using the refid attribute.");
|
||||
throw new BuildException("Nested elements are not allowed when using the refId attribute.");
|
||||
}
|
||||
getPath().add(rc);
|
||||
}
|
||||
@@ -102,12 +243,12 @@ public class Check extends Update {
|
||||
}
|
||||
|
||||
/**
|
||||
* Learn whether the refid attribute of this element been set.
|
||||
* Learn whether the refId attribute of this element been set.
|
||||
*
|
||||
* @return true if refid is valid.
|
||||
* @return true if refId is valid.
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return refid != null;
|
||||
return refId != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,11 +257,11 @@ public class Check extends Update {
|
||||
*
|
||||
* @param r the reference to a path, fileset, dirset or filelist.
|
||||
*/
|
||||
public void setRefid(Reference r) {
|
||||
public synchronized void setRefId(Reference r) {
|
||||
if (path != null) {
|
||||
throw new BuildException("Nested elements are not allowed when using the refid attribute.");
|
||||
throw new BuildException("Nested elements are not allowed when using the refId attribute.");
|
||||
}
|
||||
refid = r;
|
||||
refId = r;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,22 +272,25 @@ public class Check extends Update {
|
||||
*/
|
||||
private void dealWithReferences() throws BuildException {
|
||||
if (isReference()) {
|
||||
final Object o = refid.getReferencedObject(getProject());
|
||||
final Object o = refId.getReferencedObject(getProject());
|
||||
if (!(o instanceof ResourceCollection)) {
|
||||
throw new BuildException("refid '" + refid.getRefId()
|
||||
throw new BuildException("refId '" + refId.getRefId()
|
||||
+ "' does not refer to a resource collection.");
|
||||
}
|
||||
getPath().add((ResourceCollection) o);
|
||||
}
|
||||
}
|
||||
// END COPY from org.apache.tools.ant.taskdefs
|
||||
|
||||
/**
|
||||
* The application name for the report.
|
||||
*
|
||||
* @deprecated use projectName instead.
|
||||
* Construct a new DependencyCheckTask.
|
||||
*/
|
||||
@Deprecated
|
||||
private String applicationName = null;
|
||||
public Check() {
|
||||
super();
|
||||
// Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
|
||||
// core end up coming through this tasks logger
|
||||
StaticLoggerBinder.getSingleton().setTask(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of applicationName.
|
||||
@@ -170,10 +314,6 @@ public class Check extends Update {
|
||||
public void setApplicationName(String applicationName) {
|
||||
this.applicationName = applicationName;
|
||||
}
|
||||
/**
|
||||
* The name of the project being analyzed.
|
||||
*/
|
||||
private String projectName = "dependency-check";
|
||||
|
||||
/**
|
||||
* Get the value of projectName.
|
||||
@@ -199,12 +339,6 @@ public class Check extends Update {
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check
|
||||
* report.
|
||||
*/
|
||||
private String reportOutputDirectory = ".";
|
||||
|
||||
/**
|
||||
* Get the value of reportOutputDirectory.
|
||||
*
|
||||
@@ -222,14 +356,6 @@ public class Check extends Update {
|
||||
public void setReportOutputDirectory(String reportOutputDirectory) {
|
||||
this.reportOutputDirectory = reportOutputDirectory;
|
||||
}
|
||||
/**
|
||||
* Specifies if the build should be failed if a CVSS score above a specified
|
||||
* level is identified. The default is 11 which means since the CVSS scores
|
||||
* are 0-10, by default the build will never fail and the CVSS score is set
|
||||
* to 11. The valid range for the fail build on CVSS is 0 to 11, where
|
||||
* anything above 10 will not cause the build to fail.
|
||||
*/
|
||||
private float failBuildOnCVSS = 11;
|
||||
|
||||
/**
|
||||
* Get the value of failBuildOnCVSS.
|
||||
@@ -248,11 +374,6 @@ public class Check extends Update {
|
||||
public void setFailBuildOnCVSS(float failBuildOnCVSS) {
|
||||
this.failBuildOnCVSS = failBuildOnCVSS;
|
||||
}
|
||||
/**
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
|
||||
* recommended that this be turned to false. Default is true.
|
||||
*/
|
||||
private Boolean autoUpdate;
|
||||
|
||||
/**
|
||||
* Get the value of autoUpdate.
|
||||
@@ -271,13 +392,6 @@ public class Check extends Update {
|
||||
public void setAutoUpdate(Boolean autoUpdate) {
|
||||
this.autoUpdate = autoUpdate;
|
||||
}
|
||||
/**
|
||||
* Whether only the update phase should be executed.
|
||||
*
|
||||
* @deprecated Use the update task instead
|
||||
*/
|
||||
@Deprecated
|
||||
private boolean updateOnly = false;
|
||||
|
||||
/**
|
||||
* Get the value of updateOnly.
|
||||
@@ -301,12 +415,6 @@ public class Check extends Update {
|
||||
this.updateOnly = updateOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* The report format to be generated (HTML, XML, VULN, ALL). Default is
|
||||
* HTML.
|
||||
*/
|
||||
private String reportFormat = "HTML";
|
||||
|
||||
/**
|
||||
* Get the value of reportFormat.
|
||||
*
|
||||
@@ -324,10 +432,6 @@ public class Check extends Update {
|
||||
public void setReportFormat(ReportFormats reportFormat) {
|
||||
this.reportFormat = reportFormat.getValue();
|
||||
}
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
private String suppressionFile;
|
||||
|
||||
/**
|
||||
* Get the value of suppressionFile.
|
||||
@@ -346,10 +450,6 @@ public class Check extends Update {
|
||||
public void setSuppressionFile(String suppressionFile) {
|
||||
this.suppressionFile = suppressionFile;
|
||||
}
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
private String hintsFile;
|
||||
|
||||
/**
|
||||
* Get the value of hintsFile.
|
||||
@@ -368,10 +468,6 @@ public class Check extends Update {
|
||||
public void setHintsFile(String hintsFile) {
|
||||
this.hintsFile = hintsFile;
|
||||
}
|
||||
/**
|
||||
* flag indicating whether or not to show a summary of findings.
|
||||
*/
|
||||
private boolean showSummary = true;
|
||||
|
||||
/**
|
||||
* Get the value of showSummary.
|
||||
@@ -391,11 +487,6 @@ public class Check extends Update {
|
||||
this.showSummary = showSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether experimental analyzers are enabled.
|
||||
*/
|
||||
private Boolean enableExperimental;
|
||||
|
||||
/**
|
||||
* Get the value of enableExperimental.
|
||||
*
|
||||
@@ -414,11 +505,6 @@ public class Check extends Update {
|
||||
this.enableExperimental = enableExperimental;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the Jar Analyzer is enabled.
|
||||
*/
|
||||
private Boolean jarAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
@@ -436,10 +522,6 @@ public class Check extends Update {
|
||||
public void setJarAnalyzerEnabled(Boolean jarAnalyzerEnabled) {
|
||||
this.jarAnalyzerEnabled = jarAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the Archive Analyzer is enabled.
|
||||
*/
|
||||
private Boolean archiveAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
@@ -449,10 +531,6 @@ public class Check extends Update {
|
||||
public Boolean isArchiveAnalyzerEnabled() {
|
||||
return archiveAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the .NET Assembly Analyzer is enabled.
|
||||
*/
|
||||
private Boolean assemblyAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Sets whether or not the analyzer is enabled.
|
||||
@@ -480,10 +558,6 @@ public class Check extends Update {
|
||||
public void setAssemblyAnalyzerEnabled(Boolean assemblyAnalyzerEnabled) {
|
||||
this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the .NET Nuspec Analyzer is enabled.
|
||||
*/
|
||||
private Boolean nuspecAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
@@ -502,10 +576,6 @@ public class Check extends Update {
|
||||
public void setNuspecAnalyzerEnabled(Boolean nuspecAnalyzerEnabled) {
|
||||
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the PHP Composer Analyzer is enabled.
|
||||
*/
|
||||
private Boolean composerAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of composerAnalyzerEnabled.
|
||||
@@ -524,10 +594,6 @@ public class Check extends Update {
|
||||
public void setComposerAnalyzerEnabled(Boolean composerAnalyzerEnabled) {
|
||||
this.composerAnalyzerEnabled = composerAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the autoconf analyzer should be enabled.
|
||||
*/
|
||||
private Boolean autoconfAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of autoconfAnalyzerEnabled.
|
||||
@@ -546,10 +612,6 @@ public class Check extends Update {
|
||||
public void setAutoconfAnalyzerEnabled(Boolean autoconfAnalyzerEnabled) {
|
||||
this.autoconfAnalyzerEnabled = autoconfAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the CMake analyzer should be enabled.
|
||||
*/
|
||||
private Boolean cmakeAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of cmakeAnalyzerEnabled.
|
||||
@@ -569,12 +631,6 @@ public class Check extends Update {
|
||||
this.cmakeAnalyzerEnabled = cmakeAnalyzerEnabled;
|
||||
}
|
||||
|
||||
//start changes
|
||||
/**
|
||||
* Whether or not the Ruby Bundle Audit Analyzer is enabled.
|
||||
*/
|
||||
private Boolean bundleAuditAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns if the Bundle Audit Analyzer is enabled.
|
||||
*
|
||||
@@ -594,11 +650,6 @@ public class Check extends Update {
|
||||
this.bundleAuditAnalyzerEnabled = bundleAuditAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the path for the bundle-audit binary.
|
||||
*/
|
||||
private String bundleAuditPath;
|
||||
|
||||
/**
|
||||
* Returns the path to the bundle audit executable.
|
||||
*
|
||||
@@ -616,15 +667,11 @@ public class Check extends Update {
|
||||
public void setBundleAuditPath(String bundleAuditPath) {
|
||||
this.bundleAuditPath = bundleAuditPath;
|
||||
}
|
||||
/**
|
||||
* Whether or not the CocoaPods Analyzer is enabled.
|
||||
*/
|
||||
private Boolean cocoapodsAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns if the cocoapods analyyzer is enabled.
|
||||
* Returns if the cocoapods analyzer is enabled.
|
||||
*
|
||||
* @return if the cocoapods analyyzer is enabled
|
||||
* @return if the cocoapods analyzer is enabled
|
||||
*/
|
||||
public boolean isCocoapodsAnalyzerEnabled() {
|
||||
return cocoapodsAnalyzerEnabled;
|
||||
@@ -639,11 +686,6 @@ public class Check extends Update {
|
||||
this.cocoapodsAnalyzerEnabled = cocoapodsAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the Swift package Analyzer is enabled.
|
||||
*/
|
||||
private Boolean swiftPackageManagerAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Returns whether or not the Swift package Analyzer is enabled.
|
||||
*
|
||||
@@ -662,12 +704,6 @@ public class Check extends Update {
|
||||
public void setSwiftPackageManagerAnalyzerEnabled(Boolean swiftPackageManagerAnalyzerEnabled) {
|
||||
this.swiftPackageManagerAnalyzerEnabled = swiftPackageManagerAnalyzerEnabled;
|
||||
}
|
||||
//end changes
|
||||
|
||||
/**
|
||||
* Whether or not the openssl analyzer is enabled.
|
||||
*/
|
||||
private Boolean opensslAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of opensslAnalyzerEnabled.
|
||||
@@ -686,10 +722,6 @@ public class Check extends Update {
|
||||
public void setOpensslAnalyzerEnabled(Boolean opensslAnalyzerEnabled) {
|
||||
this.opensslAnalyzerEnabled = opensslAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the Node.js Analyzer is enabled.
|
||||
*/
|
||||
private Boolean nodeAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of nodeAnalyzerEnabled.
|
||||
@@ -708,10 +740,6 @@ public class Check extends Update {
|
||||
public void setNodeAnalyzerEnabled(Boolean nodeAnalyzerEnabled) {
|
||||
this.nodeAnalyzerEnabled = nodeAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the ruby gemspec analyzer should be enabled.
|
||||
*/
|
||||
private Boolean rubygemsAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of rubygemsAnalyzerEnabled.
|
||||
@@ -730,10 +758,6 @@ public class Check extends Update {
|
||||
public void setRubygemsAnalyzerEnabled(Boolean rubygemsAnalyzerEnabled) {
|
||||
this.rubygemsAnalyzerEnabled = rubygemsAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether the python package analyzer should be enabled.
|
||||
*/
|
||||
private Boolean pyPackageAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of pyPackageAnalyzerEnabled.
|
||||
@@ -753,11 +777,6 @@ public class Check extends Update {
|
||||
this.pyPackageAnalyzerEnabled = pyPackageAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the python distribution analyzer should be enabled.
|
||||
*/
|
||||
private Boolean pyDistributionAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of pyDistributionAnalyzerEnabled.
|
||||
*
|
||||
@@ -777,11 +796,6 @@ public class Check extends Update {
|
||||
this.pyDistributionAnalyzerEnabled = pyDistributionAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the central analyzer is enabled.
|
||||
*/
|
||||
private Boolean centralAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of centralAnalyzerEnabled.
|
||||
*
|
||||
@@ -800,11 +814,6 @@ public class Check extends Update {
|
||||
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the nexus analyzer is enabled.
|
||||
*/
|
||||
private Boolean nexusAnalyzerEnabled;
|
||||
|
||||
/**
|
||||
* Get the value of nexusAnalyzerEnabled.
|
||||
*
|
||||
@@ -823,12 +832,6 @@ public class Check extends Update {
|
||||
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL of a Nexus server's REST API end point
|
||||
* (http://domain/nexus/service/local).
|
||||
*/
|
||||
private String nexusUrl;
|
||||
|
||||
/**
|
||||
* Get the value of nexusUrl.
|
||||
*
|
||||
@@ -846,10 +849,6 @@ public class Check extends Update {
|
||||
public void setNexusUrl(String nexusUrl) {
|
||||
this.nexusUrl = nexusUrl;
|
||||
}
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
private Boolean nexusUsesProxy;
|
||||
|
||||
/**
|
||||
* Get the value of nexusUsesProxy.
|
||||
@@ -869,12 +868,6 @@ public class Check extends Update {
|
||||
this.nexusUsesProxy = nexusUsesProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional ZIP File extensions to add analyze. This should be a
|
||||
* comma-separated list of file extensions to treat like ZIP files.
|
||||
*/
|
||||
private String zipExtensions;
|
||||
|
||||
/**
|
||||
* Get the value of zipExtensions.
|
||||
*
|
||||
@@ -893,11 +886,6 @@ public class Check extends Update {
|
||||
this.zipExtensions = zipExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
||||
*/
|
||||
private String pathToMono;
|
||||
|
||||
/**
|
||||
* Get the value of pathToMono.
|
||||
*
|
||||
@@ -935,7 +923,7 @@ public class Check extends Update {
|
||||
log(ex.getMessage(), Project.MSG_ERR);
|
||||
}
|
||||
} else {
|
||||
for (Resource resource : path) {
|
||||
for (Resource resource : getPath()) {
|
||||
final FileProvider provider = resource.as(FileProvider.class);
|
||||
if (provider != null) {
|
||||
final File file = provider.getFile();
|
||||
@@ -952,21 +940,7 @@ public class Check extends Update {
|
||||
throw new BuildException(ex);
|
||||
}
|
||||
}
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
reporter.generateReports(reportOutputDirectory, reportFormat);
|
||||
engine.writeReports(getProjectName(),new File(reportOutputDirectory), reportFormat);
|
||||
|
||||
if (this.failBuildOnCVSS <= 10) {
|
||||
checkForFailure(engine.getDependencies());
|
||||
@@ -1002,7 +976,7 @@ public class Check extends Update {
|
||||
* @throws BuildException if the task was not configured correctly.
|
||||
*/
|
||||
private void validateConfiguration() throws BuildException {
|
||||
if (path == null) {
|
||||
if (getPath() == null) {
|
||||
throw new BuildException("No project dependencies have been defined to analyze.");
|
||||
}
|
||||
if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
|
||||
@@ -1054,7 +1028,7 @@ public class Check extends Update {
|
||||
*
|
||||
* @param dependencies the list of dependency objects
|
||||
* @throws BuildException thrown if a CVSS score is found that is higher
|
||||
* then the threshold set
|
||||
* than the threshold set
|
||||
*/
|
||||
private void checkForFailure(List<Dependency> dependencies) throws BuildException {
|
||||
final StringBuilder ids = new StringBuilder();
|
||||
@@ -1071,7 +1045,7 @@ public class Check extends Update {
|
||||
}
|
||||
if (ids.length() > 0) {
|
||||
final String msg = String.format("%n%nDependency-Check Failure:%n"
|
||||
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
|
||||
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater than '%.1f': %s%n"
|
||||
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
|
||||
throw new BuildException(msg);
|
||||
}
|
||||
@@ -1119,7 +1093,7 @@ public class Check extends Update {
|
||||
}
|
||||
|
||||
/**
|
||||
* An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN",
|
||||
* An enumeration of supported report formats: "ALL", "HTML", "XML", "CSV", "JSON", "VULN",
|
||||
* etc..
|
||||
*/
|
||||
public static class ReportFormats extends EnumeratedAttribute {
|
||||
|
||||
@@ -95,6 +95,12 @@ public class Purge extends Task {
|
||||
this.failOnError = failOnError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the dependency-check purge to delete the existing local copy of
|
||||
* the NVD CVE data.
|
||||
*
|
||||
* @throws BuildException thrown if there is a problem deleting the file(s)
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
populateSettings();
|
||||
@@ -138,9 +144,7 @@ public class Purge extends Task {
|
||||
*/
|
||||
protected void populateSettings() throws BuildException {
|
||||
Settings.initialize();
|
||||
InputStream taskProperties = null;
|
||||
try {
|
||||
taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
|
||||
try (InputStream taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE)) {
|
||||
Settings.mergeProperties(taskProperties);
|
||||
} catch (IOException ex) {
|
||||
final String msg = "Unable to load the dependency-check ant task.properties file.";
|
||||
@@ -148,14 +152,6 @@ public class Purge extends Task {
|
||||
throw new BuildException(msg, ex);
|
||||
}
|
||||
log(msg, ex, Project.MSG_WARN);
|
||||
} finally {
|
||||
if (taskProperties != null) {
|
||||
try {
|
||||
taskProperties.close();
|
||||
} catch (IOException ex) {
|
||||
log("", ex, Project.MSG_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dataDirectory != null) {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
|
||||
|
||||
@@ -34,6 +34,67 @@ import org.slf4j.impl.StaticLoggerBinder;
|
||||
*/
|
||||
public class Update extends Purge {
|
||||
|
||||
/**
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyServer;
|
||||
/**
|
||||
* The Proxy Port.
|
||||
*/
|
||||
private String proxyPort;
|
||||
/**
|
||||
* The Proxy username.
|
||||
*/
|
||||
private String proxyUsername;
|
||||
/**
|
||||
* The Proxy password.
|
||||
*/
|
||||
private String proxyPassword;
|
||||
/**
|
||||
* The Connection Timeout.
|
||||
*/
|
||||
private String connectionTimeout;
|
||||
/**
|
||||
* The database driver name; such as org.h2.Driver.
|
||||
*/
|
||||
private String databaseDriverName;
|
||||
/**
|
||||
* The path to the database driver JAR file if it is not on the class path.
|
||||
*/
|
||||
private String databaseDriverPath;
|
||||
/**
|
||||
* The database connection string.
|
||||
*/
|
||||
private String connectionString;
|
||||
/**
|
||||
* The user name for connecting to the database.
|
||||
*/
|
||||
private String databaseUser;
|
||||
/**
|
||||
* The password to use when connecting to the database.
|
||||
*/
|
||||
private String databasePassword;
|
||||
/**
|
||||
* The url for the modified NVD CVE (1.2 schema).
|
||||
*/
|
||||
private String cveUrl12Modified;
|
||||
/**
|
||||
* Base Data Mirror URL for CVE 1.2.
|
||||
*/
|
||||
private String cveUrl12Base;
|
||||
/**
|
||||
* Data Mirror URL for CVE 2.0.
|
||||
*/
|
||||
private String cveUrl20Base;
|
||||
/**
|
||||
* The number of hours to wait before re-checking for updates.
|
||||
*/
|
||||
private Integer cveValidForHours;
|
||||
/**
|
||||
* The url for the modified NVD CVE (2.0 schema).
|
||||
*/
|
||||
private String cveUrl20Modified;
|
||||
|
||||
/**
|
||||
* Construct a new UpdateTask.
|
||||
*/
|
||||
@@ -44,11 +105,6 @@ public class Update extends Purge {
|
||||
StaticLoggerBinder.getSingleton().setTask(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
@@ -67,11 +123,6 @@ public class Update extends Purge {
|
||||
this.proxyServer = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy Port.
|
||||
*/
|
||||
private String proxyPort;
|
||||
|
||||
/**
|
||||
* Get the value of proxyPort.
|
||||
*
|
||||
@@ -89,10 +140,6 @@ public class Update extends Purge {
|
||||
public void setProxyPort(String proxyPort) {
|
||||
this.proxyPort = proxyPort;
|
||||
}
|
||||
/**
|
||||
* The Proxy username.
|
||||
*/
|
||||
private String proxyUsername;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUsername.
|
||||
@@ -111,10 +158,6 @@ public class Update extends Purge {
|
||||
public void setProxyUsername(String proxyUsername) {
|
||||
this.proxyUsername = proxyUsername;
|
||||
}
|
||||
/**
|
||||
* The Proxy password.
|
||||
*/
|
||||
private String proxyPassword;
|
||||
|
||||
/**
|
||||
* Get the value of proxyPassword.
|
||||
@@ -133,10 +176,6 @@ public class Update extends Purge {
|
||||
public void setProxyPassword(String proxyPassword) {
|
||||
this.proxyPassword = proxyPassword;
|
||||
}
|
||||
/**
|
||||
* The Connection Timeout.
|
||||
*/
|
||||
private String connectionTimeout;
|
||||
|
||||
/**
|
||||
* Get the value of connectionTimeout.
|
||||
@@ -155,10 +194,6 @@ public class Update extends Purge {
|
||||
public void setConnectionTimeout(String connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
/**
|
||||
* The database driver name; such as org.h2.Driver.
|
||||
*/
|
||||
private String databaseDriverName;
|
||||
|
||||
/**
|
||||
* Get the value of databaseDriverName.
|
||||
@@ -178,11 +213,6 @@ public class Update extends Purge {
|
||||
this.databaseDriverName = databaseDriverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the database driver JAR file if it is not on the class path.
|
||||
*/
|
||||
private String databaseDriverPath;
|
||||
|
||||
/**
|
||||
* Get the value of databaseDriverPath.
|
||||
*
|
||||
@@ -200,10 +230,6 @@ public class Update extends Purge {
|
||||
public void setDatabaseDriverPath(String databaseDriverPath) {
|
||||
this.databaseDriverPath = databaseDriverPath;
|
||||
}
|
||||
/**
|
||||
* The database connection string.
|
||||
*/
|
||||
private String connectionString;
|
||||
|
||||
/**
|
||||
* Get the value of connectionString.
|
||||
@@ -222,10 +248,6 @@ public class Update extends Purge {
|
||||
public void setConnectionString(String connectionString) {
|
||||
this.connectionString = connectionString;
|
||||
}
|
||||
/**
|
||||
* The user name for connecting to the database.
|
||||
*/
|
||||
private String databaseUser;
|
||||
|
||||
/**
|
||||
* Get the value of databaseUser.
|
||||
@@ -245,11 +267,6 @@ public class Update extends Purge {
|
||||
this.databaseUser = databaseUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* The password to use when connecting to the database.
|
||||
*/
|
||||
private String databasePassword;
|
||||
|
||||
/**
|
||||
* Get the value of databasePassword.
|
||||
*
|
||||
@@ -268,11 +285,6 @@ public class Update extends Purge {
|
||||
this.databasePassword = databasePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (1.2 schema).
|
||||
*/
|
||||
private String cveUrl12Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Modified.
|
||||
*
|
||||
@@ -291,11 +303,6 @@ public class Update extends Purge {
|
||||
this.cveUrl12Modified = cveUrl12Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (2.0 schema).
|
||||
*/
|
||||
private String cveUrl20Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Modified.
|
||||
*
|
||||
@@ -314,11 +321,6 @@ public class Update extends Purge {
|
||||
this.cveUrl20Modified = cveUrl20Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base Data Mirror URL for CVE 1.2.
|
||||
*/
|
||||
private String cveUrl12Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Base.
|
||||
*
|
||||
@@ -337,11 +339,6 @@ public class Update extends Purge {
|
||||
this.cveUrl12Base = cveUrl12Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Mirror URL for CVE 2.0.
|
||||
*/
|
||||
private String cveUrl20Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Base.
|
||||
*
|
||||
@@ -360,11 +357,6 @@ public class Update extends Purge {
|
||||
this.cveUrl20Base = cveUrl20Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of hours to wait before re-checking for updates.
|
||||
*/
|
||||
private Integer cveValidForHours;
|
||||
|
||||
/**
|
||||
* Get the value of cveValidForHours.
|
||||
*
|
||||
|
||||
@@ -37,6 +37,11 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
* The unique instance of this class
|
||||
*/
|
||||
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
||||
/**
|
||||
* Ant tasks have the log method we actually want to call. So we hang onto
|
||||
* the task as a delegate
|
||||
*/
|
||||
private Task task = null;
|
||||
|
||||
/**
|
||||
* Return the singleton of this class.
|
||||
@@ -47,12 +52,6 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ant tasks have the log method we actually want to call. So we hang onto
|
||||
* the task as a delegate
|
||||
*/
|
||||
private Task task = null;
|
||||
|
||||
/**
|
||||
* Set the Task which will this is to log through.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@ Configuration
|
||||
The dependency-check-update task downloads and updates the local copy of the NVD.
|
||||
There are several reasons that one may want to use this task; primarily, creating
|
||||
an update that will be run only once a day or once every few days (but not greater
|
||||
then 7 days) and then use the `autoUpdate="false"` setting on individual
|
||||
than 7 days) and then use the `autoUpdate="false"` setting on individual
|
||||
dependency-check scans. See [Internet Access Required](https://jeremylong.github.io/DependencyCheck/data/index.html)
|
||||
for more information on why this task would be used.
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@ cveValidForHours | Sets the number of hours to wait before checking for new
|
||||
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
|
||||
failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true
|
||||
projectName | The name of the project being scanned. | Dependency-Check
|
||||
reportFormat | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
reportFormat | The report format to be generated (HTML, XML, CSV, JSON, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |
|
||||
proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |
|
||||
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |
|
||||
proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long
|
||||
@@ -65,15 +64,11 @@ public class DependencyCheckTaskTest {
|
||||
@Test
|
||||
public void testAddFileSet() throws Exception {
|
||||
File report = new File("target/dependency-check-report.html");
|
||||
if (report.exists()) {
|
||||
if (!report.delete()) {
|
||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
||||
}
|
||||
if (report.exists() && !report.delete()) {
|
||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
||||
}
|
||||
buildFileRule.executeTarget("test.fileset");
|
||||
|
||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,11 +61,14 @@
|
||||
|
||||
<target name="failCVSS">
|
||||
<dependency-check
|
||||
applicationName="test formatBAD"
|
||||
applicationName="test failCVSS"
|
||||
reportOutputDirectory="${project.build.directory}"
|
||||
reportFormat="XML"
|
||||
autoupdate="false"
|
||||
failBuildOnCVSS="8">
|
||||
failBuildOnCVSS="3">
|
||||
<fileset dir="${project.build.directory}/test-classes/jars">
|
||||
<include name="axis-1.4.jar"/>
|
||||
</fileset>
|
||||
</dependency-check>
|
||||
</target>
|
||||
</project>
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.5</version>
|
||||
<version>1.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
@@ -69,62 +69,6 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<!--instrumentation>
|
||||
<ignoreTrivial>true</ignoreTrivial>
|
||||
</instrumentation-->
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
<haltOnFailure>false</haltOnFailure>
|
||||
<totalBranchRate>85</totalBranchRate>
|
||||
<totalLineRate>85</totalLineRate>
|
||||
<packageLineRate>85</packageLineRate>
|
||||
<packageBranchRate>85</packageBranchRate>
|
||||
<regexes>
|
||||
<regex>
|
||||
<pattern>.*\$.*</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
<regex>
|
||||
<pattern>org.owasp.dependencycheck.App</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
</regexes>
|
||||
</check>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>clean</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>cpe</name>
|
||||
<value>data/cpe</value>
|
||||
<workingDirectory>target</workingDirectory>
|
||||
</property>
|
||||
<property>
|
||||
<name>cve</name>
|
||||
<value>data/cpe</value>
|
||||
<workingDirectory>target</workingDirectory>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>appassembler-maven-plugin</artifactId>
|
||||
@@ -196,7 +140,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<version>${reporting.pmd-plugin.version}</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<linkXRef>true</linkXRef>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
|
||||
@@ -223,13 +223,13 @@ public class App {
|
||||
int retCode = 0;
|
||||
try {
|
||||
engine = new Engine();
|
||||
final List<String> antStylePaths = new ArrayList<String>();
|
||||
final List<String> antStylePaths = new ArrayList<>();
|
||||
for (String file : files) {
|
||||
final String antPath = ensureCanonicalPath(file);
|
||||
antStylePaths.add(antPath);
|
||||
}
|
||||
|
||||
final Set<File> paths = new HashSet<File>();
|
||||
final Set<File> paths = new HashSet<>();
|
||||
for (String file : antStylePaths) {
|
||||
LOGGER.debug("Scanning {}", file);
|
||||
final DirectoryScanner scanner = new DirectoryScanner();
|
||||
@@ -281,21 +281,9 @@ public class App {
|
||||
}
|
||||
exCol = ex;
|
||||
}
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||
try {
|
||||
report.generateReports(reportDirectory, outputFormat);
|
||||
engine.writeReports(applicationName, new File(reportDirectory), outputFormat);
|
||||
} catch (ReportException ex) {
|
||||
if (exCol != null) {
|
||||
exCol.addException(ex);
|
||||
@@ -309,7 +297,7 @@ public class App {
|
||||
}
|
||||
|
||||
//Set the exit code based on whether we found a high enough vulnerability
|
||||
for (Dependency dep : dependencies) {
|
||||
for (Dependency dep : engine.getDependencies()) {
|
||||
if (!dep.getVulnerabilities().isEmpty()) {
|
||||
for (Vulnerability vuln : dep.getVulnerabilities()) {
|
||||
LOGGER.debug("VULNERABILITY FOUND " + dep.getDisplayFileName());
|
||||
@@ -319,7 +307,6 @@ public class App {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retCode;
|
||||
} finally {
|
||||
if (engine != null) {
|
||||
@@ -356,8 +343,7 @@ public class App {
|
||||
* @throws InvalidSettingException thrown when a user defined properties
|
||||
* file is unable to be loaded.
|
||||
*/
|
||||
private void populateSettings(CliParser cli) throws InvalidSettingException {
|
||||
final boolean autoUpdate = cli.isAutoUpdate();
|
||||
protected void populateSettings(CliParser cli) throws InvalidSettingException {
|
||||
final String connectionTimeout = cli.getConnectionTimeout();
|
||||
final String proxyServer = cli.getProxyServer();
|
||||
final String proxyPort = cli.getProxyPort();
|
||||
@@ -380,7 +366,8 @@ public class App {
|
||||
final String cveBase12 = cli.getBaseCve12Url();
|
||||
final String cveBase20 = cli.getBaseCve20Url();
|
||||
final Integer cveValidForHours = cli.getCveValidForHours();
|
||||
final boolean experimentalEnabled = cli.isExperimentalEnabled();
|
||||
final Boolean autoUpdate = cli.isAutoUpdate();
|
||||
final Boolean experimentalEnabled = cli.isExperimentalEnabled();
|
||||
|
||||
if (propertiesFile != null) {
|
||||
try {
|
||||
@@ -393,7 +380,7 @@ public class App {
|
||||
}
|
||||
// We have to wait until we've merged the properties before attempting to set whether we use
|
||||
// the proxy for Nexus since it could be disabled in the properties, but not explicitly stated
|
||||
// on the command line
|
||||
// on the command line. This is true of other boolean values set below not using the setBooleanIfNotNull.
|
||||
final boolean nexusUsesProxy = cli.isNexusUsesProxy();
|
||||
if (dataDirectory != null) {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
|
||||
@@ -407,7 +394,7 @@ public class App {
|
||||
final File dataDir = new File(base, sub);
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUser);
|
||||
@@ -418,7 +405,8 @@ public class App {
|
||||
Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||
|
||||
//File Type Analyzer Settings
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, experimentalEnabled);
|
||||
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, experimentalEnabled);
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !cli.isJarDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !cli.isArchiveDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, !cli.isPythonDistributionDisabled());
|
||||
@@ -468,7 +456,7 @@ public class App {
|
||||
encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
|
||||
encoder.setContext(context);
|
||||
encoder.start();
|
||||
final FileAppender<ILoggingEvent> fa = new FileAppender<ILoggingEvent>();
|
||||
final FileAppender<ILoggingEvent> fa = new FileAppender<>();
|
||||
fa.setAppend(true);
|
||||
fa.setEncoder(encoder);
|
||||
fa.setContext(context);
|
||||
|
||||
@@ -120,7 +120,7 @@ public final class CliParser {
|
||||
Format.valueOf(format);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
final String msg = String.format("An invalid 'format' of '%s' was specified. "
|
||||
+ "Supported output formats are XML, HTML, VULN, or ALL", format);
|
||||
+ "Supported output formats are HTML, XML, CSV, JSON, VULN, or ALL", format);
|
||||
throw new ParseException(msg);
|
||||
}
|
||||
}
|
||||
@@ -249,7 +249,7 @@ public final class CliParser {
|
||||
|
||||
final Option excludes = Option.builder().argName("pattern").hasArg().longOpt(ARGUMENT.EXCLUDE)
|
||||
.desc("Specify and exclusion pattern. This option can be specified multiple times"
|
||||
+ " and it accepts Ant style excludsions.")
|
||||
+ " and it accepts Ant style exclusions.")
|
||||
.build();
|
||||
|
||||
final Option props = Option.builder(ARGUMENT.PROP_SHORT).argName("file").hasArg().longOpt(ARGUMENT.PROP)
|
||||
@@ -262,7 +262,7 @@ public final class CliParser {
|
||||
.build();
|
||||
|
||||
final Option outputFormat = Option.builder(ARGUMENT.OUTPUT_FORMAT_SHORT).argName("format").hasArg().longOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||
.desc("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
|
||||
.desc("The output format to write to (XML, JSON, HTML, VULN, ALL). The default is HTML.")
|
||||
.build();
|
||||
|
||||
final Option verboseLog = Option.builder(ARGUMENT.VERBOSE_LOG_SHORT).argName("file").hasArg().longOpt(ARGUMENT.VERBOSE_LOG)
|
||||
@@ -286,7 +286,7 @@ public final class CliParser {
|
||||
.build();
|
||||
|
||||
final Option experimentalEnabled = Option.builder().longOpt(ARGUMENT.EXPERIMENTAL)
|
||||
.desc("Enables the experimental analzers.")
|
||||
.desc("Enables the experimental analyzers.")
|
||||
.build();
|
||||
|
||||
final Option failOnCVSS = Option.builder().argName("score").hasArg().longOpt(ARGUMENT.FAIL_ON_CVSS)
|
||||
@@ -567,6 +567,32 @@ public final class CliParser {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to determine if one of the disable options has been set.
|
||||
* If not set, this method will check the currently configured settings for
|
||||
* the current value to return.
|
||||
*
|
||||
* Example given `--disableArchive` on the command line would cause this
|
||||
* method to return true for the disable archive setting.
|
||||
*
|
||||
* @param argument the command line argument
|
||||
* @param setting the corresponding settings key
|
||||
* @return true if the disable option was set, if not set the currently
|
||||
* configured value will be returned
|
||||
*/
|
||||
private boolean hasDisableOption(String argument, String setting) {
|
||||
if (line == null || !line.hasOption(argument)) {
|
||||
try {
|
||||
return !Settings.getBoolean(setting);
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warn("Invalid property setting '{}' defaulting to false", setting);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableJar command line argument was specified.
|
||||
*
|
||||
@@ -574,7 +600,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isJarDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_JAR, Settings.KEYS.ANALYZER_JAR_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -584,7 +610,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isArchiveDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_ARCHIVE, Settings.KEYS.ANALYZER_ARCHIVE_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,7 +620,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isNuspecDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_NUSPEC, Settings.KEYS.ANALYZER_NUSPEC_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -604,7 +630,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isAssemblyDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_ASSEMBLY, Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -615,7 +641,7 @@ public final class CliParser {
|
||||
* specified; otherwise false
|
||||
*/
|
||||
public boolean isBundleAuditDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_BUNDLE_AUDIT);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_BUNDLE_AUDIT, Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -625,7 +651,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isPythonDistributionDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_DIST);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_PY_DIST, Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,7 +661,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isPythonPackageDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_PKG);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_PY_PKG, Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -645,7 +671,7 @@ public final class CliParser {
|
||||
* argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isRubyGemspecDisabled() {
|
||||
return (null != line) && line.hasOption(ARGUMENT.DISABLE_RUBYGEMS);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_RUBYGEMS, Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,7 +681,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isCmakeDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CMAKE);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_CMAKE, Settings.KEYS.ANALYZER_CMAKE_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -665,7 +691,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isAutoconfDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_AUTOCONF);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_AUTOCONF, Settings.KEYS.ANALYZER_AUTOCONF_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -675,7 +701,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isComposerDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_COMPOSER);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_COMPOSER, Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -685,7 +711,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isNexusDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_NEXUS, Settings.KEYS.ANALYZER_NEXUS_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,7 +721,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isOpenSSLDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_OPENSSL);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_OPENSSL, Settings.KEYS.ANALYZER_OPENSSL_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -705,7 +731,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isNodeJsDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NODE_JS);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_NODE_JS, Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -716,7 +742,7 @@ public final class CliParser {
|
||||
* specified; otherwise false
|
||||
*/
|
||||
public boolean isCocoapodsAnalyzerDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_COCOAPODS);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_COCOAPODS, Settings.KEYS.ANALYZER_COCOAPODS_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -727,7 +753,7 @@ public final class CliParser {
|
||||
* argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isSwiftPackageAnalyzerDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_SWIFT);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_SWIFT, Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -737,7 +763,7 @@ public final class CliParser {
|
||||
* otherwise false
|
||||
*/
|
||||
public boolean isCentralDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CENTRAL);
|
||||
return hasDisableOption(ARGUMENT.DISABLE_CENTRAL, Settings.KEYS.ANALYZER_CENTRAL_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1029,10 +1055,10 @@ public final class CliParser {
|
||||
* disabled via the command line this will return false.
|
||||
*
|
||||
* @return <code>true</code> if auto-update is allowed; otherwise
|
||||
* <code>false</code>
|
||||
* <code>null</code>
|
||||
*/
|
||||
public boolean isAutoUpdate() {
|
||||
return line != null && !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
|
||||
public Boolean isAutoUpdate() {
|
||||
return (line != null && line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE)) ? false : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1134,10 +1160,10 @@ public final class CliParser {
|
||||
/**
|
||||
* Returns true if the experimental analyzers are enabled.
|
||||
*
|
||||
* @return true if the experimental analyzers are enabled; otherwise false
|
||||
* @return true if the experimental analyzers are enabled; otherwise null
|
||||
*/
|
||||
public boolean isExperimentalEnabled() {
|
||||
return line.hasOption(ARGUMENT.EXPERIMENTAL);
|
||||
public Boolean isExperimentalEnabled() {
|
||||
return (line != null && line.hasOption(ARGUMENT.EXPERIMENTAL)) ? true : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,22 +4,22 @@ Command Line Arguments
|
||||
The following table lists the command line arguments:
|
||||
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
-------|-----------------------|-----------------|-------------|------------
|
||||
| \-\-project | \<name\> | The name of the project being scanned. | Required
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
|
||||
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional
|
||||
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional
|
||||
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
|
||||
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
|
||||
| \-\-failOnCvss | \<score\> | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional
|
||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional
|
||||
\-h | \-\-help | | Print the help message. | Optional
|
||||
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
||||
\-v | \-\-version | | Print the version information. | Optional
|
||||
| \-\-cveValidForHours | \<hours\> | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional
|
||||
| \-\-experimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional
|
||||
-------|------------------------|-----------------|-------------|------------
|
||||
| \-\-project | \<name\> | The name of the project being scanned. | Required
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
|
||||
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional
|
||||
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional
|
||||
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
|
||||
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, CSV, JSON, VULN, ALL). The default is HTML. | Required
|
||||
| \-\-failOnCvss | \<score\> | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional
|
||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional
|
||||
\-h | \-\-help | | Print the help message. | Optional
|
||||
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
||||
\-v | \-\-version | | Print the version information. | Optional
|
||||
| \-\-cveValidForHours | \<hours\> | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional
|
||||
| \-\-enableExperimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
|
||||
@@ -13,16 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 The OWASP Foundatio. All Rights Reserved.
|
||||
* Copyright (c) 2017 The OWASP Foundatio. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.cli.UnrecognizedOptionException;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -30,25 +35,6 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
public AppTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ensureCanonicalPath method, of class App.
|
||||
*/
|
||||
@@ -59,17 +45,83 @@ public class AppTest {
|
||||
String result = instance.ensureCanonicalPath(file);
|
||||
assertFalse(result.contains(".."));
|
||||
assertTrue(result.endsWith("*.jar"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ensureCanonicalPath method, of class App.
|
||||
*/
|
||||
@Test
|
||||
public void testEnsureCanonicalPath2() {
|
||||
String file = "../some/skip/../path/file.txt";
|
||||
App instance = new App();
|
||||
file = "../some/skip/../path/file.txt";
|
||||
String expResult = "/some/path/file.txt";
|
||||
String result = instance.ensureCanonicalPath(file);
|
||||
result = instance.ensureCanonicalPath(file);
|
||||
assertTrue("result=" + result, result.endsWith(expResult));
|
||||
}
|
||||
|
||||
@Test(expected = UnrecognizedOptionException.class)
|
||||
public void testPopulateSettingsException() throws FileNotFoundException, ParseException, InvalidSettingException, URISyntaxException {
|
||||
String[] args = {"-invalidPROPERTY"};
|
||||
assertTrue(testBooleanProperties(args, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopulateSettings() throws FileNotFoundException, ParseException, InvalidSettingException, URISyntaxException {
|
||||
File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath());
|
||||
String[] args = {"-P", prop.getAbsolutePath()};
|
||||
Map<String, Boolean> expected = new HashMap<>();
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
|
||||
|
||||
assertTrue(testBooleanProperties(args, expected));
|
||||
|
||||
String[] args2 = {"-n"};
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
|
||||
assertTrue(testBooleanProperties(args2, expected));
|
||||
|
||||
String[] args3 = {"-h"};
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
|
||||
assertTrue(testBooleanProperties(args3, expected));
|
||||
|
||||
String[] args4 = {"--disableArchive"};
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
|
||||
assertTrue(testBooleanProperties(args4, expected));
|
||||
|
||||
String[] args5 = {"-P", prop.getAbsolutePath(), "--disableArchive"};
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
|
||||
assertTrue(testBooleanProperties(args5, expected));
|
||||
|
||||
prop = new File(this.getClass().getClassLoader().getResource("sample2.properties").toURI().getPath());
|
||||
String[] args6 = {"-P", prop.getAbsolutePath(), "--disableArchive"};
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
|
||||
assertTrue(testBooleanProperties(args6, expected));
|
||||
|
||||
String[] args7 = {"-P", prop.getAbsolutePath(), "--noupdate"};
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
|
||||
assertTrue(testBooleanProperties(args7, expected));
|
||||
|
||||
String[] args8 = {"-P", prop.getAbsolutePath(), "--noupdate", "--disableArchive"};
|
||||
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
|
||||
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
|
||||
assertTrue(testBooleanProperties(args8, expected));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private boolean testBooleanProperties(String[] args, Map<String, Boolean> expected) throws URISyntaxException, FileNotFoundException, ParseException, InvalidSettingException {
|
||||
Settings.initialize();
|
||||
try {
|
||||
final CliParser cli = new CliParser();
|
||||
cli.parse(args);
|
||||
App instance = new App();
|
||||
instance.populateSettings(cli);
|
||||
boolean results = true;
|
||||
for (Map.Entry<String, Boolean> entry : expected.entrySet()) {
|
||||
results &= Settings.getBoolean(entry.getKey()) == entry.getValue();
|
||||
}
|
||||
|
||||
return results;
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,14 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import org.owasp.dependencycheck.CliParser;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -48,14 +45,6 @@ public class CliParserTest {
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of parse method, of class CliParser.
|
||||
*
|
||||
|
||||
33
dependency-check-cli/src/test/resources/sample.properties
Normal file
33
dependency-check-cli/src/test/resources/sample.properties
Normal file
@@ -0,0 +1,33 @@
|
||||
autoupdate=false
|
||||
|
||||
analyzer.experimental.enabled=false
|
||||
analyzer.jar.enabled=true
|
||||
analyzer.archive.enabled=true
|
||||
analyzer.node.package.enabled=true
|
||||
analyzer.composer.lock.enabled=true
|
||||
analyzer.python.distribution.enabled=true
|
||||
analyzer.python.package.enabled=true
|
||||
analyzer.ruby.gemspec.enabled=true
|
||||
analyzer.autoconf.enabled=true
|
||||
analyzer.cmake.enabled=true
|
||||
analyzer.assembly.enabled=true
|
||||
analyzer.nuspec.enabled=true
|
||||
analyzer.openssl.enabled=true
|
||||
analyzer.central.enabled=true
|
||||
analyzer.nexus.enabled=false
|
||||
analyzer.cocoapods.enabled=true
|
||||
analyzer.swift.package.manager.enabled=true
|
||||
#whether the nexus analyzer uses the proxy
|
||||
analyzer.nexus.proxy=true
|
||||
analyzer.cpe.enabled=true
|
||||
analyzer.cpesuppression.enabled=true
|
||||
analyzer.dependencybundling.enabled=true
|
||||
analyzer.dependencymerging.enabled=true
|
||||
analyzer.falsepositive.enabled=true
|
||||
analyzer.filename.enabled=true
|
||||
analyzer.hint.enabled=true
|
||||
analyzer.nvdcve.enabled=true
|
||||
analyzer.vulnerabilitysuppression.enabled=true
|
||||
updater.nvdcve.enabled=true
|
||||
updater.versioncheck.enabled=true
|
||||
analyzer.versionfilter.enabled=true
|
||||
33
dependency-check-cli/src/test/resources/sample2.properties
Normal file
33
dependency-check-cli/src/test/resources/sample2.properties
Normal file
@@ -0,0 +1,33 @@
|
||||
autoupdate=true
|
||||
|
||||
analyzer.experimental.enabled=true
|
||||
analyzer.jar.enabled=false
|
||||
analyzer.archive.enabled=false
|
||||
analyzer.node.package.enabled=false
|
||||
analyzer.composer.lock.enabled=false
|
||||
analyzer.python.distribution.enabled=false
|
||||
analyzer.python.package.enabled=false
|
||||
analyzer.ruby.gemspec.enabled=false
|
||||
analyzer.autoconf.enabled=false
|
||||
analyzer.cmake.enabled=false
|
||||
analyzer.assembly.enabled=false
|
||||
analyzer.nuspec.enabled=false
|
||||
analyzer.openssl.enabled=false
|
||||
analyzer.central.enabled=false
|
||||
analyzer.nexus.enabled=true
|
||||
analyzer.cocoapods.enabled=false
|
||||
analyzer.swift.package.manager.enabled=false
|
||||
#whether the nexus analyzer uses the proxy
|
||||
analyzer.nexus.proxy=false
|
||||
analyzer.cpe.enabled=false
|
||||
analyzer.cpesuppression.enabled=false
|
||||
analyzer.dependencybundling.enabled=false
|
||||
analyzer.dependencymerging.enabled=false
|
||||
analyzer.falsepositive.enabled=false
|
||||
analyzer.filename.enabled=false
|
||||
analyzer.hint.enabled=false
|
||||
analyzer.nvdcve.enabled=false
|
||||
analyzer.vulnerabilitysuppression.enabled=false
|
||||
updater.nvdcve.enabled=false
|
||||
updater.versioncheck.enabled=false
|
||||
analyzer.versionfilter.enabled=false
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.4.5</version>
|
||||
<version>1.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
@@ -121,93 +121,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<instrumentation>
|
||||
<!--ignoreTrivial>true</ignoreTrivial-->
|
||||
<ignores>
|
||||
<ignore>.*\$KEYS\.class</ignore>
|
||||
<ignore>.*\$Element\.class</ignore>
|
||||
</ignores>
|
||||
<excludes>
|
||||
<exclude>.*\$KEYS\.class</exclude>
|
||||
<exclude>.*\$Element\.class</exclude>
|
||||
</excludes>
|
||||
</instrumentation>
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
<haltOnFailure>false</haltOnFailure>
|
||||
<totalBranchRate>85</totalBranchRate>
|
||||
<totalLineRate>85</totalLineRate>
|
||||
<packageLineRate>85</packageLineRate>
|
||||
<packageBranchRate>85</packageBranchRate>
|
||||
<regexes>
|
||||
<regex>
|
||||
<pattern>.*\$.*</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
<regex>
|
||||
<pattern>org.owasp.dependencycheck.data.cpe.Fields</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
<regex>
|
||||
<pattern>org.owasp.dependencycheck.App</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
</regexes>
|
||||
</check>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>clean</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/data</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<excludes>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
<exclude>**/*MySQLTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/data</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
@@ -244,7 +157,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<version>${reporting.pmd-plugin.version}</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<linkXRef>true</linkXRef>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
@@ -340,6 +253,10 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>mailapi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<!-- The following dependencies are only used during testing -->
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.scm</groupId>
|
||||
@@ -470,6 +387,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
@@ -481,13 +399,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
@@ -507,7 +418,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</property>
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*MySQLTest.java</include>
|
||||
<include>**/*MySqlIT.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
<executions>
|
||||
@@ -538,13 +449,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
@@ -564,7 +468,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</property>
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*MySQLTest.java</include>
|
||||
<include>**/*MySqlIT.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
<executions>
|
||||
@@ -672,13 +576,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.gerrit</groupId>
|
||||
<artifactId>gerrit-extension-api</artifactId>
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.util.concurrent.Callable;
|
||||
*
|
||||
* @author Stefan Neuhaus
|
||||
*/
|
||||
class AnalysisTask implements Callable<Void> {
|
||||
public class AnalysisTask implements Callable<Void> {
|
||||
|
||||
/**
|
||||
* Instance of the logger.
|
||||
@@ -86,7 +86,6 @@ class AnalysisTask implements Callable<Void> {
|
||||
* Executes the analysis task.
|
||||
*
|
||||
* @return null
|
||||
* @throws Exception thrown if unable to execute the analysis task
|
||||
*/
|
||||
@Override
|
||||
public Void call() {
|
||||
@@ -119,7 +118,7 @@ class AnalysisTask implements Callable<Void> {
|
||||
*
|
||||
* @return whether or not the analyzer can analyze the dependency
|
||||
*/
|
||||
boolean shouldAnalyze() {
|
||||
protected boolean shouldAnalyze() {
|
||||
if (analyzer instanceof FileTypeAnalyzer) {
|
||||
final FileTypeAnalyzer fileTypeAnalyzer = (FileTypeAnalyzer) analyzer;
|
||||
return fileTypeAnalyzer.accept(dependency.getActualFile());
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -53,6 +54,9 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.exception.ReportException;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
|
||||
/**
|
||||
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and
|
||||
@@ -71,18 +75,22 @@ public class Engine implements FileFilter {
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final Map<AnalysisPhase, List<Analyzer>> analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
|
||||
private final Map<AnalysisPhase, List<Analyzer>> analyzers = new EnumMap<>(AnalysisPhase.class);
|
||||
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
|
||||
private final Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<>();
|
||||
|
||||
/**
|
||||
* The ClassLoader to use when dynamically loading Analyzer and Update
|
||||
* services.
|
||||
*/
|
||||
private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
/**
|
||||
* A reference to the database.
|
||||
*/
|
||||
private CveDB database = null;
|
||||
/**
|
||||
* The Logger for use throughout the class.
|
||||
*/
|
||||
@@ -126,6 +134,10 @@ public class Engine implements FileFilter {
|
||||
* Properly cleans up resources allocated during analysis.
|
||||
*/
|
||||
public void cleanup() {
|
||||
if (database != null) {
|
||||
database.close();
|
||||
database = null;
|
||||
}
|
||||
ConnectionFactory.cleanup();
|
||||
}
|
||||
|
||||
@@ -213,7 +225,7 @@ public class Engine implements FileFilter {
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(String[] paths, String projectReference) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
final List<Dependency> deps = new ArrayList<>();
|
||||
for (String path : paths) {
|
||||
final List<Dependency> d = scan(path, projectReference);
|
||||
if (d != null) {
|
||||
@@ -276,7 +288,7 @@ public class Engine implements FileFilter {
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(File[] files, String projectReference) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
final List<Dependency> deps = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
final List<Dependency> d = scan(file, projectReference);
|
||||
if (d != null) {
|
||||
@@ -311,7 +323,7 @@ public class Engine implements FileFilter {
|
||||
* @since v1.4.4
|
||||
*/
|
||||
public List<Dependency> scan(Collection<File> files, String projectReference) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
final List<Dependency> deps = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
final List<Dependency> d = scan(file, projectReference);
|
||||
if (d != null) {
|
||||
@@ -352,7 +364,7 @@ public class Engine implements FileFilter {
|
||||
} else {
|
||||
final Dependency d = scanFile(file, projectReference);
|
||||
if (d != null) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
final List<Dependency> deps = new ArrayList<>();
|
||||
deps.add(d);
|
||||
return deps;
|
||||
}
|
||||
@@ -384,7 +396,7 @@ public class Engine implements FileFilter {
|
||||
*/
|
||||
protected List<Dependency> scanDirectory(File dir, String projectReference) {
|
||||
final File[] files = dir.listFiles();
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
final List<Dependency> deps = new ArrayList<>();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
@@ -478,31 +490,14 @@ public class Engine implements FileFilter {
|
||||
*/
|
||||
public void analyzeDependencies() throws ExceptionCollection {
|
||||
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Invalid setting for auto-update; using true.");
|
||||
exceptions.add(ex);
|
||||
}
|
||||
if (autoUpdate) {
|
||||
try {
|
||||
doUpdates();
|
||||
} catch (UpdateException ex) {
|
||||
exceptions.add(ex);
|
||||
LOGGER.warn("Unable to update Cached Web DataSource, using local "
|
||||
+ "data instead. Results may not include recent vulnerabilities.");
|
||||
LOGGER.debug("Update Error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
initializeAndUpdateDatabase(exceptions);
|
||||
|
||||
//need to ensure that data exists
|
||||
try {
|
||||
ensureDataExists();
|
||||
} catch (NoDataException ex) {
|
||||
throwFatalExceptionCollection("Unable to continue dependency-check analysis.", ex, exceptions);
|
||||
} catch (DatabaseException ex) {
|
||||
throwFatalExceptionCollection("Unable to connect to the dependency-check database.", ex, exceptions);
|
||||
}
|
||||
|
||||
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
|
||||
@@ -549,6 +544,47 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs any necessary updates and initializes the database.
|
||||
*
|
||||
* @param exceptions a collection to store non-fatal exceptions
|
||||
* @throws ExceptionCollection thrown if fatal exceptions occur
|
||||
*/
|
||||
private void initializeAndUpdateDatabase(final List<Throwable> exceptions) throws ExceptionCollection {
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Invalid setting for auto-update; using true.");
|
||||
exceptions.add(ex);
|
||||
}
|
||||
if (autoUpdate) {
|
||||
try {
|
||||
database = CveDB.getInstance();
|
||||
doUpdates();
|
||||
} catch (UpdateException ex) {
|
||||
exceptions.add(ex);
|
||||
LOGGER.warn("Unable to update Cached Web DataSource, using local "
|
||||
+ "data instead. Results may not include recent vulnerabilities.");
|
||||
LOGGER.debug("Update Error", ex);
|
||||
} catch (DatabaseException ex) {
|
||||
throw new ExceptionCollection("Unable to connect to the database", ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (ConnectionFactory.isH2Connection() && !ConnectionFactory.h2DataFileExists()) {
|
||||
throw new ExceptionCollection(new NoDataException("Autoupdate is disabled and the database does not exist"), true);
|
||||
} else {
|
||||
database = CveDB.getInstance();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new ExceptionCollection(new DatabaseException("Autoupdate is disabled and unable to connect to the database"), true);
|
||||
} catch (DatabaseException ex) {
|
||||
throwFatalExceptionCollection("Unable to connect to the dependency-check database.", ex, exceptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes executes the analyzer using multiple threads.
|
||||
*
|
||||
@@ -557,7 +593,7 @@ public class Engine implements FileFilter {
|
||||
* @param analyzer the analyzer to execute
|
||||
* @throws ExceptionCollection thrown if exceptions occurred during analysis
|
||||
*/
|
||||
void executeAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) throws ExceptionCollection {
|
||||
protected void executeAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) throws ExceptionCollection {
|
||||
LOGGER.debug("Starting {}", analyzer.getName());
|
||||
final List<AnalysisTask> analysisTasks = getAnalysisTasks(analyzer, exceptions);
|
||||
final ExecutorService executorService = getExecutorService(analyzer);
|
||||
@@ -589,8 +625,8 @@ public class Engine implements FileFilter {
|
||||
* @param exceptions the collection of exceptions to collect
|
||||
* @return a collection of analysis tasks
|
||||
*/
|
||||
List<AnalysisTask> getAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) {
|
||||
final List<AnalysisTask> result = new ArrayList<AnalysisTask>();
|
||||
protected List<AnalysisTask> getAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) {
|
||||
final List<AnalysisTask> result = new ArrayList<>();
|
||||
synchronized (dependencies) {
|
||||
for (final Dependency dependency : dependencies) {
|
||||
final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions, Settings.getInstance());
|
||||
@@ -606,11 +642,9 @@ public class Engine implements FileFilter {
|
||||
* @param analyzer the analyzer to obtain an executor
|
||||
* @return the executor service
|
||||
*/
|
||||
ExecutorService getExecutorService(Analyzer analyzer) {
|
||||
protected ExecutorService getExecutorService(Analyzer analyzer) {
|
||||
if (analyzer.supportsParallelProcessing()) {
|
||||
// just a fair trade-off that should be reasonable for all analyzer types
|
||||
final int maximumNumberOfThreads = 4 * Runtime.getRuntime().availableProcessors();
|
||||
|
||||
final int maximumNumberOfThreads = Runtime.getRuntime().availableProcessors();
|
||||
LOGGER.debug("Parallel processing with up to {} threads: {}.", maximumNumberOfThreads, analyzer.getName());
|
||||
return Executors.newFixedThreadPool(maximumNumberOfThreads);
|
||||
} else {
|
||||
@@ -623,11 +657,10 @@ public class Engine implements FileFilter {
|
||||
* Initializes the given analyzer.
|
||||
*
|
||||
* @param analyzer the analyzer to initialize
|
||||
* @return the initialized analyzer
|
||||
* @throws InitializationException thrown when there is a problem
|
||||
* initializing the analyzer
|
||||
*/
|
||||
protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
|
||||
protected void initializeAnalyzer(Analyzer analyzer) throws InitializationException {
|
||||
try {
|
||||
LOGGER.debug("Initializing {}", analyzer.getName());
|
||||
analyzer.initialize();
|
||||
@@ -650,7 +683,6 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
throw new InitializationException("Unexpected Exception", ex);
|
||||
}
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -692,7 +724,7 @@ public class Engine implements FileFilter {
|
||||
* @return a list of Analyzers
|
||||
*/
|
||||
public List<Analyzer> getAnalyzers() {
|
||||
final List<Analyzer> ret = new ArrayList<Analyzer>();
|
||||
final List<Analyzer> ret = new ArrayList<>();
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||
ret.addAll(analyzerList);
|
||||
@@ -745,20 +777,10 @@ public class Engine implements FileFilter {
|
||||
* NoDataException is thrown.
|
||||
*
|
||||
* @throws NoDataException thrown if no data exists in the CPE Index
|
||||
* @throws DatabaseException thrown if there is an exception opening the
|
||||
* database
|
||||
*/
|
||||
private void ensureDataExists() throws NoDataException, DatabaseException {
|
||||
final CveDB cve = new CveDB();
|
||||
try {
|
||||
cve.open();
|
||||
if (!cve.dataExists()) {
|
||||
throw new NoDataException("No documents exist");
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
throw new NoDataException(ex.getMessage(), ex);
|
||||
} finally {
|
||||
cve.close();
|
||||
private void ensureDataExists() throws NoDataException {
|
||||
if (database == null || !database.dataExists()) {
|
||||
throw new NoDataException("No documents exist");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,4 +799,42 @@ public class Engine implements FileFilter {
|
||||
exceptions.add(throwable);
|
||||
throw new ExceptionCollection(message, exceptions, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the report to the given output directory.
|
||||
*
|
||||
* @param applicationName the name of the application/project
|
||||
* @param groupId the Maven groupId
|
||||
* @param artifactId the Maven artifactId
|
||||
* @param version the Maven version
|
||||
* @param outputDir the path to the output directory (can include the full
|
||||
* file name if the format is not ALL)
|
||||
* @param format the report format (ALL, HTML, CSV, JSON, etc.)
|
||||
* @throws ReportException thrown if there is an error generating the report
|
||||
*/
|
||||
public void writeReports(String applicationName, String groupId, String artifactId,
|
||||
String version, File outputDir, String format) throws ReportException {
|
||||
|
||||
DatabaseProperties prop = database.getDatabaseProperties();
|
||||
final ReportGenerator r = new ReportGenerator(applicationName, groupId, artifactId, version, dependencies, getAnalyzers(), prop);
|
||||
try {
|
||||
r.write(outputDir.getAbsolutePath(), format);
|
||||
} catch (ReportException ex) {
|
||||
final String msg = String.format("Error generating the report for %s", applicationName);
|
||||
throw new ReportException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the report to the given output directory.
|
||||
*
|
||||
* @param applicationName the name of the application/project
|
||||
* @param outputDir the path to the output directory (can include the full
|
||||
* file name if the format is not ALL)
|
||||
* @param format the report format (ALL, HTML, CSV, JSON, etc.)
|
||||
* @throws ReportException thrown if there is an error generating the report
|
||||
*/
|
||||
public void writeReports(String applicationName, File outputDir, String format) throws ReportException {
|
||||
writeReports(applicationName, null, null, null, outputDir, format);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||
import org.owasp.dependencycheck.exception.ReportException;
|
||||
import org.owasp.dependencycheck.exception.ScanAgentException;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -63,6 +64,7 @@ import org.slf4j.LoggerFactory;
|
||||
@SuppressWarnings("unused")
|
||||
public class DependencyCheckScanAgent {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="private fields">
|
||||
/**
|
||||
* System specific new line character.
|
||||
*/
|
||||
@@ -75,6 +77,141 @@ public class DependencyCheckScanAgent {
|
||||
* The application name for the report.
|
||||
*/
|
||||
private String applicationName = "Dependency-Check";
|
||||
/**
|
||||
* The pre-determined dependencies to scan
|
||||
*/
|
||||
private List<Dependency> dependencies;
|
||||
/**
|
||||
* The location of the data directory that contains
|
||||
*/
|
||||
private String dataDirectory = null;
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check
|
||||
* report.
|
||||
*/
|
||||
private String reportOutputDirectory;
|
||||
/**
|
||||
* Specifies if the build should be failed if a CVSS score above a specified
|
||||
* level is identified. The default is 11 which means since the CVSS scores
|
||||
* are 0-10, by default the build will never fail and the CVSS score is set
|
||||
* to 11. The valid range for the fail build on CVSS is 0 to 11, where
|
||||
* anything above 10 will not cause the build to fail.
|
||||
*/
|
||||
private float failBuildOnCVSS = 11;
|
||||
/**
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
|
||||
* recommended that this be turned to false. Default is true.
|
||||
*/
|
||||
private boolean autoUpdate = true;
|
||||
/**
|
||||
* flag indicating whether or not to generate a report of findings.
|
||||
*/
|
||||
private boolean generateReport = true;
|
||||
/**
|
||||
* The report format to be generated (HTML, XML, VULN, ALL). This
|
||||
* configuration option has no affect if using this within the Site plugin
|
||||
* unless the externalReport is set to true. Default is HTML.
|
||||
*/
|
||||
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
|
||||
/**
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyServer;
|
||||
/**
|
||||
* The Proxy Port.
|
||||
*/
|
||||
private String proxyPort;
|
||||
/**
|
||||
* The Proxy username.
|
||||
*/
|
||||
private String proxyUsername;
|
||||
/**
|
||||
* The Proxy password.
|
||||
*/
|
||||
private String proxyPassword;
|
||||
/**
|
||||
* The Connection Timeout.
|
||||
*/
|
||||
private String connectionTimeout;
|
||||
/**
|
||||
* The file path used for verbose logging.
|
||||
*/
|
||||
private String logFile = null;
|
||||
/**
|
||||
* flag indicating whether or not to show a summary of findings.
|
||||
*/
|
||||
private boolean showSummary = true;
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
private String suppressionFile;
|
||||
/**
|
||||
* The password to use when connecting to the database.
|
||||
*/
|
||||
private String databasePassword;
|
||||
/**
|
||||
* Whether or not the Maven Central analyzer is enabled.
|
||||
*/
|
||||
private boolean centralAnalyzerEnabled = true;
|
||||
/**
|
||||
* The URL of Maven Central.
|
||||
*/
|
||||
private String centralUrl;
|
||||
/**
|
||||
* Whether or not the nexus analyzer is enabled.
|
||||
*/
|
||||
private boolean nexusAnalyzerEnabled = true;
|
||||
/**
|
||||
* The URL of the Nexus server.
|
||||
*/
|
||||
private String nexusUrl;
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
private boolean nexusUsesProxy = true;
|
||||
/**
|
||||
* The database driver name; such as org.h2.Driver.
|
||||
*/
|
||||
private String databaseDriverName;
|
||||
/**
|
||||
* The path to the database driver JAR file if it is not on the class path.
|
||||
*/
|
||||
private String databaseDriverPath;
|
||||
/**
|
||||
* The database connection string.
|
||||
*/
|
||||
private String connectionString;
|
||||
/**
|
||||
* The user name for connecting to the database.
|
||||
*/
|
||||
private String databaseUser;
|
||||
/**
|
||||
* Additional ZIP File extensions to add analyze. This should be a
|
||||
* comma-separated list of file extensions to treat like ZIP files.
|
||||
*/
|
||||
private String zipExtensions;
|
||||
/**
|
||||
* The url for the modified NVD CVE (1.2 schema).
|
||||
*/
|
||||
private String cveUrl12Modified;
|
||||
/**
|
||||
* The url for the modified NVD CVE (2.0 schema).
|
||||
*/
|
||||
private String cveUrl20Modified;
|
||||
/**
|
||||
* Base Data Mirror URL for CVE 1.2.
|
||||
*/
|
||||
private String cveUrl12Base;
|
||||
/**
|
||||
* Data Mirror URL for CVE 2.0.
|
||||
*/
|
||||
private String cveUrl20Base;
|
||||
/**
|
||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
||||
*/
|
||||
private String pathToMono;
|
||||
//</editor-fold>
|
||||
//<editor-fold defaultstate="collapsed" desc="getters/setters">
|
||||
|
||||
/**
|
||||
* Get the value of applicationName.
|
||||
@@ -94,11 +231,6 @@ public class DependencyCheckScanAgent {
|
||||
this.applicationName = applicationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The pre-determined dependencies to scan
|
||||
*/
|
||||
private List<Dependency> dependencies;
|
||||
|
||||
/**
|
||||
* Returns a list of pre-determined dependencies.
|
||||
*
|
||||
@@ -117,11 +249,6 @@ public class DependencyCheckScanAgent {
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* The location of the data directory that contains
|
||||
*/
|
||||
private String dataDirectory = null;
|
||||
|
||||
/**
|
||||
* Get the value of dataDirectory.
|
||||
*
|
||||
@@ -140,12 +267,6 @@ public class DependencyCheckScanAgent {
|
||||
this.dataDirectory = dataDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check
|
||||
* report.
|
||||
*/
|
||||
private String reportOutputDirectory;
|
||||
|
||||
/**
|
||||
* Get the value of reportOutputDirectory.
|
||||
*
|
||||
@@ -164,15 +285,6 @@ public class DependencyCheckScanAgent {
|
||||
this.reportOutputDirectory = reportOutputDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the build should be failed if a CVSS score above a specified
|
||||
* level is identified. The default is 11 which means since the CVSS scores
|
||||
* are 0-10, by default the build will never fail and the CVSS score is set
|
||||
* to 11. The valid range for the fail build on CVSS is 0 to 11, where
|
||||
* anything above 10 will not cause the build to fail.
|
||||
*/
|
||||
private float failBuildOnCVSS = 11;
|
||||
|
||||
/**
|
||||
* Get the value of failBuildOnCVSS.
|
||||
*
|
||||
@@ -191,12 +303,6 @@ public class DependencyCheckScanAgent {
|
||||
this.failBuildOnCVSS = failBuildOnCVSS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
|
||||
* recommended that this be turned to false. Default is true.
|
||||
*/
|
||||
private boolean autoUpdate = true;
|
||||
|
||||
/**
|
||||
* Get the value of autoUpdate.
|
||||
*
|
||||
@@ -215,11 +321,6 @@ public class DependencyCheckScanAgent {
|
||||
this.autoUpdate = autoUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* flag indicating whether or not to generate a report of findings.
|
||||
*/
|
||||
private boolean generateReport = true;
|
||||
|
||||
/**
|
||||
* Get the value of generateReport.
|
||||
*
|
||||
@@ -238,13 +339,6 @@ public class DependencyCheckScanAgent {
|
||||
this.generateReport = generateReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* The report format to be generated (HTML, XML, VULN, ALL). This
|
||||
* configuration option has no affect if using this within the Site plugin
|
||||
* unless the externalReport is set to true. Default is HTML.
|
||||
*/
|
||||
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
|
||||
|
||||
/**
|
||||
* Get the value of reportFormat.
|
||||
*
|
||||
@@ -263,11 +357,6 @@ public class DependencyCheckScanAgent {
|
||||
this.reportFormat = reportFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
@@ -311,11 +400,6 @@ public class DependencyCheckScanAgent {
|
||||
this.proxyServer = proxyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy Port.
|
||||
*/
|
||||
private String proxyPort;
|
||||
|
||||
/**
|
||||
* Get the value of proxyPort.
|
||||
*
|
||||
@@ -334,11 +418,6 @@ public class DependencyCheckScanAgent {
|
||||
this.proxyPort = proxyPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy username.
|
||||
*/
|
||||
private String proxyUsername;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUsername.
|
||||
*
|
||||
@@ -357,11 +436,6 @@ public class DependencyCheckScanAgent {
|
||||
this.proxyUsername = proxyUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy password.
|
||||
*/
|
||||
private String proxyPassword;
|
||||
|
||||
/**
|
||||
* Get the value of proxyPassword.
|
||||
*
|
||||
@@ -380,11 +454,6 @@ public class DependencyCheckScanAgent {
|
||||
this.proxyPassword = proxyPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Connection Timeout.
|
||||
*/
|
||||
private String connectionTimeout;
|
||||
|
||||
/**
|
||||
* Get the value of connectionTimeout.
|
||||
*
|
||||
@@ -403,11 +472,6 @@ public class DependencyCheckScanAgent {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file path used for verbose logging.
|
||||
*/
|
||||
private String logFile = null;
|
||||
|
||||
/**
|
||||
* Get the value of logFile.
|
||||
*
|
||||
@@ -426,11 +490,6 @@ public class DependencyCheckScanAgent {
|
||||
this.logFile = logFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the suppression file.
|
||||
*/
|
||||
private String suppressionFile;
|
||||
|
||||
/**
|
||||
* Get the value of suppressionFile.
|
||||
*
|
||||
@@ -449,11 +508,6 @@ public class DependencyCheckScanAgent {
|
||||
this.suppressionFile = suppressionFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* flag indicating whether or not to show a summary of findings.
|
||||
*/
|
||||
private boolean showSummary = true;
|
||||
|
||||
/**
|
||||
* Get the value of showSummary.
|
||||
*
|
||||
@@ -472,11 +526,6 @@ public class DependencyCheckScanAgent {
|
||||
this.showSummary = showSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the Maven Central analyzer is enabled.
|
||||
*/
|
||||
private boolean centralAnalyzerEnabled = true;
|
||||
|
||||
/**
|
||||
* Get the value of centralAnalyzerEnabled.
|
||||
*
|
||||
@@ -495,11 +544,6 @@ public class DependencyCheckScanAgent {
|
||||
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL of Maven Central.
|
||||
*/
|
||||
private String centralUrl;
|
||||
|
||||
/**
|
||||
* Get the value of centralUrl.
|
||||
*
|
||||
@@ -518,11 +562,6 @@ public class DependencyCheckScanAgent {
|
||||
this.centralUrl = centralUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the nexus analyzer is enabled.
|
||||
*/
|
||||
private boolean nexusAnalyzerEnabled = true;
|
||||
|
||||
/**
|
||||
* Get the value of nexusAnalyzerEnabled.
|
||||
*
|
||||
@@ -541,11 +580,6 @@ public class DependencyCheckScanAgent {
|
||||
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL of the Nexus server.
|
||||
*/
|
||||
private String nexusUrl;
|
||||
|
||||
/**
|
||||
* Get the value of nexusUrl.
|
||||
*
|
||||
@@ -564,11 +598,6 @@ public class DependencyCheckScanAgent {
|
||||
this.nexusUrl = nexusUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
private boolean nexusUsesProxy = true;
|
||||
|
||||
/**
|
||||
* Get the value of nexusUsesProxy.
|
||||
*
|
||||
@@ -587,11 +616,6 @@ public class DependencyCheckScanAgent {
|
||||
this.nexusUsesProxy = nexusUsesProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* The database driver name; such as org.h2.Driver.
|
||||
*/
|
||||
private String databaseDriverName;
|
||||
|
||||
/**
|
||||
* Get the value of databaseDriverName.
|
||||
*
|
||||
@@ -610,11 +634,6 @@ public class DependencyCheckScanAgent {
|
||||
this.databaseDriverName = databaseDriverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the database driver JAR file if it is not on the class path.
|
||||
*/
|
||||
private String databaseDriverPath;
|
||||
|
||||
/**
|
||||
* Get the value of databaseDriverPath.
|
||||
*
|
||||
@@ -633,11 +652,6 @@ public class DependencyCheckScanAgent {
|
||||
this.databaseDriverPath = databaseDriverPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The database connection string.
|
||||
*/
|
||||
private String connectionString;
|
||||
|
||||
/**
|
||||
* Get the value of connectionString.
|
||||
*
|
||||
@@ -656,11 +670,6 @@ public class DependencyCheckScanAgent {
|
||||
this.connectionString = connectionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user name for connecting to the database.
|
||||
*/
|
||||
private String databaseUser;
|
||||
|
||||
/**
|
||||
* Get the value of databaseUser.
|
||||
*
|
||||
@@ -679,11 +688,6 @@ public class DependencyCheckScanAgent {
|
||||
this.databaseUser = databaseUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* The password to use when connecting to the database.
|
||||
*/
|
||||
private String databasePassword;
|
||||
|
||||
/**
|
||||
* Get the value of databasePassword.
|
||||
*
|
||||
@@ -702,12 +706,6 @@ public class DependencyCheckScanAgent {
|
||||
this.databasePassword = databasePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional ZIP File extensions to add analyze. This should be a
|
||||
* comma-separated list of file extensions to treat like ZIP files.
|
||||
*/
|
||||
private String zipExtensions;
|
||||
|
||||
/**
|
||||
* Get the value of zipExtensions.
|
||||
*
|
||||
@@ -726,11 +724,6 @@ public class DependencyCheckScanAgent {
|
||||
this.zipExtensions = zipExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (1.2 schema).
|
||||
*/
|
||||
private String cveUrl12Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Modified.
|
||||
*
|
||||
@@ -749,11 +742,6 @@ public class DependencyCheckScanAgent {
|
||||
this.cveUrl12Modified = cveUrl12Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (2.0 schema).
|
||||
*/
|
||||
private String cveUrl20Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Modified.
|
||||
*
|
||||
@@ -772,11 +760,6 @@ public class DependencyCheckScanAgent {
|
||||
this.cveUrl20Modified = cveUrl20Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base Data Mirror URL for CVE 1.2.
|
||||
*/
|
||||
private String cveUrl12Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Base.
|
||||
*
|
||||
@@ -795,11 +778,6 @@ public class DependencyCheckScanAgent {
|
||||
this.cveUrl12Base = cveUrl12Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Mirror URL for CVE 2.0.
|
||||
*/
|
||||
private String cveUrl20Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Base.
|
||||
*
|
||||
@@ -818,11 +796,6 @@ public class DependencyCheckScanAgent {
|
||||
this.cveUrl20Base = cveUrl20Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
||||
*/
|
||||
private String pathToMono;
|
||||
|
||||
/**
|
||||
* Get the value of pathToMono.
|
||||
*
|
||||
@@ -840,6 +813,7 @@ public class DependencyCheckScanAgent {
|
||||
public void setPathToMono(String pathToMono) {
|
||||
this.pathToMono = pathToMono;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Executes the Dependency-Check on the dependent libraries.
|
||||
@@ -866,32 +840,15 @@ public class DependencyCheckScanAgent {
|
||||
*
|
||||
* @param engine a dependency-check engine
|
||||
* @param outDirectory the directory to write the reports to
|
||||
* @throw ScanAgentException thrown if there is an error generating the
|
||||
* report
|
||||
*/
|
||||
private void generateExternalReports(Engine engine, File outDirectory) {
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
private void generateExternalReports(Engine engine, File outDirectory) throws ScanAgentException {
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
try {
|
||||
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error(
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.error(
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
engine.writeReports(applicationName, outDirectory, this.reportFormat.name());
|
||||
} catch (ReportException ex) {
|
||||
LOGGER.debug("Unexpected exception occurred during analysis; please see the verbose error log for more details.", ex);
|
||||
throw new ScanAgentException("Error generating the report", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,7 +955,7 @@ public class DependencyCheckScanAgent {
|
||||
}
|
||||
if (ids.length() > 0) {
|
||||
final String msg = String.format("%n%nDependency-Check Failure:%n"
|
||||
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
|
||||
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater than '%.1f': %s%n"
|
||||
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
|
||||
|
||||
throw new ScanAgentException(msg);
|
||||
@@ -1044,5 +1001,4 @@ public class DependencyCheckScanAgent {
|
||||
summary.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,8 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||
protected abstract void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException;
|
||||
|
||||
/**
|
||||
* Initializes a given Analyzer. This will be skipped if the analyzer is disabled.
|
||||
* Initializes a given Analyzer. This will be skipped if the analyzer is
|
||||
* disabled.
|
||||
*
|
||||
* @throws InitializationException thrown if there is an exception
|
||||
*/
|
||||
@@ -90,14 +91,15 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a given Analyzer. This will be skipped if the analyzer is disabled.
|
||||
* Closes a given Analyzer. This will be skipped if the analyzer is
|
||||
* disabled.
|
||||
*
|
||||
* @throws Exception thrown if there is an exception
|
||||
*/
|
||||
protected void closeAnalyzer() throws Exception {
|
||||
// Intentionally empty, analyzer will override this if they must close a resource.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a
|
||||
* WAR or EAR, the contents are extracted, scanned, and added to the list of
|
||||
@@ -148,7 +150,6 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The default is to support parallel processing.
|
||||
*
|
||||
|
||||
@@ -141,7 +141,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
* @return a Set of strings.
|
||||
*/
|
||||
protected static Set<String> newHashSet(String... strings) {
|
||||
final Set<String> set = new HashSet<String>(strings.length);
|
||||
final Set<String> set = new HashSet<>(strings.length);
|
||||
Collections.addAll(set, strings);
|
||||
return set;
|
||||
}
|
||||
|
||||
@@ -130,10 +130,9 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
} else {
|
||||
file = new File(suppressionFilePath);
|
||||
InputStream suppressionsFromClasspath = null;
|
||||
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath);
|
||||
try (InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath)) {
|
||||
if (suppressionsFromClasspath != null) {
|
||||
deleteTempFile = true;
|
||||
file = FileUtils.getTempFile("suppression", "xml");
|
||||
@@ -143,14 +142,6 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (suppressionsFromClasspath != null) {
|
||||
try {
|
||||
suppressionsFromClasspath.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Failed to close stream", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,13 +57,13 @@ public class AnalyzerService {
|
||||
* @return a list of Analyzers.
|
||||
*/
|
||||
public List<Analyzer> getAnalyzers() {
|
||||
final List<Analyzer> analyzers = new ArrayList<Analyzer>();
|
||||
final List<Analyzer> analyzers = new ArrayList<>();
|
||||
final Iterator<Analyzer> iterator = service.iterator();
|
||||
boolean experimentalEnabled = false;
|
||||
try {
|
||||
experimentalEnabled = Settings.getBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, false);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.error("invalide experimental setting", ex);
|
||||
LOGGER.error("invalid experimental setting", ex);
|
||||
}
|
||||
while (iterator.hasNext()) {
|
||||
final Analyzer a = iterator.next();
|
||||
|
||||
@@ -98,7 +98,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* The set of things we can handle with Zip methods
|
||||
*/
|
||||
private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
|
||||
private static final Set<String> KNOWN_ZIP_EXT = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
|
||||
/**
|
||||
* The set of file extensions supported by this analyzer. Note for
|
||||
* developers, any additions to this list will need to be explicitly handled
|
||||
@@ -106,37 +106,37 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz", "bz2", "tbz2");
|
||||
|
||||
/**
|
||||
* Detects files with extensions to remove from the engine's collection of
|
||||
* dependencies.
|
||||
*/
|
||||
private static final FileFilter REMOVE_FROM_ANALYSIS = FileFilterBuilder.newInstance().addExtensions("zip", "tar", "gz", "tgz", "bz2", "tbz2")
|
||||
.build();
|
||||
|
||||
static {
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
final String[] ext = additionalZipExt.split("\\s*,\\s*");
|
||||
Collections.addAll(ZIPPABLES, ext);
|
||||
Collections.addAll(KNOWN_ZIP_EXT, ext);
|
||||
}
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
EXTENSIONS.addAll(KNOWN_ZIP_EXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects files with extensions to remove from the engine's collection of
|
||||
* dependencies.
|
||||
*/
|
||||
private static final FileFilter REMOVE_FROM_ANALYSIS = FileFilterBuilder.newInstance()
|
||||
.addExtensions("zip", "tar", "gz", "tgz", "bz2", "tbz2").build();
|
||||
|
||||
/**
|
||||
* The file filter used to filter supported files.
|
||||
*/
|
||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects files with .zip extension.
|
||||
*/
|
||||
private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
|
||||
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
@@ -221,6 +221,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* Does not support parallel processing as it both modifies and iterates
|
||||
* over the engine's list of dependencies.
|
||||
*
|
||||
* @return <code>true</code> if the analyzer supports parallel processing;
|
||||
* otherwise <code>false</code>
|
||||
* @see #analyzeDependency(Dependency, Engine)
|
||||
* @see #findMoreDependencies(Engine, File)
|
||||
*/
|
||||
@@ -301,11 +303,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private void addDisguisedJarsToDependencies(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (ZIP_FILTER.accept(dependency.getActualFile()) && isZipFileActuallyJarFile(dependency)) {
|
||||
final File tdir = getNextTempDirectory();
|
||||
final File tempDir = getNextTempDirectory();
|
||||
final String fileName = dependency.getFileName();
|
||||
|
||||
LOGGER.info("The zip file '{}' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName);
|
||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
final File tmpLoc = new File(tempDir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
//store the archives sha1 and change it so that the engine doesn't think the zip and jar file are the same
|
||||
// and add it is a related dependency.
|
||||
final String archiveSha1 = dependency.getSha1sum();
|
||||
@@ -345,8 +347,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @return any dependencies that weren't known to the engine before
|
||||
*/
|
||||
private static List<Dependency> findMoreDependencies(Engine engine, File file) {
|
||||
final List<Dependency> added = engine.scan(file);
|
||||
return added;
|
||||
return engine.scan(file);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -398,7 +399,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
GzipCompressorInputStream gin = null;
|
||||
BZip2CompressorInputStream bzin = null;
|
||||
try {
|
||||
if (ZIPPABLES.contains(archiveExt)) {
|
||||
if (KNOWN_ZIP_EXT.contains(archiveExt)) {
|
||||
in = new BufferedInputStream(fis);
|
||||
ensureReadableJar(archiveExt, in);
|
||||
zin = new ZipArchiveInputStream(in);
|
||||
@@ -470,7 +471,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
&& b[5] == 'n'
|
||||
&& b[6] == '/') {
|
||||
boolean stillLooking = true;
|
||||
int chr, nxtChr;
|
||||
int chr;
|
||||
int nxtChr;
|
||||
while (stillLooking && (chr = in.read()) != -1) {
|
||||
if (chr == '\n' || chr == '\r') {
|
||||
in.mark(4);
|
||||
@@ -517,7 +519,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
extractAcceptedFile(input, file);
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
} catch (IOException | AnalysisException ex) {
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} finally {
|
||||
FileUtils.close(input);
|
||||
@@ -533,14 +535,12 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static void extractAcceptedFile(ArchiveInputStream input, File file) throws AnalysisException {
|
||||
LOGGER.debug("Extracting '{}'", file.getPath());
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
fos = new FileOutputStream(file);
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
IOUtils.copy(input, fos);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
@@ -550,8 +550,6 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.debug("", ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} finally {
|
||||
FileUtils.close(fos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,18 +563,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
||||
LOGGER.debug("Decompressing '{}'", outputFile.getPath());
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(outputFile);
|
||||
try (FileOutputStream out = new FileOutputStream(outputFile)) {
|
||||
IOUtils.copy(inputStream, out);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} finally {
|
||||
FileUtils.close(out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,7 +601,6 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} finally {
|
||||
ZipFile.closeQuietly(zip);
|
||||
}
|
||||
|
||||
return isJar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
protected List<String> buildArgumentList() {
|
||||
// Use file.separator as a wild guess as to whether this is Windows
|
||||
final List<String> args = new ArrayList<String>();
|
||||
final List<String> args = new ArrayList<>();
|
||||
if (!SystemUtils.IS_OS_WINDOWS) {
|
||||
if (Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH) != null) {
|
||||
args.add(Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH));
|
||||
@@ -144,7 +144,9 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
dependency.getActualFilePath());
|
||||
return;
|
||||
} else if (rc != 0) {
|
||||
LOGGER.warn("Return code {} from GrokAssembly", rc);
|
||||
LOGGER.debug("Return code {} from GrokAssembly; dependency-check is unable to analyze the library: {}",
|
||||
rc, dependency.getActualFilePath());
|
||||
return;
|
||||
}
|
||||
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
@@ -175,18 +177,17 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
} catch (ParserConfigurationException pce) {
|
||||
throw new AnalysisException("Error initializing the assembly analyzer", pce);
|
||||
} catch (IOException ioe) {
|
||||
} catch (IOException | XPathExpressionException ioe) {
|
||||
throw new AnalysisException(ioe);
|
||||
} catch (SAXException saxe) {
|
||||
LOGGER.error("----------------------------------------------------");
|
||||
LOGGER.error("Failed to read the Assembly Analyzer results. "
|
||||
+ "On some systems mono-runtime and mono-devel need to be installed.");
|
||||
LOGGER.error("----------------------------------------------------");
|
||||
throw new AnalysisException("Couldn't parse Assembly Analzyzer results (GrokAssembly)", saxe);
|
||||
} catch (XPathExpressionException xpe) {
|
||||
// This shouldn't happen
|
||||
throw new AnalysisException(xpe);
|
||||
throw new AnalysisException("Couldn't parse Assembly Analyzer results (GrokAssembly)", saxe);
|
||||
}
|
||||
// This shouldn't happen
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,40 +199,27 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||
final File tempFile;
|
||||
final String cfg;
|
||||
try {
|
||||
tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
|
||||
cfg = tempFile.getPath() + ".config";
|
||||
} catch (IOException ex) {
|
||||
setEnabled(false);
|
||||
throw new InitializationException("Unable to create temporary file for the assembly analyzerr", ex);
|
||||
throw new InitializationException("Unable to create temporary file for the assembly analyzer", ex);
|
||||
}
|
||||
FileOutputStream fos = null;
|
||||
InputStream is = null;
|
||||
try {
|
||||
fos = new FileOutputStream(tempFile);
|
||||
is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
||||
try (FileOutputStream fos = new FileOutputStream(tempFile);
|
||||
InputStream is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
||||
FileOutputStream fosCfg = new FileOutputStream(cfg);
|
||||
InputStream isCfg = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe.config")) {
|
||||
IOUtils.copy(is, fos);
|
||||
|
||||
grokAssemblyExe = tempFile;
|
||||
LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
|
||||
IOUtils.copy(isCfg, fosCfg);
|
||||
LOGGER.debug("Extracted GrokAssembly.exe.config to {}", cfg);
|
||||
} catch (IOException ioe) {
|
||||
this.setEnabled(false);
|
||||
LOGGER.warn("Could not extract GrokAssembly.exe: {}", ioe.getMessage());
|
||||
throw new InitializationException("Could not extract GrokAssembly.exe", ioe);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Error closing output stream");
|
||||
}
|
||||
}
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Error closing input stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, need to see if GrokAssembly actually runs from this location.
|
||||
@@ -242,7 +230,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
//
|
||||
// We need to create a non-fatal warning error type that will
|
||||
// get added to the report.
|
||||
//TOOD this idea needs to get replicated to the bundle audit analyzer.
|
||||
//TODO this idea needs to get replicated to the bundle audit analyzer.
|
||||
if (args == null) {
|
||||
setEnabled(false);
|
||||
LOGGER.error("----------------------------------------------------");
|
||||
@@ -273,7 +261,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (InitializationException e) {
|
||||
setEnabled(false);
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
} catch (IOException | ParserConfigurationException | SAXException | XPathExpressionException | InterruptedException e) {
|
||||
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n"
|
||||
+ "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.");
|
||||
LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage());
|
||||
@@ -359,10 +347,8 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (retCode == 0) {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Path seach failed for " + file);
|
||||
} catch (InterruptedException ex) {
|
||||
LOGGER.debug("Path seach failed for " + file);
|
||||
} catch (IOException | InterruptedException ex) {
|
||||
LOGGER.debug("Path search failed for " + file, ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -70,26 +70,26 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
/**
|
||||
* The maximum number of query results to return.
|
||||
*/
|
||||
static final int MAX_QUERY_RESULTS = 25;
|
||||
private static final int MAX_QUERY_RESULTS = 25;
|
||||
/**
|
||||
* The weighting boost to give terms when constructing the Lucene query.
|
||||
*/
|
||||
static final String WEIGHTING_BOOST = "^5";
|
||||
private static final String WEIGHTING_BOOST = "^5";
|
||||
/**
|
||||
* A string representation of a regular expression defining characters
|
||||
* utilized within the CPE Names.
|
||||
*/
|
||||
static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 ._-]";
|
||||
private static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 ._-]";
|
||||
/**
|
||||
* A string representation of a regular expression used to remove all but
|
||||
* alpha characters.
|
||||
*/
|
||||
static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
|
||||
private static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
|
||||
/**
|
||||
* The additional size to add to a new StringBuilder to account for extra
|
||||
* data that will be written into the string.
|
||||
*/
|
||||
static final int STRING_BUILDER_BUFFER = 20;
|
||||
private static final int STRING_BUILDER_BUFFER = 20;
|
||||
/**
|
||||
* The CPE in memory index.
|
||||
*/
|
||||
@@ -123,14 +123,17 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return AnalysisPhase.IDENTIFIER_ANALYSIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default is to support parallel processing.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParallelProcessing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the CPE Lucene Index.
|
||||
*
|
||||
@@ -160,8 +163,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
public void open() throws IOException, DatabaseException {
|
||||
if (!isOpen()) {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
cve = CveDB.getInstance();
|
||||
cpe = CpeMemoryIndex.getInstance();
|
||||
try {
|
||||
final long creationStart = System.currentTimeMillis();
|
||||
@@ -180,16 +182,21 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
public void closeAnalyzer() {
|
||||
if (cpe != null) {
|
||||
cpe.close();
|
||||
cpe = null;
|
||||
}
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
cve = null;
|
||||
}
|
||||
if (cpe != null) {
|
||||
cpe.close();
|
||||
cpe = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is open.
|
||||
*
|
||||
* @return <code>true</code> if the analyzer is open
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return cpe != null && cpe.isOpen();
|
||||
}
|
||||
@@ -205,7 +212,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||
*/
|
||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
||||
//TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||
//TODO test dojo-war against this. we should get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||
String vendors = "";
|
||||
String products = "";
|
||||
for (Confidence confidence : Confidence.values()) {
|
||||
@@ -293,7 +300,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||
Set<String> vendorWeightings, Set<String> productWeightings) {
|
||||
|
||||
final List<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
||||
final List<IndexEntry> ret = new ArrayList<>(MAX_QUERY_RESULTS);
|
||||
|
||||
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
||||
if (searchString == null) {
|
||||
@@ -479,7 +486,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
return false;
|
||||
}
|
||||
final String[] words = text.split("[\\s_-]");
|
||||
final List<String> list = new ArrayList<String>();
|
||||
final List<String> list = new ArrayList<>();
|
||||
String tempWord = null;
|
||||
for (String word : words) {
|
||||
/*
|
||||
@@ -557,7 +564,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||
Confidence bestGuessConf = null;
|
||||
boolean hasBroadMatch = false;
|
||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
||||
final List<IdentifierMatch> collected = new ArrayList<>();
|
||||
|
||||
//TODO the following algorithm incorrectly identifies things as a lower version
|
||||
// if there lower confidence evidence when the current (highest) version number
|
||||
@@ -596,11 +603,10 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
|
||||
if (bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
|
||||
bestGuess = evVer;
|
||||
bestGuessConf = conf;
|
||||
}
|
||||
if ((bestGuessConf == null || bestGuessConf.compareTo(conf) > 0)
|
||||
&& bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
|
||||
bestGuess = evVer;
|
||||
bestGuessConf = conf;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -610,10 +616,12 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
||||
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
||||
}
|
||||
if (bestGuessConf == null) {
|
||||
if (bestGuessConf
|
||||
== null) {
|
||||
bestGuessConf = Confidence.LOW;
|
||||
}
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", cpeName, url, IdentifierConfidence.BEST_GUESS, bestGuessConf);
|
||||
|
||||
collected.add(match);
|
||||
|
||||
Collections.sort(collected);
|
||||
@@ -645,6 +653,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_CPE_ENABLED;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -674,6 +683,19 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
private static class IdentifierMatch implements Comparable<IdentifierMatch> {
|
||||
|
||||
/**
|
||||
* The confidence in the evidence used to identify this match.
|
||||
*/
|
||||
private Confidence evidenceConfidence;
|
||||
/**
|
||||
* The confidence whether this is an exact match, or a best guess.
|
||||
*/
|
||||
private IdentifierConfidence confidence;
|
||||
/**
|
||||
* The CPE identifier.
|
||||
*/
|
||||
private Identifier identifier;
|
||||
|
||||
/**
|
||||
* Constructs an IdentifierMatch.
|
||||
*
|
||||
@@ -690,12 +712,8 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
this.confidence = identifierConfidence;
|
||||
this.evidenceConfidence = evidenceConfidence;
|
||||
}
|
||||
//<editor-fold defaultstate="collapsed" desc="Property implementations: evidenceConfidence, confidence, identifier">
|
||||
/**
|
||||
* The confidence in the evidence used to identify this match.
|
||||
*/
|
||||
private Confidence evidenceConfidence;
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Property implementations: evidenceConfidence, confidence, identifier">
|
||||
/**
|
||||
* Get the value of evidenceConfidence
|
||||
*
|
||||
@@ -713,10 +731,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
public void setEvidenceConfidence(Confidence evidenceConfidence) {
|
||||
this.evidenceConfidence = evidenceConfidence;
|
||||
}
|
||||
/**
|
||||
* The confidence whether this is an exact match, or a best guess.
|
||||
*/
|
||||
private IdentifierConfidence confidence;
|
||||
|
||||
/**
|
||||
* Get the value of confidence.
|
||||
@@ -735,10 +749,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
public void setConfidence(IdentifierConfidence confidence) {
|
||||
this.confidence = confidence;
|
||||
}
|
||||
/**
|
||||
* The CPE identifier.
|
||||
*/
|
||||
private Identifier identifier;
|
||||
|
||||
/**
|
||||
* Get the value of identifier.
|
||||
@@ -806,10 +816,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
||||
if (this.confidence != other.confidence) {
|
||||
return false;
|
||||
}
|
||||
if (this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !(this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier)));
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
|
||||
@@ -103,14 +103,14 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* <code>false</code>
|
||||
*/
|
||||
private boolean checkEnabled() {
|
||||
boolean retval = false;
|
||||
boolean retVal = false;
|
||||
|
||||
try {
|
||||
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
||||
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
||||
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
||||
LOGGER.debug("Enabling the Central analyzer");
|
||||
retval = true;
|
||||
retVal = true;
|
||||
} else {
|
||||
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
||||
}
|
||||
@@ -120,7 +120,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warn("Invalid setting. Disabling the Central analyzer");
|
||||
}
|
||||
return retval;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -101,9 +101,7 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(dependency.getActualFile());
|
||||
try (FileInputStream fis = new FileInputStream(dependency.getActualFile())) {
|
||||
final ComposerLockParser clp = new ComposerLockParser(fis);
|
||||
LOGGER.info("Checking composer.lock file {}", dependency.getActualFilePath());
|
||||
clp.process();
|
||||
@@ -120,18 +118,10 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.info("Adding dependency {}", d);
|
||||
engine.getDependencies().add(d);
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());
|
||||
} catch (ComposerException ce) {
|
||||
LOGGER.warn("Error parsing composer.json {}", dependency.getActualFilePath(), ce);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (Exception e) {
|
||||
LOGGER.debug("Unable to close file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
||||
* @return a flag indicating if this analyzer has run. This analyzer only
|
||||
* runs once
|
||||
*/
|
||||
protected boolean getAnalyzed() {
|
||||
protected synchronized boolean getAnalyzed() {
|
||||
return analyzed;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
||||
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
||||
if (!analyzed) {
|
||||
analyzed = true;
|
||||
final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
|
||||
final Set<Dependency> dependenciesToRemove = new HashSet<>();
|
||||
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
||||
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||
while (mainIterator.hasNext()) {
|
||||
@@ -154,13 +154,15 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||
while (subIterator.hasNext()) {
|
||||
final Dependency nextDependency = subIterator.next();
|
||||
if (hashesMatch(dependency, nextDependency) && !containedInWar(dependency.getFilePath())
|
||||
&& !containedInWar(nextDependency.getFilePath())) {
|
||||
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
if (hashesMatch(dependency, nextDependency)) {
|
||||
if (!containedInWar(dependency.getFilePath())
|
||||
&& !containedInWar(nextDependency.getFilePath())) {
|
||||
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
}
|
||||
}
|
||||
} else if (isShadedJar(dependency, nextDependency)) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
||||
@@ -382,7 +384,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
||||
* @return a boolean indicating whether or not the left dependency should be
|
||||
* considered the "core" version.
|
||||
*/
|
||||
boolean isCore(Dependency left, Dependency right) {
|
||||
protected boolean isCore(Dependency left, Dependency right) {
|
||||
final String leftName = left.getFileName().toLowerCase();
|
||||
final String rightName = right.getFileName().toLowerCase();
|
||||
|
||||
@@ -497,7 +499,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
||||
* @return true if the path contains '.war\' or '.ear\'.
|
||||
*/
|
||||
private boolean containedInWar(String filePath) {
|
||||
return filePath == null ? false : filePath.matches(".*\\.(ear|war)[\\\\/].*");
|
||||
return filePath != null && filePath.matches(".*\\.(ear|war)[\\\\/].*");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
|
||||
* @return a flag indicating if this analyzer has run. This analyzer only
|
||||
* runs once
|
||||
*/
|
||||
protected boolean getAnalyzed() {
|
||||
protected synchronized boolean getAnalyzed() {
|
||||
return analyzed;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
|
||||
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
||||
if (!analyzed) {
|
||||
analyzed = true;
|
||||
final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
|
||||
final Set<Dependency> dependenciesToRemove = new HashSet<>();
|
||||
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
||||
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||
while (mainIterator.hasNext()) {
|
||||
@@ -138,7 +138,7 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
|
||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||
while (subIterator.hasNext()) {
|
||||
final Dependency nextDependency = subIterator.next();
|
||||
Dependency main = null;
|
||||
Dependency main;
|
||||
if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
|
||||
if (main == dependency) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
|
||||
@@ -39,7 +39,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This analyzer attempts to remove some well known false positives - specifically regarding the java runtime.
|
||||
* This analyzer attempts to remove some well known false positives -
|
||||
* specifically regarding the java runtime.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -84,6 +85,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||
@@ -97,11 +99,13 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Analyzes the dependencies and removes bad/incorrect CPE associations based on various heuristics.
|
||||
* Analyzes the dependencies and removes bad/incorrect CPE associations
|
||||
* based on various heuristics.
|
||||
*
|
||||
* @param dependency the dependency to analyze.
|
||||
* @param engine the engine that is scanning the dependencies
|
||||
* @throws AnalysisException is thrown if there is an error reading the JAR file.
|
||||
* @throws AnalysisException is thrown if there is an error reading the JAR
|
||||
* file.
|
||||
*/
|
||||
@Override
|
||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
@@ -117,22 +121,23 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
/**
|
||||
* Removes inaccurate matches on springframework CPEs.
|
||||
*
|
||||
* @param dependency the dependency to test for and remove known inaccurate CPE matches
|
||||
* @param dependency the dependency to test for and remove known inaccurate
|
||||
* CPE matches
|
||||
*/
|
||||
private void removeBadSpringMatches(Dependency dependency) {
|
||||
String mustContain = null;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".contains(i.getType())) {
|
||||
if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||
final int endPoint = i.getValue().indexOf(':', 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
}
|
||||
if ("maven".contains(i.getType())
|
||||
&& i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||
final int endPoint = i.getValue().indexOf(':', 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mustContain != null) {
|
||||
if (mustContain
|
||||
!= null) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
@@ -149,7 +154,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate,
|
||||
* less specific CPE entries.</p>
|
||||
* <p>
|
||||
* Example:</p>
|
||||
* <code>
|
||||
@@ -167,7 +173,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
private void removeSpuriousCPE(Dependency dependency) {
|
||||
final List<Identifier> ids = new ArrayList<Identifier>(dependency.getIdentifiers());
|
||||
final List<Identifier> ids = new ArrayList<>(dependency.getIdentifiers());
|
||||
Collections.sort(ids);
|
||||
final ListIterator<Identifier> mainItr = ids.listIterator();
|
||||
while (mainItr.hasNext()) {
|
||||
@@ -200,10 +206,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
if (nextVersion.startsWith(currentVersion) || "-".equals(currentVersion)) {
|
||||
dependency.getIdentifiers().remove(currentId);
|
||||
}
|
||||
} else {
|
||||
if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
|
||||
dependency.getIdentifiers().remove(nextId);
|
||||
}
|
||||
} else if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
|
||||
dependency.getIdentifiers().remove(nextId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,7 +215,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Regex to identify core java libraries and a few other commonly misidentified ones.
|
||||
* Regex to identify core java libraries and a few other commonly
|
||||
* misidentified ones.
|
||||
*/
|
||||
public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
|
||||
+ "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
||||
@@ -226,12 +231,14 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||
/**
|
||||
* Regex to identify core jsf java library files. This is currently incomplete.
|
||||
* Regex to identify core jsf java library files. This is currently
|
||||
* incomplete.
|
||||
*/
|
||||
public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
|
||||
|
||||
/**
|
||||
* Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
|
||||
* Removes any CPE entries for the JDK/JRE unless the filename ends with
|
||||
* rt.jar
|
||||
*
|
||||
* @param dependency the dependency to remove JRE CPEs from
|
||||
*/
|
||||
@@ -275,8 +282,9 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific problems
|
||||
* identified when testing this on a LARGE volume of jar files.
|
||||
* Removes bad CPE matches for a dependency. Unfortunately, right now these
|
||||
* are hard-coded patches for specific problems identified when testing this
|
||||
* on a LARGE volume of jar files.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
*/
|
||||
@@ -351,7 +359,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes CPE matches for the wrong version of a dependency. Currently, this only covers Axis 1 & 2.
|
||||
* Removes CPE matches for the wrong version of a dependency. Currently,
|
||||
* this only covers Axis 1 & 2.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
*/
|
||||
@@ -384,8 +393,10 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and changes in
|
||||
* product names, that based on given evidence we can add the related CPE entries to ensure a complete list of CVE entries.
|
||||
* There are some known CPE entries, specifically regarding sun and oracle
|
||||
* products due to the acquisition and changes in product names, that based
|
||||
* on given evidence we can add the related CPE entries to ensure a complete
|
||||
* list of CVE entries.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
*/
|
||||
@@ -422,47 +433,47 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM entries or
|
||||
* other types of files (such as DLLs and EXEs) being contained within the JAR.
|
||||
* Removes duplicate entries identified that are contained within JAR files.
|
||||
* These occasionally crop up due to POM entries or other types of files
|
||||
* (such as DLLs and EXEs) being contained within the JAR.
|
||||
*
|
||||
* @param dependency the dependency that might be a duplicate
|
||||
* @param engine the engine used to scan all dependencies
|
||||
*/
|
||||
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||
private synchronized void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| DLL_EXE_FILTER.accept(dependency.getActualFile())) {
|
||||
String parentPath = dependency.getFilePath().toLowerCase();
|
||||
if (parentPath.contains(".jar")) {
|
||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
synchronized (dependencies) {
|
||||
final Dependency parent = findDependency(parentPath, dependencies);
|
||||
if (parent != null) {
|
||||
boolean remove = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(i.getType())) {
|
||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||
for (Identifier parentId : parent.getIdentifiers()) {
|
||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||
remove |= true;
|
||||
}
|
||||
final Dependency parent = findDependency(parentPath, dependencies);
|
||||
if (parent != null) {
|
||||
boolean remove = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(i.getType())) {
|
||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||
for (Identifier parentId : parent.getIdentifiers()) {
|
||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||
remove |= true;
|
||||
}
|
||||
}
|
||||
if (!remove) { //we can escape early
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
dependencies.remove(dependency);
|
||||
if (!remove) { //we can escape early
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
dependencies.remove(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a given dependency, based on a given path, from a list of dependencies.
|
||||
* Retrieves a given dependency, based on a given path, from a list of
|
||||
* dependencies.
|
||||
*
|
||||
* @param dependencyPath the path of the dependency to return
|
||||
* @param dependencies the collection of dependencies to search
|
||||
@@ -478,7 +489,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a full CPE and returns the CPE trimmed to include only vendor and product.
|
||||
* Takes a full CPE and returns the CPE trimmed to include only vendor and
|
||||
* product.
|
||||
*
|
||||
* @param value the CPE value to trim
|
||||
* @return a CPE value that only includes the vendor and product
|
||||
|
||||
@@ -53,6 +53,19 @@ import org.xml.sax.SAXException;
|
||||
*/
|
||||
public class HintAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
/**
|
||||
* The Logger for use throughout the class
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HintAnalyzer.class);
|
||||
/**
|
||||
* The name of the hint rule file
|
||||
*/
|
||||
private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
|
||||
/**
|
||||
* The collection of hints.
|
||||
*/
|
||||
private Hints hints;
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
@@ -82,6 +95,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||
@@ -109,19 +123,6 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* The Logger for use throughout the class
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HintAnalyzer.class);
|
||||
/**
|
||||
* The name of the hint rule file
|
||||
*/
|
||||
private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
|
||||
/**
|
||||
* The collection of hints.
|
||||
*/
|
||||
private Hints hints;
|
||||
|
||||
/**
|
||||
* The HintAnalyzer uses knowledge about a dependency to add additional
|
||||
* information to help in identification of identifiers or vulnerabilities.
|
||||
@@ -134,29 +135,38 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
@Override
|
||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
for (HintRule hint : hints.getHintRules()) {
|
||||
boolean shouldAdd = false;
|
||||
boolean matchFound = false;
|
||||
for (Evidence given : hint.getGivenVendor()) {
|
||||
if (dependency.getVendorEvidence().getEvidence().contains(given)) {
|
||||
shouldAdd = true;
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!shouldAdd) {
|
||||
if (!matchFound) {
|
||||
for (Evidence given : hint.getGivenProduct()) {
|
||||
if (dependency.getProductEvidence().getEvidence().contains(given)) {
|
||||
shouldAdd = true;
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!shouldAdd) {
|
||||
for (PropertyType pt : hint.getFilenames()) {
|
||||
if (pt.matches(dependency.getFileName())) {
|
||||
shouldAdd = true;
|
||||
if (!matchFound) {
|
||||
for (Evidence given : hint.getGivenVersion()) {
|
||||
if (dependency.getVersionEvidence().getEvidence().contains(given)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldAdd) {
|
||||
if (!matchFound) {
|
||||
for (PropertyType pt : hint.getFilenames()) {
|
||||
if (pt.matches(dependency.getFileName())) {
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchFound) {
|
||||
for (Evidence e : hint.getAddVendor()) {
|
||||
dependency.getVendorEvidence().addEvidence(e);
|
||||
}
|
||||
@@ -166,11 +176,26 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
for (Evidence e : hint.getAddVersion()) {
|
||||
dependency.getVersionEvidence().addEvidence(e);
|
||||
}
|
||||
for (Evidence e : hint.getRemoveVendor()) {
|
||||
if (dependency.getVendorEvidence().getEvidence().contains(e)) {
|
||||
dependency.getVendorEvidence().getEvidence().remove(e);
|
||||
}
|
||||
}
|
||||
for (Evidence e : hint.getRemoveProduct()) {
|
||||
if (dependency.getProductEvidence().getEvidence().contains(e)) {
|
||||
dependency.getProductEvidence().getEvidence().remove(e);
|
||||
}
|
||||
}
|
||||
for (Evidence e : hint.getRemoveVersion()) {
|
||||
if (dependency.getVersionEvidence().getEvidence().contains(e)) {
|
||||
dependency.getVersionEvidence().getEvidence().remove(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
||||
final List<Evidence> newEntries = new ArrayList<Evidence>();
|
||||
final List<Evidence> newEntries = new ArrayList<>();
|
||||
while (itr.hasNext()) {
|
||||
final Evidence e = itr.next();
|
||||
for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
|
||||
@@ -183,108 +208,6 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
for (Evidence e : newEntries) {
|
||||
dependency.getVendorEvidence().addEvidence(e);
|
||||
}
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Old implementation">
|
||||
/*
|
||||
final Evidence springTest1 = new Evidence("Manifest",
|
||||
"Implementation-Title",
|
||||
"Spring Framework",
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence springTest2 = new Evidence("Manifest",
|
||||
"Implementation-Title",
|
||||
"org.springframework.core",
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence springTest3 = new Evidence("Manifest",
|
||||
"Implementation-Title",
|
||||
"spring-core",
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence springTest4 = new Evidence("jar",
|
||||
"package name",
|
||||
"springframework",
|
||||
Confidence.LOW);
|
||||
|
||||
final Evidence springSecurityTest1 = new Evidence("Manifest",
|
||||
"Bundle-Name",
|
||||
"Spring Security Core",
|
||||
Confidence.MEDIUM);
|
||||
|
||||
final Evidence springSecurityTest2 = new Evidence("pom",
|
||||
"artifactid",
|
||||
"spring-security-core",
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence symfony = new Evidence("composer.lock",
|
||||
"vendor",
|
||||
"symfony",
|
||||
Confidence.HIGHEST);
|
||||
|
||||
final Evidence zendframeworkVendor = new Evidence("composer.lock",
|
||||
"vendor",
|
||||
"zendframework",
|
||||
Confidence.HIGHEST);
|
||||
|
||||
final Evidence zendframeworkProduct = new Evidence("composer.lock",
|
||||
"product",
|
||||
"zendframework",
|
||||
Confidence.HIGHEST);
|
||||
|
||||
//springsource/vware problem
|
||||
final Set<Evidence> product = dependency.getProductEvidence().getEvidence();
|
||||
final Set<Evidence> vendor = dependency.getVendorEvidence().getEvidence();
|
||||
|
||||
if (product.contains(springTest1) || product.contains(springTest2) || product.contains(springTest3)
|
||||
|| (dependency.getFileName().contains("spring") && product.contains(springTest4))) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource spring framework", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
|
||||
}
|
||||
|
||||
if (vendor.contains(springTest4)) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
|
||||
}
|
||||
|
||||
if (product.contains(springSecurityTest1) || product.contains(springSecurityTest2)) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_security", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||
}
|
||||
|
||||
if (vendor.contains(symfony)) {
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "sensiolabs", Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
if (vendor.contains(zendframeworkVendor)) {
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "zend", Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
if (product.contains(zendframeworkProduct)) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "vendor", "zend_framework", Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
//sun/oracle problem
|
||||
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
||||
final List<Evidence> newEntries = new ArrayList<Evidence>();
|
||||
while (itr.hasNext()) {
|
||||
final Evidence e = itr.next();
|
||||
if ("sun".equalsIgnoreCase(e.getValue(false))) {
|
||||
final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "oracle", e.getConfidence());
|
||||
newEntries.add(newEvidence);
|
||||
} else if ("oracle".equalsIgnoreCase(e.getValue(false))) {
|
||||
final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "sun", e.getConfidence());
|
||||
newEntries.add(newEvidence);
|
||||
}
|
||||
}
|
||||
for (Evidence e : newEntries) {
|
||||
dependency.getVendorEvidence().addEvidence(e);
|
||||
}
|
||||
*/
|
||||
//</editor-fold>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,10 +220,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
File file = null;
|
||||
try {
|
||||
hints = parser.parseHints(this.getClass().getClassLoader().getResourceAsStream(HINT_RULE_FILE_NAME));
|
||||
} catch (HintParseException ex) {
|
||||
LOGGER.error("Unable to parse the base hint data file");
|
||||
LOGGER.debug("Unable to parse the base hint data file", ex);
|
||||
} catch (SAXException ex) {
|
||||
} catch (HintParseException | SAXException ex) {
|
||||
LOGGER.error("Unable to parse the base hint data file");
|
||||
LOGGER.debug("Unable to parse the base hint data file", ex);
|
||||
}
|
||||
@@ -323,9 +243,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
} else {
|
||||
file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
InputStream fromClasspath = null;
|
||||
try {
|
||||
fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath);
|
||||
try (InputStream fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath)) {
|
||||
if (fromClasspath != null) {
|
||||
deleteTempFile = true;
|
||||
file = FileUtils.getTempFile("hint", "xml");
|
||||
@@ -335,10 +253,6 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
||||
throw new HintParseException("Unable to locate hints file in classpath", ex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (fromClasspath != null) {
|
||||
fromClasspath.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -43,6 +44,7 @@ import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
@@ -148,15 +150,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* A pattern to detect HTML within text.
|
||||
*/
|
||||
private static final Pattern HTML_DETECTION_PATTERN = Pattern.compile("\\<[a-z]+.*/?\\>", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
//</editor-fold>
|
||||
/**
|
||||
* Constructs a new JarAnalyzer.
|
||||
*/
|
||||
public JarAnalyzer() {
|
||||
}
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
@@ -175,6 +168,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||
|
||||
//</editor-fold>
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
/**
|
||||
* Returns the FileFilter.
|
||||
*
|
||||
@@ -260,28 +255,12 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @return whether or not evidence was added to the dependency
|
||||
*/
|
||||
protected boolean analyzePOM(Dependency dependency, List<ClassNameInformation> classes, Engine engine) throws AnalysisException {
|
||||
JarFile jar = null;
|
||||
List<String> pomEntries = null;
|
||||
try {
|
||||
jar = new JarFile(dependency.getActualFilePath());
|
||||
pomEntries = retrievePomListing(jar);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("Unable to read JarFile '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
if (jar != null) {
|
||||
try {
|
||||
jar.close();
|
||||
} catch (IOException ex1) {
|
||||
LOGGER.trace("", ex1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (pomEntries != null && pomEntries.size() <= 1) {
|
||||
try {
|
||||
String path = null;
|
||||
try (JarFile jar = new JarFile(dependency.getActualFilePath())) {
|
||||
final List<String> pomEntries = retrievePomListing(jar);
|
||||
if (pomEntries != null && pomEntries.size() <= 1) {
|
||||
String path;
|
||||
File pomFile;
|
||||
Properties pomProperties = null;
|
||||
File pomFile = null;
|
||||
if (pomEntries.size() == 1) {
|
||||
path = pomEntries.get(0);
|
||||
pomFile = extractPom(path, jar);
|
||||
@@ -295,55 +274,44 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (pom != null && pomProperties != null) {
|
||||
pom.processProperties(pomProperties);
|
||||
}
|
||||
if (pom != null) {
|
||||
return setPomEvidence(dependency, pom, classes);
|
||||
}
|
||||
return false;
|
||||
return pom != null && setPomEvidence(dependency, pom, classes);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
|
||||
//reported possible null dereference on pomEntries is on a non-feasible path
|
||||
for (String path : pomEntries) {
|
||||
//TODO - one of these is likely the pom for the main JAR we are analyzing
|
||||
LOGGER.debug("Reading pom entry: {}", path);
|
||||
try {
|
||||
jar.close();
|
||||
} catch (IOException ex) {
|
||||
//extract POM to its own directory and add it as its own dependency
|
||||
final Properties pomProperties = retrievePomProperties(path, jar);
|
||||
final File pomFile = extractPom(path, jar);
|
||||
final Model pom = PomUtils.readPom(pomFile);
|
||||
pom.processProperties(pomProperties);
|
||||
|
||||
final String displayPath = String.format("%s%s%s",
|
||||
dependency.getFilePath(),
|
||||
File.separator,
|
||||
path);
|
||||
final String displayName = String.format("%s%s%s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
path);
|
||||
final Dependency newDependency = new Dependency();
|
||||
newDependency.setActualFilePath(pomFile.getAbsolutePath());
|
||||
newDependency.setFileName(displayName);
|
||||
newDependency.setFilePath(displayPath);
|
||||
setPomEvidence(newDependency, pom, null);
|
||||
engine.getDependencies().add(newDependency);
|
||||
} catch (AnalysisException ex) {
|
||||
LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//reported possible null dereference on pomEntries is on a non-feasible path
|
||||
for (String path : pomEntries) {
|
||||
//TODO - one of these is likely the pom for the main JAR we are analyzing
|
||||
LOGGER.debug("Reading pom entry: {}", path);
|
||||
try {
|
||||
//extract POM to its own directory and add it as its own dependency
|
||||
final Properties pomProperties = retrievePomProperties(path, jar);
|
||||
final File pomFile = extractPom(path, jar);
|
||||
final Model pom = PomUtils.readPom(pomFile);
|
||||
pom.processProperties(pomProperties);
|
||||
|
||||
final String displayPath = String.format("%s%s%s",
|
||||
dependency.getFilePath(),
|
||||
File.separator,
|
||||
path);
|
||||
final String displayName = String.format("%s%s%s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
path);
|
||||
final Dependency newDependency = new Dependency();
|
||||
newDependency.setActualFilePath(pomFile.getAbsolutePath());
|
||||
newDependency.setFileName(displayName);
|
||||
newDependency.setFilePath(displayPath);
|
||||
setPomEvidence(newDependency, pom, null);
|
||||
engine.getDependencies().add(newDependency);
|
||||
} catch (AnalysisException ex) {
|
||||
LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
try {
|
||||
jar.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("Unable to read JarFile '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
return false;
|
||||
@@ -356,17 +324,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param path the path to the pom.xml within the JarFile
|
||||
* @param jar the JarFile to load the pom.properties from
|
||||
* @return a Properties object or null if no pom.properties was found
|
||||
* @throws IOException thrown if there is an exception reading the
|
||||
* pom.properties
|
||||
*/
|
||||
private Properties retrievePomProperties(String path, final JarFile jar) {
|
||||
Properties pomProperties = null;
|
||||
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
||||
final ZipEntry propEntry = jar.getEntry(propPath);
|
||||
if (propEntry != null) {
|
||||
Reader reader = null;
|
||||
try {
|
||||
reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||
try (Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8")) {
|
||||
pomProperties = new Properties();
|
||||
pomProperties.load(reader);
|
||||
LOGGER.debug("Read pom.properties: {}", propPath);
|
||||
@@ -374,14 +338,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.trace("UTF-8 is not supported", ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("Unable to read the POM properties", ex);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("close error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pomProperties;
|
||||
@@ -396,7 +352,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @throws IOException thrown if there is an exception reading a JarEntry
|
||||
*/
|
||||
private List<String> retrievePomListing(final JarFile jar) throws IOException {
|
||||
final List<String> pomEntries = new ArrayList<String>();
|
||||
final List<String> pomEntries = new ArrayList<>();
|
||||
final Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final JarEntry entry = entries.nextElement();
|
||||
@@ -419,24 +375,18 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* the file
|
||||
*/
|
||||
private File extractPom(String path, JarFile jar) throws AnalysisException {
|
||||
InputStream input = null;
|
||||
FileOutputStream fos = null;
|
||||
final File tmpDir = getNextTempDirectory();
|
||||
final File file = new File(tmpDir, "pom.xml");
|
||||
try {
|
||||
final ZipEntry entry = jar.getEntry(path);
|
||||
if (entry == null) {
|
||||
throw new AnalysisException(String.format("Pom (%s)does not exist in %s", path, jar.getName()));
|
||||
}
|
||||
input = jar.getInputStream(entry);
|
||||
fos = new FileOutputStream(file);
|
||||
final ZipEntry entry = jar.getEntry(path);
|
||||
if (entry == null) {
|
||||
throw new AnalysisException(String.format("Pom (%s) does not exist in %s", path, jar.getName()));
|
||||
}
|
||||
try (InputStream input = jar.getInputStream(entry);
|
||||
FileOutputStream fos = new FileOutputStream(file)) {
|
||||
IOUtils.copy(input, fos);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("An error occurred reading '{}' from '{}'.", path, jar.getName());
|
||||
LOGGER.error("", ex);
|
||||
} finally {
|
||||
FileUtils.close(fos);
|
||||
FileUtils.close(input);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@@ -452,11 +402,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* otherwise false
|
||||
*/
|
||||
public static boolean setPomEvidence(Dependency dependency, Model pom, List<ClassNameInformation> classes) {
|
||||
if (pom == null) {
|
||||
return false;
|
||||
}
|
||||
boolean foundSomething = false;
|
||||
boolean addAsIdentifier = true;
|
||||
if (pom == null) {
|
||||
return foundSomething;
|
||||
}
|
||||
String groupid = pom.getGroupId();
|
||||
String parentGroupId = pom.getParentGroupId();
|
||||
String artifactid = pom.getArtifactId();
|
||||
@@ -546,6 +496,12 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
addMatchingValues(classes, org, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, org, dependency.getProductEvidence());
|
||||
}
|
||||
// org name
|
||||
final String orgUrl = pom.getOrganizationUrl();
|
||||
if (orgUrl != null && !orgUrl.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "organization url", orgUrl, Confidence.MEDIUM);
|
||||
dependency.getProductEvidence().addEvidence("pom", "organization url", orgUrl, Confidence.LOW);
|
||||
}
|
||||
//pom name
|
||||
final String pomName = pom.getName();
|
||||
if (pomName
|
||||
@@ -588,8 +544,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
protected void analyzePackageNames(List<ClassNameInformation> classNames,
|
||||
Dependency dependency, boolean addPackagesAsEvidence) {
|
||||
final Map<String, Integer> vendorIdentifiers = new HashMap<String, Integer>();
|
||||
final Map<String, Integer> productIdentifiers = new HashMap<String, Integer>();
|
||||
final Map<String, Integer> vendorIdentifiers = new HashMap<>();
|
||||
final Map<String, Integer> productIdentifiers = new HashMap<>();
|
||||
analyzeFullyQualifiedClassNames(classNames, vendorIdentifiers, productIdentifiers);
|
||||
|
||||
final int classCount = classNames.size();
|
||||
@@ -636,9 +592,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> classInformation)
|
||||
throws IOException {
|
||||
boolean foundSomething = false;
|
||||
JarFile jar = null;
|
||||
try {
|
||||
jar = new JarFile(dependency.getActualFilePath());
|
||||
try (JarFile jar = new JarFile(dependency.getActualFilePath())) {
|
||||
final Manifest manifest = jar.getManifest();
|
||||
if (manifest == null) {
|
||||
if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
|
||||
@@ -793,10 +747,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
foundSomething = true;
|
||||
versionEvidence.addEvidence(source, "specification-version", specificationVersion, Confidence.HIGH);
|
||||
}
|
||||
} finally {
|
||||
if (jar != null) {
|
||||
jar.close();
|
||||
}
|
||||
}
|
||||
return foundSomething;
|
||||
}
|
||||
@@ -949,10 +899,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @return an list of fully qualified class names
|
||||
*/
|
||||
private List<ClassNameInformation> collectClassNames(Dependency dependency) {
|
||||
final List<ClassNameInformation> classNames = new ArrayList<ClassNameInformation>();
|
||||
JarFile jar = null;
|
||||
try {
|
||||
jar = new JarFile(dependency.getActualFilePath());
|
||||
final List<ClassNameInformation> classNames = new ArrayList<>();
|
||||
try (JarFile jar = new JarFile(dependency.getActualFilePath())) {
|
||||
final Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final JarEntry entry = entries.nextElement();
|
||||
@@ -966,14 +914,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("Unable to open jar file '{}'.", dependency.getFileName());
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
if (jar != null) {
|
||||
try {
|
||||
jar.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return classNames;
|
||||
}
|
||||
@@ -1116,6 +1056,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
protected static class ClassNameInformation {
|
||||
|
||||
/**
|
||||
* The fully qualified class name.
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* Up to the first four levels of the package structure, excluding a
|
||||
* leading "org" or "com".
|
||||
*/
|
||||
private final ArrayList<String> packageStructure = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Stores information about a given class name. This class will keep the
|
||||
@@ -1123,7 +1073,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* package structure. Up to the first four levels of the package
|
||||
* structure are stored, excluding a leading "org" or "com".
|
||||
* Example:</p>
|
||||
* <code>ClassNameInformation obj = new ClassNameInformation("org.owasp.dependencycheck.analyzer.JarAnalyzer");
|
||||
* <code>ClassNameInformation obj = new ClassNameInformation("org/owasp/dependencycheck/analyzer/JarAnalyzer");
|
||||
* System.out.println(obj.getName());
|
||||
* for (String p : obj.getPackageStructure())
|
||||
* System.out.println(p);
|
||||
@@ -1141,7 +1091,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
ClassNameInformation(String className) {
|
||||
name = className;
|
||||
if (name.contains("/")) {
|
||||
final String[] tmp = className.toLowerCase().split("/");
|
||||
final String[] tmp = StringUtils.split(className.toLowerCase(), '/');
|
||||
int start = 0;
|
||||
int end = 3;
|
||||
if ("com".equals(tmp[0]) || "org".equals(tmp[0])) {
|
||||
@@ -1151,17 +1101,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tmp.length <= end) {
|
||||
end = tmp.length - 1;
|
||||
}
|
||||
for (int i = start; i <= end; i++) {
|
||||
packageStructure.add(tmp[i]);
|
||||
}
|
||||
packageStructure.addAll(Arrays.asList(tmp).subList(start, end + 1));
|
||||
} else {
|
||||
packageStructure.add(name);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The fully qualified class name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Get the value of name
|
||||
@@ -1180,11 +1124,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* Up to the first four levels of the package structure, excluding a
|
||||
* leading "org" or "com".
|
||||
*/
|
||||
private final ArrayList<String> packageStructure = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Get the value of packageStructure
|
||||
|
||||
@@ -87,10 +87,6 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final String SUPPORTED_EXTENSIONS = "jar";
|
||||
|
||||
/**
|
||||
* Whether or not the Nexus analyzer should use a proxy if configured.
|
||||
*/
|
||||
private boolean useProxy;
|
||||
/**
|
||||
* The Nexus Search to be set up for this analyzer.
|
||||
*/
|
||||
@@ -148,7 +144,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.debug("Initializing Nexus Analyzer");
|
||||
LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
|
||||
if (isEnabled()) {
|
||||
useProxy = useProxy();
|
||||
final boolean useProxy = useProxy();
|
||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||
LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
|
||||
try {
|
||||
|
||||
@@ -121,17 +121,9 @@ public class NodePackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void analyzeDependency(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
final File file = dependency.getActualFile();
|
||||
JsonReader jsonReader;
|
||||
try {
|
||||
jsonReader = Json.createReader(FileUtils.openInputStream(file));
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException(
|
||||
"Problem occurred while reading dependency file.", e);
|
||||
}
|
||||
try {
|
||||
try (JsonReader jsonReader = Json.createReader(FileUtils.openInputStream(file))) {
|
||||
final JsonObject json = jsonReader.readObject();
|
||||
final EvidenceCollection productEvidence = dependency.getProductEvidence();
|
||||
final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
|
||||
@@ -151,8 +143,8 @@ public class NodePackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
dependency.setDisplayFileName(String.format("%s/%s", file.getParentFile().getName(), file.getName()));
|
||||
} catch (JsonException e) {
|
||||
LOGGER.warn("Failed to parse package.json file.", e);
|
||||
} finally {
|
||||
jsonReader.close();
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException("Problem occurred while reading dependency file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import org.owasp.dependencycheck.exception.InitializationException;
|
||||
|
||||
/**
|
||||
@@ -132,22 +131,10 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
final NuspecParser parser = new XPathNuspecParser();
|
||||
NugetPackage np = null;
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(dependency.getActualFilePath());
|
||||
try (FileInputStream fis = new FileInputStream(dependency.getActualFilePath())) {
|
||||
np = parser.parse(fis);
|
||||
} catch (NuspecParseException ex) {
|
||||
} catch (NuspecParseException | FileNotFoundException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.debug("Error closing input stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (np.getOwners() != null) {
|
||||
|
||||
@@ -44,10 +44,7 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
|
||||
* The Logger for use throughout the class
|
||||
*/
|
||||
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class);
|
||||
/**
|
||||
* The maximum number of query results to return.
|
||||
*/
|
||||
static final int MAX_QUERY_RESULTS = 100;
|
||||
|
||||
/**
|
||||
* The CVE Index.
|
||||
*/
|
||||
@@ -63,8 +60,7 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
|
||||
* loaded
|
||||
*/
|
||||
public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
|
||||
cveDB = new CveDB();
|
||||
cveDB.open();
|
||||
cveDB = CveDB.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,19 +81,6 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
|
||||
return cveDB != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the CVE Database is closed.
|
||||
*
|
||||
* @throws Throwable an exception raised by this method
|
||||
*/
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (isOpen()) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes a dependency and attempts to determine if there are any CPE
|
||||
* identifiers for this dependency.
|
||||
|
||||
@@ -102,7 +102,7 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param openSSLVersionConstant The open SSL version
|
||||
* @return the version of openssl
|
||||
*/
|
||||
static String getOpenSSLVersion(long openSSLVersionConstant) {
|
||||
protected static String getOpenSSLVersion(long openSSLVersionConstant) {
|
||||
final long major = openSSLVersionConstant >>> MAJOR_OFFSET;
|
||||
final long minor = (openSSLVersionConstant & MINOR_MASK) >>> MINOR_OFFSET;
|
||||
final long fix = (openSSLVersionConstant & FIX_MASK) >>> FIX_OFFSET;
|
||||
|
||||
@@ -360,22 +360,12 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (null == manifest) {
|
||||
LOGGER.debug("Manifest file not found.");
|
||||
} else {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new BufferedInputStream(new FileInputStream(manifest));
|
||||
try (InputStream in = new BufferedInputStream(new FileInputStream(manifest))) {
|
||||
result.load(in);
|
||||
} catch (MessagingException e) {
|
||||
} catch (MessagingException | FileNotFoundException e) {
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
} catch (FileNotFoundException e) {
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("failed to close input stream", ex);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -113,7 +113,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (!folder.isDirectory()) {
|
||||
throw new AnalysisException(String.format("%s should have been a directory.", folder.getAbsolutePath()));
|
||||
}
|
||||
final List<String> args = new ArrayList<String>();
|
||||
final List<String> args = new ArrayList<>();
|
||||
final String bundleAuditPath = Settings.getString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH);
|
||||
File bundleAudit = null;
|
||||
if (bundleAuditPath != null) {
|
||||
@@ -132,7 +132,8 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.info("Launching: " + args + " from " + folder);
|
||||
return builder.start();
|
||||
} catch (IOException ioe) {
|
||||
throw new AnalysisException("bundle-audit failure", ioe);
|
||||
throw new AnalysisException("bundle-audit initialization failure; this error can be ignored if you are not analyzing Ruby. "
|
||||
+ "Otherwise ensure that bundle-audit is installed and the path to bundle audit is correctly specified", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +146,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||
try {
|
||||
cvedb = new CveDB();
|
||||
cvedb.open();
|
||||
cvedb = CveDB.getInstance();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.warn("Exception opening the database");
|
||||
LOGGER.debug("error", ex);
|
||||
@@ -160,8 +160,6 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (AnalysisException ae) {
|
||||
|
||||
setEnabled(false);
|
||||
cvedb.close();
|
||||
cvedb = null;
|
||||
final String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
|
||||
throw new InitializationException(msg, ae);
|
||||
} catch (IOException ex) {
|
||||
@@ -174,7 +172,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
exitValue = process.waitFor();
|
||||
} catch (InterruptedException ex) {
|
||||
setEnabled(false);
|
||||
final String msg = String.format("Bundle-audit process was interupted. Disabling %s", ANALYZER_NAME);
|
||||
final String msg = String.format("Bundle-audit process was interrupted. Disabling %s", ANALYZER_NAME);
|
||||
throw new InitializationException(msg);
|
||||
}
|
||||
if (0 == exitValue) {
|
||||
@@ -182,9 +180,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String msg = String.format("Unexpected exit code from bundle-audit process. Disabling %s: %s", ANALYZER_NAME, exitValue);
|
||||
throw new InitializationException(msg);
|
||||
} else {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"))) {
|
||||
if (!reader.ready()) {
|
||||
LOGGER.warn("Bundle-audit error stream unexpectedly not ready. Disabling " + ANALYZER_NAME);
|
||||
setEnabled(false);
|
||||
@@ -203,14 +199,6 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (IOException ex) {
|
||||
setEnabled(false);
|
||||
throw new InitializationException("Unable to read bundle-audit output.", ex);
|
||||
} finally {
|
||||
if (null != reader) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Error closing reader", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +208,17 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the data source.
|
||||
*/
|
||||
@Override
|
||||
public void closeAnalyzer() {
|
||||
if (cvedb != null) {
|
||||
cvedb.close();
|
||||
cvedb = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
@@ -298,35 +297,19 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String msg = String.format("Unexpected exit code from bundle-audit process; exit code: %s", exitValue);
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
BufferedReader rdr = null;
|
||||
BufferedReader errReader = null;
|
||||
try {
|
||||
errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
||||
while (errReader.ready()) {
|
||||
final String error = errReader.readLine();
|
||||
LOGGER.warn(error);
|
||||
try (BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"))) {
|
||||
while (errReader.ready()) {
|
||||
final String error = errReader.readLine();
|
||||
LOGGER.warn(error);
|
||||
}
|
||||
}
|
||||
try (BufferedReader rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"))) {
|
||||
processBundlerAuditOutput(dependency, engine, rdr);
|
||||
}
|
||||
rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
||||
processBundlerAuditOutput(dependency, engine, rdr);
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit failure", ioe);
|
||||
} finally {
|
||||
if (errReader != null) {
|
||||
try {
|
||||
errReader.close();
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit close failure", ioe);
|
||||
}
|
||||
}
|
||||
if (null != rdr) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit close failure", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,7 +327,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
Dependency dependency = null;
|
||||
Vulnerability vulnerability = null;
|
||||
String gem = null;
|
||||
final Map<String, Dependency> map = new HashMap<String, Dependency>();
|
||||
final Map<String, Dependency> map = new HashMap<>();
|
||||
boolean appendToDescription = false;
|
||||
while (rdr.ready()) {
|
||||
final String nextLine = rdr.readLine();
|
||||
@@ -373,10 +356,8 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
+ "Title link may not work. CPE below is guessed. CVSS score is estimated (-1.0 "
|
||||
+ " indicates unknown). See link below for full details. *** ");
|
||||
}
|
||||
} else if (appendToDescription) {
|
||||
if (null != vulnerability) {
|
||||
vulnerability.setDescription(vulnerability.getDescription() + nextLine + "\n");
|
||||
}
|
||||
} else if (appendToDescription && null != vulnerability) {
|
||||
vulnerability.setDescription(vulnerability.getDescription() + nextLine + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Constaints">
|
||||
//<editor-fold defaultstate="collapsed" desc="Constants">
|
||||
/**
|
||||
* Evidence source.
|
||||
*/
|
||||
@@ -126,7 +126,7 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
||||
* the dependency.
|
||||
*/
|
||||
@Override
|
||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
String fileVersion = null;
|
||||
String pomVersion = null;
|
||||
String manifestVersion = null;
|
||||
@@ -151,16 +151,14 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
||||
if (fileMatch || manifestMatch || pomMatch) {
|
||||
LOGGER.debug("filtering evidence from {}", dependency.getFileName());
|
||||
final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
|
||||
synchronized (versionEvidence) {
|
||||
final Iterator<Evidence> itr = versionEvidence.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Evidence e = itr.next();
|
||||
if (!(pomMatch && VERSION.equals(e.getName())
|
||||
&& (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource())))
|
||||
&& !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource()))
|
||||
&& !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) {
|
||||
itr.remove();
|
||||
}
|
||||
final Iterator<Evidence> itr = versionEvidence.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Evidence e = itr.next();
|
||||
if (!(pomMatch && VERSION.equals(e.getName())
|
||||
&& (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource())))
|
||||
&& !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource()))
|
||||
&& !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -35,6 +37,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Class of methods to search Maven Central via Central.
|
||||
@@ -117,7 +120,7 @@ public class CentralSearch {
|
||||
if ("0".equals(numFound)) {
|
||||
missing = true;
|
||||
} else {
|
||||
result = new ArrayList<MavenArtifact>();
|
||||
result = new ArrayList<>();
|
||||
final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
|
||||
for (int i = 0; i < docs.getLength(); i++) {
|
||||
final String g = xpath.evaluate("./str[@name='g']", docs.item(i));
|
||||
@@ -125,11 +128,11 @@ public class CentralSearch {
|
||||
final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
|
||||
LOGGER.trace("ArtifactId: {}", a);
|
||||
final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
|
||||
NodeList atts = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET);
|
||||
NodeList attributes = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET);
|
||||
boolean pomAvailable = false;
|
||||
boolean jarAvailable = false;
|
||||
for (int x = 0; x < atts.getLength(); x++) {
|
||||
final String tmp = xpath.evaluate(".", atts.item(x));
|
||||
for (int x = 0; x < attributes.getLength(); x++) {
|
||||
final String tmp = xpath.evaluate(".", attributes.item(x));
|
||||
if (".pom".equals(tmp)) {
|
||||
pomAvailable = true;
|
||||
} else if (".jar".equals(tmp)) {
|
||||
@@ -137,10 +140,10 @@ public class CentralSearch {
|
||||
}
|
||||
}
|
||||
|
||||
atts = (NodeList) xpath.evaluate("./arr[@name='tags']/str", docs.item(i), XPathConstants.NODESET);
|
||||
attributes = (NodeList) xpath.evaluate("./arr[@name='tags']/str", docs.item(i), XPathConstants.NODESET);
|
||||
boolean useHTTPS = false;
|
||||
for (int x = 0; x < atts.getLength(); x++) {
|
||||
final String tmp = xpath.evaluate(".", atts.item(x));
|
||||
for (int x = 0; x < attributes.getLength(); x++) {
|
||||
final String tmp = xpath.evaluate(".", attributes.item(x));
|
||||
if ("https".equals(tmp)) {
|
||||
useHTTPS = true;
|
||||
}
|
||||
@@ -149,7 +152,7 @@ public class CentralSearch {
|
||||
result.add(new MavenArtifact(g, a, v, jarAvailable, pomAvailable, useHTTPS));
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
} catch (ParserConfigurationException | IOException | SAXException | XPathExpressionException e) {
|
||||
// Anything else is jacked up XML stuff that we really can't recover from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package org.owasp.dependencycheck.data.composer;
|
||||
|
||||
/**
|
||||
* Reperesents a dependency (GAV, right now) from a Composer dependency.
|
||||
* Represents a dependency (GAV, right now) from a Composer dependency.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
|
||||
@@ -42,11 +42,6 @@ public class ComposerLockParser {
|
||||
*/
|
||||
private final JsonReader jsonReader;
|
||||
|
||||
/**
|
||||
* The input stream we'll read
|
||||
*/
|
||||
private final InputStream inputStream; // NOPMD - it gets set in the constructor, read later
|
||||
|
||||
/**
|
||||
* The List of ComposerDependencies found
|
||||
*/
|
||||
@@ -58,15 +53,14 @@ public class ComposerLockParser {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ComposerLockParser.class);
|
||||
|
||||
/**
|
||||
* Createas a ComposerLockParser from a JsonReader and an InputStream.
|
||||
* Creates a ComposerLockParser from a JsonReader and an InputStream.
|
||||
*
|
||||
* @param inputStream the InputStream to parse
|
||||
*/
|
||||
public ComposerLockParser(InputStream inputStream) {
|
||||
LOGGER.info("Creating a ComposerLockParser");
|
||||
this.inputStream = inputStream;
|
||||
this.jsonReader = Json.createReader(inputStream);
|
||||
this.composerDependencies = new ArrayList<ComposerDependency>();
|
||||
this.composerDependencies = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,7 +81,7 @@ public class ComposerLockParser {
|
||||
final String group = groupName.substring(0, groupName.indexOf('/'));
|
||||
final String project = groupName.substring(groupName.indexOf('/') + 1);
|
||||
String version = pkg.getString("version");
|
||||
// Some version nubmers begin with v - which doesn't end up matching CPE's
|
||||
// Some version numbers begin with v - which doesn't end up matching CPE's
|
||||
if (version.startsWith("v")) {
|
||||
version = version.substring(1);
|
||||
}
|
||||
|
||||
@@ -62,21 +62,6 @@ public final class CpeMemoryIndex {
|
||||
* singleton instance.
|
||||
*/
|
||||
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
|
||||
|
||||
/**
|
||||
* private constructor for singleton.
|
||||
*/
|
||||
private CpeMemoryIndex() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton instance of the CpeMemoryIndex.
|
||||
*
|
||||
* @return the instance of the CpeMemoryIndex
|
||||
*/
|
||||
public static CpeMemoryIndex getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
/**
|
||||
* The in memory Lucene index.
|
||||
*/
|
||||
@@ -105,6 +90,25 @@ public final class CpeMemoryIndex {
|
||||
* The search field analyzer for the vendor field.
|
||||
*/
|
||||
private SearchFieldAnalyzer vendorFieldAnalyzer;
|
||||
/**
|
||||
* A flag indicating whether or not the index is open.
|
||||
*/
|
||||
private boolean openState = false;
|
||||
|
||||
/**
|
||||
* private constructor for singleton.
|
||||
*/
|
||||
private CpeMemoryIndex() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton instance of the CpeMemoryIndex.
|
||||
*
|
||||
* @return the instance of the CpeMemoryIndex
|
||||
*/
|
||||
public static CpeMemoryIndex getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and loads data into an in memory index.
|
||||
@@ -129,10 +133,6 @@ public final class CpeMemoryIndex {
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A flag indicating whether or not the index is open.
|
||||
*/
|
||||
private boolean openState = false;
|
||||
|
||||
/**
|
||||
* returns whether or not the index is open.
|
||||
@@ -149,7 +149,7 @@ public final class CpeMemoryIndex {
|
||||
* @return the CPE Analyzer.
|
||||
*/
|
||||
private Analyzer createSearchingAnalyzer() {
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
productFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
vendorFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
@@ -191,57 +191,35 @@ public final class CpeMemoryIndex {
|
||||
* @throws IndexException thrown if there is an issue creating the index
|
||||
*/
|
||||
private void buildIndex(CveDB cve) throws IndexException {
|
||||
Analyzer analyzer = null;
|
||||
IndexWriter indexWriter = null;
|
||||
try {
|
||||
analyzer = createSearchingAnalyzer();
|
||||
final IndexWriterConfig conf = new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer);
|
||||
indexWriter = new IndexWriter(index, conf);
|
||||
try {
|
||||
// Tip: reuse the Document and Fields for performance...
|
||||
// See "Re-use Document and Field instances" from
|
||||
// http://wiki.apache.org/lucene-java/ImproveIndexingSpeed
|
||||
final Document doc = new Document();
|
||||
final Field v = new TextField(Fields.VENDOR, Fields.VENDOR, Field.Store.YES);
|
||||
final Field p = new TextField(Fields.PRODUCT, Fields.PRODUCT, Field.Store.YES);
|
||||
doc.add(v);
|
||||
doc.add(p);
|
||||
try (Analyzer analyzer = createSearchingAnalyzer();
|
||||
IndexWriter indexWriter = new IndexWriter(index, new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer))) {
|
||||
// Tip: reuse the Document and Fields for performance...
|
||||
// See "Re-use Document and Field instances" from
|
||||
// http://wiki.apache.org/lucene-java/ImproveIndexingSpeed
|
||||
final Document doc = new Document();
|
||||
final Field v = new TextField(Fields.VENDOR, Fields.VENDOR, Field.Store.YES);
|
||||
final Field p = new TextField(Fields.PRODUCT, Fields.PRODUCT, Field.Store.YES);
|
||||
doc.add(v);
|
||||
doc.add(p);
|
||||
|
||||
final Set<Pair<String, String>> data = cve.getVendorProductList();
|
||||
for (Pair<String, String> pair : data) {
|
||||
//todo figure out why there are null products
|
||||
if (pair.getLeft() != null && pair.getRight() != null) {
|
||||
v.setStringValue(pair.getLeft());
|
||||
p.setStringValue(pair.getRight());
|
||||
indexWriter.addDocument(doc);
|
||||
resetFieldAnalyzer();
|
||||
}
|
||||
final Set<Pair<String, String>> data = cve.getVendorProductList();
|
||||
for (Pair<String, String> pair : data) {
|
||||
if (pair.getLeft() != null && pair.getRight() != null) {
|
||||
v.setStringValue(pair.getLeft());
|
||||
p.setStringValue(pair.getRight());
|
||||
indexWriter.addDocument(doc);
|
||||
resetFieldAnalyzer();
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new IndexException("Error reading CPE data", ex);
|
||||
}
|
||||
indexWriter.commit();
|
||||
indexWriter.close(true);
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new IndexException("Error reading CPE data", ex);
|
||||
} catch (CorruptIndexException ex) {
|
||||
throw new IndexException("Unable to close an in-memory index", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new IndexException("Unable to close an in-memory index", ex);
|
||||
} finally {
|
||||
if (indexWriter != null) {
|
||||
try {
|
||||
try {
|
||||
indexWriter.commit();
|
||||
} finally {
|
||||
indexWriter.close(true);
|
||||
}
|
||||
} catch (CorruptIndexException ex) {
|
||||
throw new IndexException("Unable to close an in-memory index", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new IndexException("Unable to close an in-memory index", ex);
|
||||
}
|
||||
if (analyzer != null) {
|
||||
analyzer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,11 +245,12 @@ public final class CpeMemoryIndex {
|
||||
* @throws IOException is thrown if there is an issue with the underlying
|
||||
* Index
|
||||
*/
|
||||
public TopDocs search(String searchString, int maxQueryResults) throws ParseException, IOException {
|
||||
public synchronized TopDocs search(String searchString, int maxQueryResults) throws ParseException, IOException {
|
||||
if (searchString == null || searchString.trim().isEmpty()) {
|
||||
throw new ParseException("Query is null or empty");
|
||||
}
|
||||
LOGGER.debug(searchString);
|
||||
resetFieldAnalyzer();
|
||||
final Query query = queryParser.parse(searchString);
|
||||
return search(query, maxQueryResults);
|
||||
}
|
||||
@@ -285,7 +264,7 @@ public final class CpeMemoryIndex {
|
||||
* @throws CorruptIndexException thrown if the Index is corrupt
|
||||
* @throws IOException thrown if there is an IOException
|
||||
*/
|
||||
public TopDocs search(Query query, int maxQueryResults) throws CorruptIndexException, IOException {
|
||||
public synchronized TopDocs search(Query query, int maxQueryResults) throws CorruptIndexException, IOException {
|
||||
resetFieldAnalyzer();
|
||||
return indexSearcher.search(query, maxQueryResults);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.cpe;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* A CPE entry containing the name, vendor, product, and version.
|
||||
@@ -31,7 +32,7 @@ public class IndexEntry implements Serializable {
|
||||
/**
|
||||
* the serial version uid.
|
||||
*/
|
||||
static final long serialVersionUID = 8011924485946326934L;
|
||||
private static final long serialVersionUID = 8011924485946326934L;
|
||||
/**
|
||||
* The vendor name.
|
||||
*/
|
||||
@@ -143,7 +144,8 @@ public class IndexEntry implements Serializable {
|
||||
*/
|
||||
public void parseName(String cpeName) throws UnsupportedEncodingException {
|
||||
if (cpeName != null && cpeName.length() > 7) {
|
||||
final String[] data = cpeName.substring(7).split(":");
|
||||
final String cpeNameWithoutPrefix = cpeName.substring(7);
|
||||
final String[] data = StringUtils.split(cpeNameWithoutPrefix, ':');
|
||||
if (data.length >= 1) {
|
||||
vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8");
|
||||
if (data.length >= 2) {
|
||||
@@ -172,10 +174,7 @@ public class IndexEntry implements Serializable {
|
||||
if ((this.vendor == null) ? (other.vendor != null) : !this.vendor.equals(other.vendor)) {
|
||||
return false;
|
||||
}
|
||||
if ((this.product == null) ? (other.product != null) : !this.product.equals(other.product)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !((this.product == null) ? (other.product != null) : !this.product.equals(other.product));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,12 +54,10 @@ public final class CweDB {
|
||||
* @return a HashMap of CWE data
|
||||
*/
|
||||
private static Map<String, String> loadData() {
|
||||
ObjectInputStream oin = null;
|
||||
try {
|
||||
final String filePath = "data/cwe.hashmap.serialized";
|
||||
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||
oin = new ObjectInputStream(input);
|
||||
@SuppressWarnings("unchecked")
|
||||
final String filePath = "data/cwe.hashmap.serialized";
|
||||
try (InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||
ObjectInputStream oin = new ObjectInputStream(input)) {
|
||||
|
||||
final Map<String, String> ret = (HashMap<String, String>) oin.readObject();
|
||||
return ret;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
@@ -68,14 +66,6 @@ public final class CweDB {
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("Unable to load CWE data due to an IO Error. This should not be an issue.");
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
if (oin != null) {
|
||||
try {
|
||||
oin.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class CweHandler extends DefaultHandler {
|
||||
/**
|
||||
* a HashMap containing the CWE data.
|
||||
*/
|
||||
private final HashMap<String, String> cwe = new HashMap<String, String>();
|
||||
private final HashMap<String, String> cwe = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Returns the HashMap of CWE entries (CWE-ID, Full CWE Name).
|
||||
|
||||
@@ -63,7 +63,7 @@ public abstract class AbstractTokenizingFilter extends TokenFilter {
|
||||
*/
|
||||
public AbstractTokenizingFilter(TokenStream stream) {
|
||||
super(stream);
|
||||
tokens = new LinkedList<String>();
|
||||
tokens = new LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||
*/
|
||||
public TokenPairConcatenatingFilter(TokenStream stream) {
|
||||
super(stream);
|
||||
words = new LinkedList<String>();
|
||||
words = new LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,10 +156,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||
if ((this.previousWord == null) ? (other.previousWord != null) : !this.previousWord.equals(other.previousWord)) {
|
||||
return false;
|
||||
}
|
||||
if (this.words != other.words && (this.words == null || !this.words.equals(other.words))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !(this.words != other.words && (this.words == null || !this.words.equals(other.words)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
@@ -30,6 +32,7 @@ import org.owasp.dependencycheck.utils.XmlUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Class of methods to search Nexus repositories.
|
||||
@@ -132,7 +135,7 @@ public class NexusSearch {
|
||||
ma.setPomUrl(pomLink);
|
||||
}
|
||||
return ma;
|
||||
} catch (Throwable e) {
|
||||
} catch (ParserConfigurationException | IOException | SAXException | XPathExpressionException e) {
|
||||
// Anything else is jacked-up XML stuff that we really can't recover
|
||||
// from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
@@ -170,7 +173,7 @@ public class NexusSearch {
|
||||
LOGGER.warn("Expected root node name of status, got {}", doc.getDocumentElement().getNodeName());
|
||||
return false;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
} catch (IOException | ParserConfigurationException | SAXException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,12 +53,6 @@ public class NugetPackage {
|
||||
*/
|
||||
private String licenseUrl;
|
||||
|
||||
/**
|
||||
* Creates an empty NugetPackage.
|
||||
*/
|
||||
public NugetPackage() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id.
|
||||
* @param id the id
|
||||
|
||||
@@ -17,14 +17,18 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nuget;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.owasp.dependencycheck.utils.XmlUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Parse a Nuspec file using XPath.
|
||||
@@ -78,7 +82,7 @@ public class XPathNuspecParser implements NuspecParser {
|
||||
nuspec.setLicenseUrl(getOrNull((Node) xpath.evaluate("/package/metadata/licenseUrl", d, XPathConstants.NODE)));
|
||||
nuspec.setTitle(getOrNull((Node) xpath.evaluate("/package/metadata/title", d, XPathConstants.NODE)));
|
||||
return nuspec;
|
||||
} catch (Throwable e) {
|
||||
} catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException | NuspecParseException e) {
|
||||
throw new NuspecParseException("Unable to parse nuspec", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,13 +241,31 @@ public final class ConnectionFactory {
|
||||
* @throws IOException thrown if the data directory does not exist and
|
||||
* cannot be created
|
||||
*/
|
||||
private static boolean h2DataFileExists() throws IOException {
|
||||
public static boolean h2DataFileExists() throws IOException {
|
||||
final File dir = Settings.getDataDirectory();
|
||||
final String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME);
|
||||
final File file = new File(dir, fileName);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the connection string is for an H2 database.
|
||||
*
|
||||
* @return true if the connection string is for an H2 database
|
||||
*/
|
||||
public static boolean isH2Connection() {
|
||||
String connStr;
|
||||
try {
|
||||
connStr = Settings.getConnectionString(
|
||||
Settings.KEYS.DB_CONNECTION_STRING,
|
||||
Settings.KEYS.DB_FILE_NAME);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Unable to get connectionn string", ex);
|
||||
return false;
|
||||
}
|
||||
return connStr.startsWith("jdbc:h2:file:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the database structure (tables and indexes) to store the CVE
|
||||
* data.
|
||||
@@ -342,7 +360,7 @@ public final class ConnectionFactory {
|
||||
LOGGER.warn("A new version of dependency-check is available; consider upgrading");
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
} else if (e0 == c0 && e1 == c1) {
|
||||
//do nothing - not sure how we got here, but just incase...
|
||||
//do nothing - not sure how we got here, but just in case...
|
||||
} else {
|
||||
LOGGER.error("The database schema must be upgraded to use this version of dependency-check. Please see {} for more information.",
|
||||
UPGRADE_HELP_URL);
|
||||
|
||||
@@ -23,8 +23,8 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -35,6 +35,7 @@ import java.util.MissingResourceException;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.owasp.dependencycheck.data.cwe.CweDB;
|
||||
import org.owasp.dependencycheck.dependency.Reference;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
@@ -47,13 +48,27 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.owasp.dependencycheck.data.nvdcve.CveDB.PreparedStatementCveDb.*;
|
||||
|
||||
/**
|
||||
* The database holding information about the NVD CVE data.
|
||||
* The database holding information about the NVD CVE data. This class is safe
|
||||
* to be accessed from multiple threads in parallel, however internally only one
|
||||
* connection will be used.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class CveDB {
|
||||
@ThreadSafe
|
||||
public final class CveDB implements AutoCloseable {
|
||||
|
||||
/**
|
||||
* Singleton instance of the CveDB.
|
||||
*/
|
||||
private static CveDB instance = null;
|
||||
/**
|
||||
* Track the number of current users of the CveDB; so that if someone is
|
||||
* using database another user cannot close the connection on them.
|
||||
*/
|
||||
private int usageCount = 0;
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -61,18 +76,132 @@ public class CveDB {
|
||||
/**
|
||||
* Database connection
|
||||
*/
|
||||
private Connection conn;
|
||||
private Connection connection;
|
||||
/**
|
||||
* The bundle of statements used when accessing the database.
|
||||
*/
|
||||
private ResourceBundle statementBundle = null;
|
||||
private ResourceBundle statementBundle;
|
||||
/**
|
||||
* Database properties object containing the 'properties' from the database
|
||||
* table.
|
||||
*/
|
||||
private DatabaseProperties databaseProperties;
|
||||
/**
|
||||
* The prepared statements.
|
||||
*/
|
||||
private final EnumMap<PreparedStatementCveDb, PreparedStatement> preparedStatements = new EnumMap<>(PreparedStatementCveDb.class);
|
||||
|
||||
/**
|
||||
* Creates a new CveDB object and opens the database connection. Note, the
|
||||
* connection must be closed by the caller by calling the close method.
|
||||
* ======= Does the underlying connection support batch operations?
|
||||
* The enum value names must match the keys of the statements in the
|
||||
* statement bundles "dbStatements*.properties".
|
||||
*/
|
||||
private boolean batchSupported;
|
||||
enum PreparedStatementCveDb {
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
CLEANUP_ORPHANS,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
COUNT_CPE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
DELETE_REFERENCE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
DELETE_SOFTWARE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
DELETE_VULNERABILITY,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
INSERT_CPE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
INSERT_PROPERTY,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
INSERT_REFERENCE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
INSERT_SOFTWARE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
INSERT_VULNERABILITY,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
MERGE_PROPERTY,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_CPE_ENTRIES,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_CPE_ID,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_CVE_FROM_SOFTWARE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_PROPERTIES,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_REFERENCES,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_SOFTWARE,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_VENDOR_PRODUCT_LIST,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_VULNERABILITY,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
SELECT_VULNERABILITY_ID,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
UPDATE_PROPERTY,
|
||||
/**
|
||||
* Key for SQL Statement.
|
||||
*/
|
||||
UPDATE_VULNERABILITY
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CveDB singleton object.
|
||||
*
|
||||
* @return the CveDB singleton
|
||||
* @throws DatabaseException thrown if there is a database error
|
||||
*/
|
||||
public static synchronized CveDB getInstance() throws DatabaseException {
|
||||
if (instance == null) {
|
||||
instance = new CveDB();
|
||||
}
|
||||
if (!instance.isOpen()) {
|
||||
instance.open();
|
||||
}
|
||||
instance.usageCount += 1;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CveDB object and opens the database connection. Note, the
|
||||
@@ -81,35 +210,34 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown if there is an exception opening the
|
||||
* database.
|
||||
*/
|
||||
public CveDB() throws DatabaseException {
|
||||
super();
|
||||
private CveDB() throws DatabaseException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to determine the product name of the database.
|
||||
*
|
||||
* @param conn the database connection
|
||||
* @return the product name of the database if successful, {@code null} else
|
||||
*/
|
||||
private static String determineDatabaseProductName(Connection conn) {
|
||||
try {
|
||||
open();
|
||||
try {
|
||||
final String databaseProductName = conn.getMetaData().getDatabaseProductName();
|
||||
LOGGER.debug("Database dialect: {}", databaseProductName);
|
||||
final Locale dbDialect = new Locale(databaseProductName);
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements", dbDialect);
|
||||
if ("mysql".equalsIgnoreCase(databaseProductName)) {
|
||||
batchSupported = false;
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
LOGGER.warn("Problem loading database specific dialect!", se);
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements");
|
||||
}
|
||||
databaseProperties = new DatabaseProperties(this);
|
||||
} catch (DatabaseException ex) {
|
||||
throw ex;
|
||||
final String databaseProductName = conn.getMetaData().getDatabaseProductName();
|
||||
LOGGER.debug("Database product: {}", databaseProductName);
|
||||
return databaseProductName;
|
||||
} catch (SQLException se) {
|
||||
LOGGER.warn("Problem determining database product!", se);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database connection.
|
||||
* Method added for testing, returns the current usage count of the CveDB
|
||||
* singleton.
|
||||
*
|
||||
* @return the database connection
|
||||
* @return the current usage of the CveDB singleton
|
||||
*/
|
||||
protected Connection getConnection() {
|
||||
return conn;
|
||||
protected synchronized int getUsageCount() {
|
||||
return usageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,28 +247,43 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown if there is an error opening the
|
||||
* database connection
|
||||
*/
|
||||
public final synchronized void open() throws DatabaseException {
|
||||
if (!isOpen()) {
|
||||
conn = ConnectionFactory.getConnection();
|
||||
private synchronized void open() throws DatabaseException {
|
||||
if (!instance.isOpen()) {
|
||||
instance.connection = ConnectionFactory.getConnection();
|
||||
final String databaseProductName = determineDatabaseProductName(instance.connection);
|
||||
instance.statementBundle = databaseProductName != null
|
||||
? ResourceBundle.getBundle("data/dbStatements", new Locale(databaseProductName))
|
||||
: ResourceBundle.getBundle("data/dbStatements");
|
||||
instance.prepareStatements();
|
||||
instance.databaseProperties = new DatabaseProperties(instance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the DB4O database. Close should be called on this object when it
|
||||
* is done being used.
|
||||
* Closes the database connection. Close should be called on this object
|
||||
* when it is done being used.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error("There was an error attempting to close the CveDB, see the log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.error("There was an exception attempting to close the CveDB, see the log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
if (instance != null) {
|
||||
instance.usageCount -= 1;
|
||||
if (instance.usageCount <= 0 && instance.isOpen()) {
|
||||
instance.usageCount = 0;
|
||||
instance.closeStatements();
|
||||
try {
|
||||
instance.connection.close();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error("There was an error attempting to close the CveDB, see the log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.error("There was an exception attempting to close the CveDB, see the log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
instance.statementBundle = null;
|
||||
instance.preparedStatements.clear();
|
||||
instance.databaseProperties = null;
|
||||
instance.connection = null;
|
||||
}
|
||||
conn = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,8 +292,54 @@ public class CveDB {
|
||||
*
|
||||
* @return whether the database connection is open or closed
|
||||
*/
|
||||
public synchronized boolean isOpen() {
|
||||
return conn != null;
|
||||
protected synchronized boolean isOpen() {
|
||||
return connection != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares all statements to be used.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an error preparing the
|
||||
* statements
|
||||
*/
|
||||
private void prepareStatements() throws DatabaseException {
|
||||
for (PreparedStatementCveDb key : values()) {
|
||||
final String statementString = statementBundle.getString(key.name());
|
||||
final PreparedStatement preparedStatement;
|
||||
try {
|
||||
if (key == INSERT_VULNERABILITY || key == INSERT_CPE) {
|
||||
preparedStatement = connection.prepareStatement(statementString, new String[]{"id"});
|
||||
} else {
|
||||
preparedStatement = connection.prepareStatement(statementString);
|
||||
}
|
||||
} catch (SQLException exception) {
|
||||
throw new DatabaseException(exception);
|
||||
}
|
||||
preparedStatements.put(key, preparedStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all prepared statements.
|
||||
*/
|
||||
private synchronized void closeStatements() {
|
||||
for (PreparedStatement preparedStatement : preparedStatements.values()) {
|
||||
DBUtils.closeStatement(preparedStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified prepared statement.
|
||||
*
|
||||
* @param key the prepared statement from {@link PreparedStatementCveDb} to
|
||||
* return
|
||||
* @return the prepared statement
|
||||
* @throws SQLException thrown if a SQL Exception occurs
|
||||
*/
|
||||
private synchronized PreparedStatement getPreparedStatement(PreparedStatementCveDb key) throws SQLException {
|
||||
final PreparedStatement preparedStatement = preparedStatements.get(key);
|
||||
preparedStatement.clearParameters();
|
||||
return preparedStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,8 +349,8 @@ public class CveDB {
|
||||
*/
|
||||
public synchronized void commit() throws SQLException {
|
||||
//temporary remove this as autocommit is on.
|
||||
//if (conn != null) {
|
||||
// conn.commit();
|
||||
//if (isOpen()) {
|
||||
// connection.commit();
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -177,18 +366,23 @@ public class CveDB {
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
/**
|
||||
* Database properties object containing the 'properties' from the database
|
||||
* table.
|
||||
*/
|
||||
private DatabaseProperties databaseProperties;
|
||||
|
||||
/**
|
||||
* Get the value of databaseProperties.
|
||||
*
|
||||
* @return the value of databaseProperties
|
||||
*/
|
||||
public DatabaseProperties getDatabaseProperties() {
|
||||
public synchronized DatabaseProperties getDatabaseProperties() {
|
||||
return databaseProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used within the unit tests to reload the database properties.
|
||||
*
|
||||
* @return the database properties
|
||||
*/
|
||||
protected synchronized DatabaseProperties reloadProperties() {
|
||||
databaseProperties = new DatabaseProperties(this);
|
||||
return databaseProperties;
|
||||
}
|
||||
|
||||
@@ -203,11 +397,10 @@ public class CveDB {
|
||||
* @return a set of vulnerable software
|
||||
*/
|
||||
public synchronized Set<VulnerableSoftware> getCPEs(String vendor, String product) {
|
||||
final Set<VulnerableSoftware> cpe = new HashSet<VulnerableSoftware>();
|
||||
final Set<VulnerableSoftware> cpe = new HashSet<>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_CPE_ENTRIES"));
|
||||
final PreparedStatement ps = getPreparedStatement(SELECT_CPE_ENTRIES);
|
||||
ps.setString(1, vendor);
|
||||
ps.setString(2, product);
|
||||
rs = ps.executeQuery();
|
||||
@@ -222,7 +415,6 @@ public class CveDB {
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
}
|
||||
return cpe;
|
||||
}
|
||||
@@ -235,21 +427,19 @@ public class CveDB {
|
||||
* data from the DB
|
||||
*/
|
||||
public synchronized Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
final Set<Pair<String, String>> data = new HashSet<Pair<String, String>>();
|
||||
final Set<Pair<String, String>> data = new HashSet<>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_VENDOR_PRODUCT_LIST"));
|
||||
final PreparedStatement ps = getPreparedStatement(SELECT_VENDOR_PRODUCT_LIST);
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
data.add(new Pair<String, String>(rs.getString(1), rs.getString(2)));
|
||||
data.add(new Pair<>(rs.getString(1), rs.getString(2)));
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@@ -259,12 +449,11 @@ public class CveDB {
|
||||
*
|
||||
* @return the properties from the database
|
||||
*/
|
||||
synchronized Properties getProperties() {
|
||||
public synchronized Properties getProperties() {
|
||||
final Properties prop = new Properties();
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_PROPERTIES"));
|
||||
final PreparedStatement ps = getPreparedStatement(SELECT_PROPERTIES);
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
prop.setProperty(rs.getString(1), rs.getString(2));
|
||||
@@ -273,7 +462,6 @@ public class CveDB {
|
||||
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(ps);
|
||||
DBUtils.closeResultSet(rs);
|
||||
}
|
||||
return prop;
|
||||
@@ -285,34 +473,23 @@ public class CveDB {
|
||||
* @param key the property key
|
||||
* @param value the property value
|
||||
*/
|
||||
synchronized void saveProperty(String key, String value) {
|
||||
public synchronized void saveProperty(String key, String value) {
|
||||
try {
|
||||
try {
|
||||
final PreparedStatement mergeProperty = getConnection().prepareStatement(statementBundle.getString("MERGE_PROPERTY"));
|
||||
try {
|
||||
mergeProperty.setString(1, key);
|
||||
mergeProperty.setString(2, value);
|
||||
mergeProperty.executeUpdate();
|
||||
} finally {
|
||||
DBUtils.closeStatement(mergeProperty);
|
||||
}
|
||||
final PreparedStatement mergeProperty = getPreparedStatement(MERGE_PROPERTY);
|
||||
mergeProperty.setString(1, key);
|
||||
mergeProperty.setString(2, value);
|
||||
mergeProperty.executeUpdate();
|
||||
} catch (MissingResourceException mre) {
|
||||
// No Merge statement, so doing an Update/Insert...
|
||||
PreparedStatement updateProperty = null;
|
||||
PreparedStatement insertProperty = null;
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
insertProperty.executeUpdate();
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
DBUtils.closeStatement(insertProperty);
|
||||
final PreparedStatement updateProperty = getPreparedStatement(UPDATE_PROPERTY);
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
final PreparedStatement insertProperty = getPreparedStatement(INSERT_PROPERTY);
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
insertProperty.executeUpdate();
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -336,18 +513,17 @@ public class CveDB {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
|
||||
final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
|
||||
final List<Vulnerability> vulnerabilities = new ArrayList<>();
|
||||
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_CVE_FROM_SOFTWARE"));
|
||||
final PreparedStatement ps = getPreparedStatement(SELECT_CVE_FROM_SOFTWARE);
|
||||
ps.setString(1, cpe.getVendor());
|
||||
ps.setString(2, cpe.getProduct());
|
||||
rs = ps.executeQuery();
|
||||
String currentCVE = "";
|
||||
|
||||
final Map<String, Boolean> vulnSoftware = new HashMap<String, Boolean>();
|
||||
final Map<String, Boolean> vulnSoftware = new HashMap<>();
|
||||
while (rs.next()) {
|
||||
final String cveId = rs.getString(1);
|
||||
if (!currentCVE.equals(cveId)) { //check for match and add
|
||||
@@ -377,7 +553,6 @@ public class CveDB {
|
||||
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
}
|
||||
return vulnerabilities;
|
||||
}
|
||||
@@ -390,16 +565,13 @@ public class CveDB {
|
||||
* @throws DatabaseException if an exception occurs
|
||||
*/
|
||||
public synchronized Vulnerability getVulnerability(String cve) throws DatabaseException {
|
||||
PreparedStatement psV = null;
|
||||
PreparedStatement psR = null;
|
||||
PreparedStatement psS = null;
|
||||
ResultSet rsV = null;
|
||||
ResultSet rsR = null;
|
||||
ResultSet rsS = null;
|
||||
Vulnerability vuln = null;
|
||||
|
||||
try {
|
||||
psV = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY"));
|
||||
final PreparedStatement psV = getPreparedStatement(SELECT_VULNERABILITY);
|
||||
psV.setString(1, cve);
|
||||
rsV = psV.executeQuery();
|
||||
if (rsV.next()) {
|
||||
@@ -423,13 +595,14 @@ public class CveDB {
|
||||
vuln.setCvssIntegrityImpact(rsV.getString(9));
|
||||
vuln.setCvssAvailabilityImpact(rsV.getString(10));
|
||||
|
||||
psR = getConnection().prepareStatement(statementBundle.getString("SELECT_REFERENCES"));
|
||||
final PreparedStatement psR = getPreparedStatement(SELECT_REFERENCES);
|
||||
psR.setInt(1, cveId);
|
||||
rsR = psR.executeQuery();
|
||||
while (rsR.next()) {
|
||||
vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
|
||||
}
|
||||
psS = getConnection().prepareStatement(statementBundle.getString("SELECT_SOFTWARE"));
|
||||
|
||||
final PreparedStatement psS = getPreparedStatement(SELECT_SOFTWARE);
|
||||
psS.setInt(1, cveId);
|
||||
rsS = psS.executeQuery();
|
||||
while (rsS.next()) {
|
||||
@@ -448,9 +621,6 @@ public class CveDB {
|
||||
DBUtils.closeResultSet(rsV);
|
||||
DBUtils.closeResultSet(rsR);
|
||||
DBUtils.closeResultSet(rsS);
|
||||
DBUtils.closeStatement(psV);
|
||||
DBUtils.closeStatement(psR);
|
||||
DBUtils.closeStatement(psS);
|
||||
}
|
||||
return vuln;
|
||||
}
|
||||
@@ -463,52 +633,31 @@ public class CveDB {
|
||||
* @throws DatabaseException is thrown if the database
|
||||
*/
|
||||
public synchronized void updateVulnerability(Vulnerability vuln) throws DatabaseException {
|
||||
PreparedStatement selectVulnerabilityId = null;
|
||||
PreparedStatement deleteVulnerability = null;
|
||||
PreparedStatement deleteReferences = null;
|
||||
PreparedStatement deleteSoftware = null;
|
||||
PreparedStatement updateVulnerability = null;
|
||||
PreparedStatement insertVulnerability = null;
|
||||
PreparedStatement insertReference = null;
|
||||
PreparedStatement selectCpeId = null;
|
||||
PreparedStatement insertCpe = null;
|
||||
PreparedStatement insertSoftware = null;
|
||||
|
||||
try {
|
||||
selectVulnerabilityId = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY_ID"));
|
||||
deleteVulnerability = getConnection().prepareStatement(statementBundle.getString("DELETE_VULNERABILITY"));
|
||||
deleteReferences = getConnection().prepareStatement(statementBundle.getString("DELETE_REFERENCE"));
|
||||
deleteSoftware = getConnection().prepareStatement(statementBundle.getString("DELETE_SOFTWARE"));
|
||||
updateVulnerability = getConnection().prepareStatement(statementBundle.getString("UPDATE_VULNERABILITY"));
|
||||
final String[] ids = {"id"};
|
||||
insertVulnerability = getConnection().prepareStatement(statementBundle.getString("INSERT_VULNERABILITY"),
|
||||
//Statement.RETURN_GENERATED_KEYS);
|
||||
ids);
|
||||
insertReference = getConnection().prepareStatement(statementBundle.getString("INSERT_REFERENCE"));
|
||||
selectCpeId = getConnection().prepareStatement(statementBundle.getString("SELECT_CPE_ID"));
|
||||
insertCpe = getConnection().prepareStatement(statementBundle.getString("INSERT_CPE"),
|
||||
//Statement.RETURN_GENERATED_KEYS);
|
||||
ids);
|
||||
insertSoftware = getConnection().prepareStatement(statementBundle.getString("INSERT_SOFTWARE"));
|
||||
int vulnerabilityId = 0;
|
||||
final PreparedStatement selectVulnerabilityId = getPreparedStatement(SELECT_VULNERABILITY_ID);
|
||||
selectVulnerabilityId.setString(1, vuln.getName());
|
||||
ResultSet rs = selectVulnerabilityId.executeQuery();
|
||||
if (rs.next()) {
|
||||
vulnerabilityId = rs.getInt(1);
|
||||
// first delete any existing vulnerability info. We don't know what was updated. yes, slower but atm easier.
|
||||
deleteReferences.setInt(1, vulnerabilityId);
|
||||
deleteReferences.execute();
|
||||
final PreparedStatement deleteReference = getPreparedStatement(DELETE_REFERENCE);
|
||||
deleteReference.setInt(1, vulnerabilityId);
|
||||
deleteReference.execute();
|
||||
|
||||
final PreparedStatement deleteSoftware = getPreparedStatement(DELETE_SOFTWARE);
|
||||
deleteSoftware.setInt(1, vulnerabilityId);
|
||||
deleteSoftware.execute();
|
||||
}
|
||||
DBUtils.closeResultSet(rs);
|
||||
rs = null;
|
||||
|
||||
if (vulnerabilityId != 0) {
|
||||
if (vuln.getDescription().contains("** REJECT **")) {
|
||||
final PreparedStatement deleteVulnerability = getPreparedStatement(DELETE_VULNERABILITY);
|
||||
deleteVulnerability.setInt(1, vulnerabilityId);
|
||||
deleteVulnerability.executeUpdate();
|
||||
} else {
|
||||
final PreparedStatement updateVulnerability = getPreparedStatement(UPDATE_VULNERABILITY);
|
||||
updateVulnerability.setString(1, vuln.getDescription());
|
||||
updateVulnerability.setString(2, vuln.getCwe());
|
||||
updateVulnerability.setFloat(3, vuln.getCvssScore());
|
||||
@@ -522,6 +671,7 @@ public class CveDB {
|
||||
updateVulnerability.executeUpdate();
|
||||
}
|
||||
} else {
|
||||
final PreparedStatement insertVulnerability = getPreparedStatement(INSERT_VULNERABILITY);
|
||||
insertVulnerability.setString(1, vuln.getName());
|
||||
insertVulnerability.setString(2, vuln.getDescription());
|
||||
insertVulnerability.setString(3, vuln.getCwe());
|
||||
@@ -542,29 +692,22 @@ public class CveDB {
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
rs = null;
|
||||
}
|
||||
}
|
||||
|
||||
final PreparedStatement insertReference = getPreparedStatement(INSERT_REFERENCE);
|
||||
for (Reference r : vuln.getReferences()) {
|
||||
insertReference.setInt(1, vulnerabilityId);
|
||||
insertReference.setString(2, r.getName());
|
||||
insertReference.setString(3, r.getUrl());
|
||||
insertReference.setString(4, r.getSource());
|
||||
|
||||
if (batchSupported) {
|
||||
insertReference.addBatch();
|
||||
} else {
|
||||
insertReference.execute();
|
||||
}
|
||||
}
|
||||
|
||||
if (batchSupported) {
|
||||
insertReference.executeBatch();
|
||||
insertReference.execute();
|
||||
}
|
||||
|
||||
final PreparedStatement insertSoftware = getPreparedStatement(INSERT_SOFTWARE);
|
||||
for (VulnerableSoftware s : vuln.getVulnerableSoftware()) {
|
||||
int cpeProductId = 0;
|
||||
final PreparedStatement selectCpeId = getPreparedStatement(SELECT_CPE_ID);
|
||||
selectCpeId.setString(1, s.getName());
|
||||
try {
|
||||
rs = selectCpeId.executeQuery();
|
||||
@@ -575,10 +718,10 @@ public class CveDB {
|
||||
throw new DatabaseException("Unable to get primary key for new cpe: " + s.getName(), ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
rs = null;
|
||||
}
|
||||
|
||||
if (cpeProductId == 0) {
|
||||
final PreparedStatement insertCpe = getPreparedStatement(INSERT_CPE);
|
||||
insertCpe.setString(1, s.getName());
|
||||
insertCpe.setString(2, s.getVendor());
|
||||
insertCpe.setString(3, s.getProduct());
|
||||
@@ -597,39 +740,22 @@ public class CveDB {
|
||||
} else {
|
||||
insertSoftware.setString(3, s.getPreviousVersion());
|
||||
}
|
||||
if (batchSupported) {
|
||||
insertSoftware.addBatch();
|
||||
} else {
|
||||
try {
|
||||
insertSoftware.execute();
|
||||
} catch (SQLException ex) {
|
||||
if (ex.getMessage().contains("Duplicate entry")) {
|
||||
final String msg = String.format("Duplicate software key identified in '%s:%s'", vuln.getName(), s.getName());
|
||||
LOGGER.debug(msg, ex);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
try {
|
||||
insertSoftware.execute();
|
||||
} catch (SQLException ex) {
|
||||
if (ex.getMessage().contains("Duplicate entry")) {
|
||||
final String msg = String.format("Duplicate software key identified in '%s:%s'", vuln.getName(), s.getName());
|
||||
LOGGER.info(msg, ex);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (batchSupported) {
|
||||
insertSoftware.executeBatch();
|
||||
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = String.format("Error updating '%s'", vuln.getName());
|
||||
LOGGER.debug(msg, ex);
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(selectVulnerabilityId);
|
||||
DBUtils.closeStatement(deleteReferences);
|
||||
DBUtils.closeStatement(deleteSoftware);
|
||||
DBUtils.closeStatement(updateVulnerability);
|
||||
DBUtils.closeStatement(deleteVulnerability);
|
||||
DBUtils.closeStatement(insertVulnerability);
|
||||
DBUtils.closeStatement(insertReference);
|
||||
DBUtils.closeStatement(selectCpeId);
|
||||
DBUtils.closeStatement(insertCpe);
|
||||
DBUtils.closeStatement(insertSoftware);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,17 +765,16 @@ public class CveDB {
|
||||
* @return <code>true</code> if data exists; otherwise <code>false</code>
|
||||
*/
|
||||
public synchronized boolean dataExists() {
|
||||
Statement cs = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
cs = conn.createStatement();
|
||||
rs = cs.executeQuery("SELECT COUNT(*) records FROM cpeEntry");
|
||||
final PreparedStatement cs = getPreparedStatement(COUNT_CPE);
|
||||
rs = cs.executeQuery();
|
||||
if (rs.next()) {
|
||||
if (rs.getInt(1) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
} catch (Exception ex) {
|
||||
String dd;
|
||||
try {
|
||||
dd = Settings.getDataDirectory().getAbsolutePath();
|
||||
@@ -664,7 +789,6 @@ public class CveDB {
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(cs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -675,17 +799,14 @@ public class CveDB {
|
||||
* ensure orphan entries are removed.
|
||||
*/
|
||||
public synchronized void cleanupDatabase() {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("CLEANUP_ORPHANS"));
|
||||
final PreparedStatement ps = getPreparedStatement(CLEANUP_ORPHANS);
|
||||
if (ps != null) {
|
||||
ps.executeUpdate();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(ps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,12 +824,12 @@ public class CveDB {
|
||||
* analyzed
|
||||
* @return true if the identified version is affected, otherwise false
|
||||
*/
|
||||
Entry<String, Boolean> getMatchingSoftware(Map<String, Boolean> vulnerableSoftware, String vendor, String product,
|
||||
protected Entry<String, Boolean> getMatchingSoftware(Map<String, Boolean> vulnerableSoftware, String vendor, String product,
|
||||
DependencyVersion identifiedVersion) {
|
||||
|
||||
final boolean isVersionTwoADifferentProduct = "apache".equals(vendor) && "struts".equals(product);
|
||||
|
||||
final Set<String> majorVersionsAffectingAllPrevious = new HashSet<String>();
|
||||
final Set<String> majorVersionsAffectingAllPrevious = new HashSet<>();
|
||||
final boolean matchesAnyPrevious = identifiedVersion == null || "-".equals(identifiedVersion.toString());
|
||||
String majorVersionMatch = null;
|
||||
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||
@@ -737,12 +858,12 @@ public class CveDB {
|
||||
if (!entry.getValue()) {
|
||||
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
||||
if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||
if (canSkipVersions && majorVersionMatch != null && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||
continue;
|
||||
}
|
||||
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
||||
//in the above loop or just after loop (if matchesAnyPrevious return null).
|
||||
if (identifiedVersion.equals(v)) {
|
||||
if (identifiedVersion != null && identifiedVersion.equals(v)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
@@ -751,12 +872,12 @@ public class CveDB {
|
||||
if (entry.getValue()) {
|
||||
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
||||
if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||
if (canSkipVersions && majorVersionMatch != null && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||
continue;
|
||||
}
|
||||
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
||||
//in the above loop or just after loop (if matchesAnyPrevious return null).
|
||||
if (entry.getValue() && identifiedVersion.compareTo(v) <= 0) {
|
||||
if (entry.getValue() && identifiedVersion != null && identifiedVersion.compareTo(v) <= 0) {
|
||||
if (!(isVersionTwoADifferentProduct && !identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0)))) {
|
||||
return entry;
|
||||
}
|
||||
@@ -815,7 +936,7 @@ public class CveDB {
|
||||
public synchronized void deleteUnusedCpe() {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
|
||||
ps = connection.prepareStatement(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error("Unable to delete CPE dictionary entries", ex);
|
||||
@@ -837,7 +958,7 @@ public class CveDB {
|
||||
public synchronized void addCpe(String cpe, String vendor, String product) {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("ADD_DICT_CPE"));
|
||||
ps = connection.prepareStatement(statementBundle.getString("ADD_DICT_CPE"));
|
||||
ps.setString(1, cpe);
|
||||
ps.setString(2, vendor);
|
||||
ps.setString(3, product);
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeMap;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
@@ -31,9 +32,11 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This is a wrapper around a set of properties that are stored in the database.
|
||||
* This class is safe to be accessed from multiple threads in parallel.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@ThreadSafe
|
||||
public class DatabaseProperties {
|
||||
|
||||
/**
|
||||
@@ -163,7 +166,7 @@ public class DatabaseProperties {
|
||||
* @return a map of the database meta data
|
||||
*/
|
||||
public Map<String, String> getMetaData() {
|
||||
final Map<String, String> map = new TreeMap<String, String>();
|
||||
final Map<String, String> map = new TreeMap<>();
|
||||
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||
final String key = (String) entry.getKey();
|
||||
if (!"version".equals(key)) {
|
||||
|
||||
@@ -75,7 +75,7 @@ public final class DriverLoader {
|
||||
*/
|
||||
public static Driver load(String className, String pathToDriver) throws DriverLoadException {
|
||||
final URLClassLoader parent = (URLClassLoader) ClassLoader.getSystemClassLoader();
|
||||
final List<URL> urls = new ArrayList<URL>();
|
||||
final List<URL> urls = new ArrayList<>();
|
||||
final String[] paths = pathToDriver.split(File.pathSeparator);
|
||||
for (String path : paths) {
|
||||
final File file = new File(path);
|
||||
@@ -129,19 +129,7 @@ public final class DriverLoader {
|
||||
//using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
|
||||
DriverManager.registerDriver(shim);
|
||||
return shim;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
LOGGER.debug(msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
} catch (InstantiationException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
LOGGER.debug(msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
LOGGER.debug(msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
} catch (SQLException ex) {
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
LOGGER.debug(msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
|
||||
@@ -126,11 +126,7 @@ class DriverShim implements Driver {
|
||||
if (m != null) {
|
||||
try {
|
||||
return (java.util.logging.Logger) m.invoke(m);
|
||||
} catch (IllegalAccessException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
} catch (InvocationTargetException ex) {
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public abstract class BaseUpdater {
|
||||
|
||||
/**
|
||||
* Static logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BaseUpdater.class);
|
||||
/**
|
||||
* Information about the timestamps and URLs for data that needs to be updated.
|
||||
*/
|
||||
private DatabaseProperties properties;
|
||||
/**
|
||||
* Reference to the Cve Database.
|
||||
*/
|
||||
private CveDB cveDB = null;
|
||||
|
||||
protected CveDB getCveDB() {
|
||||
return cveDB;
|
||||
}
|
||||
|
||||
protected DatabaseProperties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the CVE and CPE data stores.
|
||||
*/
|
||||
protected void closeDataStores() {
|
||||
if (cveDB != null) {
|
||||
try {
|
||||
cveDB.close();
|
||||
cveDB = null;
|
||||
properties = null;
|
||||
} catch (Throwable ignore) {
|
||||
LOGGER.trace("Error closing the database", ignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the data store.
|
||||
*
|
||||
* @throws UpdateException thrown if a data store cannot be opened
|
||||
*/
|
||||
protected final void openDataStores() throws UpdateException {
|
||||
if (cveDB != null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
cveDB = new CveDB();
|
||||
cveDB.open();
|
||||
properties = cveDB.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
closeDataStores();
|
||||
LOGGER.debug("Database Exception opening databases", ex);
|
||||
throw new UpdateException("Error updating the database, please see the log file for more details.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
* Copyright (c) 2015 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
/*
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -37,7 +37,7 @@ import org.owasp.dependencycheck.utils.XmlUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* This class is currently unused and if enabled will likely not work on MySQL
|
||||
@@ -53,110 +53,110 @@ import org.xml.sax.SAXException;
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@Deprecated
|
||||
public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
|
||||
/**
|
||||
* Static logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
|
||||
|
||||
@Override
|
||||
public void update() throws UpdateException {
|
||||
/*
|
||||
//the following could be used if this were ever used.
|
||||
try {
|
||||
if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
|
||||
return;
|
||||
}
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.trace("inavlid setting UPDATE_NVDCVE_ENABLED", ex);
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
openDataStores();
|
||||
if (updateNeeded()) {
|
||||
LOGGER.info("Updating the Common Platform Enumeration (CPE)");
|
||||
final File xml = downloadCpe();
|
||||
final List<Cpe> cpes = processXML(xml);
|
||||
getCveDB().deleteUnusedCpe();
|
||||
for (Cpe cpe : cpes) {
|
||||
getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
|
||||
}
|
||||
final long now = System.currentTimeMillis();
|
||||
getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
|
||||
LOGGER.info("CPE update complete");
|
||||
}
|
||||
} finally {
|
||||
closeDataStores();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the CPE XML file.
|
||||
*
|
||||
* @return the file reference to the CPE.xml file
|
||||
* @throws UpdateException thrown if there is an issue downloading the XML
|
||||
* file
|
||||
*/
|
||||
private File downloadCpe() throws UpdateException {
|
||||
File xml;
|
||||
final URL url;
|
||||
try {
|
||||
url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
|
||||
xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
|
||||
Downloader.fetchFile(url, xml);
|
||||
if (url.toExternalForm().endsWith(".xml.gz")) {
|
||||
ExtractionUtil.extractGzip(xml);
|
||||
}
|
||||
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new UpdateException("Invalid CPE URL", ex);
|
||||
} catch (DownloadFailedException ex) {
|
||||
throw new UpdateException("Unable to download CPE XML file", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new UpdateException("Unable to create temporary file to download CPE", ex);
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the CPE XML file to return a list of CPE entries.
|
||||
*
|
||||
* @param xml the CPE data file
|
||||
* @return the list of CPE entries
|
||||
* @throws UpdateException thrown if there is an issue with parsing the XML
|
||||
* file
|
||||
*/
|
||||
private List<Cpe> processXML(final File xml) throws UpdateException {
|
||||
try {
|
||||
final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
|
||||
final CPEHandler handler = new CPEHandler();
|
||||
saxParser.parse(xml, handler);
|
||||
return handler.getData();
|
||||
} catch (ParserConfigurationException ex) {
|
||||
throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
|
||||
} catch (SAXException ex) {
|
||||
throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new UpdateException("Unable to parse CPE XML file due to IO Failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to find the last time the CPE data was refreshed and if it needs
|
||||
* to be updated.
|
||||
*
|
||||
* @return true if the CPE data should be refreshed
|
||||
*/
|
||||
private boolean updateNeeded() {
|
||||
final long now = System.currentTimeMillis();
|
||||
final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
|
||||
long timestamp = 0;
|
||||
final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
|
||||
if (ts != null && ts.matches("^[0-9]+$")) {
|
||||
timestamp = Long.parseLong(ts);
|
||||
}
|
||||
return !DateUtil.withinDateRange(timestamp, now, days);
|
||||
}
|
||||
public class CpeUpdater { //extends BaseUpdater implements CachedWebDataSource {
|
||||
//
|
||||
// /**
|
||||
// * Static logger.
|
||||
// */
|
||||
// private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
|
||||
//
|
||||
// @Override
|
||||
// public void update() throws UpdateException {
|
||||
// /*
|
||||
// //the following could be used if this were ever used.
|
||||
// try {
|
||||
// if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
|
||||
// return;
|
||||
// }
|
||||
// } catch (InvalidSettingException ex) {
|
||||
// LOGGER.trace("invalid setting UPDATE_NVDCVE_ENABLED", ex);
|
||||
// }
|
||||
// */
|
||||
//
|
||||
// try {
|
||||
// openDataStores();
|
||||
// if (updateNeeded()) {
|
||||
// LOGGER.info("Updating the Common Platform Enumeration (CPE)");
|
||||
// final File xml = downloadCpe();
|
||||
// final List<Cpe> cpes = processXML(xml);
|
||||
// getCveDB().deleteUnusedCpe();
|
||||
// for (Cpe cpe : cpes) {
|
||||
// getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
|
||||
// }
|
||||
// final long now = System.currentTimeMillis();
|
||||
// getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
|
||||
// LOGGER.info("CPE update complete");
|
||||
// }
|
||||
// } finally {
|
||||
// closeDataStores();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Downloads the CPE XML file.
|
||||
// *
|
||||
// * @return the file reference to the CPE.xml file
|
||||
// * @throws UpdateException thrown if there is an issue downloading the XML
|
||||
// * file
|
||||
// */
|
||||
// private File downloadCpe() throws UpdateException {
|
||||
// File xml;
|
||||
// final URL url;
|
||||
// try {
|
||||
// url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
|
||||
// xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
|
||||
// Downloader.fetchFile(url, xml);
|
||||
// if (url.toExternalForm().endsWith(".xml.gz")) {
|
||||
// ExtractionUtil.extractGzip(xml);
|
||||
// }
|
||||
//
|
||||
// } catch (MalformedURLException ex) {
|
||||
// throw new UpdateException("Invalid CPE URL", ex);
|
||||
// } catch (DownloadFailedException ex) {
|
||||
// throw new UpdateException("Unable to download CPE XML file", ex);
|
||||
// } catch (IOException ex) {
|
||||
// throw new UpdateException("Unable to create temporary file to download CPE", ex);
|
||||
// }
|
||||
// return xml;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Parses the CPE XML file to return a list of CPE entries.
|
||||
// *
|
||||
// * @param xml the CPE data file
|
||||
// * @return the list of CPE entries
|
||||
// * @throws UpdateException thrown if there is an issue with parsing the XML
|
||||
// * file
|
||||
// */
|
||||
// private List<Cpe> processXML(final File xml) throws UpdateException {
|
||||
// try {
|
||||
// final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
|
||||
// final CPEHandler handler = new CPEHandler();
|
||||
// saxParser.parse(xml, handler);
|
||||
// return handler.getData();
|
||||
// } catch (ParserConfigurationException ex) {
|
||||
// throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
|
||||
// } catch (SAXException ex) {
|
||||
// throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
|
||||
// } catch (IOException ex) {
|
||||
// throw new UpdateException("Unable to parse CPE XML file due to IO Failure", ex);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Checks to find the last time the CPE data was refreshed and if it needs
|
||||
// * to be updated.
|
||||
// *
|
||||
// * @return true if the CPE data should be refreshed
|
||||
// */
|
||||
// private boolean updateNeeded() {
|
||||
// final long now = System.currentTimeMillis();
|
||||
// final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
|
||||
// long timestamp = 0;
|
||||
// final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
|
||||
// if (ts != null && ts.matches("^[0-9]+$")) {
|
||||
// timestamp = Long.parseLong(ts);
|
||||
// }
|
||||
// return !DateUtil.withinDateRange(timestamp, now, days);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Checks the gh-pages dependency-check site to determine the current released
|
||||
* version number. If the released version number is greater then the running
|
||||
* version number. If the released version number is greater than the running
|
||||
* version number a warning is printed recommending that an upgrade be
|
||||
* performed.
|
||||
*
|
||||
@@ -57,11 +57,6 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
* The property key indicating when the last version check occurred.
|
||||
*/
|
||||
public static final String CURRENT_ENGINE_RELEASE = "CurrentEngineRelease";
|
||||
/**
|
||||
* Reference to the Cve Database.
|
||||
*/
|
||||
private CveDB cveDB = null;
|
||||
|
||||
/**
|
||||
* The version retrieved from the database properties or web to check
|
||||
* against.
|
||||
@@ -98,20 +93,21 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
*/
|
||||
@Override
|
||||
public void update() throws UpdateException {
|
||||
try {
|
||||
try (CveDB db = CveDB.getInstance()) {
|
||||
final boolean autoupdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
|
||||
final boolean enabled = Settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true);
|
||||
final String original = Settings.getString(Settings.KEYS.CVE_ORIGINAL_MODIFIED_20_URL);
|
||||
final String current = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
|
||||
/**
|
||||
/*
|
||||
* Only update if auto-update is enabled, the engine check is
|
||||
* enabled, and the NVD CVE URLs have not been modified (i.e. the
|
||||
* user has not configured them to point to an internal source).
|
||||
*/
|
||||
if (enabled && autoupdate && original != null && original.equals(current)) {
|
||||
openDatabase();
|
||||
LOGGER.debug("Begin Engine Version Check");
|
||||
final DatabaseProperties properties = cveDB.getDatabaseProperties();
|
||||
|
||||
final DatabaseProperties properties = db.getDatabaseProperties();
|
||||
|
||||
final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
|
||||
final long now = System.currentTimeMillis();
|
||||
updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
|
||||
@@ -130,8 +126,6 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
throw new UpdateException("Error occurred updating database properties.");
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
|
||||
} finally {
|
||||
closeDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,33 +175,6 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the CVE and CPE data stores.
|
||||
*
|
||||
* @throws DatabaseException thrown if a data store cannot be opened
|
||||
*/
|
||||
protected final void openDatabase() throws DatabaseException {
|
||||
if (cveDB != null) {
|
||||
return;
|
||||
}
|
||||
cveDB = new CveDB();
|
||||
cveDB.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the CVE and CPE data stores.
|
||||
*/
|
||||
protected void closeDatabase() {
|
||||
if (cveDB != null) {
|
||||
try {
|
||||
cveDB.close();
|
||||
cveDB = null;
|
||||
} catch (Throwable ignore) {
|
||||
LOGGER.trace("Error closing the cveDB", ignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current released version number from the github
|
||||
* documentation site.
|
||||
|
||||
@@ -17,14 +17,26 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
@@ -36,6 +48,7 @@ import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.data.update.nvd.ProcessTask;
|
||||
import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve;
|
||||
import org.owasp.dependencycheck.utils.DateUtil;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -47,48 +60,96 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
public class NvdCveUpdater implements CachedWebDataSource {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveUpdater.class);
|
||||
/**
|
||||
* The max thread pool size to use when downloading files.
|
||||
* The thread pool size to use for CPU-intense tasks.
|
||||
*/
|
||||
public static final int MAX_THREAD_POOL_SIZE = Settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 3);
|
||||
private static final int PROCESSING_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors();
|
||||
/**
|
||||
* The thread pool size to use when downloading files.
|
||||
*/
|
||||
private static final int DOWNLOAD_THREAD_POOL_SIZE = Math.round(1.5f * Runtime.getRuntime().availableProcessors());
|
||||
/**
|
||||
* ExecutorService for CPU-intense processing tasks.
|
||||
*/
|
||||
private ExecutorService processingExecutorService = null;
|
||||
/**
|
||||
* ExecutorService for tasks that involve blocking activities and are not
|
||||
* very CPU-intense, e.g. downloading files.
|
||||
*/
|
||||
private ExecutorService downloadExecutorService = null;
|
||||
|
||||
/**
|
||||
* Reference to the DAO.
|
||||
*/
|
||||
private CveDB cveDb = null;
|
||||
/**
|
||||
* The properties obtained from the database.
|
||||
*/
|
||||
private DatabaseProperties dbProperties = null;
|
||||
|
||||
/**
|
||||
* Downloads the latest NVD CVE XML file from the web and imports it into
|
||||
* the current CVE Database.
|
||||
* the current CVE Database. A lock on a file is obtained in an attempt to
|
||||
* prevent more then one thread/JVM from updating the database at the same
|
||||
* time. This method may sleep upto 5 minutes.
|
||||
*
|
||||
* @throws UpdateException is thrown if there is an error updating the
|
||||
* database
|
||||
*/
|
||||
@Override
|
||||
public void update() throws UpdateException {
|
||||
try {
|
||||
if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
|
||||
return;
|
||||
}
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.trace("inavlid setting UPDATE_NVDCVE_ENABLED", ex);
|
||||
public synchronized void update() throws UpdateException {
|
||||
if (isUpdateConfiguredFalse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileLock lock = null;
|
||||
RandomAccessFile ulFile = null;
|
||||
File lockFile = null;
|
||||
try {
|
||||
openDataStores();
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Invalid setting for auto-update; using true.");
|
||||
if (ConnectionFactory.isH2Connection()) {
|
||||
final File dir = Settings.getDataDirectory();
|
||||
lockFile = new File(dir, "odc.update.lock");
|
||||
if (lockFile.isFile() && getFileAge(lockFile) > 5 && !lockFile.delete()) {
|
||||
LOGGER.warn("An old db update lock file was found but the system was unable to delete the file. Consider manually deleting " + lockFile.getAbsolutePath());
|
||||
}
|
||||
int ctr = 0;
|
||||
do {
|
||||
try {
|
||||
if (!lockFile.exists() && lockFile.createNewFile()) {
|
||||
ulFile = new RandomAccessFile(lockFile, "rw");
|
||||
lock = ulFile.getChannel().lock();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("Expected error as another thread has likely locked the file", ex);
|
||||
}
|
||||
if (lock == null || !lock.isValid()) {
|
||||
try {
|
||||
LOGGER.debug(String.format("Sleeping thread %s for 5 seconds because we could not obtain the update lock.", Thread.currentThread().getName()));
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException ex) {
|
||||
LOGGER.trace("ignorable error, sleep was interrupted.", ex);
|
||||
}
|
||||
}
|
||||
} while (++ctr < 60 && (lock == null || !lock.isValid()));
|
||||
if (lock == null || !lock.isValid()) {
|
||||
throw new UpdateException("Unable to obtain the update lock, skipping the database update. Skippinig the database update.");
|
||||
}
|
||||
}
|
||||
if (autoUpdate && checkUpdate()) {
|
||||
initializeExecutorServices();
|
||||
cveDb = CveDB.getInstance();
|
||||
dbProperties = cveDb.getDatabaseProperties();
|
||||
|
||||
if (checkUpdate()) {
|
||||
final UpdateableNvdCve updateable = getUpdatesNeeded();
|
||||
if (updateable.isUpdateNeeded()) {
|
||||
performUpdate(updateable);
|
||||
}
|
||||
getProperties().save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis()));
|
||||
dbProperties.save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis()));
|
||||
}
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new UpdateException("NVD CVE properties files contain an invalid URL, unable to update the data to use the most current data.", ex);
|
||||
@@ -100,8 +161,88 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
|
||||
}
|
||||
throw new UpdateException("Unable to download the NVD CVE data.", ex);
|
||||
} catch (DatabaseException ex) {
|
||||
throw new UpdateException("Database Exception, unable to update the data to use the most current data.", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new UpdateException("Database Exception", ex);
|
||||
} finally {
|
||||
closeDataStores();
|
||||
shutdownExecutorServices();
|
||||
cveDb.close();
|
||||
if (lock != null) {
|
||||
try {
|
||||
lock.release();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("Ignorable exception", ex);
|
||||
}
|
||||
}
|
||||
if (ulFile != null) {
|
||||
try {
|
||||
ulFile.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("Ignorable exception", ex);
|
||||
}
|
||||
}
|
||||
if (lockFile != null && lockFile.isFile() && !lockFile.delete()) {
|
||||
LOGGER.error("Lock file '{}' was unable to be deleted. Please manually delete this file.", lockFile.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the system is configured NOT to update.
|
||||
*
|
||||
* @return false if the system is configured to perform an update; otherwise
|
||||
* true
|
||||
*/
|
||||
private boolean isUpdateConfiguredFalse() {
|
||||
try {
|
||||
if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
|
||||
return true;
|
||||
}
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.trace("invalid setting UPDATE_NVDCVE_ENABLED", ex);
|
||||
}
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Invalid setting for auto-update; using true.");
|
||||
}
|
||||
return !autoUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the age of the file in minutes.
|
||||
*
|
||||
* @param file the file to calculate the age
|
||||
* @return the age of the file
|
||||
*/
|
||||
private long getFileAge(File file) {
|
||||
final Date d = new Date();
|
||||
final long modified = file.lastModified();
|
||||
return (d.getTime() - modified) / 1000 / 60;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the executor services for download and processing of the NVD
|
||||
* CVE XML data.
|
||||
*/
|
||||
protected void initializeExecutorServices() {
|
||||
processingExecutorService = Executors.newFixedThreadPool(PROCESSING_THREAD_POOL_SIZE);
|
||||
downloadExecutorService = Executors.newFixedThreadPool(DOWNLOAD_THREAD_POOL_SIZE);
|
||||
LOGGER.debug("#download threads: {}", DOWNLOAD_THREAD_POOL_SIZE);
|
||||
LOGGER.debug("#processing threads: {}", PROCESSING_THREAD_POOL_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown and cleanup of resources used by the executor services.
|
||||
*/
|
||||
private void shutdownExecutorServices() {
|
||||
if (processingExecutorService != null) {
|
||||
processingExecutorService.shutdownNow();
|
||||
}
|
||||
if (downloadExecutorService != null) {
|
||||
downloadExecutorService.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +264,7 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
if (dataExists() && 0 < validForHours) {
|
||||
// ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec
|
||||
final long msValid = validForHours * 60L * 60L * 1000L;
|
||||
final long lastChecked = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_CHECKED, "0"));
|
||||
final long lastChecked = Long.parseLong(dbProperties.getProperty(DatabaseProperties.LAST_CHECKED, "0"));
|
||||
final long now = System.currentTimeMillis();
|
||||
proceed = (now - lastChecked) > msValid;
|
||||
if (!proceed) {
|
||||
@@ -141,17 +282,10 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
* @return true if the database contains data
|
||||
*/
|
||||
private boolean dataExists() {
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
try (CveDB cve = CveDB.getInstance()) {
|
||||
return cve.dataExists();
|
||||
} catch (DatabaseException ex) {
|
||||
return false;
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,41 +312,28 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
LOGGER.info("NVD CVE requires several updates; this could take a couple of minutes.");
|
||||
}
|
||||
|
||||
final int poolSize = (MAX_THREAD_POOL_SIZE < maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates;
|
||||
|
||||
final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize);
|
||||
final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
|
||||
final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
|
||||
final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<>(maxUpdates);
|
||||
for (NvdCveInfo cve : updateable) {
|
||||
if (cve.getNeedsUpdate()) {
|
||||
final DownloadTask call = new DownloadTask(cve, processExecutor, getCveDB(), Settings.getInstance());
|
||||
downloadFutures.add(downloadExecutors.submit(call));
|
||||
final DownloadTask call = new DownloadTask(cve, processingExecutorService, cveDb, Settings.getInstance());
|
||||
downloadFutures.add(downloadExecutorService.submit(call));
|
||||
}
|
||||
}
|
||||
downloadExecutors.shutdown();
|
||||
|
||||
//next, move the future future processTasks to just future processTasks
|
||||
final Set<Future<ProcessTask>> processFutures = new HashSet<Future<ProcessTask>>(maxUpdates);
|
||||
final Set<Future<ProcessTask>> processFutures = new HashSet<>(maxUpdates);
|
||||
for (Future<Future<ProcessTask>> future : downloadFutures) {
|
||||
Future<ProcessTask> task = null;
|
||||
Future<ProcessTask> task;
|
||||
try {
|
||||
task = future.get();
|
||||
} catch (InterruptedException ex) {
|
||||
downloadExecutors.shutdownNow();
|
||||
processExecutor.shutdownNow();
|
||||
|
||||
LOGGER.debug("Thread was interrupted during download", ex);
|
||||
throw new UpdateException("The download was interrupted", ex);
|
||||
} catch (ExecutionException ex) {
|
||||
downloadExecutors.shutdownNow();
|
||||
processExecutor.shutdownNow();
|
||||
|
||||
LOGGER.debug("Thread was interrupted during download execution", ex);
|
||||
throw new UpdateException("The execution of the download was interrupted", ex);
|
||||
}
|
||||
if (task == null) {
|
||||
downloadExecutors.shutdownNow();
|
||||
processExecutor.shutdownNow();
|
||||
LOGGER.debug("Thread was interrupted during download");
|
||||
throw new UpdateException("The download was interrupted; unable to complete the update");
|
||||
} else {
|
||||
@@ -227,22 +348,18 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
throw task.getException();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
processExecutor.shutdownNow();
|
||||
LOGGER.debug("Thread was interrupted during processing", ex);
|
||||
throw new UpdateException(ex);
|
||||
} catch (ExecutionException ex) {
|
||||
processExecutor.shutdownNow();
|
||||
LOGGER.debug("Execution Exception during process", ex);
|
||||
throw new UpdateException(ex);
|
||||
} finally {
|
||||
processExecutor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
|
||||
getProperties().save(updateable.get(MODIFIED));
|
||||
dbProperties.save(updateable.get(MODIFIED));
|
||||
LOGGER.info("Begin database maintenance.");
|
||||
getCveDB().cleanupDatabase();
|
||||
cveDb.cleanupDatabase();
|
||||
LOGGER.info("End database maintenance.");
|
||||
}
|
||||
}
|
||||
@@ -262,7 +379,8 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
* updated properties file
|
||||
*/
|
||||
protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
|
||||
UpdateableNvdCve updates = null;
|
||||
LOGGER.info("starting getUpdatesNeeded() ...");
|
||||
UpdateableNvdCve updates;
|
||||
try {
|
||||
updates = retrieveCurrentTimestampsFromWeb();
|
||||
} catch (InvalidDataException ex) {
|
||||
@@ -277,19 +395,19 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
if (updates == null) {
|
||||
throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
|
||||
}
|
||||
if (!getProperties().isEmpty()) {
|
||||
if (dbProperties != null && !dbProperties.isEmpty()) {
|
||||
try {
|
||||
final int startYear = Settings.getInt(Settings.KEYS.CVE_START_YEAR, 2002);
|
||||
final int endYear = Calendar.getInstance().get(Calendar.YEAR);
|
||||
boolean needsFullUpdate = false;
|
||||
for (int y = startYear; y <= endYear; y++) {
|
||||
final long val = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE + y, "0"));
|
||||
final long val = Long.parseLong(dbProperties.getProperty(DatabaseProperties.LAST_UPDATED_BASE + y, "0"));
|
||||
if (val == 0) {
|
||||
needsFullUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
final long lastUpdated = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED, "0"));
|
||||
final long lastUpdated = Long.parseLong(dbProperties.getProperty(DatabaseProperties.LAST_UPDATED, "0"));
|
||||
final long now = System.currentTimeMillis();
|
||||
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
|
||||
if (!needsFullUpdate && lastUpdated == updates.getTimeStamp(MODIFIED)) {
|
||||
@@ -309,7 +427,7 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
} else {
|
||||
long currentTimestamp = 0;
|
||||
try {
|
||||
currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE
|
||||
currentTimestamp = Long.parseLong(dbProperties.getProperty(DatabaseProperties.LAST_UPDATED_BASE
|
||||
+ entry.getId(), "0"));
|
||||
} catch (NumberFormatException ex) {
|
||||
LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated",
|
||||
@@ -344,20 +462,101 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
|
||||
throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
|
||||
|
||||
final UpdateableNvdCve updates = new UpdateableNvdCve();
|
||||
updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL),
|
||||
Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
|
||||
false);
|
||||
|
||||
final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
|
||||
final int end = Calendar.getInstance().get(Calendar.YEAR);
|
||||
|
||||
final Map<String, Long> lastModifiedDates = retrieveLastModifiedDates(start, end);
|
||||
|
||||
final UpdateableNvdCve updates = new UpdateableNvdCve();
|
||||
|
||||
final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
|
||||
final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
|
||||
for (int i = start; i <= end; i++) {
|
||||
updates.add(Integer.toString(i), String.format(baseUrl20, i),
|
||||
String.format(baseUrl12, i),
|
||||
true);
|
||||
final String url = String.format(baseUrl20, i);
|
||||
updates.add(Integer.toString(i), url, String.format(baseUrl12, i),
|
||||
lastModifiedDates.get(url), true);
|
||||
}
|
||||
|
||||
final String url = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
|
||||
updates.add(MODIFIED, url, Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
|
||||
lastModifiedDates.get(url), false);
|
||||
|
||||
return updates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamps from the NVD CVE meta data file.
|
||||
*
|
||||
* @param startYear the first year whose item to check for the timestamp
|
||||
* @param endYear the last year whose item to check for the timestamp
|
||||
* @return the timestamps from the currently published NVD CVE downloads
|
||||
* page
|
||||
* @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
|
||||
* is incorrect.
|
||||
* @throws DownloadFailedException thrown if there is an error downloading
|
||||
* the NVD CVE meta data file
|
||||
*/
|
||||
private Map<String, Long> retrieveLastModifiedDates(int startYear, int endYear)
|
||||
throws MalformedURLException, DownloadFailedException {
|
||||
|
||||
final Set<String> urls = new HashSet<>();
|
||||
final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
|
||||
for (int i = startYear; i <= endYear; i++) {
|
||||
final String url = String.format(baseUrl20, i);
|
||||
urls.add(url);
|
||||
}
|
||||
urls.add(Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL));
|
||||
|
||||
final Map<String, Future<Long>> timestampFutures = new HashMap<>();
|
||||
for (String url : urls) {
|
||||
final TimestampRetriever timestampRetriever = new TimestampRetriever(url);
|
||||
final Future<Long> future = downloadExecutorService.submit(timestampRetriever);
|
||||
timestampFutures.put(url, future);
|
||||
}
|
||||
|
||||
final Map<String, Long> lastModifiedDates = new HashMap<>();
|
||||
for (String url : urls) {
|
||||
final Future<Long> timestampFuture = timestampFutures.get(url);
|
||||
final long timestamp;
|
||||
try {
|
||||
timestamp = timestampFuture.get(60, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
throw new DownloadFailedException(e);
|
||||
}
|
||||
lastModifiedDates.put(url, timestamp);
|
||||
}
|
||||
|
||||
return lastModifiedDates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the last modified timestamp from a NVD CVE meta data file.
|
||||
*/
|
||||
private static class TimestampRetriever implements Callable<Long> {
|
||||
|
||||
/**
|
||||
* The URL to obtain the timestamp from.
|
||||
*/
|
||||
private final String url;
|
||||
|
||||
/**
|
||||
* Instantiates a new timestamp retriever object.
|
||||
*
|
||||
* @param url the URL to hit
|
||||
*/
|
||||
TimestampRetriever(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long call() throws Exception {
|
||||
LOGGER.debug("Checking for updates from: {}", url);
|
||||
try {
|
||||
Settings.initialize();
|
||||
return Downloader.getLastModified(new URL(url));
|
||||
} finally {
|
||||
Settings.cleanup(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* A SAX Handler that will parse the CPE XML and load it into the databse.
|
||||
* A SAX Handler that will parse the CPE XML and load it into the database.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -60,7 +60,7 @@ public class CPEHandler extends DefaultHandler {
|
||||
/**
|
||||
* The list of CPE values.
|
||||
*/
|
||||
private final List<Cpe> data = new ArrayList<Cpe>();
|
||||
private final List<Cpe> data = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns the list of CPE values.
|
||||
@@ -154,35 +154,10 @@ public class CPEHandler extends DefaultHandler {
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
current.setNode(qName);
|
||||
if (current.isSchemaVersionNode() && !CURRENT_SCHEMA_VERSION.equals(nodeText.toString())) {
|
||||
throw new SAXException("ERROR: Unexpecgted CPE Schema Version, expected: "
|
||||
throw new SAXException("ERROR: Unexpected CPE Schema Version, expected: "
|
||||
+ CURRENT_SCHEMA_VERSION + ", file is: " + nodeText);
|
||||
|
||||
}
|
||||
// } else if (current.isCpeItemNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isTitleNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isCpeListNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isMetaNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isNotesNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isNoteNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isCheckNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isGeneratorNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isProductNameNode()) {
|
||||
// //do nothing
|
||||
// } else if (current.isProductVersionNode()) {
|
||||
// //do nothing
|
||||
// else if (current.isTimestampNode()) {
|
||||
// //do nothing
|
||||
// } else {
|
||||
// throw new SAXException("ERROR STATE: Unexpected qName '" + qName + "'");
|
||||
// }
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update.cpe;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
|
||||
@@ -36,7 +37,8 @@ public class Cpe {
|
||||
*/
|
||||
public Cpe(String value) throws UnsupportedEncodingException, InvalidDataException {
|
||||
this.value = value;
|
||||
final String[] data = value.substring(7).split(":");
|
||||
final String valueWithoutPrefix = value.substring(7);
|
||||
final String[] data = StringUtils.split(valueWithoutPrefix, ':');
|
||||
if (data.length >= 2) {
|
||||
vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8");
|
||||
product = URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8");
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.owasp.dependencycheck.data.update.nvd;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
@@ -46,6 +45,30 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DownloadTask.class);
|
||||
/**
|
||||
* The CVE DB to use when processing the files.
|
||||
*/
|
||||
private final CveDB cveDB;
|
||||
/**
|
||||
* The processor service to pass the results of the download to.
|
||||
*/
|
||||
private final ExecutorService processorService;
|
||||
/**
|
||||
* The NVD CVE Meta Data.
|
||||
*/
|
||||
private NvdCveInfo nvdCveInfo;
|
||||
/**
|
||||
* A reference to the global settings object.
|
||||
*/
|
||||
private final Settings settings;
|
||||
/**
|
||||
* a file.
|
||||
*/
|
||||
private File first;
|
||||
/**
|
||||
* a file.
|
||||
*/
|
||||
private File second;
|
||||
|
||||
/**
|
||||
* Simple constructor for the callable download task.
|
||||
@@ -77,22 +100,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
this.second = file2;
|
||||
|
||||
}
|
||||
/**
|
||||
* The CVE DB to use when processing the files.
|
||||
*/
|
||||
private final CveDB cveDB;
|
||||
/**
|
||||
* The processor service to pass the results of the download to.
|
||||
*/
|
||||
private final ExecutorService processorService;
|
||||
/**
|
||||
* The NVD CVE Meta Data.
|
||||
*/
|
||||
private NvdCveInfo nvdCveInfo;
|
||||
/**
|
||||
* A reference to the global settings object.
|
||||
*/
|
||||
private final Settings settings;
|
||||
|
||||
/**
|
||||
* Get the value of nvdCveInfo.
|
||||
@@ -111,10 +118,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
public void setNvdCveInfo(NvdCveInfo nvdCveInfo) {
|
||||
this.nvdCveInfo = nvdCveInfo;
|
||||
}
|
||||
/**
|
||||
* a file.
|
||||
*/
|
||||
private File first;
|
||||
|
||||
/**
|
||||
* Get the value of first.
|
||||
@@ -133,10 +136,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
public void setFirst(File first) {
|
||||
this.first = first;
|
||||
}
|
||||
/**
|
||||
* a file.
|
||||
*/
|
||||
private File second;
|
||||
|
||||
/**
|
||||
* Get the value of second.
|
||||
@@ -224,33 +223,19 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
if (file == null || !file.isFile()) {
|
||||
return false;
|
||||
}
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(file);
|
||||
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
final byte[] buf = new byte[5];
|
||||
int read = 0;
|
||||
try {
|
||||
read = is.read(buf);
|
||||
} catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
int read;
|
||||
read = is.read(buf);
|
||||
return read == 5
|
||||
&& buf[0] == '<'
|
||||
&& (buf[1] == '?')
|
||||
&& (buf[2] == 'x' || buf[2] == 'X')
|
||||
&& (buf[3] == 'm' || buf[3] == 'M')
|
||||
&& (buf[4] == 'l' || buf[4] == 'L');
|
||||
} catch (FileNotFoundException ex) {
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Error checking if file is xml", ex);
|
||||
return false;
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Error closing stream", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class NvdCve12Handler extends DefaultHandler {
|
||||
skip = "1".equals(reject);
|
||||
if (!skip) {
|
||||
vulnerability = attributes.getValue("name");
|
||||
software = new ArrayList<VulnerableSoftware>();
|
||||
software = new ArrayList<>();
|
||||
} else {
|
||||
vulnerability = null;
|
||||
software = null;
|
||||
@@ -132,7 +132,7 @@ public class NvdCve12Handler extends DefaultHandler {
|
||||
if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
|
||||
throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
|
||||
}
|
||||
vulnerabilities = new HashMap<String, List<VulnerableSoftware>>();
|
||||
vulnerabilities = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXNotSupportedException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import static org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler.AttributeValues.*;
|
||||
|
||||
/**
|
||||
* A SAX Handler that will parse the NVD CVE XML (schema version 2.0).
|
||||
*
|
||||
@@ -48,6 +50,19 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
* the current supported schema version.
|
||||
*/
|
||||
private static final String CURRENT_SCHEMA_VERSION = "2.0";
|
||||
/**
|
||||
* a possible attribute value of the {@link AttributeValues#XML_LANG}
|
||||
* attribute
|
||||
*/
|
||||
private static final String EN = "en";
|
||||
/**
|
||||
* the prefix of the node text of a CPE
|
||||
*/
|
||||
private static final String CPE_NODE_TEXT_PREFIX = "cpe:/a:";
|
||||
/**
|
||||
* the node text of an entry marked for deletion
|
||||
*/
|
||||
private static final String REJECT_NODE_TEXT = "** REJECT **";
|
||||
/**
|
||||
* the current element.
|
||||
*/
|
||||
@@ -73,6 +88,21 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
*/
|
||||
private int totalNumberOfEntries;
|
||||
|
||||
/**
|
||||
* The total number of application entries parsed.
|
||||
*/
|
||||
private int totalNumberOfApplicationEntries;
|
||||
/**
|
||||
* the cve database.
|
||||
*/
|
||||
private CveDB cveDB;
|
||||
|
||||
/**
|
||||
* A list of CVE entries and associated VulnerableSoftware entries that
|
||||
* contain previous entries.
|
||||
*/
|
||||
private Map<String, List<VulnerableSoftware>> prevVersionVulnMap;
|
||||
|
||||
/**
|
||||
* Get the value of totalNumberOfEntries.
|
||||
*
|
||||
@@ -81,10 +111,6 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
public int getTotalNumberOfEntries() {
|
||||
return totalNumberOfEntries;
|
||||
}
|
||||
/**
|
||||
* The total number of application entries parsed.
|
||||
*/
|
||||
private int totalNumberOfApplicationEntries;
|
||||
|
||||
/**
|
||||
* Get the value of totalNumberOfApplicationEntries.
|
||||
@@ -101,30 +127,30 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
if (current.isEntryNode()) {
|
||||
hasApplicationCpe = false;
|
||||
vulnerability = new Vulnerability();
|
||||
vulnerability.setName(attributes.getValue("id"));
|
||||
vulnerability.setName(attributes.getValue(ID));
|
||||
} else if (current.isVulnProductNode()) {
|
||||
nodeText = new StringBuilder(100);
|
||||
} else if (current.isVulnReferencesNode()) {
|
||||
final String lang = attributes.getValue("xml:lang");
|
||||
if ("en".equals(lang)) {
|
||||
final String lang = attributes.getValue(XML_LANG);
|
||||
if (EN.equals(lang)) {
|
||||
reference = new Reference();
|
||||
} else {
|
||||
reference = null;
|
||||
}
|
||||
} else if (reference != null && current.isVulnReferenceNode()) {
|
||||
reference.setUrl(attributes.getValue("href"));
|
||||
reference.setUrl(attributes.getValue(HREF));
|
||||
nodeText = new StringBuilder(130);
|
||||
} else if (reference != null && current.isVulnSourceNode()) {
|
||||
nodeText = new StringBuilder(30);
|
||||
} else if (current.isVulnSummaryNode()) {
|
||||
nodeText = new StringBuilder(500);
|
||||
} else if (current.isNVDNode()) {
|
||||
final String nvdVer = attributes.getValue("nvd_xml_version");
|
||||
final String nvdVer = attributes.getValue(NVD_XML_VERSION);
|
||||
if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
|
||||
throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
|
||||
}
|
||||
} else if (current.isVulnCWENode()) {
|
||||
vulnerability.setCwe(attributes.getValue("id"));
|
||||
vulnerability.setCwe(attributes.getValue(ID));
|
||||
} else if (current.isCVSSScoreNode()) {
|
||||
nodeText = new StringBuilder(5);
|
||||
} else if (current.isCVSSAccessVectorNode()) {
|
||||
@@ -158,9 +184,7 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
totalNumberOfApplicationEntries += 1;
|
||||
try {
|
||||
saveEntry(vulnerability);
|
||||
} catch (DatabaseException ex) {
|
||||
throw new SAXException(ex);
|
||||
} catch (CorruptIndexException ex) {
|
||||
} catch (DatabaseException | CorruptIndexException ex) {
|
||||
throw new SAXException(ex);
|
||||
} catch (IOException ex) {
|
||||
throw new SAXException(ex);
|
||||
@@ -196,7 +220,7 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
nodeText = null;
|
||||
} else if (current.isVulnProductNode()) {
|
||||
final String cpe = nodeText.toString();
|
||||
if (cpe.startsWith("cpe:/a:")) {
|
||||
if (cpe.startsWith(CPE_NODE_TEXT_PREFIX)) {
|
||||
hasApplicationCpe = true;
|
||||
vulnerability.addVulnerableSoftware(cpe);
|
||||
}
|
||||
@@ -212,16 +236,12 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
nodeText = null;
|
||||
} else if (current.isVulnSummaryNode()) {
|
||||
vulnerability.setDescription(nodeText.toString());
|
||||
if (nodeText.indexOf("** REJECT **") >= 0) {
|
||||
if (nodeText.indexOf(REJECT_NODE_TEXT) >= 0) {
|
||||
hasApplicationCpe = true; //ensure we process this to delete the vuln
|
||||
}
|
||||
nodeText = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* the cve database.
|
||||
*/
|
||||
private CveDB cveDB;
|
||||
|
||||
/**
|
||||
* Sets the cveDB.
|
||||
@@ -231,15 +251,12 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
public void setCveDB(CveDB db) {
|
||||
cveDB = db;
|
||||
}
|
||||
/**
|
||||
* A list of CVE entries and associated VulnerableSoftware entries that contain previous entries.
|
||||
*/
|
||||
private Map<String, List<VulnerableSoftware>> prevVersionVulnMap;
|
||||
|
||||
/**
|
||||
* Sets the prevVersionVulnMap.
|
||||
*
|
||||
* @param map the map of vulnerable software with previous versions being vulnerable
|
||||
* @param map the map of vulnerable software with previous versions being
|
||||
* vulnerable
|
||||
*/
|
||||
public void setPrevVersionVulnMap(Map<String, List<VulnerableSoftware>> map) {
|
||||
prevVersionVulnMap = map;
|
||||
@@ -249,7 +266,8 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
* Saves a vulnerability to the CVE Database.
|
||||
*
|
||||
* @param vuln the vulnerability to store in the database
|
||||
* @throws DatabaseException thrown if there is an error writing to the database
|
||||
* @throws DatabaseException thrown if there is an error writing to the
|
||||
* database
|
||||
* @throws CorruptIndexException is thrown if the CPE Index is corrupt
|
||||
* @throws IOException thrown if there is an IOException with the CPE Index
|
||||
*/
|
||||
@@ -268,7 +286,8 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
|
||||
/**
|
||||
* A simple class to maintain information about the current element while parsing the NVD CVE XML.
|
||||
* A simple class to maintain information about the current element while
|
||||
* parsing the NVD CVE XML.
|
||||
*/
|
||||
protected static class Element {
|
||||
|
||||
@@ -491,4 +510,28 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
}
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
/**
|
||||
* A simple class to maintain information about the attribute values
|
||||
* encountered while parsing the NVD CVE XML.
|
||||
*/
|
||||
protected static class AttributeValues {
|
||||
|
||||
/**
|
||||
* An attribute in the NVD CVE Schema 2.0
|
||||
*/
|
||||
protected static final String ID = "id";
|
||||
/**
|
||||
* An attribute in the NVD CVE Schema 2.0
|
||||
*/
|
||||
protected static final String XML_LANG = "xml:lang";
|
||||
/**
|
||||
* An attribute in the NVD CVE Schema 2.0
|
||||
*/
|
||||
protected static final String HREF = "href";
|
||||
/**
|
||||
* An attribute in the NVD CVE Schema 2.0
|
||||
*/
|
||||
protected static final String NVD_XML_VERSION = "nvd_xml_version";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.owasp.dependencycheck.data.update.nvd;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
@@ -167,19 +166,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
importXML(filePair.getFirst(), filePair.getSecond());
|
||||
cveDB.commit();
|
||||
properties.save(filePair.getNvdCveInfo());
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new UpdateException(ex);
|
||||
} catch (ParserConfigurationException ex) {
|
||||
throw new UpdateException(ex);
|
||||
} catch (SAXException ex) {
|
||||
throw new UpdateException(ex);
|
||||
} catch (IOException ex) {
|
||||
throw new UpdateException(ex);
|
||||
} catch (SQLException ex) {
|
||||
throw new UpdateException(ex);
|
||||
} catch (DatabaseException ex) {
|
||||
throw new UpdateException(ex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
} catch (ParserConfigurationException | SAXException | SQLException | DatabaseException | ClassNotFoundException | IOException ex) {
|
||||
throw new UpdateException(ex);
|
||||
} finally {
|
||||
filePair.cleanup();
|
||||
|
||||
@@ -17,16 +17,10 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update.nvd;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Contains a collection of updateable NvdCveInfo objects. This is used to determine which files need to be downloaded and
|
||||
@@ -36,14 +30,10 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
|
||||
|
||||
/**
|
||||
* A reference to the logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(UpdateableNvdCve.class);
|
||||
/**
|
||||
* A collection of sources of data.
|
||||
*/
|
||||
private final Map<String, NvdCveInfo> collection = new TreeMap<String, NvdCveInfo>();
|
||||
private final Map<String, NvdCveInfo> collection = new TreeMap<>();
|
||||
|
||||
/**
|
||||
* Returns the collection of NvdCveInfo objects. This method is mainly used for testing.
|
||||
@@ -74,31 +64,16 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
|
||||
* @param id the key for the item to be added
|
||||
* @param url the URL to download the item
|
||||
* @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need).
|
||||
* @throws MalformedURLException thrown if the URL provided is invalid
|
||||
* @throws DownloadFailedException thrown if the download fails.
|
||||
*/
|
||||
public void add(String id, String url, String oldUrl) throws MalformedURLException, DownloadFailedException {
|
||||
add(id, url, oldUrl, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new entry of updateable information to the contained collection.
|
||||
*
|
||||
* @param id the key for the item to be added
|
||||
* @param url the URL to download the item
|
||||
* @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need).
|
||||
* @param timestamp the last modified date of the downloaded item
|
||||
* @param needsUpdate whether or not the data needs to be updated
|
||||
* @throws MalformedURLException thrown if the URL provided is invalid
|
||||
* @throws DownloadFailedException thrown if the download fails.
|
||||
*/
|
||||
public void add(String id, String url, String oldUrl, boolean needsUpdate) throws MalformedURLException, DownloadFailedException {
|
||||
public void add(String id, String url, String oldUrl, long timestamp, boolean needsUpdate) {
|
||||
final NvdCveInfo item = new NvdCveInfo();
|
||||
item.setNeedsUpdate(needsUpdate); //the others default to true, to make life easier later this should default to false.
|
||||
item.setId(id);
|
||||
item.setUrl(url);
|
||||
item.setOldSchemaVersionUrl(oldUrl);
|
||||
LOGGER.debug("Checking for updates from: {}", url);
|
||||
item.setTimestamp(Downloader.getLastModified(new URL(url)));
|
||||
item.setTimestamp(timestamp);
|
||||
collection.put(id, item);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,30 +73,10 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
* The file name of the dependency.
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* The package path.
|
||||
*/
|
||||
private String packagePath;
|
||||
|
||||
/**
|
||||
* Returns the package path.
|
||||
*
|
||||
* @return the package path
|
||||
*/
|
||||
public String getPackagePath() {
|
||||
return packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the package path.
|
||||
*
|
||||
* @param packagePath the package path
|
||||
*/
|
||||
public void setPackagePath(String packagePath) {
|
||||
this.packagePath = packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The md5 hash of the dependency.
|
||||
*/
|
||||
@@ -121,6 +101,60 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
* A collection of version evidence.
|
||||
*/
|
||||
private final EvidenceCollection versionEvidence;
|
||||
/**
|
||||
* The file name to display in reports.
|
||||
*/
|
||||
private String displayName = null;
|
||||
/**
|
||||
* A set of identifiers that have been suppressed.
|
||||
*/
|
||||
private Set<Identifier> suppressedIdentifiers;
|
||||
/**
|
||||
* A set of vulnerabilities that have been suppressed.
|
||||
*/
|
||||
private SortedSet<Vulnerability> suppressedVulnerabilities;
|
||||
/**
|
||||
* The description of the JAR file.
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* The license that this dependency uses.
|
||||
*/
|
||||
private String license;
|
||||
/**
|
||||
* A list of vulnerabilities for this dependency.
|
||||
*/
|
||||
private SortedSet<Vulnerability> vulnerabilities;
|
||||
/**
|
||||
* A collection of related dependencies.
|
||||
*/
|
||||
private Set<Dependency> relatedDependencies = new TreeSet<>();
|
||||
/**
|
||||
* A list of projects that reference this dependency.
|
||||
*/
|
||||
private Set<String> projectReferences = new HashSet<>();
|
||||
/**
|
||||
* A list of available versions.
|
||||
*/
|
||||
private List<String> availableVersions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns the package path.
|
||||
*
|
||||
* @return the package path
|
||||
*/
|
||||
public String getPackagePath() {
|
||||
return packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the package path.
|
||||
*
|
||||
* @param packagePath the package path
|
||||
*/
|
||||
public void setPackagePath(String packagePath) {
|
||||
this.packagePath = packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Dependency object.
|
||||
@@ -129,10 +163,10 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
vendorEvidence = new EvidenceCollection();
|
||||
productEvidence = new EvidenceCollection();
|
||||
versionEvidence = new EvidenceCollection();
|
||||
identifiers = new TreeSet<Identifier>();
|
||||
vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
|
||||
suppressedIdentifiers = new TreeSet<Identifier>();
|
||||
suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
|
||||
identifiers = new TreeSet<>();
|
||||
vulnerabilities = new TreeSet<>(new VulnerabilityComparator());
|
||||
suppressedIdentifiers = new TreeSet<>();
|
||||
suppressedVulnerabilities = new TreeSet<>(new VulnerabilityComparator());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,11 +256,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file name to display in reports.
|
||||
*/
|
||||
private String displayName = null;
|
||||
|
||||
/**
|
||||
* Sets the file name to display in reports.
|
||||
*
|
||||
@@ -392,11 +421,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
this.identifiers.add(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of identifiers that have been suppressed.
|
||||
*/
|
||||
private Set<Identifier> suppressedIdentifiers;
|
||||
|
||||
/**
|
||||
* Get the value of suppressedIdentifiers.
|
||||
*
|
||||
@@ -424,11 +448,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
this.suppressedIdentifiers.add(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of vulnerabilities that have been suppressed.
|
||||
*/
|
||||
private SortedSet<Vulnerability> suppressedVulnerabilities;
|
||||
|
||||
/**
|
||||
* Get the value of suppressedVulnerabilities.
|
||||
*
|
||||
@@ -510,11 +529,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
return this.versionEvidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of the JAR file.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Get the value of description.
|
||||
*
|
||||
@@ -533,11 +547,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The license that this dependency uses.
|
||||
*/
|
||||
private String license;
|
||||
|
||||
/**
|
||||
* Get the value of license.
|
||||
*
|
||||
@@ -556,11 +565,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of vulnerabilities for this dependency.
|
||||
*/
|
||||
private SortedSet<Vulnerability> vulnerabilities;
|
||||
|
||||
/**
|
||||
* Get the list of vulnerabilities.
|
||||
*
|
||||
@@ -594,7 +598,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
LOGGER.warn("Unable to read '{}' to determine hashes.", file.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
LOGGER.warn("Unable to use MD5 of SHA1 checksums.");
|
||||
LOGGER.warn("Unable to use MD5 or SHA1 checksums.");
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
this.setMd5sum(md5);
|
||||
@@ -610,11 +614,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
this.vulnerabilities.add(vulnerability);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of related dependencies.
|
||||
*/
|
||||
private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
|
||||
|
||||
/**
|
||||
* Get the value of {@link #relatedDependencies}. This field is used to
|
||||
* collect other dependencies which really represent the same dependency,
|
||||
@@ -626,11 +625,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
return relatedDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of projects that reference this dependency.
|
||||
*/
|
||||
private Set<String> projectReferences = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Get the value of projectReferences.
|
||||
*
|
||||
@@ -698,11 +692,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of available versions.
|
||||
*/
|
||||
private List<String> availableVersions = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Get the value of availableVersions.
|
||||
*
|
||||
|
||||
@@ -280,9 +280,9 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
if (me == null && other == null) {
|
||||
return 0;
|
||||
} else if (me == null) {
|
||||
return -1; //the other string is greater then me
|
||||
return -1; //the other string is greater than me
|
||||
} else if (other == null) {
|
||||
return 1; //me is greater then the other string
|
||||
return 1; //me is greater than the other string
|
||||
}
|
||||
return me.compareToIgnoreCase(other);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,17 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EvidenceCollection.class);
|
||||
/**
|
||||
* Used to iterate over highest confidence evidence contained in the collection.
|
||||
* A collection of evidence.
|
||||
*/
|
||||
private final Set<Evidence> list;
|
||||
/**
|
||||
* A collection of strings used to adjust Lucene's term weighting.
|
||||
*/
|
||||
private final Set<String> weightedStrings;
|
||||
|
||||
/**
|
||||
* Used to iterate over highest confidence evidence contained in the
|
||||
* collection.
|
||||
*/
|
||||
private static final Filter<Evidence> HIGHEST_CONFIDENCE = new Filter<Evidence>() {
|
||||
@Override
|
||||
@@ -57,7 +67,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Used to iterate over high confidence evidence contained in the collection.
|
||||
* Used to iterate over high confidence evidence contained in the
|
||||
* collection.
|
||||
*/
|
||||
private static final Filter<Evidence> HIGH_CONFIDENCE = new Filter<Evidence>() {
|
||||
@Override
|
||||
@@ -66,7 +77,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Used to iterate over medium confidence evidence contained in the collection.
|
||||
* Used to iterate over medium confidence evidence contained in the
|
||||
* collection.
|
||||
*/
|
||||
private static final Filter<Evidence> MEDIUM_CONFIDENCE = new Filter<Evidence>() {
|
||||
@Override
|
||||
@@ -84,7 +96,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Used to iterate over evidence that has was used (aka read) from the collection.
|
||||
* Used to iterate over evidence that has was used (aka read) from the
|
||||
* collection.
|
||||
*/
|
||||
private static final Filter<Evidence> EVIDENCE_USED = new Filter<Evidence>() {
|
||||
@Override
|
||||
@@ -96,35 +109,32 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
/**
|
||||
* Used to iterate over evidence of the specified confidence.
|
||||
*
|
||||
* @param confidence the confidence level for the evidence to be iterated over.
|
||||
* @param confidence the confidence level for the evidence to be iterated
|
||||
* over.
|
||||
* @return Iterable<Evidence> an iterable collection of evidence
|
||||
*/
|
||||
public final Iterable<Evidence> iterator(Confidence confidence) {
|
||||
if (confidence == Confidence.HIGHEST) {
|
||||
return EvidenceCollection.HIGHEST_CONFIDENCE.filter(this.list);
|
||||
} else if (confidence == Confidence.HIGH) {
|
||||
return EvidenceCollection.HIGH_CONFIDENCE.filter(this.list);
|
||||
} else if (confidence == Confidence.MEDIUM) {
|
||||
return EvidenceCollection.MEDIUM_CONFIDENCE.filter(this.list);
|
||||
} else {
|
||||
return EvidenceCollection.LOW_CONFIDENCE.filter(this.list);
|
||||
if (null != confidence) {
|
||||
switch (confidence) {
|
||||
case HIGHEST:
|
||||
return EvidenceCollection.HIGHEST_CONFIDENCE.filter(this.list);
|
||||
case HIGH:
|
||||
return EvidenceCollection.HIGH_CONFIDENCE.filter(this.list);
|
||||
case MEDIUM:
|
||||
return EvidenceCollection.MEDIUM_CONFIDENCE.filter(this.list);
|
||||
default:
|
||||
return EvidenceCollection.LOW_CONFIDENCE.filter(this.list);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* A collection of evidence.
|
||||
*/
|
||||
private final Set<Evidence> list;
|
||||
/**
|
||||
* A collection of strings used to adjust Lucene's term weighting.
|
||||
*/
|
||||
private final Set<String> weightedStrings;
|
||||
|
||||
/**
|
||||
* Creates a new EvidenceCollection.
|
||||
*/
|
||||
public EvidenceCollection() {
|
||||
list = new TreeSet<Evidence>();
|
||||
weightedStrings = new HashSet<String>();
|
||||
list = new TreeSet<>();
|
||||
weightedStrings = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +147,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Evidence object from the parameters and adds the resulting object to the collection.
|
||||
* Creates an Evidence object from the parameters and adds the resulting
|
||||
* object to the collection.
|
||||
*
|
||||
* @param source the source of the Evidence.
|
||||
* @param name the name of the Evidence.
|
||||
@@ -150,12 +161,16 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds term to the weighting collection. The terms added here are used later to boost the score of other terms. This is a way
|
||||
* of combining evidence from multiple sources to boost the confidence of the given evidence.
|
||||
* Adds term to the weighting collection. The terms added here are used
|
||||
* later to boost the score of other terms. This is a way of combining
|
||||
* evidence from multiple sources to boost the confidence of the given
|
||||
* evidence.
|
||||
*
|
||||
* Example: The term 'Apache' is found in the manifest of a JAR and is added to the Collection. When we parse the package
|
||||
* names within the JAR file we may add these package names to the "weighted" strings collection to boost the score in the
|
||||
* Lucene query. That way when we construct the Lucene query we find the term Apache in the collection AND in the weighted
|
||||
* Example: The term 'Apache' is found in the manifest of a JAR and is added
|
||||
* to the Collection. When we parse the package names within the JAR file we
|
||||
* may add these package names to the "weighted" strings collection to boost
|
||||
* the score in the Lucene query. That way when we construct the Lucene
|
||||
* query we find the term Apache in the collection AND in the weighted
|
||||
* strings; as such, we will boost the confidence of the term Apache.
|
||||
*
|
||||
* @param str to add to the weighting collection.
|
||||
@@ -165,8 +180,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of Weightings - a list of terms that are believed to be of higher confidence when also found in another
|
||||
* location.
|
||||
* Returns a set of Weightings - a list of terms that are believed to be of
|
||||
* higher confidence when also found in another location.
|
||||
*
|
||||
* @return Set<String>
|
||||
*/
|
||||
@@ -193,7 +208,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
final Set<Evidence> ret = new HashSet<Evidence>();
|
||||
final Set<Evidence> ret = new HashSet<>();
|
||||
for (Evidence e : list) {
|
||||
if (source.equals(e.getSource())) {
|
||||
ret.add(e);
|
||||
@@ -213,7 +228,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
if (source == null || name == null) {
|
||||
return null;
|
||||
}
|
||||
final Set<Evidence> ret = new HashSet<Evidence>();
|
||||
final Set<Evidence> ret = new HashSet<>();
|
||||
for (Evidence e : list) {
|
||||
if (source.equals(e.getSource()) && name.equals(e.getName())) {
|
||||
ret.add(e);
|
||||
@@ -255,7 +270,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine if a given version was used (aka read) from the EvidenceCollection.
|
||||
* Used to determine if a given version was used (aka read) from the
|
||||
* EvidenceCollection.
|
||||
*
|
||||
* @param version the version to search for within the collected evidence.
|
||||
* @return whether or not the string was used.
|
||||
@@ -275,7 +291,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the collection contains evidence of a specified Confidence.
|
||||
* Returns whether or not the collection contains evidence of a specified
|
||||
* Confidence.
|
||||
*
|
||||
* @param confidence A Confidence value.
|
||||
* @return boolean.
|
||||
@@ -290,7 +307,8 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple EvidenceCollections together, only merging evidence that was used, into a new EvidenceCollection.
|
||||
* Merges multiple EvidenceCollections together, only merging evidence that
|
||||
* was used, into a new EvidenceCollection.
|
||||
*
|
||||
* @param ec One or more EvidenceCollections.
|
||||
* @return a new EvidenceCollection containing the used evidence.
|
||||
@@ -323,13 +341,15 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple EvidenceCollections together; flattening all of the evidence items by removing the confidence.
|
||||
* Merges multiple EvidenceCollections together; flattening all of the
|
||||
* evidence items by removing the confidence.
|
||||
*
|
||||
* @param ec One or more EvidenceCollections
|
||||
* @return new set of evidence resulting from merging the evidence in the collections
|
||||
* @return new set of evidence resulting from merging the evidence in the
|
||||
* collections
|
||||
*/
|
||||
public static Set<Evidence> mergeForDisplay(EvidenceCollection... ec) {
|
||||
final Set<Evidence> ret = new TreeSet<Evidence>();
|
||||
final Set<Evidence> ret = new TreeSet<>();
|
||||
for (EvidenceCollection col : ec) {
|
||||
for (Evidence e : col) {
|
||||
//if (e.isUsed()) {
|
||||
@@ -367,18 +387,20 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Takes a string that may contain a fully qualified domain and it will return the string having removed the query string, the
|
||||
* protocol, the sub-domain of 'www', and the file extension of the path.</p>
|
||||
* Takes a string that may contain a fully qualified domain and it will
|
||||
* return the string having removed the query string, the protocol, the
|
||||
* sub-domain of 'www', and the file extension of the path.</p>
|
||||
* <p>
|
||||
* This is useful for checking if the evidence contains a specific string. The presence of the protocol, file extension, etc.
|
||||
* may produce false positives.
|
||||
* This is useful for checking if the evidence contains a specific string.
|
||||
* The presence of the protocol, file extension, etc. may produce false
|
||||
* positives.
|
||||
*
|
||||
* <p>
|
||||
* Example, given the following input:</p>
|
||||
* <code>'Please visit https://www.somedomain.com/path1/path2/file.php?id=439'</code>
|
||||
* <code>'Please visit https://www.owasp.com/path1/path2/file.php?id=439'</code>
|
||||
* <p>
|
||||
* The function would return:</p>
|
||||
* <code>'Please visit somedomain path1 path2 file'</code>
|
||||
* <code>'Please visit owasp path1 path2 file'</code>
|
||||
*
|
||||
* @param value the value that may contain a url
|
||||
* @return the modified string
|
||||
|
||||
@@ -20,21 +20,161 @@ package org.owasp.dependencycheck.dependency;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* In identifier such as a CPE or dependency coordinates (i.e. GAV).
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="fields">
|
||||
/**
|
||||
* The serial version UID for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* The confidence that this is the correct identifier.
|
||||
*/
|
||||
private Confidence confidence;
|
||||
/**
|
||||
* The value of the identifier
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* The url for the identifier.
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* The type of the identifier.
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* A description of the identifier.
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* Notes about the vulnerability. Generally used for suppression
|
||||
* information.
|
||||
*/
|
||||
private String notes;
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="getters/setters">
|
||||
/**
|
||||
* Get the value of confidence.
|
||||
*
|
||||
* @return the value of confidence
|
||||
*/
|
||||
public Confidence getConfidence() {
|
||||
return confidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor. Should only be used for automatic class
|
||||
* creation as is the case with many XML parsers (for the parsing
|
||||
* of the Dependency-Check XML report). For all other use-cases,
|
||||
* please use the non-default constructors.
|
||||
* Set the value of confidence.
|
||||
*
|
||||
* @param confidence new value of confidence
|
||||
*/
|
||||
public void setConfidence(Confidence confidence) {
|
||||
this.confidence = confidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of value.
|
||||
*
|
||||
* @return the value of value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of value.
|
||||
*
|
||||
* @param value new value of value
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of url.
|
||||
*
|
||||
* @return the value of url
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of url.
|
||||
*
|
||||
* @param url new value of url
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of type.
|
||||
*
|
||||
* @return the value of type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Set the value of type.</p><p>
|
||||
* Example would be "CPE".</p>
|
||||
*
|
||||
* @param type new value of type
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of description.
|
||||
*
|
||||
* @return the value of description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of description.
|
||||
*
|
||||
* @param description new value of description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of notes from suppression notes.
|
||||
*
|
||||
* @return the value of notes
|
||||
*/
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of notes.
|
||||
*
|
||||
* @param notes new value of notes
|
||||
*/
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Default constructor. Should only be used for automatic class creation as
|
||||
* is the case with many XML parsers (for the parsing of the
|
||||
* Dependency-Check XML report). For all other use-cases, please use the
|
||||
* non-default constructors.
|
||||
*/
|
||||
public Identifier() {
|
||||
}
|
||||
@@ -65,120 +205,6 @@ public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The confidence that this is the correct identifier.
|
||||
*/
|
||||
private Confidence confidence;
|
||||
|
||||
/**
|
||||
* Get the value of confidence.
|
||||
*
|
||||
* @return the value of confidence
|
||||
*/
|
||||
public Confidence getConfidence() {
|
||||
return confidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of confidence.
|
||||
*
|
||||
* @param confidence new value of confidence
|
||||
*/
|
||||
public void setConfidence(Confidence confidence) {
|
||||
this.confidence = confidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of the identifier
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Get the value of value.
|
||||
*
|
||||
* @return the value of value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of value.
|
||||
*
|
||||
* @param value new value of value
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
/**
|
||||
* The url for the identifier.
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* Get the value of url.
|
||||
*
|
||||
* @return the value of url
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of url.
|
||||
*
|
||||
* @param url new value of url
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
/**
|
||||
* The type of the identifier.
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* Get the value of type.
|
||||
*
|
||||
* @return the value of type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Set the value of type.</p><p>
|
||||
* Example would be "CPE".</p>
|
||||
*
|
||||
* @param type new value of type
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
/**
|
||||
* A description of the identifier.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Get the value of description.
|
||||
*
|
||||
* @return the value of description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of description.
|
||||
*
|
||||
* @param description new value of description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
@@ -191,10 +217,7 @@ public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
if ((this.value == null) ? (other.value != null) : !this.value.equals(other.value)) {
|
||||
return false;
|
||||
}
|
||||
if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !((this.type == null) ? (other.type != null) : !this.type.equals(other.type));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -216,7 +239,8 @@ public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the comparator interface. This compares the value of the identifier only.
|
||||
* Implementation of the comparator interface. This compares the value of
|
||||
* the identifier only.
|
||||
*
|
||||
* @param o the object being compared
|
||||
* @return an integer indicating the ordering
|
||||
|
||||
@@ -119,10 +119,7 @@ public class Reference implements Serializable, Comparable<Reference> {
|
||||
if ((this.url == null) ? (other.url != null) : !this.url.equals(other.url)) {
|
||||
return false;
|
||||
}
|
||||
if ((this.source == null) ? (other.source != null) : !this.source.equals(other.source)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !((this.source == null) ? (other.source != null) : !this.source.equals(other.source));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
|
||||
/**
|
||||
@@ -34,11 +36,69 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
* The serial version uid.
|
||||
*/
|
||||
private static final long serialVersionUID = 307319490326651052L;
|
||||
|
||||
/**
|
||||
* The name of the vulnerability.
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* the description of the vulnerability.
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* References for this vulnerability.
|
||||
*/
|
||||
private Set<Reference> references = new HashSet<>();
|
||||
/**
|
||||
* A set of vulnerable software.
|
||||
*/
|
||||
private Set<VulnerableSoftware> vulnerableSoftware = new HashSet<>();
|
||||
/**
|
||||
* The CWE for the vulnerability.
|
||||
*/
|
||||
private String cwe;
|
||||
/**
|
||||
* CVSS Score.
|
||||
*/
|
||||
private float cvssScore;
|
||||
/**
|
||||
* CVSS Access Vector.
|
||||
*/
|
||||
private String cvssAccessVector;
|
||||
/**
|
||||
* CVSS Access Complexity.
|
||||
*/
|
||||
private String cvssAccessComplexity;
|
||||
|
||||
/**
|
||||
* CVSS Authentication.
|
||||
*/
|
||||
private String cvssAuthentication;
|
||||
/**
|
||||
* CVSS Confidentiality Impact.
|
||||
*/
|
||||
private String cvssConfidentialityImpact;
|
||||
/**
|
||||
* CVSS Integrity Impact.
|
||||
*/
|
||||
private String cvssIntegrityImpact;
|
||||
|
||||
/**
|
||||
* CVSS Availability Impact.
|
||||
*/
|
||||
private String cvssAvailabilityImpact;
|
||||
/**
|
||||
* The CPE id that caused this vulnerability to be flagged.
|
||||
*/
|
||||
private String matchedCPE;
|
||||
/**
|
||||
* Whether or not all previous versions were affected.
|
||||
*/
|
||||
private String matchedAllPreviousCPE;
|
||||
/**
|
||||
* Notes about the vulnerability. Generally used for suppression
|
||||
* information.
|
||||
*/
|
||||
private String notes;
|
||||
|
||||
/**
|
||||
* Get the value of name.
|
||||
@@ -57,10 +117,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* the description of the vulnerability.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Get the value of description.
|
||||
@@ -79,10 +135,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
/**
|
||||
* References for this vulnerability.
|
||||
*/
|
||||
private SortedSet<Reference> references = new TreeSet<Reference>();
|
||||
|
||||
/**
|
||||
* Get the value of references.
|
||||
@@ -93,12 +145,27 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
return references;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of references. This is primarily used within the
|
||||
* generated reports.
|
||||
*
|
||||
* @param sorted whether the returned list should be sorted
|
||||
* @return the list of references
|
||||
*/
|
||||
public List<Reference> getReferences(boolean sorted) {
|
||||
final List<Reference> sortedRefs = new ArrayList<>(this.references);
|
||||
if (sorted) {
|
||||
Collections.sort(sortedRefs);
|
||||
}
|
||||
return sortedRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of references.
|
||||
*
|
||||
* @param references new value of references
|
||||
*/
|
||||
public void setReferences(SortedSet<Reference> references) {
|
||||
public void setReferences(Set<Reference> references) {
|
||||
this.references = references;
|
||||
}
|
||||
|
||||
@@ -125,10 +192,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
ref.setUrl(referenceUrl);
|
||||
this.references.add(ref);
|
||||
}
|
||||
/**
|
||||
* A set of vulnerable software.
|
||||
*/
|
||||
private SortedSet<VulnerableSoftware> vulnerableSoftware = new TreeSet<VulnerableSoftware>();
|
||||
|
||||
/**
|
||||
* Get the value of vulnerableSoftware.
|
||||
@@ -139,12 +202,27 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
return vulnerableSoftware;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of vulnerable software. This is primarily used for
|
||||
* display within reports.
|
||||
*
|
||||
* @param sorted whether or not the list should be sorted
|
||||
* @return the list of vulnerable software
|
||||
*/
|
||||
public List<VulnerableSoftware> getVulnerableSoftware(boolean sorted) {
|
||||
final List<VulnerableSoftware> sortedVulnerableSoftware = new ArrayList<>(this.vulnerableSoftware);
|
||||
if (sorted) {
|
||||
Collections.sort(sortedVulnerableSoftware);
|
||||
}
|
||||
return sortedVulnerableSoftware;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of vulnerableSoftware.
|
||||
*
|
||||
* @param vulnerableSoftware new value of vulnerableSoftware
|
||||
*/
|
||||
public void setVulnerableSoftware(SortedSet<VulnerableSoftware> vulnerableSoftware) {
|
||||
public void setVulnerableSoftware(Set<VulnerableSoftware> vulnerableSoftware) {
|
||||
this.vulnerableSoftware = vulnerableSoftware;
|
||||
}
|
||||
|
||||
@@ -152,10 +230,9 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
* Adds an entry for vulnerable software.
|
||||
*
|
||||
* @param cpe string representation of a CPE entry
|
||||
* @return if the add succeeded
|
||||
*/
|
||||
public boolean addVulnerableSoftware(String cpe) {
|
||||
return addVulnerableSoftware(cpe, null);
|
||||
public void addVulnerableSoftware(String cpe) {
|
||||
addVulnerableSoftware(cpe, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,33 +241,27 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
* @param cpe string representation of a cpe
|
||||
* @param previousVersion the previous version (previousVersion - cpe would
|
||||
* be considered vulnerable)
|
||||
* @return if the add succeeded
|
||||
*/
|
||||
public boolean addVulnerableSoftware(String cpe, String previousVersion) {
|
||||
public void addVulnerableSoftware(String cpe, String previousVersion) {
|
||||
final VulnerableSoftware vs = new VulnerableSoftware();
|
||||
vs.setCpe(cpe);
|
||||
if (previousVersion != null) {
|
||||
vs.setPreviousVersion(previousVersion);
|
||||
}
|
||||
return updateVulnerableSoftware(vs);
|
||||
updateVulnerableSoftware(vs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a vulnerable software entry.
|
||||
*
|
||||
* @param vulnSoftware the vulnerable software
|
||||
* @return if the update succeeded
|
||||
*/
|
||||
public boolean updateVulnerableSoftware(VulnerableSoftware vulnSoftware) {
|
||||
public void updateVulnerableSoftware(VulnerableSoftware vulnSoftware) {
|
||||
if (vulnerableSoftware.contains(vulnSoftware)) {
|
||||
vulnerableSoftware.remove(vulnSoftware);
|
||||
}
|
||||
return vulnerableSoftware.add(vulnSoftware);
|
||||
vulnerableSoftware.add(vulnSoftware);
|
||||
}
|
||||
/**
|
||||
* The CWE for the vulnerability.
|
||||
*/
|
||||
private String cwe;
|
||||
|
||||
/**
|
||||
* Get the value of cwe.
|
||||
@@ -209,10 +280,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setCwe(String cwe) {
|
||||
this.cwe = cwe;
|
||||
}
|
||||
/**
|
||||
* CVSS Score.
|
||||
*/
|
||||
private float cvssScore;
|
||||
|
||||
/**
|
||||
* Get the value of cvssScore.
|
||||
@@ -231,10 +298,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setCvssScore(float cvssScore) {
|
||||
this.cvssScore = cvssScore;
|
||||
}
|
||||
/**
|
||||
* CVSS Access Vector.
|
||||
*/
|
||||
private String cvssAccessVector;
|
||||
|
||||
/**
|
||||
* Get the value of cvssAccessVector.
|
||||
@@ -253,10 +316,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setCvssAccessVector(String cvssAccessVector) {
|
||||
this.cvssAccessVector = cvssAccessVector;
|
||||
}
|
||||
/**
|
||||
* CVSS Access Complexity.
|
||||
*/
|
||||
private String cvssAccessComplexity;
|
||||
|
||||
/**
|
||||
* Get the value of cvssAccessComplexity.
|
||||
@@ -275,10 +334,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setCvssAccessComplexity(String cvssAccessComplexity) {
|
||||
this.cvssAccessComplexity = cvssAccessComplexity;
|
||||
}
|
||||
/**
|
||||
* CVSS Authentication.
|
||||
*/
|
||||
private String cvssAuthentication;
|
||||
|
||||
/**
|
||||
* Get the value of cvssAuthentication.
|
||||
@@ -297,10 +352,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setCvssAuthentication(String cvssAuthentication) {
|
||||
this.cvssAuthentication = cvssAuthentication;
|
||||
}
|
||||
/**
|
||||
* CVSS Confidentiality Impact.
|
||||
*/
|
||||
private String cvssConfidentialityImpact;
|
||||
|
||||
/**
|
||||
* Get the value of cvssConfidentialityImpact.
|
||||
@@ -319,10 +370,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setCvssConfidentialityImpact(String cvssConfidentialityImpact) {
|
||||
this.cvssConfidentialityImpact = cvssConfidentialityImpact;
|
||||
}
|
||||
/**
|
||||
* CVSS Integrity Impact.
|
||||
*/
|
||||
private String cvssIntegrityImpact;
|
||||
|
||||
/**
|
||||
* Get the value of cvssIntegrityImpact.
|
||||
@@ -341,10 +388,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
public void setCvssIntegrityImpact(String cvssIntegrityImpact) {
|
||||
this.cvssIntegrityImpact = cvssIntegrityImpact;
|
||||
}
|
||||
/**
|
||||
* CVSS Availability Impact.
|
||||
*/
|
||||
private String cvssAvailabilityImpact;
|
||||
|
||||
/**
|
||||
* Get the value of cvssAvailabilityImpact.
|
||||
@@ -364,6 +407,24 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
this.cvssAvailabilityImpact = cvssAvailabilityImpact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of notes from suppression notes.
|
||||
*
|
||||
* @return the value of notes
|
||||
*/
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of notes.
|
||||
*
|
||||
* @param notes new value of cwe
|
||||
*/
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
@@ -373,10 +434,7 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
return false;
|
||||
}
|
||||
final Vulnerability other = (Vulnerability) obj;
|
||||
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !((this.name == null) ? (other.name != null) : !this.name.equals(other.name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -391,13 +449,14 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
final StringBuilder sb = new StringBuilder("Vulnerability ");
|
||||
sb.append(this.name);
|
||||
sb.append("\nReferences:\n");
|
||||
for (Reference reference : this.references) {
|
||||
for (Reference reference : getReferences(true)) {
|
||||
sb.append("=> ");
|
||||
sb.append(reference);
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append("\nSoftware:\n");
|
||||
for (VulnerableSoftware software : this.vulnerableSoftware) {
|
||||
|
||||
for (VulnerableSoftware software : getVulnerableSoftware(true)) {
|
||||
sb.append("=> ");
|
||||
sb.append(software);
|
||||
sb.append("\n");
|
||||
@@ -417,18 +476,8 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||
return new CompareToBuilder()
|
||||
.append(this.name, v.name)
|
||||
.toComparison();
|
||||
//return v.getName().compareTo(this.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* The CPE id that caused this vulnerability to be flagged.
|
||||
*/
|
||||
private String matchedCPE;
|
||||
/**
|
||||
* Whether or not all previous versions were affected.
|
||||
*/
|
||||
private String matchedAllPreviousCPE;
|
||||
|
||||
/**
|
||||
* Sets the CPE that caused this vulnerability to be flagged.
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.dependency;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -73,7 +74,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
public void parseName(String cpeName) throws UnsupportedEncodingException {
|
||||
this.name = cpeName;
|
||||
if (cpeName != null && cpeName.length() > 7) {
|
||||
final String[] data = cpeName.substring(7).split(":");
|
||||
final String cpeNameWithoutPrefix = cpeName.substring(7);
|
||||
final String[] data = StringUtils.split(cpeNameWithoutPrefix, ':');
|
||||
if (data.length >= 1) {
|
||||
this.setVendor(urlDecode(data[0]));
|
||||
}
|
||||
@@ -138,10 +140,7 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
return false;
|
||||
}
|
||||
final VulnerableSoftware other = (VulnerableSoftware) obj;
|
||||
if ((this.name == null) ? (other.getName() != null) : !this.name.equals(other.getName())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !((this.name == null) ? (other.getName() != null) : !this.name.equals(other.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,8 +174,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
@Override
|
||||
public int compareTo(VulnerableSoftware vs) {
|
||||
int result = 0;
|
||||
final String[] left = this.name.split(":");
|
||||
final String[] right = vs.getName().split(":");
|
||||
final String[] left = StringUtils.split(this.name, ':');
|
||||
final String[] right = StringUtils.split(vs.getName(), ':');
|
||||
final int max = (left.length <= right.length) ? left.length : right.length;
|
||||
if (max > 0) {
|
||||
for (int i = 0; result == 0 && i < max; i++) {
|
||||
@@ -233,7 +232,7 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
* @param str the string to test
|
||||
* @return true if the string only contains 0-9, otherwise false.
|
||||
*/
|
||||
static boolean isPositiveInteger(final String str) {
|
||||
protected static boolean isPositiveInteger(final String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2017 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.exception;
|
||||
|
||||
/**
|
||||
* An exception used when a dependency could not be found.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class DependencyNotFoundException extends Exception {
|
||||
|
||||
/**
|
||||
* The serial version uid.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new DependencyNotFoundException.
|
||||
*/
|
||||
public DependencyNotFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DependencyNotFoundException.
|
||||
*
|
||||
* @param msg a message for the exception.
|
||||
*/
|
||||
public DependencyNotFoundException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DependencyNotFoundException.
|
||||
*
|
||||
* @param ex the cause of the exception.
|
||||
*/
|
||||
public DependencyNotFoundException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DependencyNotFoundException.
|
||||
*
|
||||
* @param msg a message for the exception.
|
||||
* @param ex the cause of the exception.
|
||||
*/
|
||||
public DependencyNotFoundException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,19 @@ import java.util.List;
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class ExceptionCollection extends Exception {
|
||||
/**
|
||||
* The serial version uid.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* A collection of exceptions.
|
||||
*/
|
||||
private final List<Throwable> exceptions;
|
||||
/**
|
||||
* Flag indicating if a fatal exception occurred that would prevent the
|
||||
* attempt at completing the analysis even if exceptions occurred.
|
||||
*/
|
||||
private boolean fatal = false;
|
||||
|
||||
/**
|
||||
* Instantiates a new exception collection.
|
||||
@@ -86,7 +99,7 @@ public class ExceptionCollection extends Exception {
|
||||
*/
|
||||
public ExceptionCollection(Throwable exceptions, boolean fatal) {
|
||||
super();
|
||||
this.exceptions = new ArrayList<Throwable>();
|
||||
this.exceptions = new ArrayList<>();
|
||||
this.exceptions.add(exceptions);
|
||||
this.fatal = fatal;
|
||||
}
|
||||
@@ -99,7 +112,7 @@ public class ExceptionCollection extends Exception {
|
||||
*/
|
||||
public ExceptionCollection(String msg, Throwable exception) {
|
||||
super(msg);
|
||||
this.exceptions = new ArrayList<Throwable>();
|
||||
this.exceptions = new ArrayList<>();
|
||||
this.exceptions.add(exception);
|
||||
this.fatal = false;
|
||||
}
|
||||
@@ -109,17 +122,8 @@ public class ExceptionCollection extends Exception {
|
||||
*/
|
||||
public ExceptionCollection() {
|
||||
super();
|
||||
this.exceptions = new ArrayList<Throwable>();
|
||||
this.exceptions = new ArrayList<>();
|
||||
}
|
||||
/**
|
||||
* The serial version uid.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* A collection of exceptions.
|
||||
*/
|
||||
private List<Throwable> exceptions;
|
||||
|
||||
/**
|
||||
* Get the value of exceptions.
|
||||
@@ -150,12 +154,6 @@ public class ExceptionCollection extends Exception {
|
||||
this.fatal = fatal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag indicating if a fatal exception occurred that would prevent the
|
||||
* attempt at completing the analysis even if exceptions occurred.
|
||||
*/
|
||||
private boolean fatal = false;
|
||||
|
||||
/**
|
||||
* Get the value of fatal.
|
||||
*
|
||||
|
||||
@@ -19,13 +19,16 @@ package org.owasp.dependencycheck.reporting;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* An extremely simple wrapper around various escape utils to perform URL and HTML encoding within the reports. This class was
|
||||
* created to simplify the velocity configuration and avoid using the "built-in" escape tool.
|
||||
* An extremely simple wrapper around various escape utils to perform URL and
|
||||
* HTML encoding within the reports. This class was created to simplify the
|
||||
* velocity configuration and avoid using the "built-in" escape tool.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -80,4 +83,84 @@ public class EscapeTool {
|
||||
}
|
||||
return StringEscapeUtils.escapeXml11(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Encodes the provided text.
|
||||
*
|
||||
* @param text the text to encode
|
||||
* @return the JSON encoded text
|
||||
*/
|
||||
public String json(String text) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
return StringEscapeUtils.escapeJson(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats text for CSV format. This includes trimming whitespace, replace
|
||||
* line breaks with spaces, and if necessary quotes the text and/or escapes
|
||||
* contained quotes.
|
||||
*
|
||||
* @param text the text to escape and quote
|
||||
* @return the escaped and quoted text
|
||||
*/
|
||||
public String csv(String text) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
return StringEscapeUtils.escapeCsv(text.trim().replace("\n", " "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a set of Identifiers, filters them to none CPE, and formats them
|
||||
* for display in a CSV.
|
||||
*
|
||||
* @param ids the set of identifiers
|
||||
* @return the formated list of none CPE identifiers
|
||||
*/
|
||||
public String csvIdentifiers(Set<Identifier> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
boolean addComma = false;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Identifier id : ids) {
|
||||
if (!"cpe".equals(id.getType())) {
|
||||
if (addComma) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
addComma = true;
|
||||
}
|
||||
sb.append(id.getValue());
|
||||
}
|
||||
}
|
||||
return StringEscapeUtils.escapeCsv(sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a set of Identifiers, filters them to just CPEs, and formats them
|
||||
* for display in a CSV.
|
||||
*
|
||||
* @param ids the set of identifiers
|
||||
* @return the formated list of CPE identifiers
|
||||
*/
|
||||
public String csvCpe(Set<Identifier> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
boolean addComma = false;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Identifier id : ids) {
|
||||
if ("cpe".equals(id.getType())) {
|
||||
if (addComma) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
addComma = true;
|
||||
}
|
||||
sb.append(id.getValue());
|
||||
}
|
||||
}
|
||||
return StringEscapeUtils.escapeCsv(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,16 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.reporting;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import static com.google.gson.stream.JsonToken.*;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
import org.apache.velocity.app.VelocityEngine;
|
||||
import org.apache.velocity.context.Context;
|
||||
@@ -78,7 +77,15 @@ public class ReportGenerator {
|
||||
/**
|
||||
* Generate HTML Vulnerability report.
|
||||
*/
|
||||
VULN
|
||||
VULN,
|
||||
/**
|
||||
* Generate JSON report.
|
||||
*/
|
||||
JSON,
|
||||
/**
|
||||
* Generate CSV report.
|
||||
*/
|
||||
CSV
|
||||
}
|
||||
/**
|
||||
* The Velocity Engine.
|
||||
@@ -100,29 +107,35 @@ public class ReportGenerator {
|
||||
*/
|
||||
public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
||||
velocityEngine = createVelocityEngine();
|
||||
context = createContext();
|
||||
|
||||
velocityEngine.init();
|
||||
final EscapeTool enc = new EscapeTool();
|
||||
context = createContext(applicationName, dependencies, analyzers, properties);
|
||||
}
|
||||
|
||||
final DateTime dt = new DateTime();
|
||||
final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("MMM d, yyyy 'at' HH:mm:ss z");
|
||||
final DateTimeFormatter dateFormatXML = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
/**
|
||||
* Constructs a new ReportGenerator.
|
||||
*
|
||||
* @param applicationName the application name being analyzed
|
||||
* @param groupID the group id of the project being analyzed
|
||||
* @param artifactID the application id of the project being analyzed
|
||||
* @param version the application version of the project being analyzed
|
||||
* @param dependencies the list of dependencies
|
||||
* @param analyzers the list of analyzers used
|
||||
* @param properties the database properties (containing timestamps of the
|
||||
* NVD CVE data)
|
||||
*/
|
||||
public ReportGenerator(String applicationName, String groupID, String artifactID, String version,
|
||||
List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
||||
|
||||
// final Date d = new Date();
|
||||
// final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z");
|
||||
// final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
final String scanDate = dateFormat.print(dt);
|
||||
final String scanDateXML = dateFormatXML.print(dt);
|
||||
|
||||
context.put("applicationName", applicationName);
|
||||
context.put("dependencies", dependencies);
|
||||
context.put("analyzers", analyzers);
|
||||
context.put("properties", properties);
|
||||
context.put("scanDate", scanDate);
|
||||
context.put("scanDateXML", scanDateXML);
|
||||
context.put("enc", enc);
|
||||
context.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
||||
this(applicationName, dependencies, analyzers, properties);
|
||||
if (version != null) {
|
||||
context.put("applicationVersion", version);
|
||||
}
|
||||
if (artifactID != null) {
|
||||
context.put("artifactID", artifactID);
|
||||
}
|
||||
if (groupID != null) {
|
||||
context.put("groupID", groupID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,94 +151,162 @@ public class ReportGenerator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Velocity Context.
|
||||
* Constructs the velocity context used to generate the dependency-check
|
||||
* reports.
|
||||
*
|
||||
* @return a Velocity Context
|
||||
* @param applicationName the application name being analyzed
|
||||
* @param dependencies the list of dependencies
|
||||
* @param analyzers the list of analyzers used
|
||||
* @param properties the database properties (containing timestamps of the
|
||||
* NVD CVE data)
|
||||
* @return the velocity context
|
||||
*/
|
||||
private Context createContext() {
|
||||
return new VelocityContext();
|
||||
private VelocityContext createContext(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
||||
final DateTime dt = new DateTime();
|
||||
final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("MMM d, yyyy 'at' HH:mm:ss z");
|
||||
final DateTimeFormatter dateFormatXML = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
|
||||
final String scanDate = dateFormat.print(dt);
|
||||
final String scanDateXML = dateFormatXML.print(dt);
|
||||
|
||||
VelocityContext ctxt = new VelocityContext();
|
||||
ctxt.put("applicationName", applicationName);
|
||||
ctxt.put("dependencies", dependencies);
|
||||
ctxt.put("analyzers", analyzers);
|
||||
ctxt.put("properties", properties);
|
||||
ctxt.put("scanDate", scanDate);
|
||||
ctxt.put("scanDateXML", scanDateXML);
|
||||
ctxt.put("enc", new EscapeTool());
|
||||
ctxt.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
||||
return ctxt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency Reports for the identified dependencies.
|
||||
* Writes the dependency-check report to the given output location.
|
||||
*
|
||||
* @param outputStream the OutputStream to send the generated report to
|
||||
* @param format the format the report should be written in
|
||||
* @throws IOException is thrown when the template file does not exist
|
||||
* @throws Exception is thrown if there is an error writing out the reports
|
||||
*/
|
||||
public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
|
||||
if (format == Format.XML || format == Format.ALL) {
|
||||
generateReport("XmlReport", outputStream);
|
||||
}
|
||||
if (format == Format.HTML || format == Format.ALL) {
|
||||
generateReport("HtmlReport", outputStream);
|
||||
}
|
||||
if (format == Format.VULN || format == Format.ALL) {
|
||||
generateReport("VulnerabilityReport", outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency Reports for the identified dependencies.
|
||||
*
|
||||
* @param outputDir the path where the reports should be written
|
||||
* @param format the format the report should be written in
|
||||
* @throws ReportException is thrown if there is an error writing out the
|
||||
* reports
|
||||
*/
|
||||
public void generateReports(String outputDir, Format format) throws ReportException {
|
||||
if (format == Format.XML || format == Format.ALL) {
|
||||
generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
|
||||
}
|
||||
if (format == Format.HTML || format == Format.ALL) {
|
||||
generateReport("HtmlReport", outputDir + File.separator + "dependency-check-report.html");
|
||||
}
|
||||
if (format == Format.VULN || format == Format.ALL) {
|
||||
generateReport("VulnerabilityReport", outputDir + File.separator + "dependency-check-vulnerability.html");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency Reports for the identified dependencies.
|
||||
*
|
||||
* @param outputDir the path where the reports should be written
|
||||
* @param outputFormat the format the report should be written in (XML,
|
||||
* HTML, ALL)
|
||||
* @param outputLocation the path where the reports should be written
|
||||
* @param format the format the report should be written in (XML, HTML,
|
||||
* JSON, CSV, ALL) or even the path to a custom velocity template (either
|
||||
* fully qualified or the template name on the class path).
|
||||
* @throws ReportException is thrown if there is an error creating out the
|
||||
* reports
|
||||
*/
|
||||
public void generateReports(String outputDir, String outputFormat) throws ReportException {
|
||||
final String format = outputFormat.toUpperCase();
|
||||
final String pathToCheck = outputDir.toLowerCase();
|
||||
if (format.matches("^(XML|HTML|VULN|ALL)$")) {
|
||||
if ("XML".equalsIgnoreCase(format)) {
|
||||
if (pathToCheck.endsWith(".xml")) {
|
||||
generateReport("XmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.XML);
|
||||
public void write(String outputLocation, String format) throws ReportException {
|
||||
Format reportFormat = null;
|
||||
try {
|
||||
reportFormat = Format.valueOf(format.toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.trace("ignore this exception", ex);
|
||||
}
|
||||
|
||||
if (reportFormat != null) {
|
||||
write(outputLocation, reportFormat);
|
||||
} else {
|
||||
File out = getReportFile(outputLocation, null);
|
||||
if (out.isDirectory()) {
|
||||
throw new ReportException("Unable to write non-standard VSL output to a directory, please specify a file name");
|
||||
}
|
||||
processTemplate(format, out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the dependency-check report(s).
|
||||
*
|
||||
* @param outputLocation the path where the reports should be written
|
||||
* @param format the format the report should be written in (XML, HTML, ALL)
|
||||
* @throws ReportException is thrown if there is an error creating out the
|
||||
* reports
|
||||
*/
|
||||
public void write(String outputLocation, Format format) throws ReportException {
|
||||
if (format == Format.ALL) {
|
||||
for (Format f : Format.values()) {
|
||||
if (f != Format.ALL) {
|
||||
write(outputLocation, f);
|
||||
}
|
||||
}
|
||||
if ("HTML".equalsIgnoreCase(format)) {
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("HtmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.HTML);
|
||||
}
|
||||
}
|
||||
if ("VULN".equalsIgnoreCase(format)) {
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("VulnReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.VULN);
|
||||
}
|
||||
}
|
||||
if ("ALL".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.ALL);
|
||||
} else {
|
||||
final File out = getReportFile(outputLocation, format);
|
||||
final String templateName = format.toString().toLowerCase() + "Report";
|
||||
processTemplate(templateName, out);
|
||||
if (format == Format.JSON) {
|
||||
pretifyJson(out.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Writes the dependency-check report(s).
|
||||
// *
|
||||
// * @param outputStream the OutputStream to send the generated report to
|
||||
// * @param format the format the report should be written in
|
||||
// * @throws ReportException thrown if the report format is ALL
|
||||
// * @throws IOException is thrown when the template file does not exist
|
||||
// * @throws Exception is thrown if there is an error writing out the reports
|
||||
// */
|
||||
// public void write(OutputStream outputStream, Format format) throws ReportException, IOException, Exception {
|
||||
// if (format == Format.ALL) {
|
||||
// throw new ReportException("Unable to write ALL reports to a single output stream, please check the API");
|
||||
// }
|
||||
// final String templateName = format.toString().toLowerCase() + "Report";
|
||||
// processTemplate(templateName, outputStream);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determines the report file name based on the give output location and
|
||||
* format. If the output location contains a full file name that has the
|
||||
* correct extension for the given report type then the output location is
|
||||
* returned. However, if the output location is a directory, this method
|
||||
* will generate the correct name for the given output format.
|
||||
*
|
||||
* @param outputLocation the specified output location
|
||||
* @param format the report format
|
||||
* @return the report File
|
||||
*/
|
||||
protected File getReportFile(String outputLocation, Format format) {
|
||||
File outFile = new File(outputLocation);
|
||||
if (outFile.getParentFile() == null) {
|
||||
outFile = new File(".", outputLocation);
|
||||
}
|
||||
final String pathToCheck = outputLocation.toLowerCase();
|
||||
if (format == Format.XML && !pathToCheck.endsWith(".xml")) {
|
||||
return new File(outFile, "dependency-check-report.xml");
|
||||
}
|
||||
if (format == Format.HTML && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) {
|
||||
return new File(outFile, "dependency-check-report.html");
|
||||
}
|
||||
if (format == Format.VULN && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) {
|
||||
return new File(outFile, "dependency-check-vulnerability.html");
|
||||
}
|
||||
if (format == Format.JSON && !pathToCheck.endsWith(".json")) {
|
||||
return new File(outFile, "dependency-check-report.json");
|
||||
}
|
||||
if (format == Format.CSV && !pathToCheck.endsWith(".csv")) {
|
||||
return new File(outFile, "dependency-check-report.csv");
|
||||
}
|
||||
return outFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report from a given Velocity Template. The template name
|
||||
* provided can be the name of a template contained in the jar file, such as
|
||||
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
||||
* template file.
|
||||
*
|
||||
* @param template the name of the template to load
|
||||
* @param file the output file to write the report to
|
||||
* @throws ReportException is thrown when the report cannot be generated
|
||||
*/
|
||||
protected void processTemplate(String template, File file) throws ReportException {
|
||||
ensureParentDirectoryExists(file);
|
||||
try (OutputStream output = new FileOutputStream(file)) {
|
||||
processTemplate(template, output);
|
||||
} catch (IOException ex) {
|
||||
throw new ReportException(String.format("Unable to write to file: %s", file), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report from a given Velocity Template. The template name
|
||||
* provided can be the name of a template contained in the jar file, such as
|
||||
@@ -236,99 +317,150 @@ public class ReportGenerator {
|
||||
* @param outputStream the OutputStream to write the report to
|
||||
* @throws ReportException is thrown when an exception occurs
|
||||
*/
|
||||
protected void generateReport(String templateName, OutputStream outputStream) throws ReportException {
|
||||
protected void processTemplate(String templateName, OutputStream outputStream) throws ReportException {
|
||||
InputStream input = null;
|
||||
String templatePath = null;
|
||||
String logTag = null;
|
||||
final File f = new File(templateName);
|
||||
if (f.exists() && f.isFile()) {
|
||||
try {
|
||||
templatePath = templateName;
|
||||
input = new FileInputStream(f);
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new ReportException("Unable to locate template file: " + templateName, ex);
|
||||
}
|
||||
} else {
|
||||
templatePath = "templates/" + templateName + ".vsl";
|
||||
input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
|
||||
}
|
||||
if (input == null) {
|
||||
throw new ReportException("Template file doesn't exist: " + templatePath);
|
||||
}
|
||||
|
||||
InputStreamReader reader = null;
|
||||
OutputStreamWriter writer = null;
|
||||
|
||||
try {
|
||||
reader = new InputStreamReader(input, "UTF-8");
|
||||
writer = new OutputStreamWriter(outputStream, "UTF-8");
|
||||
if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
|
||||
throw new ReportException("Failed to convert the template into html.");
|
||||
if (f.isFile()) {
|
||||
try {
|
||||
logTag = templateName;
|
||||
input = new FileInputStream(f);
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new ReportException("Unable to locate template file: " + templateName, ex);
|
||||
}
|
||||
} else {
|
||||
logTag = "templates/" + templateName + ".vsl";
|
||||
input = this.getClass().getClassLoader().getResourceAsStream(logTag);
|
||||
}
|
||||
if (input == null) {
|
||||
logTag = templateName;
|
||||
input = this.getClass().getClassLoader().getResourceAsStream(templateName);
|
||||
}
|
||||
if (input == null) {
|
||||
throw new ReportException("Template file doesn't exist: " + logTag);
|
||||
}
|
||||
|
||||
try (InputStreamReader reader = new InputStreamReader(input, "UTF-8");
|
||||
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8")) {
|
||||
if (!velocityEngine.evaluate(context, writer, logTag, reader)) {
|
||||
throw new ReportException("Failed to convert the template into html.");
|
||||
}
|
||||
writer.flush();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new ReportException("Unable to generate the report using UTF-8", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new ReportException("Unable to write the report", ex);
|
||||
}
|
||||
writer.flush();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new ReportException("Unable to generate the report using UTF-8", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new ReportException("Unable to write the report", ex);
|
||||
} finally {
|
||||
if (writer != null) {
|
||||
if (input != null) {
|
||||
try {
|
||||
writer.close();
|
||||
input.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
LOGGER.trace("Error closing input", ex);
|
||||
}
|
||||
}
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Validates that the given file's parent directory exists. If the directory
|
||||
* does not exist an attempt to create the necessary path is made; if that
|
||||
* fails a ReportException will be raised.
|
||||
*
|
||||
* @param file the file or directory directory
|
||||
* @throws ReportException thrown if the parent directory does not exist and
|
||||
* cannot be created
|
||||
*/
|
||||
private void ensureParentDirectoryExists(File file) throws ReportException {
|
||||
if (!file.getParentFile().exists()) {
|
||||
final boolean created = file.getParentFile().mkdirs();
|
||||
if (!created) {
|
||||
final String msg = String.format("Unable to create directory '%s'.", file.getParentFile().getAbsolutePath());
|
||||
throw new ReportException(msg);
|
||||
}
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reformats the given JSON file.
|
||||
*
|
||||
* @param pathToJson the path to the JSON file to be reformatted
|
||||
* @throws JsonSyntaxException thrown if the given JSON file is malformed
|
||||
*/
|
||||
private void pretifyJson(String pathToJson) throws JsonSyntaxException {
|
||||
final String outputPath = pathToJson + ".pretty";
|
||||
final File in = new File(pathToJson);
|
||||
final File out = new File(outputPath);
|
||||
try (JsonReader reader = new JsonReader(new InputStreamReader(new FileInputStream(in), StandardCharsets.UTF_8));
|
||||
JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(out), StandardCharsets.UTF_8))) {
|
||||
prettyPrint(reader, writer);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("Unable to generate pretty report, caused by: ", ex.getMessage());
|
||||
return;
|
||||
}
|
||||
if (out.isFile() && in.isFile() && in.delete()) {
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.moveFile(out, in);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("Unable to generate pretty report, caused by: ", ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report from a given Velocity Template. The template name
|
||||
* provided can be the name of a template contained in the jar file, such as
|
||||
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
||||
* template file.
|
||||
* Streams from a json reader to a json writer and performs pretty printing.
|
||||
*
|
||||
* @param templateName the name of the template to load
|
||||
* @param outFileName the filename and path to write the report to
|
||||
* @throws ReportException is thrown when the report cannot be generated
|
||||
* This function is copied from https://sites.google.com/site/gson/streaming
|
||||
*
|
||||
* @param reader json reader
|
||||
* @param writer json writer
|
||||
* @throws IOException thrown if the json is malformed
|
||||
*/
|
||||
protected void generateReport(String templateName, String outFileName) throws ReportException {
|
||||
File outFile = new File(outFileName);
|
||||
if (outFile.getParentFile() == null) {
|
||||
outFile = new File(".", outFileName);
|
||||
}
|
||||
if (!outFile.getParentFile().exists()) {
|
||||
final boolean created = outFile.getParentFile().mkdirs();
|
||||
if (!created) {
|
||||
throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream outputSteam = null;
|
||||
try {
|
||||
outputSteam = new FileOutputStream(outFile);
|
||||
generateReport(templateName, outputSteam);
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new ReportException("Unable to write to file: " + outFile, ex);
|
||||
} finally {
|
||||
if (outputSteam != null) {
|
||||
try {
|
||||
outputSteam.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("ignore", ex);
|
||||
}
|
||||
private static void prettyPrint(JsonReader reader, JsonWriter writer) throws IOException {
|
||||
writer.setIndent(" ");
|
||||
while (true) {
|
||||
final JsonToken token = reader.peek();
|
||||
switch (token) {
|
||||
case BEGIN_ARRAY:
|
||||
reader.beginArray();
|
||||
writer.beginArray();
|
||||
break;
|
||||
case END_ARRAY:
|
||||
reader.endArray();
|
||||
writer.endArray();
|
||||
break;
|
||||
case BEGIN_OBJECT:
|
||||
reader.beginObject();
|
||||
writer.beginObject();
|
||||
break;
|
||||
case END_OBJECT:
|
||||
reader.endObject();
|
||||
writer.endObject();
|
||||
break;
|
||||
case NAME:
|
||||
final String name = reader.nextName();
|
||||
writer.name(name);
|
||||
break;
|
||||
case STRING:
|
||||
final String s = reader.nextString();
|
||||
writer.value(s);
|
||||
break;
|
||||
case NUMBER:
|
||||
final String n = reader.nextString();
|
||||
writer.value(new BigDecimal(n));
|
||||
break;
|
||||
case BOOLEAN:
|
||||
final boolean b = reader.nextBoolean();
|
||||
writer.value(b);
|
||||
break;
|
||||
case NULL:
|
||||
reader.nextNull();
|
||||
writer.nullValue();
|
||||
break;
|
||||
case END_DOCUMENT:
|
||||
return;
|
||||
default:
|
||||
LOGGER.debug("Unexpected JSON toekn {}", token.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,15 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* DependencyCheck uses {@link org.slf4j.Logger} as a logging framework, and Apache Velocity uses a custom logging implementation
|
||||
* that outputs to a file named velocity.log by default. This class is an implementation of a custom Velocity logger that
|
||||
* redirects all velocity logging to the Java Logger class.
|
||||
* DependencyCheck uses {@link org.slf4j.Logger} as a logging framework, and
|
||||
* Apache Velocity uses a custom logging implementation that outputs to a file
|
||||
* named velocity.log by default. This class is an implementation of a custom
|
||||
* Velocity logger that redirects all velocity logging to the Java Logger class.
|
||||
* </p><p>
|
||||
* This class was written to address permission issues when using Dependency-Check in a server environment (such as the Jenkins
|
||||
* plugin). In some circumstances, Velocity would attempt to create velocity.log in an un-writable directory.</p>
|
||||
* This class was written to address permission issues when using
|
||||
* Dependency-Check in a server environment (such as the Jenkins plugin). In
|
||||
* some circumstances, Velocity would attempt to create velocity.log in an
|
||||
* un-writable directory.</p>
|
||||
*
|
||||
* @author Steve Springett
|
||||
*/
|
||||
@@ -51,7 +54,8 @@ public class VelocityLoggerRedirect implements LogChute {
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a Velocity log level and message, this method will call the appropriate Logger level and log the specified values.
|
||||
* Given a Velocity log level and message, this method will call the
|
||||
* appropriate Logger level and log the specified values.
|
||||
*
|
||||
* @param level the logging level
|
||||
* @param message the message to be logged
|
||||
@@ -76,12 +80,13 @@ public class VelocityLoggerRedirect implements LogChute {
|
||||
break;
|
||||
default:
|
||||
LOGGER.info(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a Velocity log level, message and Throwable, this method will call the appropriate Logger level and log the specified
|
||||
* values.
|
||||
* Given a Velocity log level, message and Throwable, this method will call
|
||||
* the appropriate Logger level and log the specified values.
|
||||
*
|
||||
* @param level the logging level
|
||||
* @param message the message to be logged
|
||||
@@ -107,6 +112,7 @@ public class VelocityLoggerRedirect implements LogChute {
|
||||
break;
|
||||
default:
|
||||
LOGGER.info(message, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ public final class DBUtils {
|
||||
*
|
||||
* @param statement a prepared statement that just executed an insert
|
||||
* @return a primary key
|
||||
* @throws DatabaseException thrown if there is an exception obtaining the key
|
||||
* @throws DatabaseException thrown if there is an exception obtaining the
|
||||
* key
|
||||
*/
|
||||
public static int getGeneratedKey(PreparedStatement statement) throws DatabaseException {
|
||||
ResultSet rs = null;
|
||||
@@ -72,27 +73,29 @@ public final class DBUtils {
|
||||
* @param statement a Statement object
|
||||
*/
|
||||
public static void closeStatement(Statement statement) {
|
||||
if (statement != null) {
|
||||
try {
|
||||
try {
|
||||
if (statement != null && !statement.isClosed()) {
|
||||
|
||||
statement.close();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.trace(statement.toString(), ex);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.trace(statement.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the result set capturing and ignoring any SQLExceptions that occur.
|
||||
* Closes the result set capturing and ignoring any SQLExceptions that
|
||||
* occur.
|
||||
*
|
||||
* @param rs a ResultSet to close
|
||||
*/
|
||||
public static void closeResultSet(ResultSet rs) {
|
||||
if (rs != null) {
|
||||
try {
|
||||
try {
|
||||
if (rs != null && !rs.isClosed()) {
|
||||
rs.close();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.trace(rs.toString(), ex);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.trace(rs.toString(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class DependencyVersion implements Iterable<String>, Comparable<Dependenc
|
||||
* @param version the version string to parse
|
||||
*/
|
||||
public final void parseVersion(String version) {
|
||||
versionParts = new ArrayList<String>();
|
||||
versionParts = new ArrayList<>();
|
||||
if (version != null) {
|
||||
final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
|
||||
final Matcher matcher = rx.matcher(version.toLowerCase());
|
||||
|
||||
@@ -74,7 +74,7 @@ public final class DependencyVersionUtil {
|
||||
//'-' is a special case used within the CVE entries, just include it as the version.
|
||||
if ("-".equals(text)) {
|
||||
final DependencyVersion dv = new DependencyVersion();
|
||||
final List<String> list = new ArrayList<String>();
|
||||
final List<String> list = new ArrayList<>();
|
||||
list.add(text);
|
||||
dv.setVersionParts(list);
|
||||
return dv;
|
||||
|
||||
@@ -85,18 +85,10 @@ public final class ExtractionUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new ExtractionException("Archive file was not found.", ex);
|
||||
}
|
||||
zis = new ZipInputStream(new BufferedInputStream(fis));
|
||||
ZipEntry entry;
|
||||
try {
|
||||
try (FileInputStream fis = new FileInputStream(archive);
|
||||
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
ZipInputStream zis = new ZipInputStream(bis)) {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.isDirectory()) {
|
||||
final File d = new File(extractTo, entry.getName());
|
||||
@@ -107,9 +99,7 @@ public final class ExtractionUtil {
|
||||
} else {
|
||||
final File file = new File(extractTo, entry.getName());
|
||||
if (engine == null || engine.accept(file)) {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
IOUtils.copy(zis, fos);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
@@ -119,8 +109,6 @@ public final class ExtractionUtil {
|
||||
LOGGER.debug("", ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
FileUtils.close(fos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,8 +117,6 @@ public final class ExtractionUtil {
|
||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
FileUtils.close(zis);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,31 +128,21 @@ public final class ExtractionUtil {
|
||||
* @param filter determines which files get extracted
|
||||
* @throws ExtractionException thrown if the archive is not found
|
||||
*/
|
||||
public static void extractFilesUsingFilter(File archive, File destination,
|
||||
FilenameFilter filter) throws ExtractionException {
|
||||
public static void extractFilesUsingFilter(File archive, File destination, FilenameFilter filter) throws ExtractionException {
|
||||
if (archive == null || destination == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
try (FileInputStream fis = new FileInputStream(archive)) {
|
||||
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(
|
||||
fis)), destination, filter);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new ExtractionException("Archive file was not found.", ex);
|
||||
}
|
||||
try {
|
||||
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(
|
||||
fis)), destination, filter);
|
||||
} catch (ArchiveExtractionException ex) {
|
||||
} catch (IOException | ArchiveExtractionException ex) {
|
||||
LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
throw new ExtractionException("Unable to extract from archive", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,9 +173,7 @@ public final class ExtractionUtil {
|
||||
extractFile(input, destination, filter, entry);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} catch (Throwable ex) {
|
||||
} catch (IOException | AnalysisException ex) {
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} finally {
|
||||
FileUtils.close(input);
|
||||
@@ -221,26 +195,19 @@ public final class ExtractionUtil {
|
||||
FilenameFilter filter, ArchiveEntry entry) throws ExtractionException {
|
||||
final File file = new File(destination, entry.getName());
|
||||
if (filter.accept(file.getParentFile(), file.getName())) {
|
||||
LOGGER.debug("Extracting '{}'",
|
||||
file.getPath());
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
createParentFile(file);
|
||||
fos = new FileOutputStream(file);
|
||||
LOGGER.debug("Extracting '{}'", file.getPath());
|
||||
createParentFile(file);
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
IOUtils.copy(input, fos);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
final String msg = String.format("Unable to find file '%s'.",
|
||||
file.getName());
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
final String msg = String
|
||||
.format("IO Exception while parsing file '%s'.",
|
||||
file.getName());
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
FileUtils.close(fos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,8 +220,7 @@ public final class ExtractionUtil {
|
||||
* @throws ExtractionException thrown if the parent paths could not be
|
||||
* created
|
||||
*/
|
||||
private static void createParentFile(final File file)
|
||||
throws ExtractionException {
|
||||
private static void createParentFile(final File file) throws ExtractionException {
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
final String msg = String.format(
|
||||
@@ -282,35 +248,11 @@ public final class ExtractionUtil {
|
||||
if (!file.renameTo(gzip)) {
|
||||
throw new IOException("Unable to rename '" + file.getPath() + "'");
|
||||
}
|
||||
final File newfile = new File(originalPath);
|
||||
|
||||
final byte[] buffer = new byte[4096];
|
||||
|
||||
GZIPInputStream cin = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
cin = new GZIPInputStream(new FileInputStream(gzip));
|
||||
out = new FileOutputStream(newfile);
|
||||
|
||||
int len;
|
||||
while ((len = cin.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
final File newFile = new File(originalPath);
|
||||
try (GZIPInputStream cin = new GZIPInputStream(new FileInputStream(gzip));
|
||||
FileOutputStream out = new FileOutputStream(newFile)) {
|
||||
IOUtils.copy(cin, out);
|
||||
} finally {
|
||||
if (cin != null) {
|
||||
try {
|
||||
cin.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("ignore", ex);
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("ignore", ex);
|
||||
}
|
||||
}
|
||||
if (gzip.isFile() && !org.apache.commons.io.FileUtils.deleteQuietly(gzip)) {
|
||||
LOGGER.debug("Failed to delete temporary file when extracting 'gz' {}", gzip.toString());
|
||||
gzip.deleteOnExit();
|
||||
|
||||
@@ -48,15 +48,15 @@ public class FileFilterBuilder {
|
||||
/**
|
||||
* A set of filenames to filter.
|
||||
*/
|
||||
private final Set<String> filenames = new HashSet<String>();
|
||||
private final Set<String> filenames = new HashSet<>();
|
||||
/**
|
||||
* A set of extensions to filter.
|
||||
*/
|
||||
private final Set<String> extensions = new HashSet<String>();
|
||||
private final Set<String> extensions = new HashSet<>();
|
||||
/**
|
||||
* An array list of file filters.
|
||||
*/
|
||||
private final List<IOFileFilter> fileFilters = new ArrayList<IOFileFilter>();
|
||||
private final List<IOFileFilter> fileFilters = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Create a new instance and return it. This method is for convenience in using the builder pattern within a single statement.
|
||||
@@ -125,10 +125,10 @@ public class FileFilterBuilder {
|
||||
}
|
||||
final OrFileFilter filter = new OrFileFilter();
|
||||
if (!filenames.isEmpty()) {
|
||||
filter.addFileFilter(new NameFileFilter(new ArrayList<String>(filenames)));
|
||||
filter.addFileFilter(new NameFileFilter(new ArrayList<>(filenames)));
|
||||
}
|
||||
if (!extensions.isEmpty()) {
|
||||
filter.addFileFilter(new SuffixFileFilter(new ArrayList<String>(extensions), IOCase.INSENSITIVE));
|
||||
filter.addFileFilter(new SuffixFileFilter(new ArrayList<>(extensions), IOCase.INSENSITIVE));
|
||||
}
|
||||
for (IOFileFilter iof : fileFilters) {
|
||||
filter.addFileFilter(iof);
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.owasp.dependencycheck.utils;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/*
|
||||
/**
|
||||
* This is an abstract filter that can be used to filter iterable list.
|
||||
*
|
||||
* This Filter class was copied from:
|
||||
@@ -11,15 +11,35 @@ import java.util.NoSuchElementException;
|
||||
*
|
||||
* Erik Rasmussen - © 2006 - 2012 All Rights Reserved. @author Erik Rasmussen
|
||||
* https://plus.google.com/115403795880834599019/?rel=author
|
||||
*
|
||||
* @param <T> the type to filter
|
||||
*/
|
||||
public abstract class Filter<T> {
|
||||
|
||||
/**
|
||||
* Determines whether the object passes the filter.
|
||||
*
|
||||
* @param object the object to test
|
||||
* @return whether or not the object passes the filter
|
||||
*/
|
||||
public abstract boolean passes(T object);
|
||||
|
||||
/**
|
||||
* Filters a given iterator.
|
||||
*
|
||||
* @param iterator the iterator to filter
|
||||
* @return the filtered iterator
|
||||
*/
|
||||
public Iterator<T> filter(Iterator<T> iterator) {
|
||||
return new FilterIterator(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a given iterable.
|
||||
*
|
||||
* @param iterable the iterable to filter
|
||||
* @return the filtered iterable
|
||||
*/
|
||||
public Iterable<T> filter(final Iterable<T> iterable) {
|
||||
return new Iterable<T>() {
|
||||
|
||||
@@ -71,4 +91,4 @@ public abstract class Filter<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,14 @@ package org.owasp.dependencycheck.utils;
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class Pair<L, R> {
|
||||
/**
|
||||
* The left element of the pair.
|
||||
*/
|
||||
private L left = null;
|
||||
/**
|
||||
* The right element of the pair.
|
||||
*/
|
||||
private R right = null;
|
||||
|
||||
/**
|
||||
* Constructs a new empty pair.
|
||||
@@ -43,10 +51,6 @@ public class Pair<L, R> {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
/**
|
||||
* The left element of the pair.
|
||||
*/
|
||||
private L left = null;
|
||||
|
||||
/**
|
||||
* Get the value of left.
|
||||
@@ -65,10 +69,6 @@ public class Pair<L, R> {
|
||||
public void setLeft(L left) {
|
||||
this.left = left;
|
||||
}
|
||||
/**
|
||||
* The right element of the pair.
|
||||
*/
|
||||
private R right = null;
|
||||
|
||||
/**
|
||||
* Get the value of right.
|
||||
@@ -119,9 +119,6 @@ public class Pair<L, R> {
|
||||
if (this.left != other.left && (this.left == null || !this.left.equals(other.left))) {
|
||||
return false;
|
||||
}
|
||||
if (this.right != other.right && (this.right == null || !this.right.equals(other.right))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !(this.right != other.right && (this.right == null || !this.right.equals(other.right)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ public final class UrlStringUtils {
|
||||
private static final Pattern IS_URL_TEST = Pattern.compile("^(ht|f)tps?://.*", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* Tests if the text provided contains a URL. This is somewhat limited search in that it only looks for
|
||||
* (ftp|http|https)://
|
||||
* Tests if the text provided contains a URL. This is somewhat limited
|
||||
* search in that it only looks for (ftp|http|https)://
|
||||
*
|
||||
* @param text the text to search
|
||||
* @return true if the text contains a url, otherwise false
|
||||
@@ -67,14 +67,16 @@ public final class UrlStringUtils {
|
||||
return IS_URL_TEST.matcher(text).matches();
|
||||
}
|
||||
/**
|
||||
* A listing of domain parts that should not be used as evidence. Yes, this is an incomplete list.
|
||||
* A listing of domain parts that should not be used as evidence. Yes, this
|
||||
* is an incomplete list.
|
||||
*/
|
||||
private static final Set<String> IGNORE_LIST = new HashSet<String>(
|
||||
private static final Set<String> IGNORE_LIST = new HashSet<>(
|
||||
Arrays.asList("www", "com", "org", "gov", "info", "name", "net", "pro", "tel", "mobi", "xxx"));
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Takes a URL, in String format, and adds the important parts of the URL to a list of strings.</p>
|
||||
* Takes a URL, in String format, and adds the important parts of the URL to
|
||||
* a list of strings.</p>
|
||||
* <p>
|
||||
* Example, given the following input:</p>
|
||||
* <code>"https://www.somedomain.com/path1/path2/file.php?id=439"</code>
|
||||
@@ -87,7 +89,7 @@ public final class UrlStringUtils {
|
||||
* @throws MalformedURLException thrown if the URL is malformed
|
||||
*/
|
||||
public static List<String> extractImportantUrlData(String text) throws MalformedURLException {
|
||||
final List<String> importantParts = new ArrayList<String>();
|
||||
final List<String> importantParts = new ArrayList<>();
|
||||
final URL url = new URL(text);
|
||||
final String[] domain = url.getHost().split("\\.");
|
||||
//add the domain except www and the tld.
|
||||
@@ -99,14 +101,21 @@ public final class UrlStringUtils {
|
||||
}
|
||||
final String document = url.getPath();
|
||||
final String[] pathParts = document.split("[\\//]");
|
||||
for (int i = 0; i < pathParts.length - 2; i++) {
|
||||
for (int i = 0; i < pathParts.length - 1; i++) {
|
||||
if (!pathParts[i].isEmpty()) {
|
||||
importantParts.add(pathParts[i]);
|
||||
}
|
||||
}
|
||||
if (pathParts.length > 0 && !pathParts[pathParts.length - 1].isEmpty()) {
|
||||
final String fileNameNoExt = pathParts[pathParts.length - 1].replaceAll("\\..*{0,5}$", "");
|
||||
importantParts.add(fileNameNoExt);
|
||||
final String tmp = pathParts[pathParts.length - 1];
|
||||
final int pos = tmp.lastIndexOf('.');
|
||||
if (pos > 1) {
|
||||
importantParts.add(tmp.substring(0, pos));
|
||||
} else if (pos == 0 && tmp.length() > 1) {
|
||||
importantParts.add(tmp.substring(1));
|
||||
} else {
|
||||
importantParts.add(tmp);
|
||||
}
|
||||
}
|
||||
return importantParts;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user