mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-12 21:25:31 +01:00
Compare commits
139 Commits
v1.4.5
...
issue690_t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2a8645dd4 | ||
|
|
4543835a0d | ||
|
|
c0f41c461b | ||
|
|
116ef264e1 | ||
|
|
1371dacdaa | ||
|
|
d252d0f29f | ||
|
|
3786f6ebc7 | ||
|
|
6813427867 | ||
|
|
f94cf106a6 | ||
|
|
a67e421a5d | ||
|
|
865db1b6c3 | ||
|
|
31d7379a39 | ||
|
|
f473e63a61 | ||
|
|
238a96184a | ||
|
|
44ddad8101 | ||
|
|
afa47f7dfc | ||
|
|
f289bcd285 | ||
|
|
c7adb1bb65 | ||
|
|
4bbc5e27b5 | ||
|
|
c877ade004 | ||
|
|
ebd8996ad5 | ||
|
|
f31313d021 | ||
|
|
6936dac9b4 | ||
|
|
4b2f6832fe | ||
|
|
35d0f21c47 | ||
|
|
3066d286c5 | ||
|
|
18564e8e86 | ||
|
|
832cbabc7d | ||
|
|
8b764d5e17 | ||
|
|
e2a1a59543 | ||
|
|
cedb8d3db1 | ||
|
|
539bd754df | ||
|
|
109f5c22e9 | ||
|
|
a23d127c62 | ||
|
|
6825304100 | ||
|
|
947499726a | ||
|
|
97b2e1a4da | ||
|
|
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
|
### 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.
|
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*
|
||||||
12
README.md
12
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
|
Dependency-Check
|
||||||
================
|
================
|
||||||
@@ -99,9 +101,9 @@ Then load the resulting 'DependencyCheck-Report.html' into your favorite browser
|
|||||||
|
|
||||||
### Docker
|
### 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.
|
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 newest 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
|
# After the first run, feel free to change the owner of the directories to the owner of the created files and the permissions to 744
|
||||||
DATA_DIRECTORY=$HOME/OWASP-Dependency-Check/data
|
DATA_DIRECTORY=$HOME/OWASP-Dependency-Check/data
|
||||||
REPORT_DIRECTORY=/$HOME/OWASP-Dependency-Check/reports
|
REPORT_DIRECTORY=/$HOME/OWASP-Dependency-Check/reports
|
||||||
|
|
||||||
@@ -124,7 +126,7 @@ docker run --rm \
|
|||||||
dc \
|
dc \
|
||||||
--suppression "/src/security/dependency-check-suppression.xml"\
|
--suppression "/src/security/dependency-check-suppression.xml"\
|
||||||
--format "ALL" \
|
--format "ALL" \
|
||||||
--project "My OWASP Dependency Check Projekt" \
|
--project "My OWASP Dependency Check Project" \
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -144,7 +146,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.
|
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
|
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.4.5</version>
|
<version>1.4.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-ant</artifactId>
|
<artifactId>dependency-check-ant</artifactId>
|
||||||
@@ -288,7 +288,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<version>${reporting.pmd-plugin.version}</version>
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<targetJdk>1.6</targetJdk>
|
<targetJdk>1.6</targetJdk>
|
||||||
<linkXref>true</linkXref>
|
<linkXRef>true</linkXRef>
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/generated/*.java</exclude>
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
|||||||
@@ -53,16 +53,157 @@ public class Check extends Update {
|
|||||||
* System specific new line character.
|
* System specific new line character.
|
||||||
*/
|
*/
|
||||||
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
|
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() {
|
@Deprecated
|
||||||
super();
|
private String applicationName = null;
|
||||||
// Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
|
/**
|
||||||
// core end up coming through this tasks logger
|
* The name of the project being analyzed.
|
||||||
StaticLoggerBinder.getSingleton().setTask(this);
|
*/
|
||||||
}
|
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, 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
|
//The following code was copied Apache Ant PathConvert
|
||||||
//BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert
|
//BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert
|
||||||
/**
|
/**
|
||||||
@@ -70,9 +211,9 @@ public class Check extends Update {
|
|||||||
*/
|
*/
|
||||||
private Resources path = null;
|
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.
|
* Add an arbitrary ResourceCollection.
|
||||||
@@ -82,7 +223,7 @@ public class Check extends Update {
|
|||||||
*/
|
*/
|
||||||
public void add(ResourceCollection rc) {
|
public void add(ResourceCollection rc) {
|
||||||
if (isReference()) {
|
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);
|
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() {
|
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.
|
* @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) {
|
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 {
|
private void dealWithReferences() throws BuildException {
|
||||||
if (isReference()) {
|
if (isReference()) {
|
||||||
final Object o = refid.getReferencedObject(getProject());
|
final Object o = refId.getReferencedObject(getProject());
|
||||||
if (!(o instanceof ResourceCollection)) {
|
if (!(o instanceof ResourceCollection)) {
|
||||||
throw new BuildException("refid '" + refid.getRefId()
|
throw new BuildException("refId '" + refId.getRefId()
|
||||||
+ "' does not refer to a resource collection.");
|
+ "' does not refer to a resource collection.");
|
||||||
}
|
}
|
||||||
getPath().add((ResourceCollection) o);
|
getPath().add((ResourceCollection) o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// END COPY from org.apache.tools.ant.taskdefs
|
// END COPY from org.apache.tools.ant.taskdefs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The application name for the report.
|
* Construct a new DependencyCheckTask.
|
||||||
*
|
|
||||||
* @deprecated use projectName instead.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
public Check() {
|
||||||
private String applicationName = null;
|
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.
|
* Get the value of applicationName.
|
||||||
@@ -170,10 +314,6 @@ public class Check extends Update {
|
|||||||
public void setApplicationName(String applicationName) {
|
public void setApplicationName(String applicationName) {
|
||||||
this.applicationName = applicationName;
|
this.applicationName = applicationName;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The name of the project being analyzed.
|
|
||||||
*/
|
|
||||||
private String projectName = "dependency-check";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of projectName.
|
* Get the value of projectName.
|
||||||
@@ -199,12 +339,6 @@ public class Check extends Update {
|
|||||||
this.projectName = projectName;
|
this.projectName = projectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the destination directory for the generated Dependency-Check
|
|
||||||
* report.
|
|
||||||
*/
|
|
||||||
private String reportOutputDirectory = ".";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of reportOutputDirectory.
|
* Get the value of reportOutputDirectory.
|
||||||
*
|
*
|
||||||
@@ -222,14 +356,6 @@ public class Check extends Update {
|
|||||||
public void setReportOutputDirectory(String reportOutputDirectory) {
|
public void setReportOutputDirectory(String reportOutputDirectory) {
|
||||||
this.reportOutputDirectory = 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.
|
* Get the value of failBuildOnCVSS.
|
||||||
@@ -248,11 +374,6 @@ public class Check extends Update {
|
|||||||
public void setFailBuildOnCVSS(float failBuildOnCVSS) {
|
public void setFailBuildOnCVSS(float failBuildOnCVSS) {
|
||||||
this.failBuildOnCVSS = 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.
|
* Get the value of autoUpdate.
|
||||||
@@ -271,13 +392,6 @@ public class Check extends Update {
|
|||||||
public void setAutoUpdate(Boolean autoUpdate) {
|
public void setAutoUpdate(Boolean autoUpdate) {
|
||||||
this.autoUpdate = 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.
|
* Get the value of updateOnly.
|
||||||
@@ -301,12 +415,6 @@ public class Check extends Update {
|
|||||||
this.updateOnly = updateOnly;
|
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.
|
* Get the value of reportFormat.
|
||||||
*
|
*
|
||||||
@@ -324,10 +432,6 @@ public class Check extends Update {
|
|||||||
public void setReportFormat(ReportFormats reportFormat) {
|
public void setReportFormat(ReportFormats reportFormat) {
|
||||||
this.reportFormat = reportFormat.getValue();
|
this.reportFormat = reportFormat.getValue();
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The path to the suppression file.
|
|
||||||
*/
|
|
||||||
private String suppressionFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of suppressionFile.
|
* Get the value of suppressionFile.
|
||||||
@@ -346,10 +450,6 @@ public class Check extends Update {
|
|||||||
public void setSuppressionFile(String suppressionFile) {
|
public void setSuppressionFile(String suppressionFile) {
|
||||||
this.suppressionFile = suppressionFile;
|
this.suppressionFile = suppressionFile;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The path to the suppression file.
|
|
||||||
*/
|
|
||||||
private String hintsFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of hintsFile.
|
* Get the value of hintsFile.
|
||||||
@@ -368,10 +468,6 @@ public class Check extends Update {
|
|||||||
public void setHintsFile(String hintsFile) {
|
public void setHintsFile(String hintsFile) {
|
||||||
this.hintsFile = hintsFile;
|
this.hintsFile = hintsFile;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* flag indicating whether or not to show a summary of findings.
|
|
||||||
*/
|
|
||||||
private boolean showSummary = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of showSummary.
|
* Get the value of showSummary.
|
||||||
@@ -391,11 +487,6 @@ public class Check extends Update {
|
|||||||
this.showSummary = showSummary;
|
this.showSummary = showSummary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether experimental analyzers are enabled.
|
|
||||||
*/
|
|
||||||
private Boolean enableExperimental;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of enableExperimental.
|
* Get the value of enableExperimental.
|
||||||
*
|
*
|
||||||
@@ -414,11 +505,6 @@ public class Check extends Update {
|
|||||||
this.enableExperimental = enableExperimental;
|
this.enableExperimental = enableExperimental;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the Jar Analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean jarAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the analyzer is enabled.
|
* Returns whether or not the analyzer is enabled.
|
||||||
*
|
*
|
||||||
@@ -436,10 +522,6 @@ public class Check extends Update {
|
|||||||
public void setJarAnalyzerEnabled(Boolean jarAnalyzerEnabled) {
|
public void setJarAnalyzerEnabled(Boolean jarAnalyzerEnabled) {
|
||||||
this.jarAnalyzerEnabled = jarAnalyzerEnabled;
|
this.jarAnalyzerEnabled = jarAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether or not the Archive Analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean archiveAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the analyzer is enabled.
|
* Returns whether or not the analyzer is enabled.
|
||||||
@@ -449,10 +531,6 @@ public class Check extends Update {
|
|||||||
public Boolean isArchiveAnalyzerEnabled() {
|
public Boolean isArchiveAnalyzerEnabled() {
|
||||||
return archiveAnalyzerEnabled;
|
return archiveAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether or not the .NET Assembly Analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean assemblyAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not the analyzer is enabled.
|
* Sets whether or not the analyzer is enabled.
|
||||||
@@ -480,10 +558,6 @@ public class Check extends Update {
|
|||||||
public void setAssemblyAnalyzerEnabled(Boolean assemblyAnalyzerEnabled) {
|
public void setAssemblyAnalyzerEnabled(Boolean assemblyAnalyzerEnabled) {
|
||||||
this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
|
this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether or not the .NET Nuspec Analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean nuspecAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the analyzer is enabled.
|
* Returns whether or not the analyzer is enabled.
|
||||||
@@ -502,10 +576,6 @@ public class Check extends Update {
|
|||||||
public void setNuspecAnalyzerEnabled(Boolean nuspecAnalyzerEnabled) {
|
public void setNuspecAnalyzerEnabled(Boolean nuspecAnalyzerEnabled) {
|
||||||
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
|
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether or not the PHP Composer Analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean composerAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of composerAnalyzerEnabled.
|
* Get the value of composerAnalyzerEnabled.
|
||||||
@@ -524,10 +594,6 @@ public class Check extends Update {
|
|||||||
public void setComposerAnalyzerEnabled(Boolean composerAnalyzerEnabled) {
|
public void setComposerAnalyzerEnabled(Boolean composerAnalyzerEnabled) {
|
||||||
this.composerAnalyzerEnabled = composerAnalyzerEnabled;
|
this.composerAnalyzerEnabled = composerAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether the autoconf analyzer should be enabled.
|
|
||||||
*/
|
|
||||||
private Boolean autoconfAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of autoconfAnalyzerEnabled.
|
* Get the value of autoconfAnalyzerEnabled.
|
||||||
@@ -546,10 +612,6 @@ public class Check extends Update {
|
|||||||
public void setAutoconfAnalyzerEnabled(Boolean autoconfAnalyzerEnabled) {
|
public void setAutoconfAnalyzerEnabled(Boolean autoconfAnalyzerEnabled) {
|
||||||
this.autoconfAnalyzerEnabled = autoconfAnalyzerEnabled;
|
this.autoconfAnalyzerEnabled = autoconfAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether the CMake analyzer should be enabled.
|
|
||||||
*/
|
|
||||||
private Boolean cmakeAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cmakeAnalyzerEnabled.
|
* Get the value of cmakeAnalyzerEnabled.
|
||||||
@@ -569,12 +631,6 @@ public class Check extends Update {
|
|||||||
this.cmakeAnalyzerEnabled = cmakeAnalyzerEnabled;
|
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.
|
* Returns if the Bundle Audit Analyzer is enabled.
|
||||||
*
|
*
|
||||||
@@ -594,11 +650,6 @@ public class Check extends Update {
|
|||||||
this.bundleAuditAnalyzerEnabled = bundleAuditAnalyzerEnabled;
|
this.bundleAuditAnalyzerEnabled = bundleAuditAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the path for the bundle-audit binary.
|
|
||||||
*/
|
|
||||||
private String bundleAuditPath;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path to the bundle audit executable.
|
* Returns the path to the bundle audit executable.
|
||||||
*
|
*
|
||||||
@@ -616,15 +667,11 @@ public class Check extends Update {
|
|||||||
public void setBundleAuditPath(String bundleAuditPath) {
|
public void setBundleAuditPath(String bundleAuditPath) {
|
||||||
this.bundleAuditPath = 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() {
|
public boolean isCocoapodsAnalyzerEnabled() {
|
||||||
return cocoapodsAnalyzerEnabled;
|
return cocoapodsAnalyzerEnabled;
|
||||||
@@ -639,11 +686,6 @@ public class Check extends Update {
|
|||||||
this.cocoapodsAnalyzerEnabled = cocoapodsAnalyzerEnabled;
|
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.
|
* Returns whether or not the Swift package Analyzer is enabled.
|
||||||
*
|
*
|
||||||
@@ -662,12 +704,6 @@ public class Check extends Update {
|
|||||||
public void setSwiftPackageManagerAnalyzerEnabled(Boolean swiftPackageManagerAnalyzerEnabled) {
|
public void setSwiftPackageManagerAnalyzerEnabled(Boolean swiftPackageManagerAnalyzerEnabled) {
|
||||||
this.swiftPackageManagerAnalyzerEnabled = swiftPackageManagerAnalyzerEnabled;
|
this.swiftPackageManagerAnalyzerEnabled = swiftPackageManagerAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
//end changes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the openssl analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean opensslAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of opensslAnalyzerEnabled.
|
* Get the value of opensslAnalyzerEnabled.
|
||||||
@@ -686,10 +722,6 @@ public class Check extends Update {
|
|||||||
public void setOpensslAnalyzerEnabled(Boolean opensslAnalyzerEnabled) {
|
public void setOpensslAnalyzerEnabled(Boolean opensslAnalyzerEnabled) {
|
||||||
this.opensslAnalyzerEnabled = opensslAnalyzerEnabled;
|
this.opensslAnalyzerEnabled = opensslAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether or not the Node.js Analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean nodeAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of nodeAnalyzerEnabled.
|
* Get the value of nodeAnalyzerEnabled.
|
||||||
@@ -708,10 +740,6 @@ public class Check extends Update {
|
|||||||
public void setNodeAnalyzerEnabled(Boolean nodeAnalyzerEnabled) {
|
public void setNodeAnalyzerEnabled(Boolean nodeAnalyzerEnabled) {
|
||||||
this.nodeAnalyzerEnabled = nodeAnalyzerEnabled;
|
this.nodeAnalyzerEnabled = nodeAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether the ruby gemspec analyzer should be enabled.
|
|
||||||
*/
|
|
||||||
private Boolean rubygemsAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of rubygemsAnalyzerEnabled.
|
* Get the value of rubygemsAnalyzerEnabled.
|
||||||
@@ -730,10 +758,6 @@ public class Check extends Update {
|
|||||||
public void setRubygemsAnalyzerEnabled(Boolean rubygemsAnalyzerEnabled) {
|
public void setRubygemsAnalyzerEnabled(Boolean rubygemsAnalyzerEnabled) {
|
||||||
this.rubygemsAnalyzerEnabled = rubygemsAnalyzerEnabled;
|
this.rubygemsAnalyzerEnabled = rubygemsAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether the python package analyzer should be enabled.
|
|
||||||
*/
|
|
||||||
private Boolean pyPackageAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of pyPackageAnalyzerEnabled.
|
* Get the value of pyPackageAnalyzerEnabled.
|
||||||
@@ -753,11 +777,6 @@ public class Check extends Update {
|
|||||||
this.pyPackageAnalyzerEnabled = pyPackageAnalyzerEnabled;
|
this.pyPackageAnalyzerEnabled = pyPackageAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the python distribution analyzer should be enabled.
|
|
||||||
*/
|
|
||||||
private Boolean pyDistributionAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of pyDistributionAnalyzerEnabled.
|
* Get the value of pyDistributionAnalyzerEnabled.
|
||||||
*
|
*
|
||||||
@@ -777,11 +796,6 @@ public class Check extends Update {
|
|||||||
this.pyDistributionAnalyzerEnabled = pyDistributionAnalyzerEnabled;
|
this.pyDistributionAnalyzerEnabled = pyDistributionAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the central analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean centralAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of centralAnalyzerEnabled.
|
* Get the value of centralAnalyzerEnabled.
|
||||||
*
|
*
|
||||||
@@ -800,11 +814,6 @@ public class Check extends Update {
|
|||||||
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the nexus analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private Boolean nexusAnalyzerEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of nexusAnalyzerEnabled.
|
* Get the value of nexusAnalyzerEnabled.
|
||||||
*
|
*
|
||||||
@@ -823,12 +832,6 @@ public class Check extends Update {
|
|||||||
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
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.
|
* Get the value of nexusUrl.
|
||||||
*
|
*
|
||||||
@@ -846,10 +849,6 @@ public class Check extends Update {
|
|||||||
public void setNexusUrl(String nexusUrl) {
|
public void setNexusUrl(String nexusUrl) {
|
||||||
this.nexusUrl = 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.
|
* Get the value of nexusUsesProxy.
|
||||||
@@ -869,12 +868,6 @@ public class Check extends Update {
|
|||||||
this.nexusUsesProxy = nexusUsesProxy;
|
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.
|
* Get the value of zipExtensions.
|
||||||
*
|
*
|
||||||
@@ -893,11 +886,6 @@ public class Check extends Update {
|
|||||||
this.zipExtensions = zipExtensions;
|
this.zipExtensions = zipExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
|
||||||
*/
|
|
||||||
private String pathToMono;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of pathToMono.
|
* Get the value of pathToMono.
|
||||||
*
|
*
|
||||||
@@ -935,7 +923,7 @@ public class Check extends Update {
|
|||||||
log(ex.getMessage(), Project.MSG_ERR);
|
log(ex.getMessage(), Project.MSG_ERR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Resource resource : path) {
|
for (Resource resource : getPath()) {
|
||||||
final FileProvider provider = resource.as(FileProvider.class);
|
final FileProvider provider = resource.as(FileProvider.class);
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
final File file = provider.getFile();
|
final File file = provider.getFile();
|
||||||
@@ -953,18 +941,13 @@ public class Check extends Update {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DatabaseProperties prop = null;
|
DatabaseProperties prop = null;
|
||||||
CveDB cve = null;
|
try (CveDB cve = CveDB.getInstance()) {
|
||||||
try {
|
|
||||||
cve = new CveDB();
|
|
||||||
cve.open();
|
|
||||||
prop = cve.getDatabaseProperties();
|
prop = cve.getDatabaseProperties();
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
|
//TODO shouldn't this be a fatal exception
|
||||||
log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
|
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);
|
final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||||
reporter.generateReports(reportOutputDirectory, reportFormat);
|
reporter.generateReports(reportOutputDirectory, reportFormat);
|
||||||
|
|
||||||
@@ -1002,7 +985,7 @@ public class Check extends Update {
|
|||||||
* @throws BuildException if the task was not configured correctly.
|
* @throws BuildException if the task was not configured correctly.
|
||||||
*/
|
*/
|
||||||
private void validateConfiguration() throws BuildException {
|
private void validateConfiguration() throws BuildException {
|
||||||
if (path == null) {
|
if (getPath() == null) {
|
||||||
throw new BuildException("No project dependencies have been defined to analyze.");
|
throw new BuildException("No project dependencies have been defined to analyze.");
|
||||||
}
|
}
|
||||||
if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
|
if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
|
||||||
@@ -1054,7 +1037,7 @@ public class Check extends Update {
|
|||||||
*
|
*
|
||||||
* @param dependencies the list of dependency objects
|
* @param dependencies the list of dependency objects
|
||||||
* @throws BuildException thrown if a CVSS score is found that is higher
|
* @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 {
|
private void checkForFailure(List<Dependency> dependencies) throws BuildException {
|
||||||
final StringBuilder ids = new StringBuilder();
|
final StringBuilder ids = new StringBuilder();
|
||||||
@@ -1071,7 +1054,7 @@ public class Check extends Update {
|
|||||||
}
|
}
|
||||||
if (ids.length() > 0) {
|
if (ids.length() > 0) {
|
||||||
final String msg = String.format("%n%nDependency-Check Failure:%n"
|
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());
|
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
|
||||||
throw new BuildException(msg);
|
throw new BuildException(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ public class Purge extends Task {
|
|||||||
this.failOnError = failOnError;
|
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
|
@Override
|
||||||
public void execute() throws BuildException {
|
public void execute() throws BuildException {
|
||||||
populateSettings();
|
populateSettings();
|
||||||
@@ -138,9 +144,7 @@ public class Purge extends Task {
|
|||||||
*/
|
*/
|
||||||
protected void populateSettings() throws BuildException {
|
protected void populateSettings() throws BuildException {
|
||||||
Settings.initialize();
|
Settings.initialize();
|
||||||
InputStream taskProperties = null;
|
try (InputStream taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE)) {
|
||||||
try {
|
|
||||||
taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
|
|
||||||
Settings.mergeProperties(taskProperties);
|
Settings.mergeProperties(taskProperties);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = "Unable to load the dependency-check ant task.properties file.";
|
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);
|
throw new BuildException(msg, ex);
|
||||||
}
|
}
|
||||||
log(msg, ex, Project.MSG_WARN);
|
log(msg, ex, Project.MSG_WARN);
|
||||||
} finally {
|
|
||||||
if (taskProperties != null) {
|
|
||||||
try {
|
|
||||||
taskProperties.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
log("", ex, Project.MSG_DEBUG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (dataDirectory != null) {
|
if (dataDirectory != null) {
|
||||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
|
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
|
||||||
|
|||||||
@@ -34,6 +34,67 @@ import org.slf4j.impl.StaticLoggerBinder;
|
|||||||
*/
|
*/
|
||||||
public class Update extends Purge {
|
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.
|
* Construct a new UpdateTask.
|
||||||
*/
|
*/
|
||||||
@@ -44,11 +105,6 @@ public class Update extends Purge {
|
|||||||
StaticLoggerBinder.getSingleton().setTask(this);
|
StaticLoggerBinder.getSingleton().setTask(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy Server.
|
|
||||||
*/
|
|
||||||
private String proxyServer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyServer.
|
* Get the value of proxyServer.
|
||||||
*
|
*
|
||||||
@@ -67,11 +123,6 @@ public class Update extends Purge {
|
|||||||
this.proxyServer = server;
|
this.proxyServer = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy Port.
|
|
||||||
*/
|
|
||||||
private String proxyPort;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyPort.
|
* Get the value of proxyPort.
|
||||||
*
|
*
|
||||||
@@ -89,10 +140,6 @@ public class Update extends Purge {
|
|||||||
public void setProxyPort(String proxyPort) {
|
public void setProxyPort(String proxyPort) {
|
||||||
this.proxyPort = proxyPort;
|
this.proxyPort = proxyPort;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The Proxy username.
|
|
||||||
*/
|
|
||||||
private String proxyUsername;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyUsername.
|
* Get the value of proxyUsername.
|
||||||
@@ -111,10 +158,6 @@ public class Update extends Purge {
|
|||||||
public void setProxyUsername(String proxyUsername) {
|
public void setProxyUsername(String proxyUsername) {
|
||||||
this.proxyUsername = proxyUsername;
|
this.proxyUsername = proxyUsername;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The Proxy password.
|
|
||||||
*/
|
|
||||||
private String proxyPassword;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyPassword.
|
* Get the value of proxyPassword.
|
||||||
@@ -133,10 +176,6 @@ public class Update extends Purge {
|
|||||||
public void setProxyPassword(String proxyPassword) {
|
public void setProxyPassword(String proxyPassword) {
|
||||||
this.proxyPassword = proxyPassword;
|
this.proxyPassword = proxyPassword;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The Connection Timeout.
|
|
||||||
*/
|
|
||||||
private String connectionTimeout;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of connectionTimeout.
|
* Get the value of connectionTimeout.
|
||||||
@@ -155,10 +194,6 @@ public class Update extends Purge {
|
|||||||
public void setConnectionTimeout(String connectionTimeout) {
|
public void setConnectionTimeout(String connectionTimeout) {
|
||||||
this.connectionTimeout = connectionTimeout;
|
this.connectionTimeout = connectionTimeout;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The database driver name; such as org.h2.Driver.
|
|
||||||
*/
|
|
||||||
private String databaseDriverName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databaseDriverName.
|
* Get the value of databaseDriverName.
|
||||||
@@ -178,11 +213,6 @@ public class Update extends Purge {
|
|||||||
this.databaseDriverName = databaseDriverName;
|
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.
|
* Get the value of databaseDriverPath.
|
||||||
*
|
*
|
||||||
@@ -200,10 +230,6 @@ public class Update extends Purge {
|
|||||||
public void setDatabaseDriverPath(String databaseDriverPath) {
|
public void setDatabaseDriverPath(String databaseDriverPath) {
|
||||||
this.databaseDriverPath = databaseDriverPath;
|
this.databaseDriverPath = databaseDriverPath;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The database connection string.
|
|
||||||
*/
|
|
||||||
private String connectionString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of connectionString.
|
* Get the value of connectionString.
|
||||||
@@ -222,10 +248,6 @@ public class Update extends Purge {
|
|||||||
public void setConnectionString(String connectionString) {
|
public void setConnectionString(String connectionString) {
|
||||||
this.connectionString = connectionString;
|
this.connectionString = connectionString;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The user name for connecting to the database.
|
|
||||||
*/
|
|
||||||
private String databaseUser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databaseUser.
|
* Get the value of databaseUser.
|
||||||
@@ -245,11 +267,6 @@ public class Update extends Purge {
|
|||||||
this.databaseUser = databaseUser;
|
this.databaseUser = databaseUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The password to use when connecting to the database.
|
|
||||||
*/
|
|
||||||
private String databasePassword;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databasePassword.
|
* Get the value of databasePassword.
|
||||||
*
|
*
|
||||||
@@ -268,11 +285,6 @@ public class Update extends Purge {
|
|||||||
this.databasePassword = databasePassword;
|
this.databasePassword = databasePassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The url for the modified NVD CVE (1.2 schema).
|
|
||||||
*/
|
|
||||||
private String cveUrl12Modified;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl12Modified.
|
* Get the value of cveUrl12Modified.
|
||||||
*
|
*
|
||||||
@@ -291,11 +303,6 @@ public class Update extends Purge {
|
|||||||
this.cveUrl12Modified = cveUrl12Modified;
|
this.cveUrl12Modified = cveUrl12Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The url for the modified NVD CVE (2.0 schema).
|
|
||||||
*/
|
|
||||||
private String cveUrl20Modified;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl20Modified.
|
* Get the value of cveUrl20Modified.
|
||||||
*
|
*
|
||||||
@@ -314,11 +321,6 @@ public class Update extends Purge {
|
|||||||
this.cveUrl20Modified = cveUrl20Modified;
|
this.cveUrl20Modified = cveUrl20Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Base Data Mirror URL for CVE 1.2.
|
|
||||||
*/
|
|
||||||
private String cveUrl12Base;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl12Base.
|
* Get the value of cveUrl12Base.
|
||||||
*
|
*
|
||||||
@@ -337,11 +339,6 @@ public class Update extends Purge {
|
|||||||
this.cveUrl12Base = cveUrl12Base;
|
this.cveUrl12Base = cveUrl12Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Data Mirror URL for CVE 2.0.
|
|
||||||
*/
|
|
||||||
private String cveUrl20Base;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl20Base.
|
* Get the value of cveUrl20Base.
|
||||||
*
|
*
|
||||||
@@ -360,11 +357,6 @@ public class Update extends Purge {
|
|||||||
this.cveUrl20Base = cveUrl20Base;
|
this.cveUrl20Base = cveUrl20Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of hours to wait before re-checking for updates.
|
|
||||||
*/
|
|
||||||
private Integer cveValidForHours;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveValidForHours.
|
* Get the value of cveValidForHours.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
|
|||||||
* The unique instance of this class
|
* The unique instance of this class
|
||||||
*/
|
*/
|
||||||
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
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.
|
* Return the singleton of this class.
|
||||||
@@ -47,12 +52,6 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
|
|||||||
return SINGLETON;
|
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.
|
* 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.
|
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
|
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
|
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)
|
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.
|
for more information on why this task would be used.
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import org.owasp.dependencycheck.utils.Settings;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long
|
* @author Jeremy Long
|
||||||
@@ -65,15 +64,11 @@ public class DependencyCheckTaskTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testAddFileSet() throws Exception {
|
public void testAddFileSet() throws Exception {
|
||||||
File report = new File("target/dependency-check-report.html");
|
File report = new File("target/dependency-check-report.html");
|
||||||
if (report.exists()) {
|
if (report.exists() && !report.delete()) {
|
||||||
if (!report.delete()) {
|
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
||||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
buildFileRule.executeTarget("test.fileset");
|
buildFileRule.executeTarget("test.fileset");
|
||||||
|
|
||||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,11 +61,14 @@
|
|||||||
|
|
||||||
<target name="failCVSS">
|
<target name="failCVSS">
|
||||||
<dependency-check
|
<dependency-check
|
||||||
applicationName="test formatBAD"
|
applicationName="test failCVSS"
|
||||||
reportOutputDirectory="${project.build.directory}"
|
reportOutputDirectory="${project.build.directory}"
|
||||||
reportFormat="XML"
|
reportFormat="XML"
|
||||||
autoupdate="false"
|
autoupdate="false"
|
||||||
failBuildOnCVSS="8">
|
failBuildOnCVSS="3">
|
||||||
|
<fileset dir="${project.build.directory}/test-classes/jars">
|
||||||
|
<include name="axis-1.4.jar"/>
|
||||||
|
</fileset>
|
||||||
</dependency-check>
|
</dependency-check>
|
||||||
</target>
|
</target>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.4.5</version>
|
<version>1.4.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-cli</artifactId>
|
<artifactId>dependency-check-cli</artifactId>
|
||||||
@@ -196,7 +196,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<version>${reporting.pmd-plugin.version}</version>
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<targetJdk>1.6</targetJdk>
|
<targetJdk>1.6</targetJdk>
|
||||||
<linkXref>true</linkXref>
|
<linkXRef>true</linkXRef>
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/generated/*.java</exclude>
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
|||||||
@@ -223,13 +223,13 @@ public class App {
|
|||||||
int retCode = 0;
|
int retCode = 0;
|
||||||
try {
|
try {
|
||||||
engine = new Engine();
|
engine = new Engine();
|
||||||
final List<String> antStylePaths = new ArrayList<String>();
|
final List<String> antStylePaths = new ArrayList<>();
|
||||||
for (String file : files) {
|
for (String file : files) {
|
||||||
final String antPath = ensureCanonicalPath(file);
|
final String antPath = ensureCanonicalPath(file);
|
||||||
antStylePaths.add(antPath);
|
antStylePaths.add(antPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Set<File> paths = new HashSet<File>();
|
final Set<File> paths = new HashSet<>();
|
||||||
for (String file : antStylePaths) {
|
for (String file : antStylePaths) {
|
||||||
LOGGER.debug("Scanning {}", file);
|
LOGGER.debug("Scanning {}", file);
|
||||||
final DirectoryScanner scanner = new DirectoryScanner();
|
final DirectoryScanner scanner = new DirectoryScanner();
|
||||||
@@ -283,17 +283,14 @@ public class App {
|
|||||||
}
|
}
|
||||||
final List<Dependency> dependencies = engine.getDependencies();
|
final List<Dependency> dependencies = engine.getDependencies();
|
||||||
DatabaseProperties prop = null;
|
DatabaseProperties prop = null;
|
||||||
CveDB cve = null;
|
try (CveDB cve = CveDB.getInstance()) {
|
||||||
try {
|
|
||||||
cve = new CveDB();
|
|
||||||
cve.open();
|
|
||||||
prop = cve.getDatabaseProperties();
|
prop = cve.getDatabaseProperties();
|
||||||
} finally {
|
} catch (DatabaseException ex) {
|
||||||
if (cve != null) {
|
//TODO shouldn't this be a fatal exception
|
||||||
cve.close();
|
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
report.generateReports(reportDirectory, outputFormat);
|
report.generateReports(reportDirectory, outputFormat);
|
||||||
} catch (ReportException ex) {
|
} catch (ReportException ex) {
|
||||||
@@ -468,7 +465,7 @@ public class App {
|
|||||||
encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
|
encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
|
||||||
encoder.setContext(context);
|
encoder.setContext(context);
|
||||||
encoder.start();
|
encoder.start();
|
||||||
final FileAppender<ILoggingEvent> fa = new FileAppender<ILoggingEvent>();
|
final FileAppender<ILoggingEvent> fa = new FileAppender<>();
|
||||||
fa.setAppend(true);
|
fa.setAppend(true);
|
||||||
fa.setEncoder(encoder);
|
fa.setEncoder(encoder);
|
||||||
fa.setContext(context);
|
fa.setContext(context);
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ public final class CliParser {
|
|||||||
|
|
||||||
final Option excludes = Option.builder().argName("pattern").hasArg().longOpt(ARGUMENT.EXCLUDE)
|
final Option excludes = Option.builder().argName("pattern").hasArg().longOpt(ARGUMENT.EXCLUDE)
|
||||||
.desc("Specify and exclusion pattern. This option can be specified multiple times"
|
.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();
|
.build();
|
||||||
|
|
||||||
final Option props = Option.builder(ARGUMENT.PROP_SHORT).argName("file").hasArg().longOpt(ARGUMENT.PROP)
|
final Option props = Option.builder(ARGUMENT.PROP_SHORT).argName("file").hasArg().longOpt(ARGUMENT.PROP)
|
||||||
@@ -286,7 +286,7 @@ public final class CliParser {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
final Option experimentalEnabled = Option.builder().longOpt(ARGUMENT.EXPERIMENTAL)
|
final Option experimentalEnabled = Option.builder().longOpt(ARGUMENT.EXPERIMENTAL)
|
||||||
.desc("Enables the experimental analzers.")
|
.desc("Enables the experimental analyzers.")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final Option failOnCVSS = Option.builder().argName("score").hasArg().longOpt(ARGUMENT.FAIL_ON_CVSS)
|
final Option failOnCVSS = Option.builder().argName("score").hasArg().longOpt(ARGUMENT.FAIL_ON_CVSS)
|
||||||
|
|||||||
@@ -17,10 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@@ -29,26 +25,6 @@ import static org.junit.Assert.*;
|
|||||||
* @author jeremy
|
* @author jeremy
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
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.
|
* Test of ensureCanonicalPath method, of class App.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -17,17 +17,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
import org.owasp.dependencycheck.CliParser;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
@@ -48,14 +45,6 @@ public class CliParserTest {
|
|||||||
Settings.cleanup(true);
|
Settings.cleanup(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test of parse method, of class CliParser.
|
* Test of parse method, of class CliParser.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.4.5</version>
|
<version>1.4.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-core</artifactId>
|
<artifactId>dependency-check-core</artifactId>
|
||||||
@@ -244,7 +244,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<version>${reporting.pmd-plugin.version}</version>
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<targetJdk>1.6</targetJdk>
|
<targetJdk>1.6</targetJdk>
|
||||||
<linkXref>true</linkXref>
|
<linkXRef>true</linkXRef>
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/generated/*.java</exclude>
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import java.util.concurrent.Callable;
|
|||||||
*
|
*
|
||||||
* @author Stefan Neuhaus
|
* @author Stefan Neuhaus
|
||||||
*/
|
*/
|
||||||
class AnalysisTask implements Callable<Void> {
|
public class AnalysisTask implements Callable<Void> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of the logger.
|
* Instance of the logger.
|
||||||
@@ -86,7 +86,6 @@ class AnalysisTask implements Callable<Void> {
|
|||||||
* Executes the analysis task.
|
* Executes the analysis task.
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
* @throws Exception thrown if unable to execute the analysis task
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Void call() {
|
public Void call() {
|
||||||
@@ -119,7 +118,7 @@ class AnalysisTask implements Callable<Void> {
|
|||||||
*
|
*
|
||||||
* @return whether or not the analyzer can analyze the dependency
|
* @return whether or not the analyzer can analyze the dependency
|
||||||
*/
|
*/
|
||||||
boolean shouldAnalyze() {
|
protected boolean shouldAnalyze() {
|
||||||
if (analyzer instanceof FileTypeAnalyzer) {
|
if (analyzer instanceof FileTypeAnalyzer) {
|
||||||
final FileTypeAnalyzer fileTypeAnalyzer = (FileTypeAnalyzer) analyzer;
|
final FileTypeAnalyzer fileTypeAnalyzer = (FileTypeAnalyzer) analyzer;
|
||||||
return fileTypeAnalyzer.accept(dependency.getActualFile());
|
return fileTypeAnalyzer.accept(dependency.getActualFile());
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -71,18 +72,22 @@ public class Engine implements FileFilter {
|
|||||||
/**
|
/**
|
||||||
* A Map of analyzers grouped by Analysis phase.
|
* 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.
|
* 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
|
* The ClassLoader to use when dynamically loading Analyzer and Update
|
||||||
* services.
|
* services.
|
||||||
*/
|
*/
|
||||||
private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
|
private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
/**
|
||||||
|
* A reference to the database.
|
||||||
|
*/
|
||||||
|
private CveDB database = null;
|
||||||
/**
|
/**
|
||||||
* The Logger for use throughout the class.
|
* The Logger for use throughout the class.
|
||||||
*/
|
*/
|
||||||
@@ -126,6 +131,10 @@ public class Engine implements FileFilter {
|
|||||||
* Properly cleans up resources allocated during analysis.
|
* Properly cleans up resources allocated during analysis.
|
||||||
*/
|
*/
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
|
if (database != null) {
|
||||||
|
database.close();
|
||||||
|
database = null;
|
||||||
|
}
|
||||||
ConnectionFactory.cleanup();
|
ConnectionFactory.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +222,7 @@ public class Engine implements FileFilter {
|
|||||||
* @since v1.4.4
|
* @since v1.4.4
|
||||||
*/
|
*/
|
||||||
public List<Dependency> scan(String[] paths, String projectReference) {
|
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) {
|
for (String path : paths) {
|
||||||
final List<Dependency> d = scan(path, projectReference);
|
final List<Dependency> d = scan(path, projectReference);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
@@ -276,7 +285,7 @@ public class Engine implements FileFilter {
|
|||||||
* @since v1.4.4
|
* @since v1.4.4
|
||||||
*/
|
*/
|
||||||
public List<Dependency> scan(File[] files, String projectReference) {
|
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) {
|
for (File file : files) {
|
||||||
final List<Dependency> d = scan(file, projectReference);
|
final List<Dependency> d = scan(file, projectReference);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
@@ -311,7 +320,7 @@ public class Engine implements FileFilter {
|
|||||||
* @since v1.4.4
|
* @since v1.4.4
|
||||||
*/
|
*/
|
||||||
public List<Dependency> scan(Collection<File> files, String projectReference) {
|
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) {
|
for (File file : files) {
|
||||||
final List<Dependency> d = scan(file, projectReference);
|
final List<Dependency> d = scan(file, projectReference);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
@@ -352,7 +361,7 @@ public class Engine implements FileFilter {
|
|||||||
} else {
|
} else {
|
||||||
final Dependency d = scanFile(file, projectReference);
|
final Dependency d = scanFile(file, projectReference);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
final List<Dependency> deps = new ArrayList<>();
|
||||||
deps.add(d);
|
deps.add(d);
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
@@ -384,7 +393,7 @@ public class Engine implements FileFilter {
|
|||||||
*/
|
*/
|
||||||
protected List<Dependency> scanDirectory(File dir, String projectReference) {
|
protected List<Dependency> scanDirectory(File dir, String projectReference) {
|
||||||
final File[] files = dir.listFiles();
|
final File[] files = dir.listFiles();
|
||||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
final List<Dependency> deps = new ArrayList<>();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
if (f.isDirectory()) {
|
if (f.isDirectory()) {
|
||||||
@@ -478,31 +487,14 @@ public class Engine implements FileFilter {
|
|||||||
*/
|
*/
|
||||||
public void analyzeDependencies() throws ExceptionCollection {
|
public void analyzeDependencies() throws ExceptionCollection {
|
||||||
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
|
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
|
||||||
boolean autoUpdate = true;
|
|
||||||
try {
|
initializeAndUpdateDatabase(exceptions);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//need to ensure that data exists
|
//need to ensure that data exists
|
||||||
try {
|
try {
|
||||||
ensureDataExists();
|
ensureDataExists();
|
||||||
} catch (NoDataException ex) {
|
} catch (NoDataException ex) {
|
||||||
throwFatalExceptionCollection("Unable to continue dependency-check analysis.", ex, exceptions);
|
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----------------------------------------------------");
|
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
|
||||||
@@ -549,6 +541,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.
|
* Executes executes the analyzer using multiple threads.
|
||||||
*
|
*
|
||||||
@@ -557,7 +590,7 @@ public class Engine implements FileFilter {
|
|||||||
* @param analyzer the analyzer to execute
|
* @param analyzer the analyzer to execute
|
||||||
* @throws ExceptionCollection thrown if exceptions occurred during analysis
|
* @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());
|
LOGGER.debug("Starting {}", analyzer.getName());
|
||||||
final List<AnalysisTask> analysisTasks = getAnalysisTasks(analyzer, exceptions);
|
final List<AnalysisTask> analysisTasks = getAnalysisTasks(analyzer, exceptions);
|
||||||
final ExecutorService executorService = getExecutorService(analyzer);
|
final ExecutorService executorService = getExecutorService(analyzer);
|
||||||
@@ -589,8 +622,8 @@ public class Engine implements FileFilter {
|
|||||||
* @param exceptions the collection of exceptions to collect
|
* @param exceptions the collection of exceptions to collect
|
||||||
* @return a collection of analysis tasks
|
* @return a collection of analysis tasks
|
||||||
*/
|
*/
|
||||||
List<AnalysisTask> getAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) {
|
protected List<AnalysisTask> getAnalysisTasks(Analyzer analyzer, List<Throwable> exceptions) {
|
||||||
final List<AnalysisTask> result = new ArrayList<AnalysisTask>();
|
final List<AnalysisTask> result = new ArrayList<>();
|
||||||
synchronized (dependencies) {
|
synchronized (dependencies) {
|
||||||
for (final Dependency dependency : dependencies) {
|
for (final Dependency dependency : dependencies) {
|
||||||
final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions, Settings.getInstance());
|
final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions, Settings.getInstance());
|
||||||
@@ -606,11 +639,9 @@ public class Engine implements FileFilter {
|
|||||||
* @param analyzer the analyzer to obtain an executor
|
* @param analyzer the analyzer to obtain an executor
|
||||||
* @return the executor service
|
* @return the executor service
|
||||||
*/
|
*/
|
||||||
ExecutorService getExecutorService(Analyzer analyzer) {
|
protected ExecutorService getExecutorService(Analyzer analyzer) {
|
||||||
if (analyzer.supportsParallelProcessing()) {
|
if (analyzer.supportsParallelProcessing()) {
|
||||||
// just a fair trade-off that should be reasonable for all analyzer types
|
final int maximumNumberOfThreads = Runtime.getRuntime().availableProcessors();
|
||||||
final int maximumNumberOfThreads = 4 * Runtime.getRuntime().availableProcessors();
|
|
||||||
|
|
||||||
LOGGER.debug("Parallel processing with up to {} threads: {}.", maximumNumberOfThreads, analyzer.getName());
|
LOGGER.debug("Parallel processing with up to {} threads: {}.", maximumNumberOfThreads, analyzer.getName());
|
||||||
return Executors.newFixedThreadPool(maximumNumberOfThreads);
|
return Executors.newFixedThreadPool(maximumNumberOfThreads);
|
||||||
} else {
|
} else {
|
||||||
@@ -623,11 +654,10 @@ public class Engine implements FileFilter {
|
|||||||
* Initializes the given analyzer.
|
* Initializes the given analyzer.
|
||||||
*
|
*
|
||||||
* @param analyzer the analyzer to initialize
|
* @param analyzer the analyzer to initialize
|
||||||
* @return the initialized analyzer
|
|
||||||
* @throws InitializationException thrown when there is a problem
|
* @throws InitializationException thrown when there is a problem
|
||||||
* initializing the analyzer
|
* initializing the analyzer
|
||||||
*/
|
*/
|
||||||
protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
|
protected void initializeAnalyzer(Analyzer analyzer) throws InitializationException {
|
||||||
try {
|
try {
|
||||||
LOGGER.debug("Initializing {}", analyzer.getName());
|
LOGGER.debug("Initializing {}", analyzer.getName());
|
||||||
analyzer.initialize();
|
analyzer.initialize();
|
||||||
@@ -650,7 +680,6 @@ public class Engine implements FileFilter {
|
|||||||
}
|
}
|
||||||
throw new InitializationException("Unexpected Exception", ex);
|
throw new InitializationException("Unexpected Exception", ex);
|
||||||
}
|
}
|
||||||
return analyzer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -692,7 +721,7 @@ public class Engine implements FileFilter {
|
|||||||
* @return a list of Analyzers
|
* @return a list of Analyzers
|
||||||
*/
|
*/
|
||||||
public List<Analyzer> getAnalyzers() {
|
public List<Analyzer> getAnalyzers() {
|
||||||
final List<Analyzer> ret = new ArrayList<Analyzer>();
|
final List<Analyzer> ret = new ArrayList<>();
|
||||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||||
ret.addAll(analyzerList);
|
ret.addAll(analyzerList);
|
||||||
@@ -745,20 +774,10 @@ public class Engine implements FileFilter {
|
|||||||
* NoDataException is thrown.
|
* NoDataException is thrown.
|
||||||
*
|
*
|
||||||
* @throws NoDataException thrown if no data exists in the CPE Index
|
* @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 {
|
private void ensureDataExists() throws NoDataException {
|
||||||
final CveDB cve = new CveDB();
|
if (database == null || !database.dataExists()) {
|
||||||
try {
|
throw new NoDataException("No documents exist");
|
||||||
cve.open();
|
|
||||||
if (!cve.dataExists()) {
|
|
||||||
throw new NoDataException("No documents exist");
|
|
||||||
}
|
|
||||||
} catch (DatabaseException ex) {
|
|
||||||
throw new NoDataException(ex.getMessage(), ex);
|
|
||||||
} finally {
|
|
||||||
cve.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
|
|||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||||
|
import org.owasp.dependencycheck.exception.ReportException;
|
||||||
import org.owasp.dependencycheck.exception.ScanAgentException;
|
import org.owasp.dependencycheck.exception.ScanAgentException;
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
@@ -63,6 +64,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DependencyCheckScanAgent {
|
public class DependencyCheckScanAgent {
|
||||||
|
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="private fields">
|
||||||
/**
|
/**
|
||||||
* System specific new line character.
|
* System specific new line character.
|
||||||
*/
|
*/
|
||||||
@@ -75,6 +77,141 @@ public class DependencyCheckScanAgent {
|
|||||||
* The application name for the report.
|
* The application name for the report.
|
||||||
*/
|
*/
|
||||||
private String applicationName = "Dependency-Check";
|
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.
|
* Get the value of applicationName.
|
||||||
@@ -94,11 +231,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.applicationName = applicationName;
|
this.applicationName = applicationName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The pre-determined dependencies to scan
|
|
||||||
*/
|
|
||||||
private List<Dependency> dependencies;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of pre-determined dependencies.
|
* Returns a list of pre-determined dependencies.
|
||||||
*
|
*
|
||||||
@@ -117,11 +249,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.dependencies = dependencies;
|
this.dependencies = dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The location of the data directory that contains
|
|
||||||
*/
|
|
||||||
private String dataDirectory = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of dataDirectory.
|
* Get the value of dataDirectory.
|
||||||
*
|
*
|
||||||
@@ -140,12 +267,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.dataDirectory = dataDirectory;
|
this.dataDirectory = dataDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the destination directory for the generated Dependency-Check
|
|
||||||
* report.
|
|
||||||
*/
|
|
||||||
private String reportOutputDirectory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of reportOutputDirectory.
|
* Get the value of reportOutputDirectory.
|
||||||
*
|
*
|
||||||
@@ -164,15 +285,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.reportOutputDirectory = 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.
|
* Get the value of failBuildOnCVSS.
|
||||||
*
|
*
|
||||||
@@ -191,12 +303,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.failBuildOnCVSS = 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 = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of autoUpdate.
|
* Get the value of autoUpdate.
|
||||||
*
|
*
|
||||||
@@ -215,11 +321,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.autoUpdate = autoUpdate;
|
this.autoUpdate = autoUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* flag indicating whether or not to generate a report of findings.
|
|
||||||
*/
|
|
||||||
private boolean generateReport = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of generateReport.
|
* Get the value of generateReport.
|
||||||
*
|
*
|
||||||
@@ -238,13 +339,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.generateReport = generateReport;
|
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.
|
* Get the value of reportFormat.
|
||||||
*
|
*
|
||||||
@@ -263,11 +357,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.reportFormat = reportFormat;
|
this.reportFormat = reportFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy Server.
|
|
||||||
*/
|
|
||||||
private String proxyServer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyServer.
|
* Get the value of proxyServer.
|
||||||
*
|
*
|
||||||
@@ -311,11 +400,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyServer = proxyUrl;
|
this.proxyServer = proxyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy Port.
|
|
||||||
*/
|
|
||||||
private String proxyPort;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyPort.
|
* Get the value of proxyPort.
|
||||||
*
|
*
|
||||||
@@ -334,11 +418,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyPort = proxyPort;
|
this.proxyPort = proxyPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy username.
|
|
||||||
*/
|
|
||||||
private String proxyUsername;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyUsername.
|
* Get the value of proxyUsername.
|
||||||
*
|
*
|
||||||
@@ -357,11 +436,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyUsername = proxyUsername;
|
this.proxyUsername = proxyUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy password.
|
|
||||||
*/
|
|
||||||
private String proxyPassword;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyPassword.
|
* Get the value of proxyPassword.
|
||||||
*
|
*
|
||||||
@@ -380,11 +454,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyPassword = proxyPassword;
|
this.proxyPassword = proxyPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Connection Timeout.
|
|
||||||
*/
|
|
||||||
private String connectionTimeout;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of connectionTimeout.
|
* Get the value of connectionTimeout.
|
||||||
*
|
*
|
||||||
@@ -403,11 +472,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.connectionTimeout = connectionTimeout;
|
this.connectionTimeout = connectionTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The file path used for verbose logging.
|
|
||||||
*/
|
|
||||||
private String logFile = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of logFile.
|
* Get the value of logFile.
|
||||||
*
|
*
|
||||||
@@ -426,11 +490,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.logFile = logFile;
|
this.logFile = logFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The path to the suppression file.
|
|
||||||
*/
|
|
||||||
private String suppressionFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of suppressionFile.
|
* Get the value of suppressionFile.
|
||||||
*
|
*
|
||||||
@@ -449,11 +508,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.suppressionFile = suppressionFile;
|
this.suppressionFile = suppressionFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* flag indicating whether or not to show a summary of findings.
|
|
||||||
*/
|
|
||||||
private boolean showSummary = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of showSummary.
|
* Get the value of showSummary.
|
||||||
*
|
*
|
||||||
@@ -472,11 +526,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.showSummary = showSummary;
|
this.showSummary = showSummary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the Maven Central analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private boolean centralAnalyzerEnabled = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of centralAnalyzerEnabled.
|
* Get the value of centralAnalyzerEnabled.
|
||||||
*
|
*
|
||||||
@@ -495,11 +544,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL of Maven Central.
|
|
||||||
*/
|
|
||||||
private String centralUrl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of centralUrl.
|
* Get the value of centralUrl.
|
||||||
*
|
*
|
||||||
@@ -518,11 +562,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.centralUrl = centralUrl;
|
this.centralUrl = centralUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the nexus analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private boolean nexusAnalyzerEnabled = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of nexusAnalyzerEnabled.
|
* Get the value of nexusAnalyzerEnabled.
|
||||||
*
|
*
|
||||||
@@ -541,11 +580,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL of the Nexus server.
|
|
||||||
*/
|
|
||||||
private String nexusUrl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of nexusUrl.
|
* Get the value of nexusUrl.
|
||||||
*
|
*
|
||||||
@@ -564,11 +598,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.nexusUrl = nexusUrl;
|
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.
|
* Get the value of nexusUsesProxy.
|
||||||
*
|
*
|
||||||
@@ -587,11 +616,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.nexusUsesProxy = nexusUsesProxy;
|
this.nexusUsesProxy = nexusUsesProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The database driver name; such as org.h2.Driver.
|
|
||||||
*/
|
|
||||||
private String databaseDriverName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databaseDriverName.
|
* Get the value of databaseDriverName.
|
||||||
*
|
*
|
||||||
@@ -610,11 +634,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databaseDriverName = databaseDriverName;
|
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.
|
* Get the value of databaseDriverPath.
|
||||||
*
|
*
|
||||||
@@ -633,11 +652,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databaseDriverPath = databaseDriverPath;
|
this.databaseDriverPath = databaseDriverPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The database connection string.
|
|
||||||
*/
|
|
||||||
private String connectionString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of connectionString.
|
* Get the value of connectionString.
|
||||||
*
|
*
|
||||||
@@ -656,11 +670,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.connectionString = connectionString;
|
this.connectionString = connectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The user name for connecting to the database.
|
|
||||||
*/
|
|
||||||
private String databaseUser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databaseUser.
|
* Get the value of databaseUser.
|
||||||
*
|
*
|
||||||
@@ -679,11 +688,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databaseUser = databaseUser;
|
this.databaseUser = databaseUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The password to use when connecting to the database.
|
|
||||||
*/
|
|
||||||
private String databasePassword;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databasePassword.
|
* Get the value of databasePassword.
|
||||||
*
|
*
|
||||||
@@ -702,12 +706,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databasePassword = databasePassword;
|
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.
|
* Get the value of zipExtensions.
|
||||||
*
|
*
|
||||||
@@ -726,11 +724,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.zipExtensions = zipExtensions;
|
this.zipExtensions = zipExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The url for the modified NVD CVE (1.2 schema).
|
|
||||||
*/
|
|
||||||
private String cveUrl12Modified;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl12Modified.
|
* Get the value of cveUrl12Modified.
|
||||||
*
|
*
|
||||||
@@ -749,11 +742,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl12Modified = cveUrl12Modified;
|
this.cveUrl12Modified = cveUrl12Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The url for the modified NVD CVE (2.0 schema).
|
|
||||||
*/
|
|
||||||
private String cveUrl20Modified;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl20Modified.
|
* Get the value of cveUrl20Modified.
|
||||||
*
|
*
|
||||||
@@ -772,11 +760,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl20Modified = cveUrl20Modified;
|
this.cveUrl20Modified = cveUrl20Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Base Data Mirror URL for CVE 1.2.
|
|
||||||
*/
|
|
||||||
private String cveUrl12Base;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl12Base.
|
* Get the value of cveUrl12Base.
|
||||||
*
|
*
|
||||||
@@ -795,11 +778,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl12Base = cveUrl12Base;
|
this.cveUrl12Base = cveUrl12Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Data Mirror URL for CVE 2.0.
|
|
||||||
*/
|
|
||||||
private String cveUrl20Base;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl20Base.
|
* Get the value of cveUrl20Base.
|
||||||
*
|
*
|
||||||
@@ -818,11 +796,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl20Base = cveUrl20Base;
|
this.cveUrl20Base = cveUrl20Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
|
||||||
*/
|
|
||||||
private String pathToMono;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of pathToMono.
|
* Get the value of pathToMono.
|
||||||
*
|
*
|
||||||
@@ -840,6 +813,7 @@ public class DependencyCheckScanAgent {
|
|||||||
public void setPathToMono(String pathToMono) {
|
public void setPathToMono(String pathToMono) {
|
||||||
this.pathToMono = pathToMono;
|
this.pathToMono = pathToMono;
|
||||||
}
|
}
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the Dependency-Check on the dependent libraries.
|
* Executes the Dependency-Check on the dependent libraries.
|
||||||
@@ -869,28 +843,17 @@ public class DependencyCheckScanAgent {
|
|||||||
*/
|
*/
|
||||||
private void generateExternalReports(Engine engine, File outDirectory) {
|
private void generateExternalReports(Engine engine, File outDirectory) {
|
||||||
DatabaseProperties prop = null;
|
DatabaseProperties prop = null;
|
||||||
CveDB cve = null;
|
try (CveDB cve = CveDB.getInstance()) {
|
||||||
try {
|
|
||||||
cve = new CveDB();
|
|
||||||
cve.open();
|
|
||||||
prop = cve.getDatabaseProperties();
|
prop = cve.getDatabaseProperties();
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
|
//TODO shouldn't this be a fatal exception
|
||||||
LOGGER.debug("Unable to retrieve DB Properties", 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);
|
final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||||
try {
|
try {
|
||||||
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
||||||
} catch (IOException ex) {
|
} catch (IOException | ReportException ex) {
|
||||||
LOGGER.error(
|
LOGGER.error("Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||||
"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);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -998,7 +961,7 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
if (ids.length() > 0) {
|
if (ids.length() > 0) {
|
||||||
final String msg = String.format("%n%nDependency-Check Failure:%n"
|
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());
|
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
|
||||||
|
|
||||||
throw new ScanAgentException(msg);
|
throw new ScanAgentException(msg);
|
||||||
@@ -1044,5 +1007,4 @@ public class DependencyCheckScanAgent {
|
|||||||
summary.toString());
|
summary.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
|||||||
protected abstract void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException;
|
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
|
* @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
|
* @throws Exception thrown if there is an exception
|
||||||
*/
|
*/
|
||||||
protected void closeAnalyzer() throws 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
|
* 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
|
* 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.
|
* The default is to support parallel processing.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
* @return a Set of strings.
|
* @return a Set of strings.
|
||||||
*/
|
*/
|
||||||
protected static Set<String> newHashSet(String... 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);
|
Collections.addAll(set, strings);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,10 +130,9 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file = new File(suppressionFilePath);
|
file = new File(suppressionFilePath);
|
||||||
InputStream suppressionsFromClasspath = null;
|
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
try {
|
try (InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath)) {
|
||||||
suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath);
|
|
||||||
if (suppressionsFromClasspath != null) {
|
if (suppressionsFromClasspath != null) {
|
||||||
deleteTempFile = true;
|
deleteTempFile = true;
|
||||||
file = FileUtils.getTempFile("suppression", "xml");
|
file = FileUtils.getTempFile("suppression", "xml");
|
||||||
@@ -143,14 +142,6 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
|
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.
|
* @return a list of Analyzers.
|
||||||
*/
|
*/
|
||||||
public List<Analyzer> getAnalyzers() {
|
public List<Analyzer> getAnalyzers() {
|
||||||
final List<Analyzer> analyzers = new ArrayList<Analyzer>();
|
final List<Analyzer> analyzers = new ArrayList<>();
|
||||||
final Iterator<Analyzer> iterator = service.iterator();
|
final Iterator<Analyzer> iterator = service.iterator();
|
||||||
boolean experimentalEnabled = false;
|
boolean experimentalEnabled = false;
|
||||||
try {
|
try {
|
||||||
experimentalEnabled = Settings.getBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, false);
|
experimentalEnabled = Settings.getBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, false);
|
||||||
} catch (InvalidSettingException ex) {
|
} catch (InvalidSettingException ex) {
|
||||||
LOGGER.error("invalide experimental setting", ex);
|
LOGGER.error("invalid experimental setting", ex);
|
||||||
}
|
}
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
final Analyzer a = iterator.next();
|
final Analyzer a = iterator.next();
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The set of things we can handle with Zip methods
|
* 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
|
* The set of file extensions supported by this analyzer. Note for
|
||||||
* developers, any additions to this list will need to be explicitly handled
|
* 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");
|
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 {
|
static {
|
||||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||||
if (additionalZipExt != null) {
|
if (additionalZipExt != null) {
|
||||||
final String[] ext = additionalZipExt.split("\\s*,\\s*");
|
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.
|
* The file filter used to filter supported files.
|
||||||
*/
|
*/
|
||||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
@Override
|
|
||||||
protected FileFilter getFileFilter() {
|
|
||||||
return FILTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects files with .zip extension.
|
* Detects files with .zip extension.
|
||||||
*/
|
*/
|
||||||
private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
|
private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the analyzer.
|
* 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
|
* Does not support parallel processing as it both modifies and iterates
|
||||||
* over the engine's list of dependencies.
|
* 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 #analyzeDependency(Dependency, Engine)
|
||||||
* @see #findMoreDependencies(Engine, File)
|
* @see #findMoreDependencies(Engine, File)
|
||||||
*/
|
*/
|
||||||
@@ -301,11 +303,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
private void addDisguisedJarsToDependencies(Dependency dependency, Engine engine) throws AnalysisException {
|
private void addDisguisedJarsToDependencies(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
if (ZIP_FILTER.accept(dependency.getActualFile()) && isZipFileActuallyJarFile(dependency)) {
|
if (ZIP_FILTER.accept(dependency.getActualFile()) && isZipFileActuallyJarFile(dependency)) {
|
||||||
final File tdir = getNextTempDirectory();
|
final File tempDir = getNextTempDirectory();
|
||||||
final String fileName = dependency.getFileName();
|
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);
|
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
|
//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.
|
// and add it is a related dependency.
|
||||||
final String archiveSha1 = dependency.getSha1sum();
|
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
|
* @return any dependencies that weren't known to the engine before
|
||||||
*/
|
*/
|
||||||
private static List<Dependency> findMoreDependencies(Engine engine, File file) {
|
private static List<Dependency> findMoreDependencies(Engine engine, File file) {
|
||||||
final List<Dependency> added = engine.scan(file);
|
return engine.scan(file);
|
||||||
return added;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -398,7 +399,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
GzipCompressorInputStream gin = null;
|
GzipCompressorInputStream gin = null;
|
||||||
BZip2CompressorInputStream bzin = null;
|
BZip2CompressorInputStream bzin = null;
|
||||||
try {
|
try {
|
||||||
if (ZIPPABLES.contains(archiveExt)) {
|
if (KNOWN_ZIP_EXT.contains(archiveExt)) {
|
||||||
in = new BufferedInputStream(fis);
|
in = new BufferedInputStream(fis);
|
||||||
ensureReadableJar(archiveExt, in);
|
ensureReadableJar(archiveExt, in);
|
||||||
zin = new ZipArchiveInputStream(in);
|
zin = new ZipArchiveInputStream(in);
|
||||||
@@ -470,7 +471,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
&& b[5] == 'n'
|
&& b[5] == 'n'
|
||||||
&& b[6] == '/') {
|
&& b[6] == '/') {
|
||||||
boolean stillLooking = true;
|
boolean stillLooking = true;
|
||||||
int chr, nxtChr;
|
int chr;
|
||||||
|
int nxtChr;
|
||||||
while (stillLooking && (chr = in.read()) != -1) {
|
while (stillLooking && (chr = in.read()) != -1) {
|
||||||
if (chr == '\n' || chr == '\r') {
|
if (chr == '\n' || chr == '\r') {
|
||||||
in.mark(4);
|
in.mark(4);
|
||||||
@@ -517,7 +519,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
extractAcceptedFile(input, file);
|
extractAcceptedFile(input, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable ex) {
|
} catch (IOException | AnalysisException ex) {
|
||||||
throw new ArchiveExtractionException(ex);
|
throw new ArchiveExtractionException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
FileUtils.close(input);
|
FileUtils.close(input);
|
||||||
@@ -533,14 +535,12 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
private static void extractAcceptedFile(ArchiveInputStream input, File file) throws AnalysisException {
|
private static void extractAcceptedFile(ArchiveInputStream input, File file) throws AnalysisException {
|
||||||
LOGGER.debug("Extracting '{}'", file.getPath());
|
LOGGER.debug("Extracting '{}'", file.getPath());
|
||||||
FileOutputStream fos = null;
|
final File parent = file.getParentFile();
|
||||||
try {
|
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||||
final File parent = file.getParentFile();
|
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
||||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
throw new AnalysisException(msg);
|
||||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
}
|
||||||
throw new AnalysisException(msg);
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
}
|
|
||||||
fos = new FileOutputStream(file);
|
|
||||||
IOUtils.copy(input, fos);
|
IOUtils.copy(input, fos);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
@@ -550,8 +550,6 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
LOGGER.debug("", 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 AnalysisException(msg, ex);
|
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 {
|
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
||||||
LOGGER.debug("Decompressing '{}'", outputFile.getPath());
|
LOGGER.debug("Decompressing '{}'", outputFile.getPath());
|
||||||
FileOutputStream out = null;
|
try (FileOutputStream out = new FileOutputStream(outputFile)) {
|
||||||
try {
|
|
||||||
out = new FileOutputStream(outputFile);
|
|
||||||
IOUtils.copy(inputStream, out);
|
IOUtils.copy(inputStream, out);
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
LOGGER.debug("", ex);
|
|
||||||
throw new ArchiveExtractionException(ex);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new ArchiveExtractionException(ex);
|
throw new ArchiveExtractionException(ex);
|
||||||
} finally {
|
|
||||||
FileUtils.close(out);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,7 +601,6 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
} finally {
|
} finally {
|
||||||
ZipFile.closeQuietly(zip);
|
ZipFile.closeQuietly(zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isJar;
|
return isJar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
protected List<String> buildArgumentList() {
|
protected List<String> buildArgumentList() {
|
||||||
// Use file.separator as a wild guess as to whether this is Windows
|
// 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 (!SystemUtils.IS_OS_WINDOWS) {
|
||||||
if (Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH) != null) {
|
if (Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH) != null) {
|
||||||
args.add(Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH));
|
args.add(Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH));
|
||||||
@@ -144,7 +144,9 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
dependency.getActualFilePath());
|
dependency.getActualFilePath());
|
||||||
return;
|
return;
|
||||||
} else if (rc != 0) {
|
} 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();
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
@@ -175,18 +177,17 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
|
|
||||||
} catch (ParserConfigurationException pce) {
|
} catch (ParserConfigurationException pce) {
|
||||||
throw new AnalysisException("Error initializing the assembly analyzer", pce);
|
throw new AnalysisException("Error initializing the assembly analyzer", pce);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException | XPathExpressionException ioe) {
|
||||||
throw new AnalysisException(ioe);
|
throw new AnalysisException(ioe);
|
||||||
} catch (SAXException saxe) {
|
} catch (SAXException saxe) {
|
||||||
LOGGER.error("----------------------------------------------------");
|
LOGGER.error("----------------------------------------------------");
|
||||||
LOGGER.error("Failed to read the Assembly Analyzer results. "
|
LOGGER.error("Failed to read the Assembly Analyzer results. "
|
||||||
+ "On some systems mono-runtime and mono-devel need to be installed.");
|
+ "On some systems mono-runtime and mono-devel need to be installed.");
|
||||||
LOGGER.error("----------------------------------------------------");
|
LOGGER.error("----------------------------------------------------");
|
||||||
throw new AnalysisException("Couldn't parse Assembly Analzyzer results (GrokAssembly)", saxe);
|
throw new AnalysisException("Couldn't parse Assembly Analyzer results (GrokAssembly)", saxe);
|
||||||
} catch (XPathExpressionException xpe) {
|
|
||||||
// This shouldn't happen
|
|
||||||
throw new AnalysisException(xpe);
|
|
||||||
}
|
}
|
||||||
|
// This shouldn't happen
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,40 +199,27 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
public void initializeFileTypeAnalyzer() throws InitializationException {
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
final File tempFile;
|
final File tempFile;
|
||||||
|
final String cfg;
|
||||||
try {
|
try {
|
||||||
tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
|
tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
|
||||||
|
cfg = tempFile.getPath() + ".config";
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
setEnabled(false);
|
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;
|
try (FileOutputStream fos = new FileOutputStream(tempFile);
|
||||||
InputStream is = null;
|
InputStream is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
||||||
try {
|
FileOutputStream fosCfg = new FileOutputStream(cfg);
|
||||||
fos = new FileOutputStream(tempFile);
|
InputStream isCfg = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe.config")) {
|
||||||
is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
|
||||||
IOUtils.copy(is, fos);
|
IOUtils.copy(is, fos);
|
||||||
|
|
||||||
grokAssemblyExe = tempFile;
|
grokAssemblyExe = tempFile;
|
||||||
LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
|
LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
|
||||||
|
IOUtils.copy(isCfg, fosCfg);
|
||||||
|
LOGGER.debug("Extracted GrokAssembly.exe.config to {}", cfg);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
this.setEnabled(false);
|
this.setEnabled(false);
|
||||||
LOGGER.warn("Could not extract GrokAssembly.exe: {}", ioe.getMessage());
|
LOGGER.warn("Could not extract GrokAssembly.exe: {}", ioe.getMessage());
|
||||||
throw new InitializationException("Could not extract GrokAssembly.exe", ioe);
|
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.
|
// 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
|
// We need to create a non-fatal warning error type that will
|
||||||
// get added to the report.
|
// 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) {
|
if (args == null) {
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
LOGGER.error("----------------------------------------------------");
|
LOGGER.error("----------------------------------------------------");
|
||||||
@@ -273,7 +261,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
} catch (InitializationException e) {
|
} catch (InitializationException e) {
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Throwable e) {
|
} catch (IOException | ParserConfigurationException | SAXException | XPathExpressionException | InterruptedException e) {
|
||||||
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n"
|
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.");
|
+ "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());
|
LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage());
|
||||||
@@ -359,10 +347,8 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
if (retCode == 0) {
|
if (retCode == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException | InterruptedException ex) {
|
||||||
LOGGER.debug("Path seach failed for " + file);
|
LOGGER.debug("Path search failed for " + file, ex);
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
LOGGER.debug("Path seach failed for " + file);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,26 +70,26 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The maximum number of query results to return.
|
* 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.
|
* 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
|
* A string representation of a regular expression defining characters
|
||||||
* utilized within the CPE Names.
|
* 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
|
* A string representation of a regular expression used to remove all but
|
||||||
* alpha characters.
|
* 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
|
* The additional size to add to a new StringBuilder to account for extra
|
||||||
* data that will be written into the string.
|
* 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.
|
* The CPE in memory index.
|
||||||
*/
|
*/
|
||||||
@@ -123,14 +123,17 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
public AnalysisPhase getAnalysisPhase() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return AnalysisPhase.IDENTIFIER_ANALYSIS;
|
return AnalysisPhase.IDENTIFIER_ANALYSIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default is to support parallel processing.
|
* The default is to support parallel processing.
|
||||||
|
*
|
||||||
* @return false
|
* @return false
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsParallelProcessing() {
|
public boolean supportsParallelProcessing() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the CPE Lucene Index.
|
* Creates the CPE Lucene Index.
|
||||||
*
|
*
|
||||||
@@ -160,8 +163,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
*/
|
*/
|
||||||
public void open() throws IOException, DatabaseException {
|
public void open() throws IOException, DatabaseException {
|
||||||
if (!isOpen()) {
|
if (!isOpen()) {
|
||||||
cve = new CveDB();
|
cve = CveDB.getInstance();
|
||||||
cve.open();
|
|
||||||
cpe = CpeMemoryIndex.getInstance();
|
cpe = CpeMemoryIndex.getInstance();
|
||||||
try {
|
try {
|
||||||
final long creationStart = System.currentTimeMillis();
|
final long creationStart = System.currentTimeMillis();
|
||||||
@@ -180,16 +182,21 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void closeAnalyzer() {
|
public void closeAnalyzer() {
|
||||||
if (cpe != null) {
|
|
||||||
cpe.close();
|
|
||||||
cpe = null;
|
|
||||||
}
|
|
||||||
if (cve != null) {
|
if (cve != null) {
|
||||||
cve.close();
|
cve.close();
|
||||||
cve = null;
|
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() {
|
public boolean isOpen() {
|
||||||
return cpe != null && cpe.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.
|
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||||
*/
|
*/
|
||||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
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 vendors = "";
|
||||||
String products = "";
|
String products = "";
|
||||||
for (Confidence confidence : Confidence.values()) {
|
for (Confidence confidence : Confidence.values()) {
|
||||||
@@ -293,7 +300,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
protected List<IndexEntry> searchCPE(String vendor, String product,
|
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||||
Set<String> vendorWeightings, Set<String> productWeightings) {
|
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);
|
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
||||||
if (searchString == null) {
|
if (searchString == null) {
|
||||||
@@ -479,7 +486,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final String[] words = text.split("[\\s_-]");
|
final String[] words = text.split("[\\s_-]");
|
||||||
final List<String> list = new ArrayList<String>();
|
final List<String> list = new ArrayList<>();
|
||||||
String tempWord = null;
|
String tempWord = null;
|
||||||
for (String word : words) {
|
for (String word : words) {
|
||||||
/*
|
/*
|
||||||
@@ -557,7 +564,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||||
Confidence bestGuessConf = null;
|
Confidence bestGuessConf = null;
|
||||||
boolean hasBroadMatch = false;
|
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
|
//TODO the following algorithm incorrectly identifies things as a lower version
|
||||||
// if there lower confidence evidence when the current (highest) version number
|
// 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 ((bestGuessConf == null || bestGuessConf.compareTo(conf) > 0)
|
||||||
if (bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
|
&& bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
|
||||||
bestGuess = evVer;
|
bestGuess = evVer;
|
||||||
bestGuessConf = conf;
|
bestGuessConf = conf;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -610,10 +616,12 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
||||||
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
||||||
}
|
}
|
||||||
if (bestGuessConf == null) {
|
if (bestGuessConf
|
||||||
|
== null) {
|
||||||
bestGuessConf = Confidence.LOW;
|
bestGuessConf = Confidence.LOW;
|
||||||
}
|
}
|
||||||
final IdentifierMatch match = new IdentifierMatch("cpe", cpeName, url, IdentifierConfidence.BEST_GUESS, bestGuessConf);
|
final IdentifierMatch match = new IdentifierMatch("cpe", cpeName, url, IdentifierConfidence.BEST_GUESS, bestGuessConf);
|
||||||
|
|
||||||
collected.add(match);
|
collected.add(match);
|
||||||
|
|
||||||
Collections.sort(collected);
|
Collections.sort(collected);
|
||||||
@@ -645,6 +653,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
protected String getAnalyzerEnabledSettingKey() {
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
return Settings.KEYS.ANALYZER_CPE_ENABLED;
|
return Settings.KEYS.ANALYZER_CPE_ENABLED;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -674,6 +683,19 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
*/
|
*/
|
||||||
private static class IdentifierMatch implements Comparable<IdentifierMatch> {
|
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.
|
* Constructs an IdentifierMatch.
|
||||||
*
|
*
|
||||||
@@ -690,12 +712,8 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
this.confidence = identifierConfidence;
|
this.confidence = identifierConfidence;
|
||||||
this.evidenceConfidence = evidenceConfidence;
|
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
|
* Get the value of evidenceConfidence
|
||||||
*
|
*
|
||||||
@@ -713,10 +731,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
public void setEvidenceConfidence(Confidence evidenceConfidence) {
|
public void setEvidenceConfidence(Confidence evidenceConfidence) {
|
||||||
this.evidenceConfidence = evidenceConfidence;
|
this.evidenceConfidence = evidenceConfidence;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The confidence whether this is an exact match, or a best guess.
|
|
||||||
*/
|
|
||||||
private IdentifierConfidence confidence;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of confidence.
|
* Get the value of confidence.
|
||||||
@@ -735,10 +749,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
public void setConfidence(IdentifierConfidence confidence) {
|
public void setConfidence(IdentifierConfidence confidence) {
|
||||||
this.confidence = confidence;
|
this.confidence = confidence;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The CPE identifier.
|
|
||||||
*/
|
|
||||||
private Identifier identifier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of identifier.
|
* Get the value of identifier.
|
||||||
@@ -806,10 +816,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
|
|||||||
if (this.confidence != other.confidence) {
|
if (this.confidence != other.confidence) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier))) {
|
return !(this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier)));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
|
|||||||
@@ -103,14 +103,14 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* <code>false</code>
|
* <code>false</code>
|
||||||
*/
|
*/
|
||||||
private boolean checkEnabled() {
|
private boolean checkEnabled() {
|
||||||
boolean retval = false;
|
boolean retVal = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
||||||
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
||||||
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
||||||
LOGGER.debug("Enabling the Central analyzer");
|
LOGGER.debug("Enabling the Central analyzer");
|
||||||
retval = true;
|
retVal = true;
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
} catch (InvalidSettingException ise) {
|
} catch (InvalidSettingException ise) {
|
||||||
LOGGER.warn("Invalid setting. Disabling the Central analyzer");
|
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.FileFilter;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
@@ -101,9 +101,7 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
FileInputStream fis = null;
|
try (FileInputStream fis = new FileInputStream(dependency.getActualFile())) {
|
||||||
try {
|
|
||||||
fis = new FileInputStream(dependency.getActualFile());
|
|
||||||
final ComposerLockParser clp = new ComposerLockParser(fis);
|
final ComposerLockParser clp = new ComposerLockParser(fis);
|
||||||
LOGGER.info("Checking composer.lock file {}", dependency.getActualFilePath());
|
LOGGER.info("Checking composer.lock file {}", dependency.getActualFilePath());
|
||||||
clp.process();
|
clp.process();
|
||||||
@@ -120,18 +118,10 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
LOGGER.info("Adding dependency {}", d);
|
LOGGER.info("Adding dependency {}", d);
|
||||||
engine.getDependencies().add(d);
|
engine.getDependencies().add(d);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException fnfe) {
|
} catch (IOException ex) {
|
||||||
LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());
|
LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());
|
||||||
} catch (ComposerException ce) {
|
} catch (ComposerException ce) {
|
||||||
LOGGER.warn("Error parsing composer.json {}", dependency.getActualFilePath(), 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
|
* @return a flag indicating if this analyzer has run. This analyzer only
|
||||||
* runs once
|
* runs once
|
||||||
*/
|
*/
|
||||||
protected boolean getAnalyzed() {
|
protected synchronized boolean getAnalyzed() {
|
||||||
return analyzed;
|
return analyzed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
|||||||
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
||||||
if (!analyzed) {
|
if (!analyzed) {
|
||||||
analyzed = true;
|
analyzed = true;
|
||||||
final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
|
final Set<Dependency> dependenciesToRemove = new HashSet<>();
|
||||||
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
||||||
//for (Dependency nextDependency : engine.getDependencies()) {
|
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||||
while (mainIterator.hasNext()) {
|
while (mainIterator.hasNext()) {
|
||||||
@@ -154,13 +154,15 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
|||||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||||
while (subIterator.hasNext()) {
|
while (subIterator.hasNext()) {
|
||||||
final Dependency nextDependency = subIterator.next();
|
final Dependency nextDependency = subIterator.next();
|
||||||
if (hashesMatch(dependency, nextDependency) && !containedInWar(dependency.getFilePath())
|
if (hashesMatch(dependency, nextDependency)) {
|
||||||
&& !containedInWar(nextDependency.getFilePath())) {
|
if (!containedInWar(dependency.getFilePath())
|
||||||
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
&& !containedInWar(nextDependency.getFilePath())) {
|
||||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||||
} else {
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
} else {
|
||||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||||
|
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (isShadedJar(dependency, nextDependency)) {
|
} else if (isShadedJar(dependency, nextDependency)) {
|
||||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
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
|
* @return a boolean indicating whether or not the left dependency should be
|
||||||
* considered the "core" version.
|
* 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 leftName = left.getFileName().toLowerCase();
|
||||||
final String rightName = right.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\'.
|
* @return true if the path contains '.war\' or '.ear\'.
|
||||||
*/
|
*/
|
||||||
private boolean containedInWar(String filePath) {
|
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
|
* @return a flag indicating if this analyzer has run. This analyzer only
|
||||||
* runs once
|
* runs once
|
||||||
*/
|
*/
|
||||||
protected boolean getAnalyzed() {
|
protected synchronized boolean getAnalyzed() {
|
||||||
return analyzed;
|
return analyzed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
|
|||||||
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
||||||
if (!analyzed) {
|
if (!analyzed) {
|
||||||
analyzed = true;
|
analyzed = true;
|
||||||
final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
|
final Set<Dependency> dependenciesToRemove = new HashSet<>();
|
||||||
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
||||||
//for (Dependency nextDependency : engine.getDependencies()) {
|
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||||
while (mainIterator.hasNext()) {
|
while (mainIterator.hasNext()) {
|
||||||
@@ -138,7 +138,7 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
|
|||||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||||
while (subIterator.hasNext()) {
|
while (subIterator.hasNext()) {
|
||||||
final Dependency nextDependency = subIterator.next();
|
final Dependency nextDependency = subIterator.next();
|
||||||
Dependency main = null;
|
Dependency main;
|
||||||
if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
|
if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
|
||||||
if (main == dependency) {
|
if (main == dependency) {
|
||||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
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
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
@@ -84,6 +85,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
public AnalysisPhase getAnalysisPhase() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Returns the setting key to determine if the analyzer is enabled.</p>
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
@@ -97,11 +99,13 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
//</editor-fold>
|
//</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 dependency the dependency to analyze.
|
||||||
* @param engine the engine that is scanning the dependencies
|
* @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
|
@Override
|
||||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
@@ -117,22 +121,23 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* Removes inaccurate matches on springframework CPEs.
|
* 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) {
|
private void removeBadSpringMatches(Dependency dependency) {
|
||||||
String mustContain = null;
|
String mustContain = null;
|
||||||
for (Identifier i : dependency.getIdentifiers()) {
|
for (Identifier i : dependency.getIdentifiers()) {
|
||||||
if ("maven".contains(i.getType())) {
|
if ("maven".contains(i.getType())
|
||||||
if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
&& i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||||
final int endPoint = i.getValue().indexOf(':', 19);
|
final int endPoint = i.getValue().indexOf(':', 19);
|
||||||
if (endPoint >= 0) {
|
if (endPoint >= 0) {
|
||||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mustContain != null) {
|
if (mustContain
|
||||||
|
!= null) {
|
||||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Identifier i = itr.next();
|
final Identifier i = itr.next();
|
||||||
@@ -149,7 +154,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <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>
|
* <p>
|
||||||
* Example:</p>
|
* Example:</p>
|
||||||
* <code>
|
* <code>
|
||||||
@@ -167,7 +173,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
private void removeSpuriousCPE(Dependency dependency) {
|
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);
|
Collections.sort(ids);
|
||||||
final ListIterator<Identifier> mainItr = ids.listIterator();
|
final ListIterator<Identifier> mainItr = ids.listIterator();
|
||||||
while (mainItr.hasNext()) {
|
while (mainItr.hasNext()) {
|
||||||
@@ -200,10 +206,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
if (nextVersion.startsWith(currentVersion) || "-".equals(currentVersion)) {
|
if (nextVersion.startsWith(currentVersion) || "-".equals(currentVersion)) {
|
||||||
dependency.getIdentifiers().remove(currentId);
|
dependency.getIdentifiers().remove(currentId);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
|
||||||
if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
|
dependency.getIdentifiers().remove(nextId);
|
||||||
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|"
|
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)?|"
|
+ "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$");
|
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$");
|
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
|
* @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
|
* Removes bad CPE matches for a dependency. Unfortunately, right now these
|
||||||
* identified when testing this on a LARGE volume of jar files.
|
* are hard-coded patches for specific problems identified when testing this
|
||||||
|
* on a LARGE volume of jar files.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @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
|
* @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
|
* There are some known CPE entries, specifically regarding sun and oracle
|
||||||
* product names, that based on given evidence we can add the related CPE entries to ensure a complete list of CVE entries.
|
* 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
|
* @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
|
* Removes duplicate entries identified that are contained within JAR files.
|
||||||
* other types of files (such as DLLs and EXEs) being contained within the JAR.
|
* 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 dependency the dependency that might be a duplicate
|
||||||
* @param engine the engine used to scan all dependencies
|
* @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")
|
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||||
|| DLL_EXE_FILTER.accept(dependency.getActualFile())) {
|
|| DLL_EXE_FILTER.accept(dependency.getActualFile())) {
|
||||||
String parentPath = dependency.getFilePath().toLowerCase();
|
String parentPath = dependency.getFilePath().toLowerCase();
|
||||||
if (parentPath.contains(".jar")) {
|
if (parentPath.contains(".jar")) {
|
||||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||||
final List<Dependency> dependencies = engine.getDependencies();
|
final List<Dependency> dependencies = engine.getDependencies();
|
||||||
synchronized (dependencies) {
|
final Dependency parent = findDependency(parentPath, dependencies);
|
||||||
final Dependency parent = findDependency(parentPath, dependencies);
|
if (parent != null) {
|
||||||
if (parent != null) {
|
boolean remove = false;
|
||||||
boolean remove = false;
|
for (Identifier i : dependency.getIdentifiers()) {
|
||||||
for (Identifier i : dependency.getIdentifiers()) {
|
if ("cpe".equals(i.getType())) {
|
||||||
if ("cpe".equals(i.getType())) {
|
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
for (Identifier parentId : parent.getIdentifiers()) {
|
||||||
for (Identifier parentId : parent.getIdentifiers()) {
|
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
remove |= true;
|
||||||
remove |= true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!remove) { //we can escape early
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (remove) {
|
if (!remove) { //we can escape early
|
||||||
dependencies.remove(dependency);
|
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 dependencyPath the path of the dependency to return
|
||||||
* @param dependencies the collection of dependencies to search
|
* @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
|
* @param value the CPE value to trim
|
||||||
* @return a CPE value that only includes the vendor and product
|
* @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 {
|
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">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
@@ -82,6 +95,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
|||||||
public AnalysisPhase getAnalysisPhase() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Returns the setting key to determine if the analyzer is enabled.</p>
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
@@ -109,19 +123,6 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
//</editor-fold>
|
//</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
|
* The HintAnalyzer uses knowledge about a dependency to add additional
|
||||||
* information to help in identification of identifiers or vulnerabilities.
|
* information to help in identification of identifiers or vulnerabilities.
|
||||||
@@ -134,29 +135,38 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
for (HintRule hint : hints.getHintRules()) {
|
for (HintRule hint : hints.getHintRules()) {
|
||||||
boolean shouldAdd = false;
|
boolean matchFound = false;
|
||||||
for (Evidence given : hint.getGivenVendor()) {
|
for (Evidence given : hint.getGivenVendor()) {
|
||||||
if (dependency.getVendorEvidence().getEvidence().contains(given)) {
|
if (dependency.getVendorEvidence().getEvidence().contains(given)) {
|
||||||
shouldAdd = true;
|
matchFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!shouldAdd) {
|
if (!matchFound) {
|
||||||
for (Evidence given : hint.getGivenProduct()) {
|
for (Evidence given : hint.getGivenProduct()) {
|
||||||
if (dependency.getProductEvidence().getEvidence().contains(given)) {
|
if (dependency.getProductEvidence().getEvidence().contains(given)) {
|
||||||
shouldAdd = true;
|
matchFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!shouldAdd) {
|
if (!matchFound) {
|
||||||
for (PropertyType pt : hint.getFilenames()) {
|
for (Evidence given : hint.getGivenVersion()) {
|
||||||
if (pt.matches(dependency.getFileName())) {
|
if (dependency.getVersionEvidence().getEvidence().contains(given)) {
|
||||||
shouldAdd = true;
|
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()) {
|
for (Evidence e : hint.getAddVendor()) {
|
||||||
dependency.getVendorEvidence().addEvidence(e);
|
dependency.getVendorEvidence().addEvidence(e);
|
||||||
}
|
}
|
||||||
@@ -166,11 +176,26 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
|||||||
for (Evidence e : hint.getAddVersion()) {
|
for (Evidence e : hint.getAddVersion()) {
|
||||||
dependency.getVersionEvidence().addEvidence(e);
|
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 Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
||||||
final List<Evidence> newEntries = new ArrayList<Evidence>();
|
final List<Evidence> newEntries = new ArrayList<>();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Evidence e = itr.next();
|
final Evidence e = itr.next();
|
||||||
for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
|
for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
|
||||||
@@ -183,108 +208,6 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
|||||||
for (Evidence e : newEntries) {
|
for (Evidence e : newEntries) {
|
||||||
dependency.getVendorEvidence().addEvidence(e);
|
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;
|
File file = null;
|
||||||
try {
|
try {
|
||||||
hints = parser.parseHints(this.getClass().getClassLoader().getResourceAsStream(HINT_RULE_FILE_NAME));
|
hints = parser.parseHints(this.getClass().getClassLoader().getResourceAsStream(HINT_RULE_FILE_NAME));
|
||||||
} catch (HintParseException 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);
|
|
||||||
} catch (SAXException ex) {
|
|
||||||
LOGGER.error("Unable to parse the base hint data file");
|
LOGGER.error("Unable to parse the base hint data file");
|
||||||
LOGGER.debug("Unable to parse the base hint data file", ex);
|
LOGGER.debug("Unable to parse the base hint data file", ex);
|
||||||
}
|
}
|
||||||
@@ -323,9 +243,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
|
|||||||
} else {
|
} else {
|
||||||
file = new File(filePath);
|
file = new File(filePath);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
InputStream fromClasspath = null;
|
try (InputStream fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath)) {
|
||||||
try {
|
|
||||||
fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath);
|
|
||||||
if (fromClasspath != null) {
|
if (fromClasspath != null) {
|
||||||
deleteTempFile = true;
|
deleteTempFile = true;
|
||||||
file = FileUtils.getTempFile("hint", "xml");
|
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);
|
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.Reader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -43,6 +44,7 @@ import java.util.regex.Pattern;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import org.apache.commons.compress.utils.IOUtils;
|
import org.apache.commons.compress.utils.IOUtils;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
@@ -148,15 +150,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* A pattern to detect HTML within text.
|
* A pattern to detect HTML within text.
|
||||||
*/
|
*/
|
||||||
private static final Pattern HTML_DETECTION_PATTERN = Pattern.compile("\\<[a-z]+.*/?\\>", Pattern.CASE_INSENSITIVE);
|
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.
|
* The name of the analyzer.
|
||||||
*/
|
*/
|
||||||
@@ -175,6 +168,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
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.
|
* Returns the FileFilter.
|
||||||
*
|
*
|
||||||
@@ -260,28 +255,12 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @return whether or not evidence was added to the dependency
|
* @return whether or not evidence was added to the dependency
|
||||||
*/
|
*/
|
||||||
protected boolean analyzePOM(Dependency dependency, List<ClassNameInformation> classes, Engine engine) throws AnalysisException {
|
protected boolean analyzePOM(Dependency dependency, List<ClassNameInformation> classes, Engine engine) throws AnalysisException {
|
||||||
JarFile jar = null;
|
try (JarFile jar = new JarFile(dependency.getActualFilePath())) {
|
||||||
List<String> pomEntries = null;
|
final List<String> pomEntries = retrievePomListing(jar);
|
||||||
try {
|
if (pomEntries != null && pomEntries.size() <= 1) {
|
||||||
jar = new JarFile(dependency.getActualFilePath());
|
String path;
|
||||||
pomEntries = retrievePomListing(jar);
|
File pomFile;
|
||||||
} 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;
|
|
||||||
Properties pomProperties = null;
|
Properties pomProperties = null;
|
||||||
File pomFile = null;
|
|
||||||
if (pomEntries.size() == 1) {
|
if (pomEntries.size() == 1) {
|
||||||
path = pomEntries.get(0);
|
path = pomEntries.get(0);
|
||||||
pomFile = extractPom(path, jar);
|
pomFile = extractPom(path, jar);
|
||||||
@@ -295,55 +274,44 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
if (pom != null && pomProperties != null) {
|
if (pom != null && pomProperties != null) {
|
||||||
pom.processProperties(pomProperties);
|
pom.processProperties(pomProperties);
|
||||||
}
|
}
|
||||||
if (pom != null) {
|
return pom != null && setPomEvidence(dependency, pom, classes);
|
||||||
return setPomEvidence(dependency, pom, classes);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
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 {
|
try {
|
||||||
jar.close();
|
//extract POM to its own directory and add it as its own dependency
|
||||||
} catch (IOException ex) {
|
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);
|
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) {
|
} catch (IOException ex) {
|
||||||
|
LOGGER.warn("Unable to read JarFile '{}'.", dependency.getActualFilePath());
|
||||||
LOGGER.trace("", ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -356,17 +324,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @param path the path to the pom.xml within the JarFile
|
* @param path the path to the pom.xml within the JarFile
|
||||||
* @param jar the JarFile to load the pom.properties from
|
* @param jar the JarFile to load the pom.properties from
|
||||||
* @return a Properties object or null if no pom.properties was found
|
* @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) {
|
private Properties retrievePomProperties(String path, final JarFile jar) {
|
||||||
Properties pomProperties = null;
|
Properties pomProperties = null;
|
||||||
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
||||||
final ZipEntry propEntry = jar.getEntry(propPath);
|
final ZipEntry propEntry = jar.getEntry(propPath);
|
||||||
if (propEntry != null) {
|
if (propEntry != null) {
|
||||||
Reader reader = null;
|
try (Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8")) {
|
||||||
try {
|
|
||||||
reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
|
||||||
pomProperties = new Properties();
|
pomProperties = new Properties();
|
||||||
pomProperties.load(reader);
|
pomProperties.load(reader);
|
||||||
LOGGER.debug("Read pom.properties: {}", propPath);
|
LOGGER.debug("Read pom.properties: {}", propPath);
|
||||||
@@ -374,14 +338,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
LOGGER.trace("UTF-8 is not supported", ex);
|
LOGGER.trace("UTF-8 is not supported", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.trace("Unable to read the POM properties", 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;
|
return pomProperties;
|
||||||
@@ -396,7 +352,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @throws IOException thrown if there is an exception reading a JarEntry
|
* @throws IOException thrown if there is an exception reading a JarEntry
|
||||||
*/
|
*/
|
||||||
private List<String> retrievePomListing(final JarFile jar) throws IOException {
|
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();
|
final Enumeration<JarEntry> entries = jar.entries();
|
||||||
while (entries.hasMoreElements()) {
|
while (entries.hasMoreElements()) {
|
||||||
final JarEntry entry = entries.nextElement();
|
final JarEntry entry = entries.nextElement();
|
||||||
@@ -419,24 +375,18 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* the file
|
* the file
|
||||||
*/
|
*/
|
||||||
private File extractPom(String path, JarFile jar) throws AnalysisException {
|
private File extractPom(String path, JarFile jar) throws AnalysisException {
|
||||||
InputStream input = null;
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
final File tmpDir = getNextTempDirectory();
|
final File tmpDir = getNextTempDirectory();
|
||||||
final File file = new File(tmpDir, "pom.xml");
|
final File file = new File(tmpDir, "pom.xml");
|
||||||
try {
|
final ZipEntry entry = jar.getEntry(path);
|
||||||
final ZipEntry entry = jar.getEntry(path);
|
if (entry == null) {
|
||||||
if (entry == null) {
|
throw new AnalysisException(String.format("Pom (%s) does not exist in %s", path, jar.getName()));
|
||||||
throw new AnalysisException(String.format("Pom (%s)does not exist in %s", path, jar.getName()));
|
}
|
||||||
}
|
try (InputStream input = jar.getInputStream(entry);
|
||||||
input = jar.getInputStream(entry);
|
FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
fos = new FileOutputStream(file);
|
|
||||||
IOUtils.copy(input, fos);
|
IOUtils.copy(input, fos);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.warn("An error occurred reading '{}' from '{}'.", path, jar.getName());
|
LOGGER.warn("An error occurred reading '{}' from '{}'.", path, jar.getName());
|
||||||
LOGGER.error("", ex);
|
LOGGER.error("", ex);
|
||||||
} finally {
|
|
||||||
FileUtils.close(fos);
|
|
||||||
FileUtils.close(input);
|
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
@@ -452,11 +402,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* otherwise false
|
* otherwise false
|
||||||
*/
|
*/
|
||||||
public static boolean setPomEvidence(Dependency dependency, Model pom, List<ClassNameInformation> classes) {
|
public static boolean setPomEvidence(Dependency dependency, Model pom, List<ClassNameInformation> classes) {
|
||||||
|
if (pom == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
boolean foundSomething = false;
|
boolean foundSomething = false;
|
||||||
boolean addAsIdentifier = true;
|
boolean addAsIdentifier = true;
|
||||||
if (pom == null) {
|
|
||||||
return foundSomething;
|
|
||||||
}
|
|
||||||
String groupid = pom.getGroupId();
|
String groupid = pom.getGroupId();
|
||||||
String parentGroupId = pom.getParentGroupId();
|
String parentGroupId = pom.getParentGroupId();
|
||||||
String artifactid = pom.getArtifactId();
|
String artifactid = pom.getArtifactId();
|
||||||
@@ -546,6 +496,12 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
addMatchingValues(classes, org, dependency.getVendorEvidence());
|
addMatchingValues(classes, org, dependency.getVendorEvidence());
|
||||||
addMatchingValues(classes, org, dependency.getProductEvidence());
|
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
|
//pom name
|
||||||
final String pomName = pom.getName();
|
final String pomName = pom.getName();
|
||||||
if (pomName
|
if (pomName
|
||||||
@@ -588,8 +544,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
protected void analyzePackageNames(List<ClassNameInformation> classNames,
|
protected void analyzePackageNames(List<ClassNameInformation> classNames,
|
||||||
Dependency dependency, boolean addPackagesAsEvidence) {
|
Dependency dependency, boolean addPackagesAsEvidence) {
|
||||||
final Map<String, Integer> vendorIdentifiers = new HashMap<String, Integer>();
|
final Map<String, Integer> vendorIdentifiers = new HashMap<>();
|
||||||
final Map<String, Integer> productIdentifiers = new HashMap<String, Integer>();
|
final Map<String, Integer> productIdentifiers = new HashMap<>();
|
||||||
analyzeFullyQualifiedClassNames(classNames, vendorIdentifiers, productIdentifiers);
|
analyzeFullyQualifiedClassNames(classNames, vendorIdentifiers, productIdentifiers);
|
||||||
|
|
||||||
final int classCount = classNames.size();
|
final int classCount = classNames.size();
|
||||||
@@ -636,9 +592,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> classInformation)
|
protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> classInformation)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
boolean foundSomething = false;
|
boolean foundSomething = false;
|
||||||
JarFile jar = null;
|
try (JarFile jar = new JarFile(dependency.getActualFilePath())) {
|
||||||
try {
|
|
||||||
jar = new JarFile(dependency.getActualFilePath());
|
|
||||||
final Manifest manifest = jar.getManifest();
|
final Manifest manifest = jar.getManifest();
|
||||||
if (manifest == null) {
|
if (manifest == null) {
|
||||||
if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
|
if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
|
||||||
@@ -793,10 +747,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
versionEvidence.addEvidence(source, "specification-version", specificationVersion, Confidence.HIGH);
|
versionEvidence.addEvidence(source, "specification-version", specificationVersion, Confidence.HIGH);
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
if (jar != null) {
|
|
||||||
jar.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return foundSomething;
|
return foundSomething;
|
||||||
}
|
}
|
||||||
@@ -949,10 +899,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @return an list of fully qualified class names
|
* @return an list of fully qualified class names
|
||||||
*/
|
*/
|
||||||
private List<ClassNameInformation> collectClassNames(Dependency dependency) {
|
private List<ClassNameInformation> collectClassNames(Dependency dependency) {
|
||||||
final List<ClassNameInformation> classNames = new ArrayList<ClassNameInformation>();
|
final List<ClassNameInformation> classNames = new ArrayList<>();
|
||||||
JarFile jar = null;
|
try (JarFile jar = new JarFile(dependency.getActualFilePath())) {
|
||||||
try {
|
|
||||||
jar = new JarFile(dependency.getActualFilePath());
|
|
||||||
final Enumeration<JarEntry> entries = jar.entries();
|
final Enumeration<JarEntry> entries = jar.entries();
|
||||||
while (entries.hasMoreElements()) {
|
while (entries.hasMoreElements()) {
|
||||||
final JarEntry entry = entries.nextElement();
|
final JarEntry entry = entries.nextElement();
|
||||||
@@ -966,14 +914,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.warn("Unable to open jar file '{}'.", dependency.getFileName());
|
LOGGER.warn("Unable to open jar file '{}'.", dependency.getFileName());
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
|
||||||
if (jar != null) {
|
|
||||||
try {
|
|
||||||
jar.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.trace("", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return classNames;
|
return classNames;
|
||||||
}
|
}
|
||||||
@@ -1116,6 +1056,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
protected static class ClassNameInformation {
|
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>
|
* <p>
|
||||||
* Stores information about a given class name. This class will keep the
|
* 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
|
* package structure. Up to the first four levels of the package
|
||||||
* structure are stored, excluding a leading "org" or "com".
|
* structure are stored, excluding a leading "org" or "com".
|
||||||
* Example:</p>
|
* 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());
|
* System.out.println(obj.getName());
|
||||||
* for (String p : obj.getPackageStructure())
|
* for (String p : obj.getPackageStructure())
|
||||||
* System.out.println(p);
|
* System.out.println(p);
|
||||||
@@ -1141,7 +1091,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
ClassNameInformation(String className) {
|
ClassNameInformation(String className) {
|
||||||
name = className;
|
name = className;
|
||||||
if (name.contains("/")) {
|
if (name.contains("/")) {
|
||||||
final String[] tmp = className.toLowerCase().split("/");
|
final String[] tmp = StringUtils.split(className.toLowerCase(), '/');
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int end = 3;
|
int end = 3;
|
||||||
if ("com".equals(tmp[0]) || "org".equals(tmp[0])) {
|
if ("com".equals(tmp[0]) || "org".equals(tmp[0])) {
|
||||||
@@ -1151,17 +1101,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
if (tmp.length <= end) {
|
if (tmp.length <= end) {
|
||||||
end = tmp.length - 1;
|
end = tmp.length - 1;
|
||||||
}
|
}
|
||||||
for (int i = start; i <= end; i++) {
|
packageStructure.addAll(Arrays.asList(tmp).subList(start, end + 1));
|
||||||
packageStructure.add(tmp[i]);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
packageStructure.add(name);
|
packageStructure.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The fully qualified class name.
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of name
|
* Get the value of name
|
||||||
@@ -1180,11 +1124,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = 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
|
* Get the value of packageStructure
|
||||||
|
|||||||
@@ -87,10 +87,6 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
private static final String SUPPORTED_EXTENSIONS = "jar";
|
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.
|
* 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("Initializing Nexus Analyzer");
|
||||||
LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
|
LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
useProxy = useProxy();
|
final boolean useProxy = useProxy();
|
||||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||||
LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
|
LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -121,17 +121,9 @@ public class NodePackageAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void analyzeDependency(Dependency dependency, Engine engine)
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
throws AnalysisException {
|
|
||||||
final File file = dependency.getActualFile();
|
final File file = dependency.getActualFile();
|
||||||
JsonReader jsonReader;
|
try (JsonReader jsonReader = Json.createReader(FileUtils.openInputStream(file))) {
|
||||||
try {
|
|
||||||
jsonReader = Json.createReader(FileUtils.openInputStream(file));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AnalysisException(
|
|
||||||
"Problem occurred while reading dependency file.", e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final JsonObject json = jsonReader.readObject();
|
final JsonObject json = jsonReader.readObject();
|
||||||
final EvidenceCollection productEvidence = dependency.getProductEvidence();
|
final EvidenceCollection productEvidence = dependency.getProductEvidence();
|
||||||
final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
|
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()));
|
dependency.setDisplayFileName(String.format("%s/%s", file.getParentFile().getName(), file.getName()));
|
||||||
} catch (JsonException e) {
|
} catch (JsonException e) {
|
||||||
LOGGER.warn("Failed to parse package.json file.", e);
|
LOGGER.warn("Failed to parse package.json file.", e);
|
||||||
} finally {
|
} catch (IOException e) {
|
||||||
jsonReader.close();
|
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.FileFilter;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
|
||||||
import org.owasp.dependencycheck.exception.InitializationException;
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,22 +131,10 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
final NuspecParser parser = new XPathNuspecParser();
|
final NuspecParser parser = new XPathNuspecParser();
|
||||||
NugetPackage np = null;
|
NugetPackage np = null;
|
||||||
FileInputStream fis = null;
|
try (FileInputStream fis = new FileInputStream(dependency.getActualFilePath())) {
|
||||||
try {
|
|
||||||
fis = new FileInputStream(dependency.getActualFilePath());
|
|
||||||
np = parser.parse(fis);
|
np = parser.parse(fis);
|
||||||
} catch (NuspecParseException ex) {
|
} catch (NuspecParseException | FileNotFoundException ex) {
|
||||||
throw new AnalysisException(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) {
|
if (np.getOwners() != null) {
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
|
|||||||
* The Logger for use throughout the class
|
* The Logger for use throughout the class
|
||||||
*/
|
*/
|
||||||
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.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.
|
* The CVE Index.
|
||||||
*/
|
*/
|
||||||
@@ -63,8 +60,7 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
|
|||||||
* loaded
|
* loaded
|
||||||
*/
|
*/
|
||||||
public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
|
public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
|
||||||
cveDB = new CveDB();
|
cveDB = CveDB.getInstance();
|
||||||
cveDB.open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,19 +81,6 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
|
|||||||
return cveDB != null;
|
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
|
* Analyzes a dependency and attempts to determine if there are any CPE
|
||||||
* identifiers for this dependency.
|
* identifiers for this dependency.
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @param openSSLVersionConstant The open SSL version
|
* @param openSSLVersionConstant The open SSL version
|
||||||
* @return the version of openssl
|
* @return the version of openssl
|
||||||
*/
|
*/
|
||||||
static String getOpenSSLVersion(long openSSLVersionConstant) {
|
protected static String getOpenSSLVersion(long openSSLVersionConstant) {
|
||||||
final long major = openSSLVersionConstant >>> MAJOR_OFFSET;
|
final long major = openSSLVersionConstant >>> MAJOR_OFFSET;
|
||||||
final long minor = (openSSLVersionConstant & MINOR_MASK) >>> MINOR_OFFSET;
|
final long minor = (openSSLVersionConstant & MINOR_MASK) >>> MINOR_OFFSET;
|
||||||
final long fix = (openSSLVersionConstant & FIX_MASK) >>> FIX_OFFSET;
|
final long fix = (openSSLVersionConstant & FIX_MASK) >>> FIX_OFFSET;
|
||||||
|
|||||||
@@ -360,22 +360,12 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
if (null == manifest) {
|
if (null == manifest) {
|
||||||
LOGGER.debug("Manifest file not found.");
|
LOGGER.debug("Manifest file not found.");
|
||||||
} else {
|
} else {
|
||||||
InputStream in = null;
|
try (InputStream in = new BufferedInputStream(new FileInputStream(manifest))) {
|
||||||
try {
|
|
||||||
in = new BufferedInputStream(new FileInputStream(manifest));
|
|
||||||
result.load(in);
|
result.load(in);
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException | FileNotFoundException e) {
|
||||||
LOGGER.warn(e.getMessage(), e);
|
LOGGER.warn(e.getMessage(), e);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (IOException ex) {
|
||||||
LOGGER.warn(e.getMessage(), e);
|
LOGGER.warn(ex.getMessage(), ex);
|
||||||
} finally {
|
|
||||||
if (in != null) {
|
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.debug("failed to close input stream", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
if (!folder.isDirectory()) {
|
if (!folder.isDirectory()) {
|
||||||
throw new AnalysisException(String.format("%s should have been a directory.", folder.getAbsolutePath()));
|
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);
|
final String bundleAuditPath = Settings.getString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH);
|
||||||
File bundleAudit = null;
|
File bundleAudit = null;
|
||||||
if (bundleAuditPath != null) {
|
if (bundleAuditPath != null) {
|
||||||
@@ -132,7 +132,8 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
LOGGER.info("Launching: " + args + " from " + folder);
|
LOGGER.info("Launching: " + args + " from " + folder);
|
||||||
return builder.start();
|
return builder.start();
|
||||||
} catch (IOException ioe) {
|
} 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
|
@Override
|
||||||
public void initializeFileTypeAnalyzer() throws InitializationException {
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
try {
|
try {
|
||||||
cvedb = new CveDB();
|
cvedb = CveDB.getInstance();
|
||||||
cvedb.open();
|
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.warn("Exception opening the database");
|
LOGGER.warn("Exception opening the database");
|
||||||
LOGGER.debug("error", ex);
|
LOGGER.debug("error", ex);
|
||||||
@@ -160,8 +160,6 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
} catch (AnalysisException ae) {
|
} catch (AnalysisException ae) {
|
||||||
|
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
cvedb.close();
|
|
||||||
cvedb = null;
|
|
||||||
final String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
|
final String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
|
||||||
throw new InitializationException(msg, ae);
|
throw new InitializationException(msg, ae);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
@@ -174,7 +172,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
exitValue = process.waitFor();
|
exitValue = process.waitFor();
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
setEnabled(false);
|
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);
|
throw new InitializationException(msg);
|
||||||
}
|
}
|
||||||
if (0 == exitValue) {
|
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);
|
final String msg = String.format("Unexpected exit code from bundle-audit process. Disabling %s: %s", ANALYZER_NAME, exitValue);
|
||||||
throw new InitializationException(msg);
|
throw new InitializationException(msg);
|
||||||
} else {
|
} else {
|
||||||
BufferedReader reader = null;
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"))) {
|
||||||
try {
|
|
||||||
reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
|
||||||
if (!reader.ready()) {
|
if (!reader.ready()) {
|
||||||
LOGGER.warn("Bundle-audit error stream unexpectedly not ready. Disabling " + ANALYZER_NAME);
|
LOGGER.warn("Bundle-audit error stream unexpectedly not ready. Disabling " + ANALYZER_NAME);
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
@@ -203,14 +199,6 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
throw new InitializationException("Unable to read bundle-audit output.", ex);
|
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.
|
* 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);
|
final String msg = String.format("Unexpected exit code from bundle-audit process; exit code: %s", exitValue);
|
||||||
throw new AnalysisException(msg);
|
throw new AnalysisException(msg);
|
||||||
}
|
}
|
||||||
BufferedReader rdr = null;
|
|
||||||
BufferedReader errReader = null;
|
|
||||||
try {
|
try {
|
||||||
errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
try (BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"))) {
|
||||||
while (errReader.ready()) {
|
while (errReader.ready()) {
|
||||||
final String error = errReader.readLine();
|
final String error = errReader.readLine();
|
||||||
LOGGER.warn(error);
|
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) {
|
} catch (IOException ioe) {
|
||||||
LOGGER.warn("bundle-audit failure", 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;
|
Dependency dependency = null;
|
||||||
Vulnerability vulnerability = null;
|
Vulnerability vulnerability = null;
|
||||||
String gem = null;
|
String gem = null;
|
||||||
final Map<String, Dependency> map = new HashMap<String, Dependency>();
|
final Map<String, Dependency> map = new HashMap<>();
|
||||||
boolean appendToDescription = false;
|
boolean appendToDescription = false;
|
||||||
while (rdr.ready()) {
|
while (rdr.ready()) {
|
||||||
final String nextLine = rdr.readLine();
|
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 "
|
+ "Title link may not work. CPE below is guessed. CVSS score is estimated (-1.0 "
|
||||||
+ " indicates unknown). See link below for full details. *** ");
|
+ " indicates unknown). See link below for full details. *** ");
|
||||||
}
|
}
|
||||||
} else if (appendToDescription) {
|
} else if (appendToDescription && null != vulnerability) {
|
||||||
if (null != vulnerability) {
|
vulnerability.setDescription(vulnerability.getDescription() + nextLine + "\n");
|
||||||
vulnerability.setDescription(vulnerability.getDescription() + nextLine + "\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
*/
|
*/
|
||||||
public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Constaints">
|
//<editor-fold defaultstate="collapsed" desc="Constants">
|
||||||
/**
|
/**
|
||||||
* Evidence source.
|
* Evidence source.
|
||||||
*/
|
*/
|
||||||
@@ -126,7 +126,7 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
|||||||
* the dependency.
|
* the dependency.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
String fileVersion = null;
|
String fileVersion = null;
|
||||||
String pomVersion = null;
|
String pomVersion = null;
|
||||||
String manifestVersion = null;
|
String manifestVersion = null;
|
||||||
@@ -151,16 +151,14 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
|||||||
if (fileMatch || manifestMatch || pomMatch) {
|
if (fileMatch || manifestMatch || pomMatch) {
|
||||||
LOGGER.debug("filtering evidence from {}", dependency.getFileName());
|
LOGGER.debug("filtering evidence from {}", dependency.getFileName());
|
||||||
final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
|
final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
|
||||||
synchronized (versionEvidence) {
|
final Iterator<Evidence> itr = versionEvidence.iterator();
|
||||||
final Iterator<Evidence> itr = versionEvidence.iterator();
|
while (itr.hasNext()) {
|
||||||
while (itr.hasNext()) {
|
final Evidence e = itr.next();
|
||||||
final Evidence e = itr.next();
|
if (!(pomMatch && VERSION.equals(e.getName())
|
||||||
if (!(pomMatch && VERSION.equals(e.getName())
|
&& (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource())))
|
||||||
&& (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource())))
|
&& !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource()))
|
||||||
&& !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource()))
|
&& !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) {
|
||||||
&& !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) {
|
itr.remove();
|
||||||
itr.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ import java.net.URL;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathConstants;
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
@@ -35,6 +37,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class of methods to search Maven Central via Central.
|
* Class of methods to search Maven Central via Central.
|
||||||
@@ -117,7 +120,7 @@ public class CentralSearch {
|
|||||||
if ("0".equals(numFound)) {
|
if ("0".equals(numFound)) {
|
||||||
missing = true;
|
missing = true;
|
||||||
} else {
|
} else {
|
||||||
result = new ArrayList<MavenArtifact>();
|
result = new ArrayList<>();
|
||||||
final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
|
final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
|
||||||
for (int i = 0; i < docs.getLength(); i++) {
|
for (int i = 0; i < docs.getLength(); i++) {
|
||||||
final String g = xpath.evaluate("./str[@name='g']", docs.item(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));
|
final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
|
||||||
LOGGER.trace("ArtifactId: {}", a);
|
LOGGER.trace("ArtifactId: {}", a);
|
||||||
final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
|
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 pomAvailable = false;
|
||||||
boolean jarAvailable = false;
|
boolean jarAvailable = false;
|
||||||
for (int x = 0; x < atts.getLength(); x++) {
|
for (int x = 0; x < attributes.getLength(); x++) {
|
||||||
final String tmp = xpath.evaluate(".", atts.item(x));
|
final String tmp = xpath.evaluate(".", attributes.item(x));
|
||||||
if (".pom".equals(tmp)) {
|
if (".pom".equals(tmp)) {
|
||||||
pomAvailable = true;
|
pomAvailable = true;
|
||||||
} else if (".jar".equals(tmp)) {
|
} 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;
|
boolean useHTTPS = false;
|
||||||
for (int x = 0; x < atts.getLength(); x++) {
|
for (int x = 0; x < attributes.getLength(); x++) {
|
||||||
final String tmp = xpath.evaluate(".", atts.item(x));
|
final String tmp = xpath.evaluate(".", attributes.item(x));
|
||||||
if ("https".equals(tmp)) {
|
if ("https".equals(tmp)) {
|
||||||
useHTTPS = true;
|
useHTTPS = true;
|
||||||
}
|
}
|
||||||
@@ -149,7 +152,7 @@ public class CentralSearch {
|
|||||||
result.add(new MavenArtifact(g, a, v, jarAvailable, pomAvailable, useHTTPS));
|
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
|
// Anything else is jacked up XML stuff that we really can't recover from well
|
||||||
throw new IOException(e.getMessage(), e);
|
throw new IOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
package org.owasp.dependencycheck.data.composer;
|
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
|
* @author colezlaw
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -42,11 +42,6 @@ public class ComposerLockParser {
|
|||||||
*/
|
*/
|
||||||
private final JsonReader jsonReader;
|
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
|
* The List of ComposerDependencies found
|
||||||
*/
|
*/
|
||||||
@@ -58,15 +53,14 @@ public class ComposerLockParser {
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ComposerLockParser.class);
|
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
|
* @param inputStream the InputStream to parse
|
||||||
*/
|
*/
|
||||||
public ComposerLockParser(InputStream inputStream) {
|
public ComposerLockParser(InputStream inputStream) {
|
||||||
LOGGER.info("Creating a ComposerLockParser");
|
LOGGER.info("Creating a ComposerLockParser");
|
||||||
this.inputStream = inputStream;
|
|
||||||
this.jsonReader = Json.createReader(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 group = groupName.substring(0, groupName.indexOf('/'));
|
||||||
final String project = groupName.substring(groupName.indexOf('/') + 1);
|
final String project = groupName.substring(groupName.indexOf('/') + 1);
|
||||||
String version = pkg.getString("version");
|
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")) {
|
if (version.startsWith("v")) {
|
||||||
version = version.substring(1);
|
version = version.substring(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,21 +62,6 @@ public final class CpeMemoryIndex {
|
|||||||
* singleton instance.
|
* singleton instance.
|
||||||
*/
|
*/
|
||||||
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
|
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.
|
* The in memory Lucene index.
|
||||||
*/
|
*/
|
||||||
@@ -105,6 +90,25 @@ public final class CpeMemoryIndex {
|
|||||||
* The search field analyzer for the vendor field.
|
* The search field analyzer for the vendor field.
|
||||||
*/
|
*/
|
||||||
private SearchFieldAnalyzer vendorFieldAnalyzer;
|
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.
|
* 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.
|
* returns whether or not the index is open.
|
||||||
@@ -149,7 +149,7 @@ public final class CpeMemoryIndex {
|
|||||||
* @return the CPE Analyzer.
|
* @return the CPE Analyzer.
|
||||||
*/
|
*/
|
||||||
private Analyzer createSearchingAnalyzer() {
|
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());
|
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||||
productFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
productFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||||
vendorFieldAnalyzer = 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
|
* @throws IndexException thrown if there is an issue creating the index
|
||||||
*/
|
*/
|
||||||
private void buildIndex(CveDB cve) throws IndexException {
|
private void buildIndex(CveDB cve) throws IndexException {
|
||||||
Analyzer analyzer = null;
|
try (Analyzer analyzer = createSearchingAnalyzer();
|
||||||
IndexWriter indexWriter = null;
|
IndexWriter indexWriter = new IndexWriter(index, new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer))) {
|
||||||
try {
|
// Tip: reuse the Document and Fields for performance...
|
||||||
analyzer = createSearchingAnalyzer();
|
// See "Re-use Document and Field instances" from
|
||||||
final IndexWriterConfig conf = new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer);
|
// http://wiki.apache.org/lucene-java/ImproveIndexingSpeed
|
||||||
indexWriter = new IndexWriter(index, conf);
|
final Document doc = new Document();
|
||||||
try {
|
final Field v = new TextField(Fields.VENDOR, Fields.VENDOR, Field.Store.YES);
|
||||||
// Tip: reuse the Document and Fields for performance...
|
final Field p = new TextField(Fields.PRODUCT, Fields.PRODUCT, Field.Store.YES);
|
||||||
// See "Re-use Document and Field instances" from
|
doc.add(v);
|
||||||
// http://wiki.apache.org/lucene-java/ImproveIndexingSpeed
|
doc.add(p);
|
||||||
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();
|
final Set<Pair<String, String>> data = cve.getVendorProductList();
|
||||||
for (Pair<String, String> pair : data) {
|
for (Pair<String, String> pair : data) {
|
||||||
//todo figure out why there are null products
|
if (pair.getLeft() != null && pair.getRight() != null) {
|
||||||
if (pair.getLeft() != null && pair.getRight() != null) {
|
v.setStringValue(pair.getLeft());
|
||||||
v.setStringValue(pair.getLeft());
|
p.setStringValue(pair.getRight());
|
||||||
p.setStringValue(pair.getRight());
|
indexWriter.addDocument(doc);
|
||||||
indexWriter.addDocument(doc);
|
resetFieldAnalyzer();
|
||||||
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) {
|
} catch (CorruptIndexException ex) {
|
||||||
throw new IndexException("Unable to close an in-memory index", ex);
|
throw new IndexException("Unable to close an in-memory index", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new IndexException("Unable to close an in-memory index", 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
|
* @throws IOException is thrown if there is an issue with the underlying
|
||||||
* Index
|
* 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()) {
|
if (searchString == null || searchString.trim().isEmpty()) {
|
||||||
throw new ParseException("Query is null or empty");
|
throw new ParseException("Query is null or empty");
|
||||||
}
|
}
|
||||||
LOGGER.debug(searchString);
|
LOGGER.debug(searchString);
|
||||||
|
resetFieldAnalyzer();
|
||||||
final Query query = queryParser.parse(searchString);
|
final Query query = queryParser.parse(searchString);
|
||||||
return search(query, maxQueryResults);
|
return search(query, maxQueryResults);
|
||||||
}
|
}
|
||||||
@@ -285,7 +264,7 @@ public final class CpeMemoryIndex {
|
|||||||
* @throws CorruptIndexException thrown if the Index is corrupt
|
* @throws CorruptIndexException thrown if the Index is corrupt
|
||||||
* @throws IOException thrown if there is an IOException
|
* @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();
|
resetFieldAnalyzer();
|
||||||
return indexSearcher.search(query, maxQueryResults);
|
return indexSearcher.search(query, maxQueryResults);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.cpe;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A CPE entry containing the name, vendor, product, and version.
|
* A CPE entry containing the name, vendor, product, and version.
|
||||||
@@ -31,7 +32,7 @@ public class IndexEntry implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* the serial version uid.
|
* the serial version uid.
|
||||||
*/
|
*/
|
||||||
static final long serialVersionUID = 8011924485946326934L;
|
private static final long serialVersionUID = 8011924485946326934L;
|
||||||
/**
|
/**
|
||||||
* The vendor name.
|
* The vendor name.
|
||||||
*/
|
*/
|
||||||
@@ -143,7 +144,8 @@ public class IndexEntry implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void parseName(String cpeName) throws UnsupportedEncodingException {
|
public void parseName(String cpeName) throws UnsupportedEncodingException {
|
||||||
if (cpeName != null && cpeName.length() > 7) {
|
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) {
|
if (data.length >= 1) {
|
||||||
vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8");
|
vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8");
|
||||||
if (data.length >= 2) {
|
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)) {
|
if ((this.vendor == null) ? (other.vendor != null) : !this.vendor.equals(other.vendor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((this.product == null) ? (other.product != null) : !this.product.equals(other.product)) {
|
return !((this.product == null) ? (other.product != null) : !this.product.equals(other.product));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -54,12 +54,10 @@ public final class CweDB {
|
|||||||
* @return a HashMap of CWE data
|
* @return a HashMap of CWE data
|
||||||
*/
|
*/
|
||||||
private static Map<String, String> loadData() {
|
private static Map<String, String> loadData() {
|
||||||
ObjectInputStream oin = null;
|
final String filePath = "data/cwe.hashmap.serialized";
|
||||||
try {
|
try (InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||||
final String filePath = "data/cwe.hashmap.serialized";
|
ObjectInputStream oin = new ObjectInputStream(input)) {
|
||||||
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
|
||||||
oin = new ObjectInputStream(input);
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final Map<String, String> ret = (HashMap<String, String>) oin.readObject();
|
final Map<String, String> ret = (HashMap<String, String>) oin.readObject();
|
||||||
return ret;
|
return ret;
|
||||||
} catch (ClassNotFoundException ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
@@ -68,14 +66,6 @@ public final class CweDB {
|
|||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.warn("Unable to load CWE data due to an IO Error. This should not be an issue.");
|
LOGGER.warn("Unable to load CWE data due to an IO Error. This should not be an issue.");
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
|
||||||
if (oin != null) {
|
|
||||||
try {
|
|
||||||
oin.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.trace("", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class CweHandler extends DefaultHandler {
|
|||||||
/**
|
/**
|
||||||
* a HashMap containing the CWE data.
|
* 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).
|
* 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) {
|
public AbstractTokenizingFilter(TokenStream stream) {
|
||||||
super(stream);
|
super(stream);
|
||||||
tokens = new LinkedList<String>();
|
tokens = new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
|||||||
*/
|
*/
|
||||||
public TokenPairConcatenatingFilter(TokenStream stream) {
|
public TokenPairConcatenatingFilter(TokenStream stream) {
|
||||||
super(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)) {
|
if ((this.previousWord == null) ? (other.previousWord != null) : !this.previousWord.equals(other.previousWord)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.words != other.words && (this.words == null || !this.words.equals(other.words))) {
|
return !(this.words != other.words && (this.words == null || !this.words.equals(other.words)));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ import java.io.IOException;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||||
@@ -30,6 +32,7 @@ import org.owasp.dependencycheck.utils.XmlUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class of methods to search Nexus repositories.
|
* Class of methods to search Nexus repositories.
|
||||||
@@ -132,7 +135,7 @@ public class NexusSearch {
|
|||||||
ma.setPomUrl(pomLink);
|
ma.setPomUrl(pomLink);
|
||||||
}
|
}
|
||||||
return ma;
|
return ma;
|
||||||
} catch (Throwable e) {
|
} catch (ParserConfigurationException | IOException | SAXException | XPathExpressionException e) {
|
||||||
// Anything else is jacked-up XML stuff that we really can't recover
|
// Anything else is jacked-up XML stuff that we really can't recover
|
||||||
// from well
|
// from well
|
||||||
throw new IOException(e.getMessage(), e);
|
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());
|
LOGGER.warn("Expected root node name of status, got {}", doc.getDocumentElement().getNodeName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (IOException | ParserConfigurationException | SAXException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,12 +53,6 @@ public class NugetPackage {
|
|||||||
*/
|
*/
|
||||||
private String licenseUrl;
|
private String licenseUrl;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty NugetPackage.
|
|
||||||
*/
|
|
||||||
public NugetPackage() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the id.
|
* Sets the id.
|
||||||
* @param id the id
|
* @param id the id
|
||||||
|
|||||||
@@ -17,14 +17,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.nuget;
|
package org.owasp.dependencycheck.data.nuget;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathConstants;
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
import org.owasp.dependencycheck.utils.XmlUtils;
|
import org.owasp.dependencycheck.utils.XmlUtils;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a Nuspec file using XPath.
|
* 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.setLicenseUrl(getOrNull((Node) xpath.evaluate("/package/metadata/licenseUrl", d, XPathConstants.NODE)));
|
||||||
nuspec.setTitle(getOrNull((Node) xpath.evaluate("/package/metadata/title", d, XPathConstants.NODE)));
|
nuspec.setTitle(getOrNull((Node) xpath.evaluate("/package/metadata/title", d, XPathConstants.NODE)));
|
||||||
return nuspec;
|
return nuspec;
|
||||||
} catch (Throwable e) {
|
} catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException | NuspecParseException e) {
|
||||||
throw new NuspecParseException("Unable to parse nuspec", 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
|
* @throws IOException thrown if the data directory does not exist and
|
||||||
* cannot be created
|
* cannot be created
|
||||||
*/
|
*/
|
||||||
private static boolean h2DataFileExists() throws IOException {
|
public static boolean h2DataFileExists() throws IOException {
|
||||||
final File dir = Settings.getDataDirectory();
|
final File dir = Settings.getDataDirectory();
|
||||||
final String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME);
|
final String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME);
|
||||||
final File file = new File(dir, fileName);
|
final File file = new File(dir, fileName);
|
||||||
return file.exists();
|
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
|
* Creates the database structure (tables and indexes) to store the CVE
|
||||||
* data.
|
* data.
|
||||||
@@ -342,7 +360,7 @@ public final class ConnectionFactory {
|
|||||||
LOGGER.warn("A new version of dependency-check is available; consider upgrading");
|
LOGGER.warn("A new version of dependency-check is available; consider upgrading");
|
||||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||||
} else if (e0 == c0 && e1 == c1) {
|
} 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 {
|
} else {
|
||||||
LOGGER.error("The database schema must be upgraded to use this version of dependency-check. Please see {} for more information.",
|
LOGGER.error("The database schema must be upgraded to use this version of dependency-check. Please see {} for more information.",
|
||||||
UPGRADE_HELP_URL);
|
UPGRADE_HELP_URL);
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import java.sql.Connection;
|
|||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -35,6 +35,7 @@ import java.util.MissingResourceException;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import org.owasp.dependencycheck.data.cwe.CweDB;
|
import org.owasp.dependencycheck.data.cwe.CweDB;
|
||||||
import org.owasp.dependencycheck.dependency.Reference;
|
import org.owasp.dependencycheck.dependency.Reference;
|
||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
@@ -47,13 +48,27 @@ import org.owasp.dependencycheck.utils.Settings;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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
|
* @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.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
@@ -61,18 +76,132 @@ public class CveDB {
|
|||||||
/**
|
/**
|
||||||
* Database connection
|
* Database connection
|
||||||
*/
|
*/
|
||||||
private Connection conn;
|
private Connection connection;
|
||||||
/**
|
/**
|
||||||
* The bundle of statements used when accessing the database.
|
* 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
|
* The enum value names must match the keys of the statements in the
|
||||||
* connection must be closed by the caller by calling the close method.
|
* statement bundles "dbStatements*.properties".
|
||||||
* ======= Does the underlying connection support batch operations?
|
|
||||||
*/
|
*/
|
||||||
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
|
* Creates a new CveDB object and opens the database connection. Note, the
|
||||||
@@ -81,35 +210,24 @@ public class CveDB {
|
|||||||
* @throws DatabaseException thrown if there is an exception opening the
|
* @throws DatabaseException thrown if there is an exception opening the
|
||||||
* database.
|
* database.
|
||||||
*/
|
*/
|
||||||
public CveDB() throws DatabaseException {
|
private CveDB() throws DatabaseException {
|
||||||
super();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the database connection.
|
* Tries to determine the product name of the database.
|
||||||
*
|
*
|
||||||
* @return the database connection
|
* @param conn the database connection
|
||||||
|
* @return the product name of the database if successful, {@code null} else
|
||||||
*/
|
*/
|
||||||
protected Connection getConnection() {
|
private static String determineDatabaseProductName(Connection conn) {
|
||||||
return conn;
|
try {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,28 +237,43 @@ public class CveDB {
|
|||||||
* @throws DatabaseException thrown if there is an error opening the
|
* @throws DatabaseException thrown if there is an error opening the
|
||||||
* database connection
|
* database connection
|
||||||
*/
|
*/
|
||||||
public final synchronized void open() throws DatabaseException {
|
private synchronized void open() throws DatabaseException {
|
||||||
if (!isOpen()) {
|
if (!instance.isOpen()) {
|
||||||
conn = ConnectionFactory.getConnection();
|
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
|
* Closes the database connection. Close should be called on this object
|
||||||
* is done being used.
|
* when it is done being used.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public synchronized void close() {
|
public synchronized void close() {
|
||||||
if (conn != null) {
|
if (instance != null) {
|
||||||
try {
|
instance.usageCount -= 1;
|
||||||
conn.close();
|
if (instance.usageCount <= 0 && instance.isOpen()) {
|
||||||
} catch (SQLException ex) {
|
instance.usageCount = 0;
|
||||||
LOGGER.error("There was an error attempting to close the CveDB, see the log for more details.");
|
instance.closeStatements();
|
||||||
LOGGER.debug("", ex);
|
try {
|
||||||
} catch (Throwable ex) {
|
instance.connection.close();
|
||||||
LOGGER.error("There was an exception attempting to close the CveDB, see the log for more details.");
|
} catch (SQLException ex) {
|
||||||
LOGGER.debug("", 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 +282,54 @@ public class CveDB {
|
|||||||
*
|
*
|
||||||
* @return whether the database connection is open or closed
|
* @return whether the database connection is open or closed
|
||||||
*/
|
*/
|
||||||
public synchronized boolean isOpen() {
|
protected synchronized boolean isOpen() {
|
||||||
return conn != null;
|
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 +339,8 @@ public class CveDB {
|
|||||||
*/
|
*/
|
||||||
public synchronized void commit() throws SQLException {
|
public synchronized void commit() throws SQLException {
|
||||||
//temporary remove this as autocommit is on.
|
//temporary remove this as autocommit is on.
|
||||||
//if (conn != null) {
|
//if (isOpen()) {
|
||||||
// conn.commit();
|
// connection.commit();
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,18 +356,23 @@ public class CveDB {
|
|||||||
close();
|
close();
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Database properties object containing the 'properties' from the database
|
|
||||||
* table.
|
|
||||||
*/
|
|
||||||
private DatabaseProperties databaseProperties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databaseProperties.
|
* Get the value of databaseProperties.
|
||||||
*
|
*
|
||||||
* @return 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;
|
return databaseProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,11 +387,10 @@ public class CveDB {
|
|||||||
* @return a set of vulnerable software
|
* @return a set of vulnerable software
|
||||||
*/
|
*/
|
||||||
public synchronized Set<VulnerableSoftware> getCPEs(String vendor, String product) {
|
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;
|
ResultSet rs = null;
|
||||||
PreparedStatement ps = null;
|
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_CPE_ENTRIES"));
|
final PreparedStatement ps = getPreparedStatement(SELECT_CPE_ENTRIES);
|
||||||
ps.setString(1, vendor);
|
ps.setString(1, vendor);
|
||||||
ps.setString(2, product);
|
ps.setString(2, product);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
@@ -222,7 +405,6 @@ public class CveDB {
|
|||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
DBUtils.closeStatement(ps);
|
|
||||||
}
|
}
|
||||||
return cpe;
|
return cpe;
|
||||||
}
|
}
|
||||||
@@ -235,21 +417,19 @@ public class CveDB {
|
|||||||
* data from the DB
|
* data from the DB
|
||||||
*/
|
*/
|
||||||
public synchronized Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
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;
|
ResultSet rs = null;
|
||||||
PreparedStatement ps = null;
|
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_VENDOR_PRODUCT_LIST"));
|
final PreparedStatement ps = getPreparedStatement(SELECT_VENDOR_PRODUCT_LIST);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
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) {
|
} catch (SQLException ex) {
|
||||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||||
throw new DatabaseException(msg, ex);
|
throw new DatabaseException(msg, ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
DBUtils.closeStatement(ps);
|
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -259,12 +439,11 @@ public class CveDB {
|
|||||||
*
|
*
|
||||||
* @return the properties from the database
|
* @return the properties from the database
|
||||||
*/
|
*/
|
||||||
synchronized Properties getProperties() {
|
public synchronized Properties getProperties() {
|
||||||
final Properties prop = new Properties();
|
final Properties prop = new Properties();
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_PROPERTIES"));
|
final PreparedStatement ps = getPreparedStatement(SELECT_PROPERTIES);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
prop.setProperty(rs.getString(1), rs.getString(2));
|
prop.setProperty(rs.getString(1), rs.getString(2));
|
||||||
@@ -273,7 +452,6 @@ public class CveDB {
|
|||||||
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeStatement(ps);
|
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
}
|
}
|
||||||
return prop;
|
return prop;
|
||||||
@@ -285,34 +463,23 @@ public class CveDB {
|
|||||||
* @param key the property key
|
* @param key the property key
|
||||||
* @param value the property value
|
* @param value the property value
|
||||||
*/
|
*/
|
||||||
synchronized void saveProperty(String key, String value) {
|
public synchronized void saveProperty(String key, String value) {
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
final PreparedStatement mergeProperty = getConnection().prepareStatement(statementBundle.getString("MERGE_PROPERTY"));
|
final PreparedStatement mergeProperty = getPreparedStatement(MERGE_PROPERTY);
|
||||||
try {
|
mergeProperty.setString(1, key);
|
||||||
mergeProperty.setString(1, key);
|
mergeProperty.setString(2, value);
|
||||||
mergeProperty.setString(2, value);
|
mergeProperty.executeUpdate();
|
||||||
mergeProperty.executeUpdate();
|
|
||||||
} finally {
|
|
||||||
DBUtils.closeStatement(mergeProperty);
|
|
||||||
}
|
|
||||||
} catch (MissingResourceException mre) {
|
} catch (MissingResourceException mre) {
|
||||||
// No Merge statement, so doing an Update/Insert...
|
// No Merge statement, so doing an Update/Insert...
|
||||||
PreparedStatement updateProperty = null;
|
final PreparedStatement updateProperty = getPreparedStatement(UPDATE_PROPERTY);
|
||||||
PreparedStatement insertProperty = null;
|
updateProperty.setString(1, value);
|
||||||
try {
|
updateProperty.setString(2, key);
|
||||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
if (updateProperty.executeUpdate() == 0) {
|
||||||
updateProperty.setString(1, value);
|
final PreparedStatement insertProperty = getPreparedStatement(INSERT_PROPERTY);
|
||||||
updateProperty.setString(2, key);
|
insertProperty.setString(1, key);
|
||||||
if (updateProperty.executeUpdate() == 0) {
|
insertProperty.setString(2, value);
|
||||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
insertProperty.executeUpdate();
|
||||||
insertProperty.setString(1, key);
|
|
||||||
insertProperty.setString(2, value);
|
|
||||||
insertProperty.executeUpdate();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
DBUtils.closeStatement(updateProperty);
|
|
||||||
DBUtils.closeStatement(insertProperty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
@@ -336,18 +503,17 @@ public class CveDB {
|
|||||||
LOGGER.trace("", ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
|
final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
|
||||||
final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
|
final List<Vulnerability> vulnerabilities = new ArrayList<>();
|
||||||
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
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(1, cpe.getVendor());
|
||||||
ps.setString(2, cpe.getProduct());
|
ps.setString(2, cpe.getProduct());
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
String currentCVE = "";
|
String currentCVE = "";
|
||||||
|
|
||||||
final Map<String, Boolean> vulnSoftware = new HashMap<String, Boolean>();
|
final Map<String, Boolean> vulnSoftware = new HashMap<>();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
final String cveId = rs.getString(1);
|
final String cveId = rs.getString(1);
|
||||||
if (!currentCVE.equals(cveId)) { //check for match and add
|
if (!currentCVE.equals(cveId)) { //check for match and add
|
||||||
@@ -377,7 +543,6 @@ public class CveDB {
|
|||||||
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
|
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
DBUtils.closeStatement(ps);
|
|
||||||
}
|
}
|
||||||
return vulnerabilities;
|
return vulnerabilities;
|
||||||
}
|
}
|
||||||
@@ -390,16 +555,13 @@ public class CveDB {
|
|||||||
* @throws DatabaseException if an exception occurs
|
* @throws DatabaseException if an exception occurs
|
||||||
*/
|
*/
|
||||||
public synchronized Vulnerability getVulnerability(String cve) throws DatabaseException {
|
public synchronized Vulnerability getVulnerability(String cve) throws DatabaseException {
|
||||||
PreparedStatement psV = null;
|
|
||||||
PreparedStatement psR = null;
|
|
||||||
PreparedStatement psS = null;
|
|
||||||
ResultSet rsV = null;
|
ResultSet rsV = null;
|
||||||
ResultSet rsR = null;
|
ResultSet rsR = null;
|
||||||
ResultSet rsS = null;
|
ResultSet rsS = null;
|
||||||
Vulnerability vuln = null;
|
Vulnerability vuln = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
psV = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY"));
|
final PreparedStatement psV = getPreparedStatement(SELECT_VULNERABILITY);
|
||||||
psV.setString(1, cve);
|
psV.setString(1, cve);
|
||||||
rsV = psV.executeQuery();
|
rsV = psV.executeQuery();
|
||||||
if (rsV.next()) {
|
if (rsV.next()) {
|
||||||
@@ -423,13 +585,14 @@ public class CveDB {
|
|||||||
vuln.setCvssIntegrityImpact(rsV.getString(9));
|
vuln.setCvssIntegrityImpact(rsV.getString(9));
|
||||||
vuln.setCvssAvailabilityImpact(rsV.getString(10));
|
vuln.setCvssAvailabilityImpact(rsV.getString(10));
|
||||||
|
|
||||||
psR = getConnection().prepareStatement(statementBundle.getString("SELECT_REFERENCES"));
|
final PreparedStatement psR = getPreparedStatement(SELECT_REFERENCES);
|
||||||
psR.setInt(1, cveId);
|
psR.setInt(1, cveId);
|
||||||
rsR = psR.executeQuery();
|
rsR = psR.executeQuery();
|
||||||
while (rsR.next()) {
|
while (rsR.next()) {
|
||||||
vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
|
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);
|
psS.setInt(1, cveId);
|
||||||
rsS = psS.executeQuery();
|
rsS = psS.executeQuery();
|
||||||
while (rsS.next()) {
|
while (rsS.next()) {
|
||||||
@@ -448,9 +611,6 @@ public class CveDB {
|
|||||||
DBUtils.closeResultSet(rsV);
|
DBUtils.closeResultSet(rsV);
|
||||||
DBUtils.closeResultSet(rsR);
|
DBUtils.closeResultSet(rsR);
|
||||||
DBUtils.closeResultSet(rsS);
|
DBUtils.closeResultSet(rsS);
|
||||||
DBUtils.closeStatement(psV);
|
|
||||||
DBUtils.closeStatement(psR);
|
|
||||||
DBUtils.closeStatement(psS);
|
|
||||||
}
|
}
|
||||||
return vuln;
|
return vuln;
|
||||||
}
|
}
|
||||||
@@ -463,52 +623,31 @@ public class CveDB {
|
|||||||
* @throws DatabaseException is thrown if the database
|
* @throws DatabaseException is thrown if the database
|
||||||
*/
|
*/
|
||||||
public synchronized void updateVulnerability(Vulnerability vuln) throws DatabaseException {
|
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 {
|
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;
|
int vulnerabilityId = 0;
|
||||||
|
final PreparedStatement selectVulnerabilityId = getPreparedStatement(SELECT_VULNERABILITY_ID);
|
||||||
selectVulnerabilityId.setString(1, vuln.getName());
|
selectVulnerabilityId.setString(1, vuln.getName());
|
||||||
ResultSet rs = selectVulnerabilityId.executeQuery();
|
ResultSet rs = selectVulnerabilityId.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
vulnerabilityId = rs.getInt(1);
|
vulnerabilityId = rs.getInt(1);
|
||||||
// first delete any existing vulnerability info. We don't know what was updated. yes, slower but atm easier.
|
// first delete any existing vulnerability info. We don't know what was updated. yes, slower but atm easier.
|
||||||
deleteReferences.setInt(1, vulnerabilityId);
|
final PreparedStatement deleteReference = getPreparedStatement(DELETE_REFERENCE);
|
||||||
deleteReferences.execute();
|
deleteReference.setInt(1, vulnerabilityId);
|
||||||
|
deleteReference.execute();
|
||||||
|
|
||||||
|
final PreparedStatement deleteSoftware = getPreparedStatement(DELETE_SOFTWARE);
|
||||||
deleteSoftware.setInt(1, vulnerabilityId);
|
deleteSoftware.setInt(1, vulnerabilityId);
|
||||||
deleteSoftware.execute();
|
deleteSoftware.execute();
|
||||||
}
|
}
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
rs = null;
|
|
||||||
|
|
||||||
if (vulnerabilityId != 0) {
|
if (vulnerabilityId != 0) {
|
||||||
if (vuln.getDescription().contains("** REJECT **")) {
|
if (vuln.getDescription().contains("** REJECT **")) {
|
||||||
|
final PreparedStatement deleteVulnerability = getPreparedStatement(DELETE_VULNERABILITY);
|
||||||
deleteVulnerability.setInt(1, vulnerabilityId);
|
deleteVulnerability.setInt(1, vulnerabilityId);
|
||||||
deleteVulnerability.executeUpdate();
|
deleteVulnerability.executeUpdate();
|
||||||
} else {
|
} else {
|
||||||
|
final PreparedStatement updateVulnerability = getPreparedStatement(UPDATE_VULNERABILITY);
|
||||||
updateVulnerability.setString(1, vuln.getDescription());
|
updateVulnerability.setString(1, vuln.getDescription());
|
||||||
updateVulnerability.setString(2, vuln.getCwe());
|
updateVulnerability.setString(2, vuln.getCwe());
|
||||||
updateVulnerability.setFloat(3, vuln.getCvssScore());
|
updateVulnerability.setFloat(3, vuln.getCvssScore());
|
||||||
@@ -522,6 +661,7 @@ public class CveDB {
|
|||||||
updateVulnerability.executeUpdate();
|
updateVulnerability.executeUpdate();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
final PreparedStatement insertVulnerability = getPreparedStatement(INSERT_VULNERABILITY);
|
||||||
insertVulnerability.setString(1, vuln.getName());
|
insertVulnerability.setString(1, vuln.getName());
|
||||||
insertVulnerability.setString(2, vuln.getDescription());
|
insertVulnerability.setString(2, vuln.getDescription());
|
||||||
insertVulnerability.setString(3, vuln.getCwe());
|
insertVulnerability.setString(3, vuln.getCwe());
|
||||||
@@ -542,29 +682,22 @@ public class CveDB {
|
|||||||
throw new DatabaseException(msg, ex);
|
throw new DatabaseException(msg, ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
rs = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final PreparedStatement insertReference = getPreparedStatement(INSERT_REFERENCE);
|
||||||
for (Reference r : vuln.getReferences()) {
|
for (Reference r : vuln.getReferences()) {
|
||||||
insertReference.setInt(1, vulnerabilityId);
|
insertReference.setInt(1, vulnerabilityId);
|
||||||
insertReference.setString(2, r.getName());
|
insertReference.setString(2, r.getName());
|
||||||
insertReference.setString(3, r.getUrl());
|
insertReference.setString(3, r.getUrl());
|
||||||
insertReference.setString(4, r.getSource());
|
insertReference.setString(4, r.getSource());
|
||||||
|
insertReference.execute();
|
||||||
if (batchSupported) {
|
|
||||||
insertReference.addBatch();
|
|
||||||
} else {
|
|
||||||
insertReference.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (batchSupported) {
|
|
||||||
insertReference.executeBatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final PreparedStatement insertSoftware = getPreparedStatement(INSERT_SOFTWARE);
|
||||||
for (VulnerableSoftware s : vuln.getVulnerableSoftware()) {
|
for (VulnerableSoftware s : vuln.getVulnerableSoftware()) {
|
||||||
int cpeProductId = 0;
|
int cpeProductId = 0;
|
||||||
|
final PreparedStatement selectCpeId = getPreparedStatement(SELECT_CPE_ID);
|
||||||
selectCpeId.setString(1, s.getName());
|
selectCpeId.setString(1, s.getName());
|
||||||
try {
|
try {
|
||||||
rs = selectCpeId.executeQuery();
|
rs = selectCpeId.executeQuery();
|
||||||
@@ -575,10 +708,10 @@ public class CveDB {
|
|||||||
throw new DatabaseException("Unable to get primary key for new cpe: " + s.getName(), ex);
|
throw new DatabaseException("Unable to get primary key for new cpe: " + s.getName(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
rs = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpeProductId == 0) {
|
if (cpeProductId == 0) {
|
||||||
|
final PreparedStatement insertCpe = getPreparedStatement(INSERT_CPE);
|
||||||
insertCpe.setString(1, s.getName());
|
insertCpe.setString(1, s.getName());
|
||||||
insertCpe.setString(2, s.getVendor());
|
insertCpe.setString(2, s.getVendor());
|
||||||
insertCpe.setString(3, s.getProduct());
|
insertCpe.setString(3, s.getProduct());
|
||||||
@@ -597,39 +730,22 @@ public class CveDB {
|
|||||||
} else {
|
} else {
|
||||||
insertSoftware.setString(3, s.getPreviousVersion());
|
insertSoftware.setString(3, s.getPreviousVersion());
|
||||||
}
|
}
|
||||||
if (batchSupported) {
|
try {
|
||||||
insertSoftware.addBatch();
|
insertSoftware.execute();
|
||||||
} else {
|
} catch (SQLException ex) {
|
||||||
try {
|
if (ex.getMessage().contains("Duplicate entry")) {
|
||||||
insertSoftware.execute();
|
final String msg = String.format("Duplicate software key identified in '%s:%s'", vuln.getName(), s.getName());
|
||||||
} catch (SQLException ex) {
|
LOGGER.info(msg, ex);
|
||||||
if (ex.getMessage().contains("Duplicate entry")) {
|
} else {
|
||||||
final String msg = String.format("Duplicate software key identified in '%s:%s'", vuln.getName(), s.getName());
|
throw ex;
|
||||||
LOGGER.debug(msg, ex);
|
|
||||||
} else {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (batchSupported) {
|
|
||||||
insertSoftware.executeBatch();
|
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = String.format("Error updating '%s'", vuln.getName());
|
final String msg = String.format("Error updating '%s'", vuln.getName());
|
||||||
LOGGER.debug(msg, ex);
|
LOGGER.debug(msg, ex);
|
||||||
throw new DatabaseException(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 +755,16 @@ public class CveDB {
|
|||||||
* @return <code>true</code> if data exists; otherwise <code>false</code>
|
* @return <code>true</code> if data exists; otherwise <code>false</code>
|
||||||
*/
|
*/
|
||||||
public synchronized boolean dataExists() {
|
public synchronized boolean dataExists() {
|
||||||
Statement cs = null;
|
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
cs = conn.createStatement();
|
final PreparedStatement cs = getPreparedStatement(COUNT_CPE);
|
||||||
rs = cs.executeQuery("SELECT COUNT(*) records FROM cpeEntry");
|
rs = cs.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
if (rs.getInt(1) > 0) {
|
if (rs.getInt(1) > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (Exception ex) {
|
||||||
String dd;
|
String dd;
|
||||||
try {
|
try {
|
||||||
dd = Settings.getDataDirectory().getAbsolutePath();
|
dd = Settings.getDataDirectory().getAbsolutePath();
|
||||||
@@ -664,7 +779,6 @@ public class CveDB {
|
|||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
DBUtils.closeStatement(cs);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -675,17 +789,14 @@ public class CveDB {
|
|||||||
* ensure orphan entries are removed.
|
* ensure orphan entries are removed.
|
||||||
*/
|
*/
|
||||||
public synchronized void cleanupDatabase() {
|
public synchronized void cleanupDatabase() {
|
||||||
PreparedStatement ps = null;
|
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(statementBundle.getString("CLEANUP_ORPHANS"));
|
final PreparedStatement ps = getPreparedStatement(CLEANUP_ORPHANS);
|
||||||
if (ps != null) {
|
if (ps != null) {
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
|
||||||
DBUtils.closeStatement(ps);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,12 +814,12 @@ public class CveDB {
|
|||||||
* analyzed
|
* analyzed
|
||||||
* @return true if the identified version is affected, otherwise false
|
* @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) {
|
DependencyVersion identifiedVersion) {
|
||||||
|
|
||||||
final boolean isVersionTwoADifferentProduct = "apache".equals(vendor) && "struts".equals(product);
|
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());
|
final boolean matchesAnyPrevious = identifiedVersion == null || "-".equals(identifiedVersion.toString());
|
||||||
String majorVersionMatch = null;
|
String majorVersionMatch = null;
|
||||||
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||||
@@ -737,12 +848,12 @@ public class CveDB {
|
|||||||
if (!entry.getValue()) {
|
if (!entry.getValue()) {
|
||||||
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||||
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
//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;
|
continue;
|
||||||
}
|
}
|
||||||
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
//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).
|
//in the above loop or just after loop (if matchesAnyPrevious return null).
|
||||||
if (identifiedVersion.equals(v)) {
|
if (identifiedVersion != null && identifiedVersion.equals(v)) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -751,12 +862,12 @@ public class CveDB {
|
|||||||
if (entry.getValue()) {
|
if (entry.getValue()) {
|
||||||
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||||
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
//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;
|
continue;
|
||||||
}
|
}
|
||||||
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
//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).
|
//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)))) {
|
if (!(isVersionTwoADifferentProduct && !identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0)))) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -815,7 +926,7 @@ public class CveDB {
|
|||||||
public synchronized void deleteUnusedCpe() {
|
public synchronized void deleteUnusedCpe() {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
|
ps = connection.prepareStatement(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.error("Unable to delete CPE dictionary entries", ex);
|
LOGGER.error("Unable to delete CPE dictionary entries", ex);
|
||||||
@@ -837,7 +948,7 @@ public class CveDB {
|
|||||||
public synchronized void addCpe(String cpe, String vendor, String product) {
|
public synchronized void addCpe(String cpe, String vendor, String product) {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(statementBundle.getString("ADD_DICT_CPE"));
|
ps = connection.prepareStatement(statementBundle.getString("ADD_DICT_CPE"));
|
||||||
ps.setString(1, cpe);
|
ps.setString(1, cpe);
|
||||||
ps.setString(2, vendor);
|
ps.setString(2, vendor);
|
||||||
ps.setString(3, product);
|
ps.setString(3, product);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.format.DateTimeFormat;
|
import org.joda.time.format.DateTimeFormat;
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
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 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
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
|
@ThreadSafe
|
||||||
public class DatabaseProperties {
|
public class DatabaseProperties {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,7 +166,7 @@ public class DatabaseProperties {
|
|||||||
* @return a map of the database meta data
|
* @return a map of the database meta data
|
||||||
*/
|
*/
|
||||||
public Map<String, String> getMetaData() {
|
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()) {
|
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||||
final String key = (String) entry.getKey();
|
final String key = (String) entry.getKey();
|
||||||
if (!"version".equals(key)) {
|
if (!"version".equals(key)) {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public final class DriverLoader {
|
|||||||
*/
|
*/
|
||||||
public static Driver load(String className, String pathToDriver) throws DriverLoadException {
|
public static Driver load(String className, String pathToDriver) throws DriverLoadException {
|
||||||
final URLClassLoader parent = (URLClassLoader) ClassLoader.getSystemClassLoader();
|
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);
|
final String[] paths = pathToDriver.split(File.pathSeparator);
|
||||||
for (String path : paths) {
|
for (String path : paths) {
|
||||||
final File file = new File(path);
|
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
|
//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);
|
DriverManager.registerDriver(shim);
|
||||||
return shim;
|
return shim;
|
||||||
} catch (ClassNotFoundException 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);
|
|
||||||
} 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) {
|
|
||||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||||
LOGGER.debug(msg, ex);
|
LOGGER.debug(msg, ex);
|
||||||
throw new DriverLoadException(msg, ex);
|
throw new DriverLoadException(msg, ex);
|
||||||
|
|||||||
@@ -126,11 +126,7 @@ class DriverShim implements Driver {
|
|||||||
if (m != null) {
|
if (m != null) {
|
||||||
try {
|
try {
|
||||||
return (java.util.logging.Logger) m.invoke(m);
|
return (java.util.logging.Logger) m.invoke(m);
|
||||||
} catch (IllegalAccessException ex) {
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||||
LOGGER.trace("", ex);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
LOGGER.trace("", ex);
|
|
||||||
} catch (InvocationTargetException ex) {
|
|
||||||
LOGGER.trace("", 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.
|
* Copyright (c) 2015 Jeremy Long. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.update;
|
package org.owasp.dependencycheck.data.update;
|
||||||
|
/*
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
@@ -37,7 +37,7 @@ import org.owasp.dependencycheck.utils.XmlUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* This class is currently unused and if enabled will likely not work on MySQL
|
* 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
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
public class CpeUpdater { //extends BaseUpdater implements CachedWebDataSource {
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Static logger.
|
// * Static logger.
|
||||||
*/
|
// */
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
|
// private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void update() throws UpdateException {
|
// public void update() throws UpdateException {
|
||||||
/*
|
// /*
|
||||||
//the following could be used if this were ever used.
|
// //the following could be used if this were ever used.
|
||||||
try {
|
// try {
|
||||||
if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
|
// if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
} catch (InvalidSettingException ex) {
|
// } catch (InvalidSettingException ex) {
|
||||||
LOGGER.trace("inavlid setting UPDATE_NVDCVE_ENABLED", ex);
|
// LOGGER.trace("invalid setting UPDATE_NVDCVE_ENABLED", ex);
|
||||||
}
|
// }
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
openDataStores();
|
// openDataStores();
|
||||||
if (updateNeeded()) {
|
// if (updateNeeded()) {
|
||||||
LOGGER.info("Updating the Common Platform Enumeration (CPE)");
|
// LOGGER.info("Updating the Common Platform Enumeration (CPE)");
|
||||||
final File xml = downloadCpe();
|
// final File xml = downloadCpe();
|
||||||
final List<Cpe> cpes = processXML(xml);
|
// final List<Cpe> cpes = processXML(xml);
|
||||||
getCveDB().deleteUnusedCpe();
|
// getCveDB().deleteUnusedCpe();
|
||||||
for (Cpe cpe : cpes) {
|
// for (Cpe cpe : cpes) {
|
||||||
getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
|
// getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
|
||||||
}
|
// }
|
||||||
final long now = System.currentTimeMillis();
|
// final long now = System.currentTimeMillis();
|
||||||
getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
|
// getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
|
||||||
LOGGER.info("CPE update complete");
|
// LOGGER.info("CPE update complete");
|
||||||
}
|
// }
|
||||||
} finally {
|
// } finally {
|
||||||
closeDataStores();
|
// closeDataStores();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Downloads the CPE XML file.
|
// * Downloads the CPE XML file.
|
||||||
*
|
// *
|
||||||
* @return the file reference to the CPE.xml file
|
// * @return the file reference to the CPE.xml file
|
||||||
* @throws UpdateException thrown if there is an issue downloading the XML
|
// * @throws UpdateException thrown if there is an issue downloading the XML
|
||||||
* file
|
// * file
|
||||||
*/
|
// */
|
||||||
private File downloadCpe() throws UpdateException {
|
// private File downloadCpe() throws UpdateException {
|
||||||
File xml;
|
// File xml;
|
||||||
final URL url;
|
// final URL url;
|
||||||
try {
|
// try {
|
||||||
url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
|
// url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
|
||||||
xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
|
// xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
|
||||||
Downloader.fetchFile(url, xml);
|
// Downloader.fetchFile(url, xml);
|
||||||
if (url.toExternalForm().endsWith(".xml.gz")) {
|
// if (url.toExternalForm().endsWith(".xml.gz")) {
|
||||||
ExtractionUtil.extractGzip(xml);
|
// ExtractionUtil.extractGzip(xml);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
} catch (MalformedURLException ex) {
|
// } catch (MalformedURLException ex) {
|
||||||
throw new UpdateException("Invalid CPE URL", ex);
|
// throw new UpdateException("Invalid CPE URL", ex);
|
||||||
} catch (DownloadFailedException ex) {
|
// } catch (DownloadFailedException ex) {
|
||||||
throw new UpdateException("Unable to download CPE XML file", ex);
|
// throw new UpdateException("Unable to download CPE XML file", ex);
|
||||||
} catch (IOException ex) {
|
// } catch (IOException ex) {
|
||||||
throw new UpdateException("Unable to create temporary file to download CPE", ex);
|
// throw new UpdateException("Unable to create temporary file to download CPE", ex);
|
||||||
}
|
// }
|
||||||
return xml;
|
// return xml;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Parses the CPE XML file to return a list of CPE entries.
|
// * Parses the CPE XML file to return a list of CPE entries.
|
||||||
*
|
// *
|
||||||
* @param xml the CPE data file
|
// * @param xml the CPE data file
|
||||||
* @return the list of CPE entries
|
// * @return the list of CPE entries
|
||||||
* @throws UpdateException thrown if there is an issue with parsing the XML
|
// * @throws UpdateException thrown if there is an issue with parsing the XML
|
||||||
* file
|
// * file
|
||||||
*/
|
// */
|
||||||
private List<Cpe> processXML(final File xml) throws UpdateException {
|
// private List<Cpe> processXML(final File xml) throws UpdateException {
|
||||||
try {
|
// try {
|
||||||
final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
|
// final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
|
||||||
final CPEHandler handler = new CPEHandler();
|
// final CPEHandler handler = new CPEHandler();
|
||||||
saxParser.parse(xml, handler);
|
// saxParser.parse(xml, handler);
|
||||||
return handler.getData();
|
// return handler.getData();
|
||||||
} catch (ParserConfigurationException ex) {
|
// } catch (ParserConfigurationException ex) {
|
||||||
throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
|
// throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
|
||||||
} catch (SAXException ex) {
|
// } catch (SAXException ex) {
|
||||||
throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
|
// throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
|
||||||
} catch (IOException ex) {
|
// } catch (IOException ex) {
|
||||||
throw new UpdateException("Unable to parse CPE XML file due to IO Failure", 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
|
// * Checks to find the last time the CPE data was refreshed and if it needs
|
||||||
* to be updated.
|
// * to be updated.
|
||||||
*
|
// *
|
||||||
* @return true if the CPE data should be refreshed
|
// * @return true if the CPE data should be refreshed
|
||||||
*/
|
// */
|
||||||
private boolean updateNeeded() {
|
// private boolean updateNeeded() {
|
||||||
final long now = System.currentTimeMillis();
|
// final long now = System.currentTimeMillis();
|
||||||
final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
|
// final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
|
||||||
long timestamp = 0;
|
// long timestamp = 0;
|
||||||
final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
|
// final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
|
||||||
if (ts != null && ts.matches("^[0-9]+$")) {
|
// if (ts != null && ts.matches("^[0-9]+$")) {
|
||||||
timestamp = Long.parseLong(ts);
|
// timestamp = Long.parseLong(ts);
|
||||||
}
|
// }
|
||||||
return !DateUtil.withinDateRange(timestamp, now, days);
|
// 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
|
* 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
|
* version number a warning is printed recommending that an upgrade be
|
||||||
* performed.
|
* performed.
|
||||||
*
|
*
|
||||||
@@ -57,11 +57,6 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
|||||||
* The property key indicating when the last version check occurred.
|
* The property key indicating when the last version check occurred.
|
||||||
*/
|
*/
|
||||||
public static final String CURRENT_ENGINE_RELEASE = "CurrentEngineRelease";
|
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
|
* The version retrieved from the database properties or web to check
|
||||||
* against.
|
* against.
|
||||||
@@ -98,20 +93,21 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void update() throws UpdateException {
|
public void update() throws UpdateException {
|
||||||
try {
|
try (CveDB db = CveDB.getInstance()) {
|
||||||
final boolean autoupdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
|
final boolean autoupdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
|
||||||
final boolean enabled = Settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, 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 original = Settings.getString(Settings.KEYS.CVE_ORIGINAL_MODIFIED_20_URL);
|
||||||
final String current = Settings.getString(Settings.KEYS.CVE_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
|
* Only update if auto-update is enabled, the engine check is
|
||||||
* enabled, and the NVD CVE URLs have not been modified (i.e. the
|
* enabled, and the NVD CVE URLs have not been modified (i.e. the
|
||||||
* user has not configured them to point to an internal source).
|
* user has not configured them to point to an internal source).
|
||||||
*/
|
*/
|
||||||
if (enabled && autoupdate && original != null && original.equals(current)) {
|
if (enabled && autoupdate && original != null && original.equals(current)) {
|
||||||
openDatabase();
|
|
||||||
LOGGER.debug("Begin Engine Version Check");
|
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 lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
|
updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
|
||||||
@@ -130,8 +126,6 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
|||||||
throw new UpdateException("Error occurred updating database properties.");
|
throw new UpdateException("Error occurred updating database properties.");
|
||||||
} catch (InvalidSettingException ex) {
|
} catch (InvalidSettingException ex) {
|
||||||
LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
|
LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
|
||||||
} finally {
|
|
||||||
closeDatabase();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,33 +175,6 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
|||||||
return false;
|
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
|
* Retrieves the current released version number from the github
|
||||||
* documentation site.
|
* documentation site.
|
||||||
|
|||||||
@@ -17,14 +17,26 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.update;
|
package org.owasp.dependencycheck.data.update;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
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.CveDB;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
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.ProcessTask;
|
||||||
import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve;
|
import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve;
|
||||||
import org.owasp.dependencycheck.utils.DateUtil;
|
import org.owasp.dependencycheck.utils.DateUtil;
|
||||||
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
@@ -47,48 +60,96 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Jeremy Long
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
public class NvdCveUpdater implements CachedWebDataSource {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveUpdater.class);
|
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
|
* 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
|
* @throws UpdateException is thrown if there is an error updating the
|
||||||
* database
|
* database
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void update() throws UpdateException {
|
public synchronized void update() throws UpdateException {
|
||||||
try {
|
if (isUpdateConfiguredFalse()) {
|
||||||
if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (InvalidSettingException ex) {
|
|
||||||
LOGGER.trace("inavlid setting UPDATE_NVDCVE_ENABLED", ex);
|
|
||||||
}
|
}
|
||||||
|
FileLock lock = null;
|
||||||
|
RandomAccessFile ulFile = null;
|
||||||
|
File lockFile = null;
|
||||||
try {
|
try {
|
||||||
openDataStores();
|
if (ConnectionFactory.isH2Connection()) {
|
||||||
boolean autoUpdate = true;
|
final File dir = Settings.getDataDirectory();
|
||||||
try {
|
lockFile = new File(dir, "odc.update.lock");
|
||||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
if (lockFile.isFile() && getFileAge(lockFile) > 5 && !lockFile.delete()) {
|
||||||
} catch (InvalidSettingException ex) {
|
LOGGER.warn("An old db update lock file was found but the system was unable to delete the file. Consider manually deleting " + lockFile.getAbsolutePath());
|
||||||
LOGGER.debug("Invalid setting for auto-update; using true.");
|
}
|
||||||
|
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();
|
final UpdateableNvdCve updateable = getUpdatesNeeded();
|
||||||
if (updateable.isUpdateNeeded()) {
|
if (updateable.isUpdateNeeded()) {
|
||||||
performUpdate(updateable);
|
performUpdate(updateable);
|
||||||
}
|
}
|
||||||
getProperties().save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis()));
|
dbProperties.save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis()));
|
||||||
}
|
}
|
||||||
} catch (MalformedURLException ex) {
|
} 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);
|
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.");
|
"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);
|
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 {
|
} 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.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
if (dataExists() && 0 < validForHours) {
|
||||||
// ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec
|
// 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 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();
|
final long now = System.currentTimeMillis();
|
||||||
proceed = (now - lastChecked) > msValid;
|
proceed = (now - lastChecked) > msValid;
|
||||||
if (!proceed) {
|
if (!proceed) {
|
||||||
@@ -141,17 +282,10 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
|||||||
* @return true if the database contains data
|
* @return true if the database contains data
|
||||||
*/
|
*/
|
||||||
private boolean dataExists() {
|
private boolean dataExists() {
|
||||||
CveDB cve = null;
|
try (CveDB cve = CveDB.getInstance()) {
|
||||||
try {
|
|
||||||
cve = new CveDB();
|
|
||||||
cve.open();
|
|
||||||
return cve.dataExists();
|
return cve.dataExists();
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
return false;
|
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.");
|
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 Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<>(maxUpdates);
|
||||||
|
|
||||||
final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize);
|
|
||||||
final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
|
|
||||||
final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
|
|
||||||
for (NvdCveInfo cve : updateable) {
|
for (NvdCveInfo cve : updateable) {
|
||||||
if (cve.getNeedsUpdate()) {
|
if (cve.getNeedsUpdate()) {
|
||||||
final DownloadTask call = new DownloadTask(cve, processExecutor, getCveDB(), Settings.getInstance());
|
final DownloadTask call = new DownloadTask(cve, processingExecutorService, cveDb, Settings.getInstance());
|
||||||
downloadFutures.add(downloadExecutors.submit(call));
|
downloadFutures.add(downloadExecutorService.submit(call));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
downloadExecutors.shutdown();
|
|
||||||
|
|
||||||
//next, move the future future processTasks to just future processTasks
|
//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) {
|
for (Future<Future<ProcessTask>> future : downloadFutures) {
|
||||||
Future<ProcessTask> task = null;
|
Future<ProcessTask> task;
|
||||||
try {
|
try {
|
||||||
task = future.get();
|
task = future.get();
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
downloadExecutors.shutdownNow();
|
|
||||||
processExecutor.shutdownNow();
|
|
||||||
|
|
||||||
LOGGER.debug("Thread was interrupted during download", ex);
|
LOGGER.debug("Thread was interrupted during download", ex);
|
||||||
throw new UpdateException("The download was interrupted", ex);
|
throw new UpdateException("The download was interrupted", ex);
|
||||||
} catch (ExecutionException ex) {
|
} catch (ExecutionException ex) {
|
||||||
downloadExecutors.shutdownNow();
|
|
||||||
processExecutor.shutdownNow();
|
|
||||||
|
|
||||||
LOGGER.debug("Thread was interrupted during download execution", ex);
|
LOGGER.debug("Thread was interrupted during download execution", ex);
|
||||||
throw new UpdateException("The execution of the download was interrupted", ex);
|
throw new UpdateException("The execution of the download was interrupted", ex);
|
||||||
}
|
}
|
||||||
if (task == null) {
|
if (task == null) {
|
||||||
downloadExecutors.shutdownNow();
|
|
||||||
processExecutor.shutdownNow();
|
|
||||||
LOGGER.debug("Thread was interrupted during download");
|
LOGGER.debug("Thread was interrupted during download");
|
||||||
throw new UpdateException("The download was interrupted; unable to complete the update");
|
throw new UpdateException("The download was interrupted; unable to complete the update");
|
||||||
} else {
|
} else {
|
||||||
@@ -227,22 +348,18 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
|||||||
throw task.getException();
|
throw task.getException();
|
||||||
}
|
}
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
processExecutor.shutdownNow();
|
|
||||||
LOGGER.debug("Thread was interrupted during processing", ex);
|
LOGGER.debug("Thread was interrupted during processing", ex);
|
||||||
throw new UpdateException(ex);
|
throw new UpdateException(ex);
|
||||||
} catch (ExecutionException ex) {
|
} catch (ExecutionException ex) {
|
||||||
processExecutor.shutdownNow();
|
|
||||||
LOGGER.debug("Execution Exception during process", ex);
|
LOGGER.debug("Execution Exception during process", ex);
|
||||||
throw new UpdateException(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)
|
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.");
|
LOGGER.info("Begin database maintenance.");
|
||||||
getCveDB().cleanupDatabase();
|
cveDb.cleanupDatabase();
|
||||||
LOGGER.info("End database maintenance.");
|
LOGGER.info("End database maintenance.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,7 +379,8 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
|||||||
* updated properties file
|
* updated properties file
|
||||||
*/
|
*/
|
||||||
protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
|
protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
|
||||||
UpdateableNvdCve updates = null;
|
LOGGER.info("starting getUpdatesNeeded() ...");
|
||||||
|
UpdateableNvdCve updates;
|
||||||
try {
|
try {
|
||||||
updates = retrieveCurrentTimestampsFromWeb();
|
updates = retrieveCurrentTimestampsFromWeb();
|
||||||
} catch (InvalidDataException ex) {
|
} catch (InvalidDataException ex) {
|
||||||
@@ -277,19 +395,19 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
|||||||
if (updates == null) {
|
if (updates == null) {
|
||||||
throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
|
throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
|
||||||
}
|
}
|
||||||
if (!getProperties().isEmpty()) {
|
if (dbProperties != null && !dbProperties.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
final int startYear = Settings.getInt(Settings.KEYS.CVE_START_YEAR, 2002);
|
final int startYear = Settings.getInt(Settings.KEYS.CVE_START_YEAR, 2002);
|
||||||
final int endYear = Calendar.getInstance().get(Calendar.YEAR);
|
final int endYear = Calendar.getInstance().get(Calendar.YEAR);
|
||||||
boolean needsFullUpdate = false;
|
boolean needsFullUpdate = false;
|
||||||
for (int y = startYear; y <= endYear; y++) {
|
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) {
|
if (val == 0) {
|
||||||
needsFullUpdate = true;
|
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 long now = System.currentTimeMillis();
|
||||||
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
|
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
|
||||||
if (!needsFullUpdate && lastUpdated == updates.getTimeStamp(MODIFIED)) {
|
if (!needsFullUpdate && lastUpdated == updates.getTimeStamp(MODIFIED)) {
|
||||||
@@ -309,7 +427,7 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
|||||||
} else {
|
} else {
|
||||||
long currentTimestamp = 0;
|
long currentTimestamp = 0;
|
||||||
try {
|
try {
|
||||||
currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE
|
currentTimestamp = Long.parseLong(dbProperties.getProperty(DatabaseProperties.LAST_UPDATED_BASE
|
||||||
+ entry.getId(), "0"));
|
+ entry.getId(), "0"));
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated",
|
LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated",
|
||||||
@@ -344,20 +462,101 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
|||||||
private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
|
private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
|
||||||
throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
|
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 start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
|
||||||
final int end = Calendar.getInstance().get(Calendar.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 baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
|
||||||
final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
|
final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
|
||||||
for (int i = start; i <= end; i++) {
|
for (int i = start; i <= end; i++) {
|
||||||
updates.add(Integer.toString(i), String.format(baseUrl20, i),
|
final String url = String.format(baseUrl20, i);
|
||||||
String.format(baseUrl12, i),
|
updates.add(Integer.toString(i), url, String.format(baseUrl12, i),
|
||||||
true);
|
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;
|
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;
|
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
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
@@ -60,7 +60,7 @@ public class CPEHandler extends DefaultHandler {
|
|||||||
/**
|
/**
|
||||||
* The list of CPE values.
|
* 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.
|
* 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 {
|
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||||
current.setNode(qName);
|
current.setNode(qName);
|
||||||
if (current.isSchemaVersionNode() && !CURRENT_SCHEMA_VERSION.equals(nodeText.toString())) {
|
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);
|
+ 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">
|
// <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;
|
package org.owasp.dependencycheck.data.update.cpe;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
|
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
|
||||||
@@ -36,7 +37,8 @@ public class Cpe {
|
|||||||
*/
|
*/
|
||||||
public Cpe(String value) throws UnsupportedEncodingException, InvalidDataException {
|
public Cpe(String value) throws UnsupportedEncodingException, InvalidDataException {
|
||||||
this.value = value;
|
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) {
|
if (data.length >= 2) {
|
||||||
vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8");
|
vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8");
|
||||||
product = URLDecoder.decode(data[1].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.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -46,6 +45,30 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
|||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(DownloadTask.class);
|
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.
|
* Simple constructor for the callable download task.
|
||||||
@@ -77,22 +100,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
|||||||
this.second = file2;
|
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.
|
* Get the value of nvdCveInfo.
|
||||||
@@ -111,10 +118,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
|||||||
public void setNvdCveInfo(NvdCveInfo nvdCveInfo) {
|
public void setNvdCveInfo(NvdCveInfo nvdCveInfo) {
|
||||||
this.nvdCveInfo = nvdCveInfo;
|
this.nvdCveInfo = nvdCveInfo;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* a file.
|
|
||||||
*/
|
|
||||||
private File first;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of first.
|
* Get the value of first.
|
||||||
@@ -133,10 +136,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
|||||||
public void setFirst(File first) {
|
public void setFirst(File first) {
|
||||||
this.first = first;
|
this.first = first;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* a file.
|
|
||||||
*/
|
|
||||||
private File second;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of second.
|
* Get the value of second.
|
||||||
@@ -224,33 +223,19 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
|||||||
if (file == null || !file.isFile()) {
|
if (file == null || !file.isFile()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
InputStream is = null;
|
try (InputStream is = new FileInputStream(file)) {
|
||||||
try {
|
|
||||||
is = new FileInputStream(file);
|
|
||||||
|
|
||||||
final byte[] buf = new byte[5];
|
final byte[] buf = new byte[5];
|
||||||
int read = 0;
|
int read;
|
||||||
try {
|
read = is.read(buf);
|
||||||
read = is.read(buf);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return read == 5
|
return read == 5
|
||||||
&& buf[0] == '<'
|
&& buf[0] == '<'
|
||||||
&& (buf[1] == '?')
|
&& (buf[1] == '?')
|
||||||
&& (buf[2] == 'x' || buf[2] == 'X')
|
&& (buf[2] == 'x' || buf[2] == 'X')
|
||||||
&& (buf[3] == 'm' || buf[3] == 'M')
|
&& (buf[3] == 'm' || buf[3] == 'M')
|
||||||
&& (buf[4] == 'l' || buf[4] == 'L');
|
&& (buf[4] == 'l' || buf[4] == 'L');
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (IOException ex) {
|
||||||
|
LOGGER.debug("Error checking if file is xml", ex);
|
||||||
return false;
|
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);
|
skip = "1".equals(reject);
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
vulnerability = attributes.getValue("name");
|
vulnerability = attributes.getValue("name");
|
||||||
software = new ArrayList<VulnerableSoftware>();
|
software = new ArrayList<>();
|
||||||
} else {
|
} else {
|
||||||
vulnerability = null;
|
vulnerability = null;
|
||||||
software = null;
|
software = null;
|
||||||
@@ -132,7 +132,7 @@ public class NvdCve12Handler extends DefaultHandler {
|
|||||||
if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
|
if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
|
||||||
throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
|
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.SAXNotSupportedException;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
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).
|
* 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.
|
* the current supported schema version.
|
||||||
*/
|
*/
|
||||||
private static final String CURRENT_SCHEMA_VERSION = "2.0";
|
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.
|
* the current element.
|
||||||
*/
|
*/
|
||||||
@@ -73,6 +88,21 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
*/
|
*/
|
||||||
private int totalNumberOfEntries;
|
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.
|
* Get the value of totalNumberOfEntries.
|
||||||
*
|
*
|
||||||
@@ -81,10 +111,6 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
public int getTotalNumberOfEntries() {
|
public int getTotalNumberOfEntries() {
|
||||||
return totalNumberOfEntries;
|
return totalNumberOfEntries;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The total number of application entries parsed.
|
|
||||||
*/
|
|
||||||
private int totalNumberOfApplicationEntries;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of totalNumberOfApplicationEntries.
|
* Get the value of totalNumberOfApplicationEntries.
|
||||||
@@ -101,30 +127,30 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
if (current.isEntryNode()) {
|
if (current.isEntryNode()) {
|
||||||
hasApplicationCpe = false;
|
hasApplicationCpe = false;
|
||||||
vulnerability = new Vulnerability();
|
vulnerability = new Vulnerability();
|
||||||
vulnerability.setName(attributes.getValue("id"));
|
vulnerability.setName(attributes.getValue(ID));
|
||||||
} else if (current.isVulnProductNode()) {
|
} else if (current.isVulnProductNode()) {
|
||||||
nodeText = new StringBuilder(100);
|
nodeText = new StringBuilder(100);
|
||||||
} else if (current.isVulnReferencesNode()) {
|
} else if (current.isVulnReferencesNode()) {
|
||||||
final String lang = attributes.getValue("xml:lang");
|
final String lang = attributes.getValue(XML_LANG);
|
||||||
if ("en".equals(lang)) {
|
if (EN.equals(lang)) {
|
||||||
reference = new Reference();
|
reference = new Reference();
|
||||||
} else {
|
} else {
|
||||||
reference = null;
|
reference = null;
|
||||||
}
|
}
|
||||||
} else if (reference != null && current.isVulnReferenceNode()) {
|
} else if (reference != null && current.isVulnReferenceNode()) {
|
||||||
reference.setUrl(attributes.getValue("href"));
|
reference.setUrl(attributes.getValue(HREF));
|
||||||
nodeText = new StringBuilder(130);
|
nodeText = new StringBuilder(130);
|
||||||
} else if (reference != null && current.isVulnSourceNode()) {
|
} else if (reference != null && current.isVulnSourceNode()) {
|
||||||
nodeText = new StringBuilder(30);
|
nodeText = new StringBuilder(30);
|
||||||
} else if (current.isVulnSummaryNode()) {
|
} else if (current.isVulnSummaryNode()) {
|
||||||
nodeText = new StringBuilder(500);
|
nodeText = new StringBuilder(500);
|
||||||
} else if (current.isNVDNode()) {
|
} 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)) {
|
if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
|
||||||
throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
|
throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
|
||||||
}
|
}
|
||||||
} else if (current.isVulnCWENode()) {
|
} else if (current.isVulnCWENode()) {
|
||||||
vulnerability.setCwe(attributes.getValue("id"));
|
vulnerability.setCwe(attributes.getValue(ID));
|
||||||
} else if (current.isCVSSScoreNode()) {
|
} else if (current.isCVSSScoreNode()) {
|
||||||
nodeText = new StringBuilder(5);
|
nodeText = new StringBuilder(5);
|
||||||
} else if (current.isCVSSAccessVectorNode()) {
|
} else if (current.isCVSSAccessVectorNode()) {
|
||||||
@@ -158,9 +184,7 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
totalNumberOfApplicationEntries += 1;
|
totalNumberOfApplicationEntries += 1;
|
||||||
try {
|
try {
|
||||||
saveEntry(vulnerability);
|
saveEntry(vulnerability);
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException | CorruptIndexException ex) {
|
||||||
throw new SAXException(ex);
|
|
||||||
} catch (CorruptIndexException ex) {
|
|
||||||
throw new SAXException(ex);
|
throw new SAXException(ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new SAXException(ex);
|
throw new SAXException(ex);
|
||||||
@@ -196,7 +220,7 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
nodeText = null;
|
nodeText = null;
|
||||||
} else if (current.isVulnProductNode()) {
|
} else if (current.isVulnProductNode()) {
|
||||||
final String cpe = nodeText.toString();
|
final String cpe = nodeText.toString();
|
||||||
if (cpe.startsWith("cpe:/a:")) {
|
if (cpe.startsWith(CPE_NODE_TEXT_PREFIX)) {
|
||||||
hasApplicationCpe = true;
|
hasApplicationCpe = true;
|
||||||
vulnerability.addVulnerableSoftware(cpe);
|
vulnerability.addVulnerableSoftware(cpe);
|
||||||
}
|
}
|
||||||
@@ -212,16 +236,12 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
nodeText = null;
|
nodeText = null;
|
||||||
} else if (current.isVulnSummaryNode()) {
|
} else if (current.isVulnSummaryNode()) {
|
||||||
vulnerability.setDescription(nodeText.toString());
|
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
|
hasApplicationCpe = true; //ensure we process this to delete the vuln
|
||||||
}
|
}
|
||||||
nodeText = null;
|
nodeText = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* the cve database.
|
|
||||||
*/
|
|
||||||
private CveDB cveDB;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the cveDB.
|
* Sets the cveDB.
|
||||||
@@ -231,15 +251,12 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
public void setCveDB(CveDB db) {
|
public void setCveDB(CveDB db) {
|
||||||
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.
|
* 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) {
|
public void setPrevVersionVulnMap(Map<String, List<VulnerableSoftware>> map) {
|
||||||
prevVersionVulnMap = map;
|
prevVersionVulnMap = map;
|
||||||
@@ -249,7 +266,8 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
* Saves a vulnerability to the CVE Database.
|
* Saves a vulnerability to the CVE Database.
|
||||||
*
|
*
|
||||||
* @param vuln the vulnerability to store in the 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 CorruptIndexException is thrown if the CPE Index is corrupt
|
||||||
* @throws IOException thrown if there is an IOException with the CPE Index
|
* @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">
|
// <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 {
|
protected static class Element {
|
||||||
|
|
||||||
@@ -491,4 +510,28 @@ public class NvdCve20Handler extends DefaultHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// </editor-fold>
|
// </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;
|
package org.owasp.dependencycheck.data.update.nvd;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -167,19 +166,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
|||||||
importXML(filePair.getFirst(), filePair.getSecond());
|
importXML(filePair.getFirst(), filePair.getSecond());
|
||||||
cveDB.commit();
|
cveDB.commit();
|
||||||
properties.save(filePair.getNvdCveInfo());
|
properties.save(filePair.getNvdCveInfo());
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (ParserConfigurationException | SAXException | SQLException | DatabaseException | ClassNotFoundException | IOException 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) {
|
|
||||||
throw new UpdateException(ex);
|
throw new UpdateException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
filePair.cleanup();
|
filePair.cleanup();
|
||||||
|
|||||||
@@ -17,16 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.update.nvd;
|
package org.owasp.dependencycheck.data.update.nvd;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.TreeMap;
|
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
|
* 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> {
|
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.
|
* 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.
|
* 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 id the key for the item to be added
|
||||||
* @param url the URL to download the item
|
* @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 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
|
* @param timestamp the last modified date of the downloaded item
|
||||||
* @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 needsUpdate whether or not the data needs to be updated
|
* @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();
|
final NvdCveInfo item = new NvdCveInfo();
|
||||||
item.setNeedsUpdate(needsUpdate); //the others default to true, to make life easier later this should default to false.
|
item.setNeedsUpdate(needsUpdate); //the others default to true, to make life easier later this should default to false.
|
||||||
item.setId(id);
|
item.setId(id);
|
||||||
item.setUrl(url);
|
item.setUrl(url);
|
||||||
item.setOldSchemaVersionUrl(oldUrl);
|
item.setOldSchemaVersionUrl(oldUrl);
|
||||||
LOGGER.debug("Checking for updates from: {}", url);
|
item.setTimestamp(timestamp);
|
||||||
item.setTimestamp(Downloader.getLastModified(new URL(url)));
|
|
||||||
collection.put(id, item);
|
collection.put(id, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,30 +73,10 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
* The file name of the dependency.
|
* The file name of the dependency.
|
||||||
*/
|
*/
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The package path.
|
* The package path.
|
||||||
*/
|
*/
|
||||||
private String packagePath;
|
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.
|
* The md5 hash of the dependency.
|
||||||
*/
|
*/
|
||||||
@@ -121,6 +101,60 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
* A collection of version evidence.
|
* A collection of version evidence.
|
||||||
*/
|
*/
|
||||||
private final EvidenceCollection versionEvidence;
|
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.
|
* Constructs a new Dependency object.
|
||||||
@@ -129,10 +163,10 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
vendorEvidence = new EvidenceCollection();
|
vendorEvidence = new EvidenceCollection();
|
||||||
productEvidence = new EvidenceCollection();
|
productEvidence = new EvidenceCollection();
|
||||||
versionEvidence = new EvidenceCollection();
|
versionEvidence = new EvidenceCollection();
|
||||||
identifiers = new TreeSet<Identifier>();
|
identifiers = new TreeSet<>();
|
||||||
vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
|
vulnerabilities = new TreeSet<>(new VulnerabilityComparator());
|
||||||
suppressedIdentifiers = new TreeSet<Identifier>();
|
suppressedIdentifiers = new TreeSet<>();
|
||||||
suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
|
suppressedVulnerabilities = new TreeSet<>(new VulnerabilityComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,11 +256,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The file name to display in reports.
|
|
||||||
*/
|
|
||||||
private String displayName = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the file name to display in reports.
|
* Sets the file name to display in reports.
|
||||||
*
|
*
|
||||||
@@ -392,11 +421,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
this.identifiers.add(identifier);
|
this.identifiers.add(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of identifiers that have been suppressed.
|
|
||||||
*/
|
|
||||||
private Set<Identifier> suppressedIdentifiers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of suppressedIdentifiers.
|
* Get the value of suppressedIdentifiers.
|
||||||
*
|
*
|
||||||
@@ -424,11 +448,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
this.suppressedIdentifiers.add(identifier);
|
this.suppressedIdentifiers.add(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of vulnerabilities that have been suppressed.
|
|
||||||
*/
|
|
||||||
private SortedSet<Vulnerability> suppressedVulnerabilities;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of suppressedVulnerabilities.
|
* Get the value of suppressedVulnerabilities.
|
||||||
*
|
*
|
||||||
@@ -510,11 +529,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
return this.versionEvidence;
|
return this.versionEvidence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The description of the JAR file.
|
|
||||||
*/
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of description.
|
* Get the value of description.
|
||||||
*
|
*
|
||||||
@@ -533,11 +547,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The license that this dependency uses.
|
|
||||||
*/
|
|
||||||
private String license;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of license.
|
* Get the value of license.
|
||||||
*
|
*
|
||||||
@@ -556,11 +565,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
this.license = license;
|
this.license = license;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of vulnerabilities for this dependency.
|
|
||||||
*/
|
|
||||||
private SortedSet<Vulnerability> vulnerabilities;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of 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.warn("Unable to read '{}' to determine hashes.", file.getName());
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} catch (NoSuchAlgorithmException 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);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
this.setMd5sum(md5);
|
this.setMd5sum(md5);
|
||||||
@@ -610,11 +614,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
this.vulnerabilities.add(vulnerability);
|
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
|
* Get the value of {@link #relatedDependencies}. This field is used to
|
||||||
* collect other dependencies which really represent the same dependency,
|
* collect other dependencies which really represent the same dependency,
|
||||||
@@ -626,11 +625,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
return relatedDependencies;
|
return relatedDependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of projects that reference this dependency.
|
|
||||||
*/
|
|
||||||
private Set<String> projectReferences = new HashSet<String>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of projectReferences.
|
* 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.
|
* Get the value of availableVersions.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -280,9 +280,9 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
|||||||
if (me == null && other == null) {
|
if (me == null && other == null) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (me == null) {
|
} 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) {
|
} 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);
|
return me.compareToIgnoreCase(other);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,17 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
|||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(EvidenceCollection.class);
|
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>() {
|
private static final Filter<Evidence> HIGHEST_CONFIDENCE = new Filter<Evidence>() {
|
||||||
@Override
|
@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>() {
|
private static final Filter<Evidence> HIGH_CONFIDENCE = new Filter<Evidence>() {
|
||||||
@Override
|
@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>() {
|
private static final Filter<Evidence> MEDIUM_CONFIDENCE = new Filter<Evidence>() {
|
||||||
@Override
|
@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>() {
|
private static final Filter<Evidence> EVIDENCE_USED = new Filter<Evidence>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -96,35 +109,32 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
|||||||
/**
|
/**
|
||||||
* Used to iterate over evidence of the specified confidence.
|
* 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
|
* @return Iterable<Evidence> an iterable collection of evidence
|
||||||
*/
|
*/
|
||||||
public final Iterable<Evidence> iterator(Confidence confidence) {
|
public final Iterable<Evidence> iterator(Confidence confidence) {
|
||||||
if (confidence == Confidence.HIGHEST) {
|
if (null != confidence) {
|
||||||
return EvidenceCollection.HIGHEST_CONFIDENCE.filter(this.list);
|
switch (confidence) {
|
||||||
} else if (confidence == Confidence.HIGH) {
|
case HIGHEST:
|
||||||
return EvidenceCollection.HIGH_CONFIDENCE.filter(this.list);
|
return EvidenceCollection.HIGHEST_CONFIDENCE.filter(this.list);
|
||||||
} else if (confidence == Confidence.MEDIUM) {
|
case HIGH:
|
||||||
return EvidenceCollection.MEDIUM_CONFIDENCE.filter(this.list);
|
return EvidenceCollection.HIGH_CONFIDENCE.filter(this.list);
|
||||||
} else {
|
case MEDIUM:
|
||||||
return EvidenceCollection.LOW_CONFIDENCE.filter(this.list);
|
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.
|
* Creates a new EvidenceCollection.
|
||||||
*/
|
*/
|
||||||
public EvidenceCollection() {
|
public EvidenceCollection() {
|
||||||
list = new TreeSet<Evidence>();
|
list = new TreeSet<>();
|
||||||
weightedStrings = new HashSet<String>();
|
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 source the source of the Evidence.
|
||||||
* @param name the name 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
|
* Adds term to the weighting collection. The terms added here are used
|
||||||
* of combining evidence from multiple sources to boost the confidence of the given evidence.
|
* 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
|
* Example: The term 'Apache' is found in the manifest of a JAR and is added
|
||||||
* names within the JAR file we may add these package names to the "weighted" strings collection to boost the score in the
|
* to the Collection. When we parse the package names within the JAR file we
|
||||||
* Lucene query. That way when we construct the Lucene query we find the term Apache in the collection AND in the weighted
|
* 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.
|
* strings; as such, we will boost the confidence of the term Apache.
|
||||||
*
|
*
|
||||||
* @param str to add to the weighting collection.
|
* @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
|
* Returns a set of Weightings - a list of terms that are believed to be of
|
||||||
* location.
|
* higher confidence when also found in another location.
|
||||||
*
|
*
|
||||||
* @return Set<String>
|
* @return Set<String>
|
||||||
*/
|
*/
|
||||||
@@ -193,7 +208,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
|||||||
if (source == null) {
|
if (source == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Set<Evidence> ret = new HashSet<Evidence>();
|
final Set<Evidence> ret = new HashSet<>();
|
||||||
for (Evidence e : list) {
|
for (Evidence e : list) {
|
||||||
if (source.equals(e.getSource())) {
|
if (source.equals(e.getSource())) {
|
||||||
ret.add(e);
|
ret.add(e);
|
||||||
@@ -213,7 +228,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
|||||||
if (source == null || name == null) {
|
if (source == null || name == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Set<Evidence> ret = new HashSet<Evidence>();
|
final Set<Evidence> ret = new HashSet<>();
|
||||||
for (Evidence e : list) {
|
for (Evidence e : list) {
|
||||||
if (source.equals(e.getSource()) && name.equals(e.getName())) {
|
if (source.equals(e.getSource()) && name.equals(e.getName())) {
|
||||||
ret.add(e);
|
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.
|
* @param version the version to search for within the collected evidence.
|
||||||
* @return whether or not the string was used.
|
* @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.
|
* @param confidence A Confidence value.
|
||||||
* @return boolean.
|
* @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.
|
* @param ec One or more EvidenceCollections.
|
||||||
* @return a new EvidenceCollection containing the used evidence.
|
* @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
|
* @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) {
|
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 (EvidenceCollection col : ec) {
|
||||||
for (Evidence e : col) {
|
for (Evidence e : col) {
|
||||||
//if (e.isUsed()) {
|
//if (e.isUsed()) {
|
||||||
@@ -367,18 +387,20 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Takes a string that may contain a fully qualified domain and it will return the string having removed the query string, the
|
* Takes a string that may contain a fully qualified domain and it will
|
||||||
* protocol, the sub-domain of 'www', and the file extension of the path.</p>
|
* return the string having removed the query string, the protocol, the
|
||||||
|
* sub-domain of 'www', and the file extension of the path.</p>
|
||||||
* <p>
|
* <p>
|
||||||
* This is useful for checking if the evidence contains a specific string. The presence of the protocol, file extension, etc.
|
* This is useful for checking if the evidence contains a specific string.
|
||||||
* may produce false positives.
|
* The presence of the protocol, file extension, etc. may produce false
|
||||||
|
* positives.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Example, given the following input:</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>
|
* <p>
|
||||||
* The function would return:</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
|
* @param value the value that may contain a url
|
||||||
* @return the modified string
|
* @return the modified string
|
||||||
|
|||||||
@@ -20,21 +20,161 @@ package org.owasp.dependencycheck.dependency;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* In identifier such as a CPE or dependency coordinates (i.e. GAV).
|
||||||
*
|
*
|
||||||
* @author Jeremy Long
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class Identifier implements Serializable, Comparable<Identifier> {
|
public class Identifier implements Serializable, Comparable<Identifier> {
|
||||||
|
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="fields">
|
||||||
/**
|
/**
|
||||||
* The serial version UID for serialization.
|
* The serial version UID for serialization.
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1L;
|
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
|
* Set the value of confidence.
|
||||||
* creation as is the case with many XML parsers (for the parsing
|
*
|
||||||
* of the Dependency-Check XML report). For all other use-cases,
|
* @param confidence new value of confidence
|
||||||
* please use the non-default constructors.
|
*/
|
||||||
|
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() {
|
public Identifier() {
|
||||||
}
|
}
|
||||||
@@ -65,120 +205,6 @@ public class Identifier implements Serializable, Comparable<Identifier> {
|
|||||||
this.description = description;
|
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
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj == null) {
|
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)) {
|
if ((this.value == null) ? (other.value != null) : !this.value.equals(other.value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) {
|
return !((this.type == null) ? (other.type != null) : !this.type.equals(other.type));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
* @param o the object being compared
|
||||||
* @return an integer indicating the ordering
|
* @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)) {
|
if ((this.url == null) ? (other.url != null) : !this.url.equals(other.url)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((this.source == null) ? (other.source != null) : !this.source.equals(other.source)) {
|
return !((this.source == null) ? (other.source != null) : !this.source.equals(other.source));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,9 +18,11 @@
|
|||||||
package org.owasp.dependencycheck.dependency;
|
package org.owasp.dependencycheck.dependency;
|
||||||
|
|
||||||
import java.io.Serializable;
|
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.Set;
|
||||||
import java.util.SortedSet;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,11 +36,69 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
* The serial version uid.
|
* The serial version uid.
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 307319490326651052L;
|
private static final long serialVersionUID = 307319490326651052L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the vulnerability.
|
* The name of the vulnerability.
|
||||||
*/
|
*/
|
||||||
private String name;
|
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.
|
* Get the value of name.
|
||||||
@@ -57,10 +117,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* the description of the vulnerability.
|
|
||||||
*/
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of description.
|
* Get the value of description.
|
||||||
@@ -79,10 +135,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setDescription(String description) {
|
public void setDescription(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* References for this vulnerability.
|
|
||||||
*/
|
|
||||||
private SortedSet<Reference> references = new TreeSet<Reference>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of references.
|
* Get the value of references.
|
||||||
@@ -93,12 +145,27 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
return references;
|
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.
|
* Set the value of references.
|
||||||
*
|
*
|
||||||
* @param references new value of references
|
* @param references new value of references
|
||||||
*/
|
*/
|
||||||
public void setReferences(SortedSet<Reference> references) {
|
public void setReferences(Set<Reference> references) {
|
||||||
this.references = references;
|
this.references = references;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,10 +192,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
ref.setUrl(referenceUrl);
|
ref.setUrl(referenceUrl);
|
||||||
this.references.add(ref);
|
this.references.add(ref);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* A set of vulnerable software.
|
|
||||||
*/
|
|
||||||
private SortedSet<VulnerableSoftware> vulnerableSoftware = new TreeSet<VulnerableSoftware>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of vulnerableSoftware.
|
* Get the value of vulnerableSoftware.
|
||||||
@@ -139,12 +202,27 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
return vulnerableSoftware;
|
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.
|
* Set the value of vulnerableSoftware.
|
||||||
*
|
*
|
||||||
* @param vulnerableSoftware new value of vulnerableSoftware
|
* @param vulnerableSoftware new value of vulnerableSoftware
|
||||||
*/
|
*/
|
||||||
public void setVulnerableSoftware(SortedSet<VulnerableSoftware> vulnerableSoftware) {
|
public void setVulnerableSoftware(Set<VulnerableSoftware> vulnerableSoftware) {
|
||||||
this.vulnerableSoftware = vulnerableSoftware;
|
this.vulnerableSoftware = vulnerableSoftware;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,10 +230,9 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
* Adds an entry for vulnerable software.
|
* Adds an entry for vulnerable software.
|
||||||
*
|
*
|
||||||
* @param cpe string representation of a CPE entry
|
* @param cpe string representation of a CPE entry
|
||||||
* @return if the add succeeded
|
|
||||||
*/
|
*/
|
||||||
public boolean addVulnerableSoftware(String cpe) {
|
public void addVulnerableSoftware(String cpe) {
|
||||||
return addVulnerableSoftware(cpe, null);
|
addVulnerableSoftware(cpe, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -164,33 +241,27 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
* @param cpe string representation of a cpe
|
* @param cpe string representation of a cpe
|
||||||
* @param previousVersion the previous version (previousVersion - cpe would
|
* @param previousVersion the previous version (previousVersion - cpe would
|
||||||
* be considered vulnerable)
|
* 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();
|
final VulnerableSoftware vs = new VulnerableSoftware();
|
||||||
vs.setCpe(cpe);
|
vs.setCpe(cpe);
|
||||||
if (previousVersion != null) {
|
if (previousVersion != null) {
|
||||||
vs.setPreviousVersion(previousVersion);
|
vs.setPreviousVersion(previousVersion);
|
||||||
}
|
}
|
||||||
return updateVulnerableSoftware(vs);
|
updateVulnerableSoftware(vs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds or updates a vulnerable software entry.
|
* Adds or updates a vulnerable software entry.
|
||||||
*
|
*
|
||||||
* @param vulnSoftware the vulnerable software
|
* @param vulnSoftware the vulnerable software
|
||||||
* @return if the update succeeded
|
|
||||||
*/
|
*/
|
||||||
public boolean updateVulnerableSoftware(VulnerableSoftware vulnSoftware) {
|
public void updateVulnerableSoftware(VulnerableSoftware vulnSoftware) {
|
||||||
if (vulnerableSoftware.contains(vulnSoftware)) {
|
if (vulnerableSoftware.contains(vulnSoftware)) {
|
||||||
vulnerableSoftware.remove(vulnSoftware);
|
vulnerableSoftware.remove(vulnSoftware);
|
||||||
}
|
}
|
||||||
return vulnerableSoftware.add(vulnSoftware);
|
vulnerableSoftware.add(vulnSoftware);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The CWE for the vulnerability.
|
|
||||||
*/
|
|
||||||
private String cwe;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cwe.
|
* Get the value of cwe.
|
||||||
@@ -209,10 +280,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setCwe(String cwe) {
|
public void setCwe(String cwe) {
|
||||||
this.cwe = cwe;
|
this.cwe = cwe;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* CVSS Score.
|
|
||||||
*/
|
|
||||||
private float cvssScore;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cvssScore.
|
* Get the value of cvssScore.
|
||||||
@@ -231,10 +298,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setCvssScore(float cvssScore) {
|
public void setCvssScore(float cvssScore) {
|
||||||
this.cvssScore = cvssScore;
|
this.cvssScore = cvssScore;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* CVSS Access Vector.
|
|
||||||
*/
|
|
||||||
private String cvssAccessVector;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cvssAccessVector.
|
* Get the value of cvssAccessVector.
|
||||||
@@ -253,10 +316,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setCvssAccessVector(String cvssAccessVector) {
|
public void setCvssAccessVector(String cvssAccessVector) {
|
||||||
this.cvssAccessVector = cvssAccessVector;
|
this.cvssAccessVector = cvssAccessVector;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* CVSS Access Complexity.
|
|
||||||
*/
|
|
||||||
private String cvssAccessComplexity;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cvssAccessComplexity.
|
* Get the value of cvssAccessComplexity.
|
||||||
@@ -275,10 +334,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setCvssAccessComplexity(String cvssAccessComplexity) {
|
public void setCvssAccessComplexity(String cvssAccessComplexity) {
|
||||||
this.cvssAccessComplexity = cvssAccessComplexity;
|
this.cvssAccessComplexity = cvssAccessComplexity;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* CVSS Authentication.
|
|
||||||
*/
|
|
||||||
private String cvssAuthentication;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cvssAuthentication.
|
* Get the value of cvssAuthentication.
|
||||||
@@ -297,10 +352,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setCvssAuthentication(String cvssAuthentication) {
|
public void setCvssAuthentication(String cvssAuthentication) {
|
||||||
this.cvssAuthentication = cvssAuthentication;
|
this.cvssAuthentication = cvssAuthentication;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* CVSS Confidentiality Impact.
|
|
||||||
*/
|
|
||||||
private String cvssConfidentialityImpact;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cvssConfidentialityImpact.
|
* Get the value of cvssConfidentialityImpact.
|
||||||
@@ -319,10 +370,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setCvssConfidentialityImpact(String cvssConfidentialityImpact) {
|
public void setCvssConfidentialityImpact(String cvssConfidentialityImpact) {
|
||||||
this.cvssConfidentialityImpact = cvssConfidentialityImpact;
|
this.cvssConfidentialityImpact = cvssConfidentialityImpact;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* CVSS Integrity Impact.
|
|
||||||
*/
|
|
||||||
private String cvssIntegrityImpact;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cvssIntegrityImpact.
|
* Get the value of cvssIntegrityImpact.
|
||||||
@@ -341,10 +388,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public void setCvssIntegrityImpact(String cvssIntegrityImpact) {
|
public void setCvssIntegrityImpact(String cvssIntegrityImpact) {
|
||||||
this.cvssIntegrityImpact = cvssIntegrityImpact;
|
this.cvssIntegrityImpact = cvssIntegrityImpact;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* CVSS Availability Impact.
|
|
||||||
*/
|
|
||||||
private String cvssAvailabilityImpact;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cvssAvailabilityImpact.
|
* Get the value of cvssAvailabilityImpact.
|
||||||
@@ -364,6 +407,24 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
this.cvssAvailabilityImpact = cvssAvailabilityImpact;
|
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
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
@@ -373,10 +434,7 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Vulnerability other = (Vulnerability) obj;
|
final Vulnerability other = (Vulnerability) obj;
|
||||||
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
|
return !((this.name == null) ? (other.name != null) : !this.name.equals(other.name));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -391,13 +449,14 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
final StringBuilder sb = new StringBuilder("Vulnerability ");
|
final StringBuilder sb = new StringBuilder("Vulnerability ");
|
||||||
sb.append(this.name);
|
sb.append(this.name);
|
||||||
sb.append("\nReferences:\n");
|
sb.append("\nReferences:\n");
|
||||||
for (Reference reference : this.references) {
|
for (Reference reference : getReferences(true)) {
|
||||||
sb.append("=> ");
|
sb.append("=> ");
|
||||||
sb.append(reference);
|
sb.append(reference);
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
sb.append("\nSoftware:\n");
|
sb.append("\nSoftware:\n");
|
||||||
for (VulnerableSoftware software : this.vulnerableSoftware) {
|
|
||||||
|
for (VulnerableSoftware software : getVulnerableSoftware(true)) {
|
||||||
sb.append("=> ");
|
sb.append("=> ");
|
||||||
sb.append(software);
|
sb.append(software);
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
@@ -417,18 +476,8 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
return new CompareToBuilder()
|
return new CompareToBuilder()
|
||||||
.append(this.name, v.name)
|
.append(this.name, v.name)
|
||||||
.toComparison();
|
.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.
|
* 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.Serializable;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -73,7 +74,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
|||||||
public void parseName(String cpeName) throws UnsupportedEncodingException {
|
public void parseName(String cpeName) throws UnsupportedEncodingException {
|
||||||
this.name = cpeName;
|
this.name = cpeName;
|
||||||
if (cpeName != null && cpeName.length() > 7) {
|
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) {
|
if (data.length >= 1) {
|
||||||
this.setVendor(urlDecode(data[0]));
|
this.setVendor(urlDecode(data[0]));
|
||||||
}
|
}
|
||||||
@@ -138,10 +140,7 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final VulnerableSoftware other = (VulnerableSoftware) obj;
|
final VulnerableSoftware other = (VulnerableSoftware) obj;
|
||||||
if ((this.name == null) ? (other.getName() != null) : !this.name.equals(other.getName())) {
|
return !((this.name == null) ? (other.getName() != null) : !this.name.equals(other.getName()));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,8 +174,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
|||||||
@Override
|
@Override
|
||||||
public int compareTo(VulnerableSoftware vs) {
|
public int compareTo(VulnerableSoftware vs) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
final String[] left = this.name.split(":");
|
final String[] left = StringUtils.split(this.name, ':');
|
||||||
final String[] right = vs.getName().split(":");
|
final String[] right = StringUtils.split(vs.getName(), ':');
|
||||||
final int max = (left.length <= right.length) ? left.length : right.length;
|
final int max = (left.length <= right.length) ? left.length : right.length;
|
||||||
if (max > 0) {
|
if (max > 0) {
|
||||||
for (int i = 0; result == 0 && i < max; i++) {
|
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
|
* @param str the string to test
|
||||||
* @return true if the string only contains 0-9, otherwise false.
|
* @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()) {
|
if (str == null || str.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,19 @@ import java.util.List;
|
|||||||
* @author Jeremy Long
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class ExceptionCollection extends Exception {
|
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.
|
* Instantiates a new exception collection.
|
||||||
@@ -86,7 +99,7 @@ public class ExceptionCollection extends Exception {
|
|||||||
*/
|
*/
|
||||||
public ExceptionCollection(Throwable exceptions, boolean fatal) {
|
public ExceptionCollection(Throwable exceptions, boolean fatal) {
|
||||||
super();
|
super();
|
||||||
this.exceptions = new ArrayList<Throwable>();
|
this.exceptions = new ArrayList<>();
|
||||||
this.exceptions.add(exceptions);
|
this.exceptions.add(exceptions);
|
||||||
this.fatal = fatal;
|
this.fatal = fatal;
|
||||||
}
|
}
|
||||||
@@ -99,7 +112,7 @@ public class ExceptionCollection extends Exception {
|
|||||||
*/
|
*/
|
||||||
public ExceptionCollection(String msg, Throwable exception) {
|
public ExceptionCollection(String msg, Throwable exception) {
|
||||||
super(msg);
|
super(msg);
|
||||||
this.exceptions = new ArrayList<Throwable>();
|
this.exceptions = new ArrayList<>();
|
||||||
this.exceptions.add(exception);
|
this.exceptions.add(exception);
|
||||||
this.fatal = false;
|
this.fatal = false;
|
||||||
}
|
}
|
||||||
@@ -109,17 +122,8 @@ public class ExceptionCollection extends Exception {
|
|||||||
*/
|
*/
|
||||||
public ExceptionCollection() {
|
public ExceptionCollection() {
|
||||||
super();
|
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.
|
* Get the value of exceptions.
|
||||||
@@ -150,12 +154,6 @@ public class ExceptionCollection extends Exception {
|
|||||||
this.fatal = fatal;
|
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.
|
* Get the value of fatal.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -240,55 +240,39 @@ public class ReportGenerator {
|
|||||||
InputStream input = null;
|
InputStream input = null;
|
||||||
String templatePath = null;
|
String templatePath = null;
|
||||||
final File f = new File(templateName);
|
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 {
|
try {
|
||||||
reader = new InputStreamReader(input, "UTF-8");
|
if (f.exists() && f.isFile()) {
|
||||||
writer = new OutputStreamWriter(outputStream, "UTF-8");
|
try {
|
||||||
if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
|
templatePath = templateName;
|
||||||
throw new ReportException("Failed to convert the template into html.");
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(input, "UTF-8");
|
||||||
|
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8")) {
|
||||||
|
if (!velocityEngine.evaluate(context, writer, templatePath, 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 {
|
} finally {
|
||||||
if (writer != null) {
|
if (input != null) {
|
||||||
try {
|
try {
|
||||||
writer.close();
|
input.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.trace("", ex);
|
LOGGER.trace("Error closing input", ex);
|
||||||
}
|
|
||||||
}
|
|
||||||
if (outputStream != null) {
|
|
||||||
try {
|
|
||||||
outputStream.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.trace("", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (reader != null) {
|
|
||||||
try {
|
|
||||||
reader.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.trace("", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,21 +299,10 @@ public class ReportGenerator {
|
|||||||
throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
|
throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try (OutputStream outputSteam = new FileOutputStream(outFile)) {
|
||||||
OutputStream outputSteam = null;
|
|
||||||
try {
|
|
||||||
outputSteam = new FileOutputStream(outFile);
|
|
||||||
generateReport(templateName, outputSteam);
|
generateReport(templateName, outputSteam);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (IOException ex) {
|
||||||
throw new ReportException("Unable to write to file: " + outFile, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* DependencyCheck uses {@link org.slf4j.Logger} as a logging framework, and Apache Velocity uses a custom logging implementation
|
* DependencyCheck uses {@link org.slf4j.Logger} as a logging framework, and
|
||||||
* that outputs to a file named velocity.log by default. This class is an implementation of a custom Velocity logger that
|
* Apache Velocity uses a custom logging implementation that outputs to a file
|
||||||
* redirects all velocity logging to the Java Logger class.
|
* 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>
|
* </p><p>
|
||||||
* This class was written to address permission issues when using Dependency-Check in a server environment (such as the Jenkins
|
* This class was written to address permission issues when using
|
||||||
* plugin). In some circumstances, Velocity would attempt to create velocity.log in an un-writable directory.</p>
|
* 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
|
* @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 level the logging level
|
||||||
* @param message the message to be logged
|
* @param message the message to be logged
|
||||||
@@ -76,12 +80,13 @@ public class VelocityLoggerRedirect implements LogChute {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGGER.info(message);
|
LOGGER.info(message);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a Velocity log level, message and Throwable, this method will call the appropriate Logger level and log the specified
|
* Given a Velocity log level, message and Throwable, this method will call
|
||||||
* values.
|
* the appropriate Logger level and log the specified values.
|
||||||
*
|
*
|
||||||
* @param level the logging level
|
* @param level the logging level
|
||||||
* @param message the message to be logged
|
* @param message the message to be logged
|
||||||
@@ -107,6 +112,7 @@ public class VelocityLoggerRedirect implements LogChute {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGGER.info(message, t);
|
LOGGER.info(message, t);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ public final class DBUtils {
|
|||||||
*
|
*
|
||||||
* @param statement a prepared statement that just executed an insert
|
* @param statement a prepared statement that just executed an insert
|
||||||
* @return a primary key
|
* @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 {
|
public static int getGeneratedKey(PreparedStatement statement) throws DatabaseException {
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -72,27 +73,29 @@ public final class DBUtils {
|
|||||||
* @param statement a Statement object
|
* @param statement a Statement object
|
||||||
*/
|
*/
|
||||||
public static void closeStatement(Statement statement) {
|
public static void closeStatement(Statement statement) {
|
||||||
if (statement != null) {
|
try {
|
||||||
try {
|
if (statement != null && !statement.isClosed()) {
|
||||||
|
|
||||||
statement.close();
|
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
|
* @param rs a ResultSet to close
|
||||||
*/
|
*/
|
||||||
public static void closeResultSet(ResultSet rs) {
|
public static void closeResultSet(ResultSet rs) {
|
||||||
if (rs != null) {
|
try {
|
||||||
try {
|
if (rs != null && !rs.isClosed()) {
|
||||||
rs.close();
|
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
|
* @param version the version string to parse
|
||||||
*/
|
*/
|
||||||
public final void parseVersion(String version) {
|
public final void parseVersion(String version) {
|
||||||
versionParts = new ArrayList<String>();
|
versionParts = new ArrayList<>();
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
|
final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
|
||||||
final Matcher matcher = rx.matcher(version.toLowerCase());
|
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.
|
//'-' is a special case used within the CVE entries, just include it as the version.
|
||||||
if ("-".equals(text)) {
|
if ("-".equals(text)) {
|
||||||
final DependencyVersion dv = new DependencyVersion();
|
final DependencyVersion dv = new DependencyVersion();
|
||||||
final List<String> list = new ArrayList<String>();
|
final List<String> list = new ArrayList<>();
|
||||||
list.add(text);
|
list.add(text);
|
||||||
dv.setVersionParts(list);
|
dv.setVersionParts(list);
|
||||||
return dv;
|
return dv;
|
||||||
|
|||||||
@@ -85,18 +85,10 @@ public final class ExtractionUtil {
|
|||||||
return;
|
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;
|
ZipEntry entry;
|
||||||
try {
|
try (FileInputStream fis = new FileInputStream(archive);
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||||
|
ZipInputStream zis = new ZipInputStream(bis)) {
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
final File d = new File(extractTo, entry.getName());
|
final File d = new File(extractTo, entry.getName());
|
||||||
@@ -107,9 +99,7 @@ public final class ExtractionUtil {
|
|||||||
} else {
|
} else {
|
||||||
final File file = new File(extractTo, entry.getName());
|
final File file = new File(extractTo, entry.getName());
|
||||||
if (engine == null || engine.accept(file)) {
|
if (engine == null || engine.accept(file)) {
|
||||||
FileOutputStream fos = null;
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
try {
|
|
||||||
fos = new FileOutputStream(file);
|
|
||||||
IOUtils.copy(zis, fos);
|
IOUtils.copy(zis, fos);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
@@ -119,8 +109,6 @@ public final class ExtractionUtil {
|
|||||||
LOGGER.debug("", 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);
|
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());
|
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new ExtractionException(msg, 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
|
* @param filter determines which files get extracted
|
||||||
* @throws ExtractionException thrown if the archive is not found
|
* @throws ExtractionException thrown if the archive is not found
|
||||||
*/
|
*/
|
||||||
public static void extractFilesUsingFilter(File archive, File destination,
|
public static void extractFilesUsingFilter(File archive, File destination, FilenameFilter filter) throws ExtractionException {
|
||||||
FilenameFilter filter) throws ExtractionException {
|
|
||||||
if (archive == null || destination == null) {
|
if (archive == null || destination == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInputStream fis = null;
|
try (FileInputStream fis = new FileInputStream(archive)) {
|
||||||
try {
|
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(
|
||||||
fis = new FileInputStream(archive);
|
fis)), destination, filter);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new ExtractionException("Archive file was not found.", ex);
|
throw new ExtractionException("Archive file was not found.", ex);
|
||||||
}
|
} catch (IOException | ArchiveExtractionException ex) {
|
||||||
try {
|
|
||||||
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(
|
|
||||||
fis)), destination, filter);
|
|
||||||
} catch (ArchiveExtractionException ex) {
|
|
||||||
LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
|
LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
throw new ExtractionException("Unable to extract from archive", ex);
|
||||||
try {
|
|
||||||
fis.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.debug("", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,9 +173,7 @@ public final class ExtractionUtil {
|
|||||||
extractFile(input, destination, filter, entry);
|
extractFile(input, destination, filter, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException | AnalysisException ex) {
|
||||||
throw new ArchiveExtractionException(ex);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
throw new ArchiveExtractionException(ex);
|
throw new ArchiveExtractionException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
FileUtils.close(input);
|
FileUtils.close(input);
|
||||||
@@ -221,26 +195,19 @@ public final class ExtractionUtil {
|
|||||||
FilenameFilter filter, ArchiveEntry entry) throws ExtractionException {
|
FilenameFilter filter, ArchiveEntry entry) throws ExtractionException {
|
||||||
final File file = new File(destination, entry.getName());
|
final File file = new File(destination, entry.getName());
|
||||||
if (filter.accept(file.getParentFile(), file.getName())) {
|
if (filter.accept(file.getParentFile(), file.getName())) {
|
||||||
LOGGER.debug("Extracting '{}'",
|
LOGGER.debug("Extracting '{}'", file.getPath());
|
||||||
file.getPath());
|
createParentFile(file);
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
createParentFile(file);
|
|
||||||
fos = new FileOutputStream(file);
|
|
||||||
IOUtils.copy(input, fos);
|
IOUtils.copy(input, fos);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
final String msg = String.format("Unable to find file '%s'.",
|
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||||
file.getName());
|
|
||||||
throw new ExtractionException(msg, ex);
|
throw new ExtractionException(msg, ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
final String msg = String
|
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||||
.format("IO Exception while parsing file '%s'.",
|
|
||||||
file.getName());
|
|
||||||
throw new ExtractionException(msg, ex);
|
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
|
* @throws ExtractionException thrown if the parent paths could not be
|
||||||
* created
|
* created
|
||||||
*/
|
*/
|
||||||
private static void createParentFile(final File file)
|
private static void createParentFile(final File file) throws ExtractionException {
|
||||||
throws ExtractionException {
|
|
||||||
final File parent = file.getParentFile();
|
final File parent = file.getParentFile();
|
||||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||||
final String msg = String.format(
|
final String msg = String.format(
|
||||||
@@ -282,35 +248,11 @@ public final class ExtractionUtil {
|
|||||||
if (!file.renameTo(gzip)) {
|
if (!file.renameTo(gzip)) {
|
||||||
throw new IOException("Unable to rename '" + file.getPath() + "'");
|
throw new IOException("Unable to rename '" + file.getPath() + "'");
|
||||||
}
|
}
|
||||||
final File newfile = new File(originalPath);
|
final File newFile = new File(originalPath);
|
||||||
|
try (GZIPInputStream cin = new GZIPInputStream(new FileInputStream(gzip));
|
||||||
final byte[] buffer = new byte[4096];
|
FileOutputStream out = new FileOutputStream(newFile)) {
|
||||||
|
IOUtils.copy(cin, out);
|
||||||
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);
|
|
||||||
}
|
|
||||||
} finally {
|
} 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)) {
|
if (gzip.isFile() && !org.apache.commons.io.FileUtils.deleteQuietly(gzip)) {
|
||||||
LOGGER.debug("Failed to delete temporary file when extracting 'gz' {}", gzip.toString());
|
LOGGER.debug("Failed to delete temporary file when extracting 'gz' {}", gzip.toString());
|
||||||
gzip.deleteOnExit();
|
gzip.deleteOnExit();
|
||||||
|
|||||||
@@ -48,15 +48,15 @@ public class FileFilterBuilder {
|
|||||||
/**
|
/**
|
||||||
* A set of filenames to filter.
|
* 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.
|
* 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.
|
* 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.
|
* 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();
|
final OrFileFilter filter = new OrFileFilter();
|
||||||
if (!filenames.isEmpty()) {
|
if (!filenames.isEmpty()) {
|
||||||
filter.addFileFilter(new NameFileFilter(new ArrayList<String>(filenames)));
|
filter.addFileFilter(new NameFileFilter(new ArrayList<>(filenames)));
|
||||||
}
|
}
|
||||||
if (!extensions.isEmpty()) {
|
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) {
|
for (IOFileFilter iof : fileFilters) {
|
||||||
filter.addFileFilter(iof);
|
filter.addFileFilter(iof);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package org.owasp.dependencycheck.utils;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* This is an abstract filter that can be used to filter iterable list.
|
* This is an abstract filter that can be used to filter iterable list.
|
||||||
*
|
*
|
||||||
* This Filter class was copied from:
|
* This Filter class was copied from:
|
||||||
@@ -11,15 +11,35 @@ import java.util.NoSuchElementException;
|
|||||||
*
|
*
|
||||||
* Erik Rasmussen - © 2006 - 2012 All Rights Reserved. @author Erik Rasmussen
|
* Erik Rasmussen - © 2006 - 2012 All Rights Reserved. @author Erik Rasmussen
|
||||||
* https://plus.google.com/115403795880834599019/?rel=author
|
* https://plus.google.com/115403795880834599019/?rel=author
|
||||||
|
*
|
||||||
|
* @param <T> the type to filter
|
||||||
*/
|
*/
|
||||||
public abstract class Filter<T> {
|
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);
|
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) {
|
public Iterator<T> filter(Iterator<T> iterator) {
|
||||||
return new FilterIterator(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) {
|
public Iterable<T> filter(final Iterable<T> iterable) {
|
||||||
return new Iterable<T>() {
|
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
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class Pair<L, R> {
|
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.
|
* Constructs a new empty pair.
|
||||||
@@ -43,10 +51,6 @@ public class Pair<L, R> {
|
|||||||
this.left = left;
|
this.left = left;
|
||||||
this.right = right;
|
this.right = right;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The left element of the pair.
|
|
||||||
*/
|
|
||||||
private L left = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of left.
|
* Get the value of left.
|
||||||
@@ -65,10 +69,6 @@ public class Pair<L, R> {
|
|||||||
public void setLeft(L left) {
|
public void setLeft(L left) {
|
||||||
this.left = left;
|
this.left = left;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The right element of the pair.
|
|
||||||
*/
|
|
||||||
private R right = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of right.
|
* 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))) {
|
if (this.left != other.left && (this.left == null || !this.left.equals(other.left))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.right != other.right && (this.right == null || !this.right.equals(other.right))) {
|
return !(this.right != other.right && (this.right == null || !this.right.equals(other.right)));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ public final class UrlStringUtils {
|
|||||||
private static final Pattern IS_URL_TEST = Pattern.compile("^(ht|f)tps?://.*", Pattern.CASE_INSENSITIVE);
|
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
|
* Tests if the text provided contains a URL. This is somewhat limited
|
||||||
* (ftp|http|https)://
|
* search in that it only looks for (ftp|http|https)://
|
||||||
*
|
*
|
||||||
* @param text the text to search
|
* @param text the text to search
|
||||||
* @return true if the text contains a url, otherwise false
|
* @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();
|
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"));
|
Arrays.asList("www", "com", "org", "gov", "info", "name", "net", "pro", "tel", "mobi", "xxx"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <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>
|
* <p>
|
||||||
* Example, given the following input:</p>
|
* Example, given the following input:</p>
|
||||||
* <code>"https://www.somedomain.com/path1/path2/file.php?id=439"</code>
|
* <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
|
* @throws MalformedURLException thrown if the URL is malformed
|
||||||
*/
|
*/
|
||||||
public static List<String> extractImportantUrlData(String text) throws MalformedURLException {
|
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 URL url = new URL(text);
|
||||||
final String[] domain = url.getHost().split("\\.");
|
final String[] domain = url.getHost().split("\\.");
|
||||||
//add the domain except www and the tld.
|
//add the domain except www and the tld.
|
||||||
@@ -99,14 +101,21 @@ public final class UrlStringUtils {
|
|||||||
}
|
}
|
||||||
final String document = url.getPath();
|
final String document = url.getPath();
|
||||||
final String[] pathParts = document.split("[\\//]");
|
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()) {
|
if (!pathParts[i].isEmpty()) {
|
||||||
importantParts.add(pathParts[i]);
|
importantParts.add(pathParts[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pathParts.length > 0 && !pathParts[pathParts.length - 1].isEmpty()) {
|
if (pathParts.length > 0 && !pathParts[pathParts.length - 1].isEmpty()) {
|
||||||
final String fileNameNoExt = pathParts[pathParts.length - 1].replaceAll("\\..*{0,5}$", "");
|
final String tmp = pathParts[pathParts.length - 1];
|
||||||
importantParts.add(fileNameNoExt);
|
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;
|
return importantParts;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ public class HintHandler extends DefaultHandler {
|
|||||||
* Element name.
|
* Element name.
|
||||||
*/
|
*/
|
||||||
private static final String ADD = "add";
|
private static final String ADD = "add";
|
||||||
|
/**
|
||||||
|
* Element name.
|
||||||
|
*/
|
||||||
|
private static final String REMOVE = "remove";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Element name.
|
* Element name.
|
||||||
*/
|
*/
|
||||||
@@ -110,7 +115,7 @@ public class HintHandler extends DefaultHandler {
|
|||||||
/**
|
/**
|
||||||
* The list of hint rules.
|
* The list of hint rules.
|
||||||
*/
|
*/
|
||||||
private final List<HintRule> hintRules = new ArrayList<HintRule>();
|
private final List<HintRule> hintRules = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of hint rules.
|
* Returns the list of hint rules.
|
||||||
@@ -124,7 +129,7 @@ public class HintHandler extends DefaultHandler {
|
|||||||
/**
|
/**
|
||||||
* The list of vendor duplicating hint rules.
|
* The list of vendor duplicating hint rules.
|
||||||
*/
|
*/
|
||||||
private final List<VendorDuplicatingHintRule> vendorDuplicatingHintRules = new ArrayList<VendorDuplicatingHintRule>();
|
private final List<VendorDuplicatingHintRule> vendorDuplicatingHintRules = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of vendor duplicating hint rules.
|
* Returns the list of vendor duplicating hint rules.
|
||||||
@@ -139,16 +144,34 @@ public class HintHandler extends DefaultHandler {
|
|||||||
* The current rule being read.
|
* The current rule being read.
|
||||||
*/
|
*/
|
||||||
private HintRule rule;
|
private HintRule rule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal type to track the parent node state.
|
||||||
|
*/
|
||||||
|
enum ParentType {
|
||||||
|
/**
|
||||||
|
* Marks the add node.
|
||||||
|
*/
|
||||||
|
ADD,
|
||||||
|
/**
|
||||||
|
* Marks the given node.
|
||||||
|
*/
|
||||||
|
GIVEN,
|
||||||
|
/**
|
||||||
|
* Marks the remove node.
|
||||||
|
*/
|
||||||
|
REMOVE
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* The current state of the parent node (to differentiate between 'add' and
|
* The current state of the parent node (to differentiate between 'add' and
|
||||||
* 'given').
|
* 'given').
|
||||||
*/
|
*/
|
||||||
private boolean inAddNode = false;
|
private ParentType nodeType = ParentType.GIVEN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the start element event.
|
* Handles the start element event.
|
||||||
*
|
*
|
||||||
* @param uri the uri of the element being processed
|
* @param uri the URI of the element being processed
|
||||||
* @param localName the local name of the element being processed
|
* @param localName the local name of the element being processed
|
||||||
* @param qName the qName of the element being processed
|
* @param qName the qName of the element being processed
|
||||||
* @param attr the attributes of the element being processed
|
* @param attr the attributes of the element being processed
|
||||||
@@ -156,62 +179,99 @@ public class HintHandler extends DefaultHandler {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attr) throws SAXException {
|
public void startElement(String uri, String localName, String qName, Attributes attr) throws SAXException {
|
||||||
if (HINT.equals(qName)) {
|
if (null != qName) {
|
||||||
rule = new HintRule();
|
switch (qName) {
|
||||||
} else if (ADD.equals(qName)) {
|
case HINT:
|
||||||
inAddNode = true;
|
rule = new HintRule();
|
||||||
} else if (GIVEN.equals(qName)) {
|
break;
|
||||||
inAddNode = false;
|
case ADD:
|
||||||
} else if (EVIDENCE.equals(qName)) {
|
nodeType = ParentType.ADD;
|
||||||
final String hintType = attr.getValue(TYPE);
|
break;
|
||||||
if (VENDOR.equals(hintType)) {
|
case GIVEN:
|
||||||
if (inAddNode) {
|
nodeType = ParentType.GIVEN;
|
||||||
rule.addAddVendor(attr.getValue(SOURCE),
|
break;
|
||||||
attr.getValue(NAME),
|
case REMOVE:
|
||||||
attr.getValue(VALUE),
|
nodeType = ParentType.REMOVE;
|
||||||
Confidence.valueOf(attr.getValue(CONFIDENCE)));
|
break;
|
||||||
} else {
|
case EVIDENCE:
|
||||||
rule.addGivenVendor(attr.getValue(SOURCE),
|
final String hintType = attr.getValue(TYPE);
|
||||||
attr.getValue(NAME),
|
if (null != hintType && null != nodeType) {
|
||||||
attr.getValue(VALUE),
|
final String source = attr.getValue(SOURCE);
|
||||||
Confidence.valueOf(attr.getValue(CONFIDENCE)));
|
final String name = attr.getValue(NAME);
|
||||||
}
|
final String value = attr.getValue(VALUE);
|
||||||
} else if (PRODUCT.equals(hintType)) {
|
final Confidence confidence = Confidence.valueOf(attr.getValue(CONFIDENCE));
|
||||||
if (inAddNode) {
|
switch (hintType) {
|
||||||
rule.addAddProduct(attr.getValue(SOURCE),
|
case VENDOR:
|
||||||
attr.getValue(NAME),
|
switch (nodeType) {
|
||||||
attr.getValue(VALUE),
|
case ADD:
|
||||||
Confidence.valueOf(attr.getValue(CONFIDENCE)));
|
rule.addAddVendor(source, name, value, confidence);
|
||||||
} else {
|
break;
|
||||||
rule.addGivenProduct(attr.getValue(SOURCE),
|
case REMOVE:
|
||||||
attr.getValue(NAME),
|
rule.addRemoveVendor(source, name, value, confidence);
|
||||||
attr.getValue(VALUE),
|
break;
|
||||||
Confidence.valueOf(attr.getValue(CONFIDENCE)));
|
case GIVEN:
|
||||||
}
|
rule.addGivenVendor(source, name, value, confidence);
|
||||||
} else if (VERSION.equals(hintType)) {
|
break;
|
||||||
if (inAddNode) {
|
default:
|
||||||
rule.addAddVersion(attr.getValue(SOURCE),
|
break;
|
||||||
attr.getValue(NAME),
|
}
|
||||||
attr.getValue(VALUE),
|
break;
|
||||||
Confidence.valueOf(attr.getValue(CONFIDENCE)));
|
case PRODUCT:
|
||||||
}
|
switch (nodeType) {
|
||||||
|
case ADD:
|
||||||
|
rule.addAddProduct(source, name, value, confidence);
|
||||||
|
break;
|
||||||
|
case REMOVE:
|
||||||
|
rule.addRemoveProduct(source, name, value, confidence);
|
||||||
|
break;
|
||||||
|
case GIVEN:
|
||||||
|
rule.addGivenProduct(source, name, value, confidence);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VERSION:
|
||||||
|
switch (nodeType) {
|
||||||
|
case ADD:
|
||||||
|
rule.addAddVersion(source, name, value, confidence);
|
||||||
|
break;
|
||||||
|
case REMOVE:
|
||||||
|
rule.addRemoveVersion(source, name, value, confidence);
|
||||||
|
break;
|
||||||
|
case GIVEN:
|
||||||
|
rule.addGivenVersion(source, name, value, confidence);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FILE_NAME:
|
||||||
|
final PropertyType pt = new PropertyType();
|
||||||
|
pt.setValue(attr.getValue(CONTAINS));
|
||||||
|
if (attr.getLength() > 0) {
|
||||||
|
final String regex = attr.getValue(REGEX);
|
||||||
|
if (regex != null) {
|
||||||
|
pt.setRegex(Boolean.parseBoolean(regex));
|
||||||
|
}
|
||||||
|
final String caseSensitive = attr.getValue(CASE_SENSITIVE);
|
||||||
|
if (caseSensitive != null) {
|
||||||
|
pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rule.addFilename(pt);
|
||||||
|
break;
|
||||||
|
case VENDOR_DUPLICATING_RULE:
|
||||||
|
vendorDuplicatingHintRules.add(new VendorDuplicatingHintRule(attr.getValue(VALUE), attr.getValue(DUPLICATE)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (FILE_NAME.equals(qName)) {
|
|
||||||
final PropertyType pt = new PropertyType();
|
|
||||||
pt.setValue(attr.getValue(CONTAINS));
|
|
||||||
if (attr.getLength() > 0) {
|
|
||||||
final String regex = attr.getValue(REGEX);
|
|
||||||
if (regex != null) {
|
|
||||||
pt.setRegex(Boolean.parseBoolean(regex));
|
|
||||||
}
|
|
||||||
final String caseSensitive = attr.getValue(CASE_SENSITIVE);
|
|
||||||
if (caseSensitive != null) {
|
|
||||||
pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rule.addFilename(pt);
|
|
||||||
} else if (VENDOR_DUPLICATING_RULE.equals(qName)) {
|
|
||||||
vendorDuplicatingHintRules.add(new VendorDuplicatingHintRule(attr.getValue(VALUE), attr.getValue(DUPLICATE)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,12 @@ public class HintParser {
|
|||||||
/**
|
/**
|
||||||
* The schema for the hint XML files.
|
* The schema for the hint XML files.
|
||||||
*/
|
*/
|
||||||
private static final String HINT_SCHEMA = "schema/dependency-hint.1.1.xsd";
|
private static final String HINT_SCHEMA = "schema/dependency-hint.1.2.xsd";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The schema for the hint XML files.
|
||||||
|
*/
|
||||||
|
private static final String HINT_SCHEMA_OLD = "schema/dependency-hint.1.1.xsd";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the given XML file and returns a list of the hints contained.
|
* Parses the given XML file and returns a list of the hints contained.
|
||||||
@@ -74,22 +79,19 @@ public class HintParser {
|
|||||||
* @throws HintParseException thrown if the XML file cannot be parsed
|
* @throws HintParseException thrown if the XML file cannot be parsed
|
||||||
*/
|
*/
|
||||||
public Hints parseHints(File file) throws HintParseException {
|
public Hints parseHints(File file) throws HintParseException {
|
||||||
FileInputStream fis = null;
|
//TODO there must be a better way to determine which schema to use for validation.
|
||||||
try {
|
try {
|
||||||
fis = new FileInputStream(file);
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
return parseHints(fis);
|
return parseHints(fis);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new HintParseException(ex);
|
throw new HintParseException(ex);
|
||||||
|
}
|
||||||
} catch (SAXException ex) {
|
} catch (SAXException ex) {
|
||||||
throw new HintParseException(ex);
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
} finally {
|
return parseHints(fis, HINT_SCHEMA_OLD);
|
||||||
if (fis != null) {
|
} catch (SAXException | IOException ex1) {
|
||||||
try {
|
throw new HintParseException(ex);
|
||||||
fis.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.debug("Unable to close stream", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,24 +106,35 @@ public class HintParser {
|
|||||||
* @throws SAXException thrown if the XML cannot be parsed
|
* @throws SAXException thrown if the XML cannot be parsed
|
||||||
*/
|
*/
|
||||||
public Hints parseHints(InputStream inputStream) throws HintParseException, SAXException {
|
public Hints parseHints(InputStream inputStream) throws HintParseException, SAXException {
|
||||||
InputStream schemaStream = null;
|
return parseHints(inputStream, HINT_SCHEMA);
|
||||||
try {
|
}
|
||||||
schemaStream = this.getClass().getClassLoader().getResourceAsStream(HINT_SCHEMA);
|
|
||||||
|
/**
|
||||||
|
* Parses the given XML stream and returns a list of the hint rules
|
||||||
|
* contained.
|
||||||
|
*
|
||||||
|
* @param inputStream an InputStream containing hint rules
|
||||||
|
* @param schema the XSD to use to validate the XML against
|
||||||
|
* @return a list of hint rules
|
||||||
|
* @throws HintParseException thrown if the XML cannot be parsed
|
||||||
|
* @throws SAXException thrown if the XML cannot be parsed
|
||||||
|
*/
|
||||||
|
private Hints parseHints(InputStream inputStream, String schema) throws HintParseException, SAXException {
|
||||||
|
try (InputStream schemaStream = this.getClass().getClassLoader().getResourceAsStream(schema)) {
|
||||||
final HintHandler handler = new HintHandler();
|
final HintHandler handler = new HintHandler();
|
||||||
final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream);
|
final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream);
|
||||||
final XMLReader xmlReader = saxParser.getXMLReader();
|
final XMLReader xmlReader = saxParser.getXMLReader();
|
||||||
xmlReader.setErrorHandler(new HintErrorHandler());
|
xmlReader.setErrorHandler(new HintErrorHandler());
|
||||||
xmlReader.setContentHandler(handler);
|
xmlReader.setContentHandler(handler);
|
||||||
|
try (Reader reader = new InputStreamReader(inputStream, "UTF-8")) {
|
||||||
final Reader reader = new InputStreamReader(inputStream, "UTF-8");
|
final InputSource in = new InputSource(reader);
|
||||||
final InputSource in = new InputSource(reader);
|
xmlReader.parse(in);
|
||||||
|
final Hints hints = new Hints();
|
||||||
xmlReader.parse(in);
|
hints.setHintRules(handler.getHintRules());
|
||||||
final Hints hints = new Hints();
|
hints.setVendorDuplicatingHintRules(handler.getVendorDuplicatingHintRules());
|
||||||
hints.setHintRules(handler.getHintRules());
|
return hints;
|
||||||
hints.setVendorDuplicatingHintRules(handler.getVendorDuplicatingHintRules());
|
}
|
||||||
return hints;
|
} catch (ParserConfigurationException | FileNotFoundException ex) {
|
||||||
} catch (ParserConfigurationException ex) {
|
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new HintParseException(ex);
|
throw new HintParseException(ex);
|
||||||
} catch (SAXException ex) {
|
} catch (SAXException ex) {
|
||||||
@@ -131,20 +144,9 @@ public class HintParser {
|
|||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new HintParseException(ex);
|
throw new HintParseException(ex);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
LOGGER.debug("", ex);
|
|
||||||
throw new HintParseException(ex);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new HintParseException(ex);
|
throw new HintParseException(ex);
|
||||||
} finally {
|
|
||||||
if (schemaStream != null) {
|
|
||||||
try {
|
|
||||||
schemaStream.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.debug("Error closing hint file stream", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,44 @@ public class HintRule {
|
|||||||
/**
|
/**
|
||||||
* The list of file names to match.
|
* The list of file names to match.
|
||||||
*/
|
*/
|
||||||
private final List<PropertyType> filenames = new ArrayList<PropertyType>();
|
private final List<PropertyType> filenames = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of vendor evidence that is being matched.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> givenVendor = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of product evidence that is being matched.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> givenProduct = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of product evidence that is being matched.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> givenVersion = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of vendor hints to add.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> addVendor = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of product evidence to add.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> addProduct = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of version evidence to add.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> addVersion = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of vendor hints to add.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> removeVendor = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of product evidence to add.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> removeProduct = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The list of version evidence to add.
|
||||||
|
*/
|
||||||
|
private final List<Evidence> removeVersion = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the filename evidence to the collection.
|
* Adds the filename evidence to the collection.
|
||||||
@@ -54,10 +91,6 @@ public class HintRule {
|
|||||||
public List<PropertyType> getFilenames() {
|
public List<PropertyType> getFilenames() {
|
||||||
return filenames;
|
return filenames;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The list of product evidence that is being matched.
|
|
||||||
*/
|
|
||||||
private final List<Evidence> givenProduct = new ArrayList<Evidence>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a given product to the list of evidence to matched.
|
* Adds a given product to the list of evidence to matched.
|
||||||
@@ -80,20 +113,6 @@ public class HintRule {
|
|||||||
return givenProduct;
|
return givenProduct;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of vendor evidence that is being matched.
|
|
||||||
*/
|
|
||||||
private final List<Evidence> givenVendor = new ArrayList<Evidence>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of product evidence to add.
|
|
||||||
*/
|
|
||||||
private final List<Evidence> addProduct = new ArrayList<Evidence>();
|
|
||||||
/**
|
|
||||||
* The list of version evidence to add.
|
|
||||||
*/
|
|
||||||
private final List<Evidence> addVersion = new ArrayList<Evidence>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a given vendors to the list of evidence to matched.
|
* Adds a given vendors to the list of evidence to matched.
|
||||||
*
|
*
|
||||||
@@ -157,11 +176,6 @@ public class HintRule {
|
|||||||
return addVersion;
|
return addVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of vendor hints to add.
|
|
||||||
*/
|
|
||||||
private final List<Evidence> addVendor = new ArrayList<Evidence>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a given vendor to the list of evidence to add when matched.
|
* Adds a given vendor to the list of evidence to add when matched.
|
||||||
*
|
*
|
||||||
@@ -182,4 +196,81 @@ public class HintRule {
|
|||||||
public List<Evidence> getAddVendor() {
|
public List<Evidence> getAddVendor() {
|
||||||
return addVendor;
|
return addVendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a given vendor to the list of evidence to remove when matched.
|
||||||
|
*
|
||||||
|
* @param source the source of the evidence
|
||||||
|
* @param name the name of the evidence
|
||||||
|
* @param value the value of the evidence
|
||||||
|
* @param confidence the confidence of the evidence
|
||||||
|
*/
|
||||||
|
public void addRemoveVendor(String source, String name, String value, Confidence confidence) {
|
||||||
|
removeVendor.add(new Evidence(source, name, value, confidence));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the value of removeVendor.
|
||||||
|
*
|
||||||
|
* @return the value of removeVendor
|
||||||
|
*/
|
||||||
|
public List<Evidence> getRemoveVendor() {
|
||||||
|
return removeVendor;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds a given product to the list of evidence to remove when matched.
|
||||||
|
*
|
||||||
|
* @param source the source of the evidence
|
||||||
|
* @param name the name of the evidence
|
||||||
|
* @param value the value of the evidence
|
||||||
|
* @param confidence the confidence of the evidence
|
||||||
|
*/
|
||||||
|
public void addRemoveProduct(String source, String name, String value, Confidence confidence) {
|
||||||
|
removeProduct.add(new Evidence(source, name, value, confidence));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the value of removeProduct.
|
||||||
|
*
|
||||||
|
* @return the value of removeProduct
|
||||||
|
*/
|
||||||
|
public List<Evidence> getRemoveProduct() {
|
||||||
|
return removeProduct;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds a given version to the list of evidence to remove when matched.
|
||||||
|
*
|
||||||
|
* @param source the source of the evidence
|
||||||
|
* @param name the name of the evidence
|
||||||
|
* @param value the value of the evidence
|
||||||
|
* @param confidence the confidence of the evidence
|
||||||
|
*/
|
||||||
|
public void addRemoveVersion(String source, String name, String value, Confidence confidence) {
|
||||||
|
removeVersion.add(new Evidence(source, name, value, confidence));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the value of removeVersion.
|
||||||
|
*
|
||||||
|
* @return the value of removeVersion
|
||||||
|
*/
|
||||||
|
public List<Evidence> getRemoveVersion() {
|
||||||
|
return removeVersion;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds a given version to the list of evidence to match.
|
||||||
|
*
|
||||||
|
* @param source the source of the evidence
|
||||||
|
* @param name the name of the evidence
|
||||||
|
* @param value the value of the evidence
|
||||||
|
* @param confidence the confidence of the evidence
|
||||||
|
*/
|
||||||
|
public void addGivenVersion(String source, String name, String value, Confidence confidence) {
|
||||||
|
givenVersion.add(new Evidence(source, name, value, confidence));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the value of givenVersion.
|
||||||
|
*
|
||||||
|
* @return the value of givenVersion
|
||||||
|
*/
|
||||||
|
public List<Evidence> getGivenVersion() {
|
||||||
|
return givenVersion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,24 @@
|
|||||||
package org.owasp.dependencycheck.xml.hints;
|
package org.owasp.dependencycheck.xml.hints;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to duplicate vendor evidence within a collection. The intent is if any evidence
|
* Used to duplicate vendor evidence within a collection. The intent is if any
|
||||||
* is found in a collection that matches the value given the evidence will be
|
* evidence is found in a collection that matches the value given the evidence
|
||||||
* duplicated and the value replaced with the value indicated.
|
* will be duplicated and the value replaced with the value indicated.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class VendorDuplicatingHintRule {
|
public class VendorDuplicatingHintRule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The evidence value to duplicate if found.
|
||||||
|
*/
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value to replace when duplicating the evidence.
|
||||||
|
*/
|
||||||
|
private String duplicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new duplicating rule.
|
* Constructs a new duplicating rule.
|
||||||
*
|
*
|
||||||
@@ -37,11 +47,6 @@ public class VendorDuplicatingHintRule {
|
|||||||
this.duplicate = duplicate;
|
this.duplicate = duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The evidence value to duplicate if found.
|
|
||||||
*/
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of value.
|
* Get the value of value.
|
||||||
*
|
*
|
||||||
@@ -60,11 +65,6 @@ public class VendorDuplicatingHintRule {
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The value to replace when duplicating the evidence.
|
|
||||||
*/
|
|
||||||
private String duplicate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of duplicate.
|
* Get the value of duplicate.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -23,6 +23,15 @@ package org.owasp.dependencycheck.xml.pom;
|
|||||||
*/
|
*/
|
||||||
public class License {
|
public class License {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The url to the license.
|
||||||
|
*/
|
||||||
|
private String url;
|
||||||
|
/**
|
||||||
|
* The name of the license.
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new license object.
|
* Constructs a new license object.
|
||||||
*/
|
*/
|
||||||
@@ -41,11 +50,6 @@ public class License {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The url to the license.
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of url.
|
* Get the value of url.
|
||||||
*
|
*
|
||||||
@@ -64,11 +68,6 @@ public class License {
|
|||||||
this.url = url;
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the license.
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of name.
|
* Get the value of name.
|
||||||
*
|
*
|
||||||
@@ -118,10 +117,7 @@ public class License {
|
|||||||
if ((this.url == null) ? (other.url != null) : !this.url.equals(other.url)) {
|
if ((this.url == null) ? (other.url != null) : !this.url.equals(other.url)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
|
return !((this.name == null) ? (other.name != null) : !this.name.equals(other.name));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,6 +35,50 @@ public class Model {
|
|||||||
* The name of the project.
|
* The name of the project.
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
/**
|
||||||
|
* The organization name.
|
||||||
|
*/
|
||||||
|
private String organization;
|
||||||
|
/**
|
||||||
|
* The organization URL.
|
||||||
|
*/
|
||||||
|
private String organizationUrl;
|
||||||
|
/**
|
||||||
|
* The description.
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
/**
|
||||||
|
* The group id.
|
||||||
|
*/
|
||||||
|
private String groupId;
|
||||||
|
/**
|
||||||
|
* The artifact id.
|
||||||
|
*/
|
||||||
|
private String artifactId;
|
||||||
|
/**
|
||||||
|
* The version number.
|
||||||
|
*/
|
||||||
|
private String version;
|
||||||
|
/**
|
||||||
|
* The parent group id.
|
||||||
|
*/
|
||||||
|
private String parentGroupId;
|
||||||
|
/**
|
||||||
|
* The parent artifact id.
|
||||||
|
*/
|
||||||
|
private String parentArtifactId;
|
||||||
|
/**
|
||||||
|
* The parent version number.
|
||||||
|
*/
|
||||||
|
private String parentVersion;
|
||||||
|
/**
|
||||||
|
* The list of licenses.
|
||||||
|
*/
|
||||||
|
private final List<License> licenses = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The project URL.
|
||||||
|
*/
|
||||||
|
private String projectURL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of name.
|
* Get the value of name.
|
||||||
@@ -54,11 +98,6 @@ public class Model {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The organization name.
|
|
||||||
*/
|
|
||||||
private String organization;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of organization.
|
* Get the value of organization.
|
||||||
*
|
*
|
||||||
@@ -78,9 +117,22 @@ public class Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The description.
|
* Get the value of organizationUrl.
|
||||||
|
*
|
||||||
|
* @return the value of organizationUrl
|
||||||
*/
|
*/
|
||||||
private String description;
|
public String getOrganizationUrl() {
|
||||||
|
return organizationUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of organizationUrl.
|
||||||
|
*
|
||||||
|
* @param organizationUrl new value of organizationUrl
|
||||||
|
*/
|
||||||
|
public void setOrganizationUrl(String organizationUrl) {
|
||||||
|
this.organizationUrl = organizationUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of description.
|
* Get the value of description.
|
||||||
@@ -100,11 +152,6 @@ public class Model {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The group id.
|
|
||||||
*/
|
|
||||||
private String groupId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of groupId.
|
* Get the value of groupId.
|
||||||
*
|
*
|
||||||
@@ -123,11 +170,6 @@ public class Model {
|
|||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The artifact id.
|
|
||||||
*/
|
|
||||||
private String artifactId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of artifactId.
|
* Get the value of artifactId.
|
||||||
*
|
*
|
||||||
@@ -146,11 +188,6 @@ public class Model {
|
|||||||
this.artifactId = artifactId;
|
this.artifactId = artifactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The version number.
|
|
||||||
*/
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of version.
|
* Get the value of version.
|
||||||
*
|
*
|
||||||
@@ -169,11 +206,6 @@ public class Model {
|
|||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The parent group id.
|
|
||||||
*/
|
|
||||||
private String parentGroupId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of parentGroupId.
|
* Get the value of parentGroupId.
|
||||||
*
|
*
|
||||||
@@ -192,11 +224,6 @@ public class Model {
|
|||||||
this.parentGroupId = parentGroupId;
|
this.parentGroupId = parentGroupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The parent artifact id.
|
|
||||||
*/
|
|
||||||
private String parentArtifactId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of parentArtifactId.
|
* Get the value of parentArtifactId.
|
||||||
*
|
*
|
||||||
@@ -215,11 +242,6 @@ public class Model {
|
|||||||
this.parentArtifactId = parentArtifactId;
|
this.parentArtifactId = parentArtifactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The parent version number.
|
|
||||||
*/
|
|
||||||
private String parentVersion;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of parentVersion.
|
* Get the value of parentVersion.
|
||||||
*
|
*
|
||||||
@@ -238,11 +260,6 @@ public class Model {
|
|||||||
this.parentVersion = parentVersion;
|
this.parentVersion = parentVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of licenses.
|
|
||||||
*/
|
|
||||||
private final List<License> licenses = new ArrayList<License>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of licenses.
|
* Returns the list of licenses.
|
||||||
*
|
*
|
||||||
@@ -261,11 +278,6 @@ public class Model {
|
|||||||
licenses.add(license);
|
licenses.add(license);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The project URL.
|
|
||||||
*/
|
|
||||||
private String projectURL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of projectURL.
|
* Get the value of projectURL.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public class PomHandler extends DefaultHandler {
|
|||||||
/**
|
/**
|
||||||
* The stack of elements processed; used to determine the parent node.
|
* The stack of elements processed; used to determine the parent node.
|
||||||
*/
|
*/
|
||||||
private final Deque<String> stack = new ArrayDeque<String>();
|
private final Deque<String> stack = new ArrayDeque<>();
|
||||||
/**
|
/**
|
||||||
* The license object.
|
* The license object.
|
||||||
*/
|
*/
|
||||||
@@ -132,47 +132,76 @@ public class PomHandler extends DefaultHandler {
|
|||||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
final String parentNode = stack.peek();
|
final String parentNode = stack.peek();
|
||||||
if (PROJECT.equals(parentNode)) {
|
if (null != parentNode) {
|
||||||
if (GROUPID.equals(qName)) {
|
switch (parentNode) {
|
||||||
model.setGroupId(currentText.toString());
|
case PROJECT:
|
||||||
} else if (ARTIFACTID.equals(qName)) {
|
if (null != qName) {
|
||||||
model.setArtifactId(currentText.toString());
|
switch (qName) {
|
||||||
} else if (VERSION.equals(qName)) {
|
case GROUPID:
|
||||||
model.setVersion(currentText.toString());
|
model.setGroupId(currentText.toString());
|
||||||
} else if (NAME.equals(qName)) {
|
break;
|
||||||
model.setName(currentText.toString());
|
case ARTIFACTID:
|
||||||
} else if (ORGANIZATION.equals(qName)) {
|
model.setArtifactId(currentText.toString());
|
||||||
model.setOrganization(currentText.toString());
|
break;
|
||||||
} else if (DESCRIPTION.equals(qName)) {
|
case VERSION:
|
||||||
model.setDescription(currentText.toString());
|
model.setVersion(currentText.toString());
|
||||||
} else if (URL.equals(qName)) {
|
break;
|
||||||
model.setProjectURL(currentText.toString());
|
case NAME:
|
||||||
}
|
model.setName(currentText.toString());
|
||||||
} else if (PARENT.equals(parentNode)) {
|
break;
|
||||||
if (GROUPID.equals(qName)) {
|
case DESCRIPTION:
|
||||||
model.setParentGroupId(currentText.toString());
|
model.setDescription(currentText.toString());
|
||||||
} else if (ARTIFACTID.equals(qName)) {
|
break;
|
||||||
model.setParentArtifactId(currentText.toString());
|
case URL:
|
||||||
} else if (VERSION.equals(qName)) {
|
model.setProjectURL(currentText.toString());
|
||||||
model.setParentVersion(currentText.toString());
|
break;
|
||||||
}
|
default:
|
||||||
} else if (LICENSE.equals(parentNode)) {
|
break;
|
||||||
if (license != null) {
|
}
|
||||||
if (NAME.equals(qName)) {
|
}
|
||||||
license.setName(currentText.toString());
|
break;
|
||||||
} else if (URL.equals(qName)) {
|
case ORGANIZATION:
|
||||||
license.setUrl(currentText.toString());
|
if (NAME.equals(qName)) {
|
||||||
}
|
model.setOrganization(currentText.toString());
|
||||||
//} else {
|
} else if (URL.equals(qName)) {
|
||||||
//TODO add error logging
|
model.setOrganizationUrl(currentText.toString());
|
||||||
}
|
}
|
||||||
} else if (LICENSES.equals(parentNode)) {
|
break;
|
||||||
if (LICENSE.equals(qName)) {
|
case PARENT:
|
||||||
if (license != null) {
|
if (null != qName) {
|
||||||
model.addLicense(license);
|
switch (qName) {
|
||||||
//} else {
|
case GROUPID:
|
||||||
//TODO add error logging
|
model.setParentGroupId(currentText.toString());
|
||||||
}
|
break;
|
||||||
|
case ARTIFACTID:
|
||||||
|
model.setParentArtifactId(currentText.toString());
|
||||||
|
break;
|
||||||
|
case VERSION:
|
||||||
|
model.setParentVersion(currentText.toString());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LICENSE:
|
||||||
|
if (license != null) {
|
||||||
|
if (NAME.equals(qName)) {
|
||||||
|
license.setName(currentText.toString());
|
||||||
|
} else if (URL.equals(qName)) {
|
||||||
|
license.setUrl(currentText.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LICENSES:
|
||||||
|
if (LICENSE.equals(qName)) {
|
||||||
|
if (license != null) {
|
||||||
|
model.addLicense(license);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.parsers.SAXParser;
|
import javax.xml.parsers.SAXParser;
|
||||||
|
import org.apache.commons.io.ByteOrderMark;
|
||||||
|
import org.apache.commons.io.input.BOMInputStream;
|
||||||
import org.owasp.dependencycheck.utils.XmlUtils;
|
import org.owasp.dependencycheck.utils.XmlUtils;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -56,21 +58,11 @@ public class PomParser {
|
|||||||
* @throws PomParseException thrown if the xml file cannot be parsed
|
* @throws PomParseException thrown if the xml file cannot be parsed
|
||||||
*/
|
*/
|
||||||
public Model parse(File file) throws PomParseException {
|
public Model parse(File file) throws PomParseException {
|
||||||
FileInputStream fis = null;
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
try {
|
|
||||||
fis = new FileInputStream(file);
|
|
||||||
return parse(fis);
|
return parse(fis);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new PomParseException(ex);
|
throw new PomParseException(ex);
|
||||||
} finally {
|
|
||||||
if (fis != null) {
|
|
||||||
try {
|
|
||||||
fis.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.debug("Unable to close stream", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,17 +80,15 @@ public class PomParser {
|
|||||||
final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
|
final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
|
||||||
final XMLReader xmlReader = saxParser.getXMLReader();
|
final XMLReader xmlReader = saxParser.getXMLReader();
|
||||||
xmlReader.setContentHandler(handler);
|
xmlReader.setContentHandler(handler);
|
||||||
final Reader reader = new InputStreamReader(inputStream, "UTF-8");
|
final BOMInputStream bomStream = new BOMInputStream(inputStream);
|
||||||
|
final ByteOrderMark bom = bomStream.getBOM();
|
||||||
|
final String defaultEncoding = "UTF-8";
|
||||||
|
final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName();
|
||||||
|
final Reader reader = new InputStreamReader(bomStream, charsetName);
|
||||||
final InputSource in = new InputSource(reader);
|
final InputSource in = new InputSource(reader);
|
||||||
xmlReader.parse(in);
|
xmlReader.parse(in);
|
||||||
return handler.getModel();
|
return handler.getModel();
|
||||||
} catch (ParserConfigurationException ex) {
|
} catch (ParserConfigurationException | SAXException | FileNotFoundException ex) {
|
||||||
LOGGER.debug("", ex);
|
|
||||||
throw new PomParseException(ex);
|
|
||||||
} catch (SAXException ex) {
|
|
||||||
LOGGER.debug("", ex);
|
|
||||||
throw new PomParseException(ex);
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new PomParseException(ex);
|
throw new PomParseException(ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public final class PomUtils {
|
|||||||
* Reads in the specified POM and converts it to a Model.
|
* Reads in the specified POM and converts it to a Model.
|
||||||
*
|
*
|
||||||
* @param file the pom.xml file
|
* @param file the pom.xml file
|
||||||
* @return returns a
|
* @return returns an object representation of the POM
|
||||||
* @throws AnalysisException is thrown if there is an exception extracting
|
* @throws AnalysisException is thrown if there is an exception extracting
|
||||||
* or parsing the POM {@link Model} object
|
* or parsing the POM {@link Model} object
|
||||||
*/
|
*/
|
||||||
@@ -59,14 +59,12 @@ public final class PomUtils {
|
|||||||
throw new AnalysisException(String.format("Unable to parse pom '%s'", file.getPath()));
|
throw new AnalysisException(String.format("Unable to parse pom '%s'", file.getPath()));
|
||||||
}
|
}
|
||||||
return model;
|
return model;
|
||||||
|
} catch (AnalysisException ex) {
|
||||||
|
throw ex;
|
||||||
} catch (PomParseException ex) {
|
} catch (PomParseException ex) {
|
||||||
LOGGER.warn("Unable to parse pom '{}'", file.getPath());
|
LOGGER.warn("Unable to parse pom '{}'", file.getPath());
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
throw new AnalysisException(ex);
|
throw new AnalysisException(ex);
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.warn("Unable to parse pom '{}'(IO Exception)", file.getPath());
|
|
||||||
LOGGER.debug("", ex);
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
LOGGER.warn("Unexpected error during parsing of the pom '{}'", file.getPath());
|
LOGGER.warn("Unexpected error during parsing of the pom '{}'", file.getPath());
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
@@ -79,7 +77,7 @@ public final class PomUtils {
|
|||||||
*
|
*
|
||||||
* @param path the path to the pom.xml file within the jar file
|
* @param path the path to the pom.xml file within the jar file
|
||||||
* @param jar the jar file to extract the pom from
|
* @param jar the jar file to extract the pom from
|
||||||
* @return returns a
|
* @return returns an object representation of the POM
|
||||||
* @throws AnalysisException is thrown if there is an exception extracting
|
* @throws AnalysisException is thrown if there is an exception extracting
|
||||||
* or parsing the POM {@link Model} object
|
* or parsing the POM {@link Model} object
|
||||||
*/
|
*/
|
||||||
@@ -93,6 +91,8 @@ public final class PomUtils {
|
|||||||
if (model == null) {
|
if (model == null) {
|
||||||
throw new AnalysisException(String.format("Unable to parse pom '%s/%s'", jar.getName(), path));
|
throw new AnalysisException(String.format("Unable to parse pom '%s/%s'", jar.getName(), path));
|
||||||
}
|
}
|
||||||
|
} catch (AnalysisException ex) {
|
||||||
|
throw ex;
|
||||||
} catch (SecurityException ex) {
|
} catch (SecurityException ex) {
|
||||||
LOGGER.warn("Unable to parse pom '{}' in jar '{}'; invalid signature", path, jar.getName());
|
LOGGER.warn("Unable to parse pom '{}' in jar '{}'; invalid signature", path, jar.getName());
|
||||||
LOGGER.debug("", ex);
|
LOGGER.debug("", ex);
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ public class PropertyType {
|
|||||||
* The value.
|
* The value.
|
||||||
*/
|
*/
|
||||||
private String value;
|
private String value;
|
||||||
|
/**
|
||||||
|
* Whether or not the expression is a regex.
|
||||||
|
*/
|
||||||
|
private boolean regex = false;
|
||||||
|
/**
|
||||||
|
* Indicates case sensitivity.
|
||||||
|
*/
|
||||||
|
private boolean caseSensitive = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the value property.
|
* Gets the value of the value property.
|
||||||
@@ -51,10 +59,6 @@ public class PropertyType {
|
|||||||
public void setValue(String value) {
|
public void setValue(String value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Whether or not the expression is a regex.
|
|
||||||
*/
|
|
||||||
private boolean regex = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the value is a regex.
|
* Returns whether or not the value is a regex.
|
||||||
@@ -75,11 +79,6 @@ public class PropertyType {
|
|||||||
public void setRegex(boolean value) {
|
public void setRegex(boolean value) {
|
||||||
this.regex = value;
|
this.regex = value;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Indicates case sensitivity.
|
|
||||||
*/
|
|
||||||
private boolean caseSensitive = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the caseSensitive property.
|
* Gets the value of the caseSensitive property.
|
||||||
*
|
*
|
||||||
@@ -164,10 +163,7 @@ public class PropertyType {
|
|||||||
if (this.regex != other.regex) {
|
if (this.regex != other.regex) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.caseSensitive != other.caseSensitive) {
|
return this.caseSensitive == other.caseSensitive;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
package org.owasp.dependencycheck.xml.suppression;
|
package org.owasp.dependencycheck.xml.suppression;
|
||||||
|
|
||||||
import org.owasp.dependencycheck.utils.XmlUtils;
|
import org.owasp.dependencycheck.utils.XmlUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.xml.sax.ErrorHandler;
|
import org.xml.sax.ErrorHandler;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.SAXParseException;
|
import org.xml.sax.SAXParseException;
|
||||||
@@ -32,7 +34,7 @@ public class SuppressionErrorHandler implements ErrorHandler {
|
|||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
//private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionErrorHandler.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionErrorHandler.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs warnings.
|
* Logs warnings.
|
||||||
@@ -42,7 +44,7 @@ public class SuppressionErrorHandler implements ErrorHandler {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void warning(SAXParseException ex) throws SAXException {
|
public void warning(SAXParseException ex) throws SAXException {
|
||||||
//LOGGER.debug("", ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +62,7 @@ public class SuppressionErrorHandler implements ErrorHandler {
|
|||||||
* Handles fatal exceptions.
|
* Handles fatal exceptions.
|
||||||
*
|
*
|
||||||
* @param ex a fatal exception
|
* @param ex a fatal exception
|
||||||
* @throws SAXException is always
|
* @throws SAXException is always thrown
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void fatalError(SAXParseException ex) throws SAXException {
|
public void fatalError(SAXParseException ex) throws SAXException {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user