mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
146 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f333ef76d9 | ||
|
|
af5ba6854e | ||
|
|
8b7ce06793 | ||
|
|
297a5e516f | ||
|
|
92b11526be | ||
|
|
299350f655 | ||
|
|
127eafc9b3 | ||
|
|
ad1ad3a997 | ||
|
|
82151c5b3f | ||
|
|
90457c89ff | ||
|
|
3f3ac86d38 | ||
|
|
aa126039e5 | ||
|
|
662815b1ee | ||
|
|
243c36849c | ||
|
|
52d5baaf3f | ||
|
|
89217f778e | ||
|
|
9bc9bc9169 | ||
|
|
6b73430473 | ||
|
|
5ca5bca3df | ||
|
|
89ab382a18 | ||
|
|
bad425c0d7 | ||
|
|
cdbbb1b94c | ||
|
|
0a9d8a9b22 | ||
|
|
e662041d06 | ||
|
|
155464bc87 | ||
|
|
06cd811ae4 | ||
|
|
1b31268f59 | ||
|
|
b57ef7291f | ||
|
|
c3bf6aa3f8 | ||
|
|
d2fa14bbe2 | ||
|
|
9b6e55e90c | ||
|
|
afb07b651f | ||
|
|
e6806fdf2b | ||
|
|
e5ff2cff4e | ||
|
|
17d7d47b9a | ||
|
|
64e32061ab | ||
|
|
931110ba6c | ||
|
|
d90e7820cd | ||
|
|
824898dba5 | ||
|
|
761dd61ed4 | ||
|
|
89c63e6d87 | ||
|
|
a2361f9327 | ||
|
|
ea15205be8 | ||
|
|
0a45048535 | ||
|
|
1c51655ce3 | ||
|
|
7749f0da7c | ||
|
|
5695238f95 | ||
|
|
e1feeb7e21 | ||
|
|
84fecaf040 | ||
|
|
da77727673 | ||
|
|
f8c913a3e8 | ||
|
|
2024881ee1 | ||
|
|
35ed3a51e5 | ||
|
|
24b1c4d0a4 | ||
|
|
7ec2458fb5 | ||
|
|
175feaea23 | ||
|
|
dda6cf728b | ||
|
|
a7fd410b01 | ||
|
|
d281c36733 | ||
|
|
dc91e44c0a | ||
|
|
7967a858f4 | ||
|
|
2081407e38 | ||
|
|
976eabd527 | ||
|
|
b6d6a5de2b | ||
|
|
2d58cfe0ce | ||
|
|
9df8bdff5f | ||
|
|
c86b821951 | ||
|
|
4def086bf9 | ||
|
|
885c890d7d | ||
|
|
06060a6694 | ||
|
|
70667814f6 | ||
|
|
766b7a940c | ||
|
|
0c37586357 | ||
|
|
b4aa55ce1f | ||
|
|
109443ce77 | ||
|
|
5f38741831 | ||
|
|
c6f391501d | ||
|
|
d1f3105fbd | ||
|
|
8f88ca9d3d | ||
|
|
f9e4ca0cc2 | ||
|
|
5caf023677 | ||
|
|
35c2f4873c | ||
|
|
1ed7bab375 | ||
|
|
f0d1bfb777 | ||
|
|
42519ac843 | ||
|
|
8869e13385 | ||
|
|
8f9cbfe806 | ||
|
|
6481938626 | ||
|
|
9c7cc2acbf | ||
|
|
89a57d4ed3 | ||
|
|
732378592b | ||
|
|
19dc46660b | ||
|
|
4aad3471af | ||
|
|
92bd305b00 | ||
|
|
f71eb09f74 | ||
|
|
83d4a7bc18 | ||
|
|
29595324c4 | ||
|
|
f9064e526f | ||
|
|
93ec2e8639 | ||
|
|
0e2a31709a | ||
|
|
c785b39eda | ||
|
|
8fab2f58da | ||
|
|
e44ee3bfe1 | ||
|
|
62065c9d28 | ||
|
|
c76275275f | ||
|
|
257f78879d | ||
|
|
894263809c | ||
|
|
c503935d6a | ||
|
|
d4756c9eb8 | ||
|
|
0004767775 | ||
|
|
74908642c7 | ||
|
|
aadfb71c98 | ||
|
|
1244af649d | ||
|
|
7bd48cc811 | ||
|
|
8f3ce38418 | ||
|
|
1b2d9b4245 | ||
|
|
c6b2b34fde | ||
|
|
e58fc13fdb | ||
|
|
922d53d2e4 | ||
|
|
fec53b3951 | ||
|
|
e72e2c6a02 | ||
|
|
08d001ee05 | ||
|
|
99d8a07f4a | ||
|
|
eef565134b | ||
|
|
9d78293437 | ||
|
|
fc0a556e5f | ||
|
|
b6b070584f | ||
|
|
e13225eee6 | ||
|
|
da20fb2922 | ||
|
|
459c2beb12 | ||
|
|
f1cc44dead | ||
|
|
d24cfdc382 | ||
|
|
ae4cc543f6 | ||
|
|
abdb3d17f9 | ||
|
|
4095c5da38 | ||
|
|
78fab728e4 | ||
|
|
52097a6867 | ||
|
|
cb990b55b5 | ||
|
|
5070fe303a | ||
|
|
b4405ebf3e | ||
|
|
d9e6bf5068 | ||
|
|
6822188f52 | ||
|
|
15858d03ff | ||
|
|
814a733258 | ||
|
|
3ce85d8ca9 | ||
|
|
d3bff2f39d |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,6 +7,9 @@
|
||||
# Eclipse project files
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
maven-eclipse.xml
|
||||
.externalToolBuilders
|
||||
# Netbeans configuration
|
||||
nb-configuration.xml
|
||||
/target/
|
||||
|
||||
@@ -15,13 +15,12 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
|
||||
@@ -46,17 +46,17 @@ Note, that specific analyzers will automatically disable themselves if no file
|
||||
types that they support are detected - so specifically disabling them may not
|
||||
be needed.
|
||||
|
||||
Property | Description | Default Value
|
||||
------------------------|------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
Property | Description | Default Value
|
||||
------------------------|---------------------------------------------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus Pro URL. If not set the Nexus Analyzer will be disabled. |
|
||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems |
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
|
||||
@@ -15,13 +15,12 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
@@ -287,12 +286,12 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>appassembler-maven-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<version>1.8.1</version>
|
||||
<configuration>
|
||||
<programs>
|
||||
<program>
|
||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||
<name>dependency-check</name>
|
||||
<id>dependency-check</id>
|
||||
</program>
|
||||
</programs>
|
||||
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd
|
||||
"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd"
|
||||
>
|
||||
<id>release</id>
|
||||
<formats>
|
||||
|
||||
@@ -21,15 +21,19 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.owasp.dependencycheck.cli.CliParser;
|
||||
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.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.DirectoryScanner;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.LogUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -93,7 +97,11 @@ public class App {
|
||||
cli.printVersionInfo();
|
||||
} else if (cli.isRunScan()) {
|
||||
populateSettings(cli);
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
|
||||
try {
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles(), cli.getExcludeList());
|
||||
} catch (InvalidScanPathException ex) {
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "An invalid scan path was detected; unable to scan '//*' paths");
|
||||
}
|
||||
} else {
|
||||
cli.printHelp();
|
||||
}
|
||||
@@ -106,18 +114,71 @@ public class App {
|
||||
* @param outputFormat the output format of the report
|
||||
* @param applicationName the application name for the report
|
||||
* @param files the files/directories to scan
|
||||
* @param excludes the patterns for files/directories to exclude
|
||||
*
|
||||
* @throws InvalidScanPathException thrown if the path to scan starts with "//"
|
||||
*/
|
||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files) {
|
||||
Engine scanner = null;
|
||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
|
||||
String[] excludes) throws InvalidScanPathException {
|
||||
Engine engine = null;
|
||||
try {
|
||||
scanner = new Engine();
|
||||
|
||||
for (String file : files) {
|
||||
scanner.scan(file);
|
||||
engine = new Engine();
|
||||
List<String> antStylePaths = new ArrayList<String>();
|
||||
if (excludes == null || excludes.length == 0) {
|
||||
for (String file : files) {
|
||||
if (file.contains("*") || file.contains("?")) {
|
||||
antStylePaths.add(file);
|
||||
} else {
|
||||
engine.scan(file);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
antStylePaths = Arrays.asList(files);
|
||||
}
|
||||
|
||||
scanner.analyzeDependencies();
|
||||
final List<Dependency> dependencies = scanner.getDependencies();
|
||||
final Set<File> paths = new HashSet<File>();
|
||||
for (String file : antStylePaths) {
|
||||
final DirectoryScanner scanner = new DirectoryScanner();
|
||||
String include = file.replace('\\', '/');
|
||||
File baseDir;
|
||||
|
||||
if (include.startsWith("//")) {
|
||||
throw new InvalidScanPathException("Unable to scan paths specified by //");
|
||||
} else if (include.startsWith("./")) {
|
||||
baseDir = new File(".");
|
||||
include = include.substring(2);
|
||||
} else if (include.startsWith("/")) {
|
||||
baseDir = new File("/");
|
||||
include = include.substring(1);
|
||||
} else if (include.contains("/")) {
|
||||
final int pos = include.indexOf('/');
|
||||
final String tmp = include.substring(0, pos);
|
||||
if (tmp.contains("*") || tmp.contains("?")) {
|
||||
baseDir = new File(".");
|
||||
} else {
|
||||
baseDir = new File(tmp);
|
||||
include = include.substring(pos + 1);
|
||||
}
|
||||
} else { //no path info - must just be a file in the working directory
|
||||
baseDir = new File(".");
|
||||
}
|
||||
scanner.setBasedir(baseDir);
|
||||
scanner.setIncludes(include);
|
||||
if (excludes != null && excludes.length > 0) {
|
||||
scanner.addExcludes(excludes);
|
||||
}
|
||||
scanner.scan();
|
||||
if (scanner.getIncludedFilesCount() > 0) {
|
||||
for (String s : scanner.getIncludedFiles()) {
|
||||
final File f = new File(baseDir, s);
|
||||
paths.add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
engine.scan(paths);
|
||||
|
||||
engine.analyzeDependencies();
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
@@ -131,7 +192,7 @@ public class App {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop);
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||
try {
|
||||
report.generateReports(reportDirectory, outputFormat);
|
||||
} catch (IOException ex) {
|
||||
@@ -145,8 +206,8 @@ public class App {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
if (scanner != null) {
|
||||
scanner.cleanup();
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.cli;
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -134,14 +134,33 @@ public final class CliParser {
|
||||
* @throws FileNotFoundException is thrown if the path being validated does not exist.
|
||||
*/
|
||||
private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
|
||||
if (!path.contains("*.")) {
|
||||
if (path == null) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: null", argumentName);
|
||||
throw new FileNotFoundException(msg);
|
||||
} else if (!path.contains("*") && !path.contains("?")) {
|
||||
final File f = new File(path);
|
||||
if (!f.exists()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
if ("o".equals(argumentName.substring(0, 1).toLowerCase()) && !"ALL".equals(this.getReportFormat().toUpperCase())) {
|
||||
final String checkPath = path.toLowerCase();
|
||||
if (checkPath.endsWith(".html") || checkPath.endsWith(".xml") || checkPath.endsWith(".htm")) {
|
||||
if (!f.getParentFile().isDirectory()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!f.exists()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
} // else { // TODO add a validation for *.zip extensions rather then relying on the engine to validate it.
|
||||
} else if (path.startsWith("//") || path.startsWith("\\\\")) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'%nUnable to scan paths that start with '//'.", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +170,6 @@ public final class CliParser {
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private Options createCommandLineOptions() {
|
||||
|
||||
final Options options = new Options();
|
||||
addStandardOptions(options);
|
||||
addAdvancedOptions(options);
|
||||
@@ -184,16 +202,22 @@ public final class CliParser {
|
||||
.create(ARGUMENT.APP_NAME_SHORT);
|
||||
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
||||
.withDescription("The path to scan - this option can be specified multiple times. To limit the scan"
|
||||
+ " to specific file types *.[ext] can be added to the end of the path.")
|
||||
.withDescription("The path to scan - this option can be specified multiple times. Ant style"
|
||||
+ " paths are supported (e.g. path/**/*.jar).")
|
||||
.create(ARGUMENT.SCAN_SHORT);
|
||||
|
||||
final Option excludes = OptionBuilder.withArgName("pattern").hasArg().withLongOpt(ARGUMENT.EXCLUDE)
|
||||
.withDescription("Specify and exclusion pattern. This option can be specified multiple times"
|
||||
+ " and it accepts Ant style excludsions.")
|
||||
.create();
|
||||
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
|
||||
.withDescription("A property file to load.")
|
||||
.create(ARGUMENT.PROP_SHORT);
|
||||
|
||||
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ARGUMENT.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory.")
|
||||
final Option out = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory. "
|
||||
+ "It is possible to set this to a specific file name if the format argument is not set to ALL.")
|
||||
.create(ARGUMENT.OUT_SHORT);
|
||||
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||
@@ -212,7 +236,11 @@ public final class CliParser {
|
||||
final OptionGroup og = new OptionGroup();
|
||||
og.addOption(path);
|
||||
|
||||
final OptionGroup exog = new OptionGroup();
|
||||
exog.addOption(excludes);
|
||||
|
||||
options.addOptionGroup(og)
|
||||
.addOptionGroup(exog)
|
||||
.addOption(out)
|
||||
.addOption(outputFormat)
|
||||
.addOption(appName)
|
||||
@@ -297,7 +325,7 @@ public final class CliParser {
|
||||
.create();
|
||||
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
||||
.withDescription("The url to the Nexus Server.")
|
||||
.withDescription("The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled.")
|
||||
.create();
|
||||
|
||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.NEXUS_USES_PROXY)
|
||||
@@ -479,7 +507,6 @@ public final class CliParser {
|
||||
options,
|
||||
"",
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -491,6 +518,15 @@ public final class CliParser {
|
||||
return line.getOptionValues(ARGUMENT.SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of excluded file patterns specified by the 'exclude' argument.
|
||||
*
|
||||
* @return the excluded file patterns
|
||||
*/
|
||||
public String[] getExcludeList() {
|
||||
return line.getOptionValues(ARGUMENT.EXCLUDE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory to write the reports to specified on the command line.
|
||||
*
|
||||
@@ -877,5 +913,9 @@ public final class CliParser {
|
||||
* The CLI argument name for setting extra extensions.
|
||||
*/
|
||||
public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
|
||||
/**
|
||||
* Exclude path argument.
|
||||
*/
|
||||
public static final String EXCLUDE = "exclude";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2014 OWASP.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
/**
|
||||
* Thrown if an invalid path is encountered.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
class InvalidScanPathException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*/
|
||||
public InvalidScanPathException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param msg a message for the exception
|
||||
*/
|
||||
public InvalidScanPathException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param ex the cause of the exception
|
||||
*/
|
||||
public InvalidScanPathException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param msg a message for the exception
|
||||
* @param ex the cause of the exception
|
||||
*/
|
||||
public InvalidScanPathException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.cli</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* Includes utility classes such as the CLI Parser,
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.cli;
|
||||
@@ -6,8 +6,9 @@ The following table lists the command line arguments:
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
-------|-----------------------|-----------------|-------------|------------
|
||||
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. | Required
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify specific file types that should be scanned by supplying a scan path of '[path]/[to]/[scan]/*.zip'. The wild card can only be used to denote any file-name with a specific extension. | Required
|
||||
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
|
||||
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**) . | Optional
|
||||
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
|
||||
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
|
||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||
@@ -18,26 +19,25 @@ Short | Argument Name | Parameter | Description | Requir
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-------------|---------------
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-----------------------------------------------------------------------------|---------------
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
| \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Disable the Nexus Analyzer. |
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Server. | https://repository.sonatype.org/service/local/
|
||||
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled. |
|
||||
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |
|
||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. |
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.cli;
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import org.owasp.dependencycheck.CliParser;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
@@ -400,6 +400,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
@@ -418,6 +419,12 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<version>4.3.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--dependency>
|
||||
<groupId>org.jmockit</groupId>
|
||||
<artifactId>jmockit</artifactId>
|
||||
<version>1.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency-->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
@@ -464,50 +471,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>velocity</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-tools</artifactId>
|
||||
<version>2.0</version>
|
||||
<!-- very limited use of the velocity-tools, not all of the dependencies are needed-->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-chain</groupId>
|
||||
<artifactId>commons-chain</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>sslext</groupId>
|
||||
<artifactId>sslext</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-taglib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-tiles</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
@@ -621,6 +584,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<version>1.1.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
@@ -737,6 +707,28 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>2.12</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.faces</groupId>
|
||||
<artifactId>jsf-impl</artifactId>
|
||||
<version>2.2.8-02</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
@@ -52,7 +53,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Engine {
|
||||
public class Engine implements Serializable {
|
||||
|
||||
/**
|
||||
* The list of dependencies.
|
||||
@@ -61,19 +62,19 @@ public class Engine {
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
|
||||
private final transient EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final Set<FileTypeAnalyzer> fileTypeAnalyzers;
|
||||
private final transient Set<FileTypeAnalyzer> fileTypeAnalyzers;
|
||||
/**
|
||||
* The ClassLoader to use when dynamically loading Analyzer and Update services.
|
||||
*/
|
||||
private ClassLoader serviceClassLoader;
|
||||
private transient ClassLoader serviceClassLoader;
|
||||
/**
|
||||
* The Logger for use throughout the class.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
private static final transient Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a new Engine.
|
||||
@@ -167,142 +168,171 @@ public class Engine {
|
||||
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param paths an array of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param paths an array of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(String[] paths) {
|
||||
public List<Dependency> scan(String[] paths) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (String path : paths) {
|
||||
final File file = new File(path);
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param path the path to a file or directory to be analyzed.
|
||||
* @param path the path to a file or directory to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*/
|
||||
public void scan(String path) {
|
||||
if (path.matches("^.*[\\/]\\*\\.[^\\/:*|?<>\"]+$")) {
|
||||
final String[] parts = path.split("\\*\\.");
|
||||
final String[] ext = new String[]{parts[parts.length - 1]};
|
||||
final File dir = new File(path.substring(0, path.length() - ext[0].length() - 2));
|
||||
if (dir.isDirectory()) {
|
||||
final List<File> files = (List<File>) org.apache.commons.io.FileUtils.listFiles(dir, ext, true);
|
||||
scan(files);
|
||||
} else {
|
||||
final String msg = String.format("Invalid file path provided to scan '%s'", path);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
}
|
||||
} else {
|
||||
final File file = new File(path);
|
||||
scan(file);
|
||||
}
|
||||
public List<Dependency> scan(String path) {
|
||||
final File file = new File(path);
|
||||
return scan(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*
|
||||
* @param files an array of paths to files or directories to be analyzed.
|
||||
* @return the list of dependencies
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(File[] files) {
|
||||
public List<Dependency> scan(File[] files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(Set<File> files) {
|
||||
public List<Dependency> scan(Set<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(List<File> files) {
|
||||
public List<Dependency> scan(List<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param file the path to a file or directory to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @since v0.3.2.4
|
||||
*
|
||||
* @param file the path to a file or directory to be analyzed.
|
||||
*/
|
||||
public void scan(File file) {
|
||||
public List<Dependency> scan(File file) {
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
scanDirectory(file);
|
||||
return scanDirectory(file);
|
||||
} else {
|
||||
scanFile(file);
|
||||
final Dependency d = scanFile(file);
|
||||
if (d != null) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
deps.add(d);
|
||||
return deps;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scans files and directories. Any dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @param dir the directory to scan.
|
||||
* @param dir the directory to scan
|
||||
* @return the list of Dependency objects scanned
|
||||
*/
|
||||
protected void scanDirectory(File dir) {
|
||||
protected List<Dependency> scanDirectory(File dir) {
|
||||
final File[] files = dir.listFiles();
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
scanDirectory(f);
|
||||
final List<Dependency> d = scanDirectory(f);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
} else {
|
||||
scanFile(f);
|
||||
final Dependency d = scanFile(f);
|
||||
deps.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a specified file. If a dependency is identified it is added to the dependency collection.
|
||||
*
|
||||
* @param file The file to scan.
|
||||
* @param file The file to scan
|
||||
* @return the scanned dependency
|
||||
*/
|
||||
protected void scanFile(File file) {
|
||||
protected Dependency scanFile(File file) {
|
||||
if (!file.isFile()) {
|
||||
final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
final String fileName = file.getName();
|
||||
final String extension = FileUtils.getFileExtension(fileName);
|
||||
Dependency dependency = null;
|
||||
if (extension != null) {
|
||||
if (supportsExtension(extension)) {
|
||||
final Dependency dependency = new Dependency(file);
|
||||
dependency = new Dependency(file);
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.",
|
||||
file.toString());
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", file.toString());
|
||||
LOGGER.log(Level.FINEST, msg);
|
||||
}
|
||||
return dependency;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,8 +468,7 @@ public class Engine {
|
||||
} catch (UpdateException ex) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
|
||||
LOGGER.log(Level.FINE,
|
||||
String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
||||
LOGGER.log(Level.FINE, String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
static {
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
final HashSet ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
final HashSet<String> ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
ZIPPABLES.addAll(ext);
|
||||
}
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
@@ -186,7 +186,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success && tempFileLocation != null & tempFileLocation.exists()) {
|
||||
if (!success && tempFileLocation != null && tempFileLocation.exists() && tempFileLocation.list().length > 0) {
|
||||
LOGGER.log(Level.WARNING, "Failed to delete some temporary files, see the log for more details");
|
||||
}
|
||||
}
|
||||
@@ -221,9 +221,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String displayPath = String.format("%s%s",
|
||||
dependency.getFilePath(),
|
||||
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||
final String displayName = String.format("%s%s%s",
|
||||
final String displayName = String.format("%s: %s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
d.getFileName());
|
||||
d.setFilePath(displayPath);
|
||||
d.setFileName(displayName);
|
||||
|
||||
@@ -120,9 +120,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
||||
String line = null;
|
||||
// CheckStyle:VisibilityModifier OFF
|
||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
|
||||
}
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
int rc = 0;
|
||||
doc = builder.parse(proc.getInputStream());
|
||||
|
||||
@@ -233,9 +235,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final Process p = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
||||
// CheckStyle:VisibilityModifier OFF
|
||||
while (rdr.ready() && rdr.readLine() != null) {
|
||||
// We expect this to complain
|
||||
}
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
|
||||
@@ -170,29 +170,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||
*/
|
||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
||||
Confidence confidence = Confidence.HIGHEST;
|
||||
|
||||
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), confidence);
|
||||
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), confidence);
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
|
||||
int ctr = 0;
|
||||
do {
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
|
||||
for (IndexEntry e : entries) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
determineIdentifiers(dependency, vendor, product);
|
||||
}
|
||||
}
|
||||
}
|
||||
confidence = reduceConfidence(confidence);
|
||||
//TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||
String vendors = "";
|
||||
String products = "";
|
||||
for (Confidence confidence : Confidence.values()) {
|
||||
if (dependency.getVendorEvidence().contains(confidence)) {
|
||||
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
||||
}
|
||||
@@ -201,10 +182,28 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
if (dependency.getVersionEvidence().contains(confidence)) {
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
// if (dependency.getVersionEvidence().contains(confidence)) {
|
||||
// addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
// }
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
if (entries == null) {
|
||||
continue;
|
||||
}
|
||||
boolean identifierAdded = false;
|
||||
for (IndexEntry e : entries) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||
}
|
||||
}
|
||||
if (identifierAdded) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((++ctr) < 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,22 +238,6 @@ public class CPEAnalyzer implements Analyzer {
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the given confidence by one level. This returns LOW if the confidence passed in is not HIGH.
|
||||
*
|
||||
* @param c the confidence to reduce.
|
||||
* @return One less then the confidence passed in.
|
||||
*/
|
||||
private Confidence reduceConfidence(final Confidence c) {
|
||||
if (c == Confidence.HIGHEST) {
|
||||
return Confidence.HIGH;
|
||||
} else if (c == Confidence.HIGH) {
|
||||
return Confidence.MEDIUM;
|
||||
} else {
|
||||
return Confidence.LOW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
||||
@@ -269,27 +252,24 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @param vendorWeightings a list of strings to use to add weighting factors to the vendor field
|
||||
* @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search
|
||||
* @return a list of possible CPE values
|
||||
* @throws CorruptIndexException when the Lucene index is corrupt
|
||||
* @throws IOException when the Lucene index is not found
|
||||
* @throws ParseException when the generated query is not valid
|
||||
*/
|
||||
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||
Set<String> vendorWeightings, Set<String> productWeightings)
|
||||
throws CorruptIndexException, IOException, ParseException {
|
||||
Set<String> vendorWeightings, Set<String> productWeightings) {
|
||||
|
||||
final ArrayList<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
||||
|
||||
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
||||
if (searchString == null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||
for (ScoreDoc d : docs.scoreDocs) {
|
||||
if (d.score >= 0.08) {
|
||||
final Document doc = cpe.getDocument(d.doc);
|
||||
final IndexEntry entry = new IndexEntry();
|
||||
entry.setVendor(doc.get(Fields.VENDOR));
|
||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||
try {
|
||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||
for (ScoreDoc d : docs.scoreDocs) {
|
||||
if (d.score >= 0.08) {
|
||||
final Document doc = cpe.getDocument(d.doc);
|
||||
final IndexEntry entry = new IndexEntry();
|
||||
entry.setVendor(doc.get(Fields.VENDOR));
|
||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||
// if (d.score < 0.08) {
|
||||
// System.out.print(entry.getVendor());
|
||||
// System.out.print(":");
|
||||
@@ -297,13 +277,23 @@ public class CPEAnalyzer implements Analyzer {
|
||||
// System.out.print(":");
|
||||
// System.out.println(d.score);
|
||||
// }
|
||||
entry.setSearchScore(d.score);
|
||||
if (!ret.contains(entry)) {
|
||||
ret.add(entry);
|
||||
entry.setSearchScore(d.score);
|
||||
if (!ret.contains(entry)) {
|
||||
ret.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} catch (ParseException ex) {
|
||||
final String msg = String.format("Unable to parse: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured querying the CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("IO Error with search string: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured reading CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
}
|
||||
return ret;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,14 +498,21 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @param dependency the Dependency being analyzed
|
||||
* @param vendor the vendor for the CPE being analyzed
|
||||
* @param product the product for the CPE being analyzed
|
||||
* @param currentConfidence the current confidence being used during analysis
|
||||
* @return <code>true</code> if an identifier was added to the dependency; otherwise <code>false</code>
|
||||
* @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
|
||||
*/
|
||||
private void determineIdentifiers(Dependency dependency, String vendor, String product) throws UnsupportedEncodingException {
|
||||
protected boolean determineIdentifiers(Dependency dependency, String vendor, String product,
|
||||
Confidence currentConfidence) throws UnsupportedEncodingException {
|
||||
final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
|
||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||
Confidence bestGuessConf = null;
|
||||
boolean hasBroadMatch = false;
|
||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
||||
for (Confidence conf : Confidence.values()) {
|
||||
// if (conf.compareTo(currentConfidence) > 0) {
|
||||
// break;
|
||||
// }
|
||||
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
||||
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
||||
if (evVer == null) {
|
||||
@@ -528,9 +525,12 @@ public class CPEAnalyzer implements Analyzer {
|
||||
} else {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||
}
|
||||
if (dbVer == null //special case, no version specified - everything is vulnerable
|
||||
|| evVer.equals(dbVer)) { //yeah! exact match
|
||||
|
||||
if (dbVer == null) { //special case, no version specified - everything is vulnerable
|
||||
hasBroadMatch = true;
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else if (evVer.equals(dbVer)) { //yeah! exact match
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
||||
collected.add(match);
|
||||
@@ -556,7 +556,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
}
|
||||
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
|
||||
final String url = null;
|
||||
String url = null;
|
||||
if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess.
|
||||
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
||||
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
||||
}
|
||||
if (bestGuessConf == null) {
|
||||
bestGuessConf = Confidence.LOW;
|
||||
}
|
||||
@@ -566,6 +570,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
Collections.sort(collected);
|
||||
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
||||
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
||||
boolean identifierAdded = false;
|
||||
for (IdentifierMatch m : collected) {
|
||||
if (bestIdentifierQuality.equals(m.getConfidence())
|
||||
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
||||
@@ -576,8 +581,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
i.setConfidence(bestEvidenceQuality);
|
||||
}
|
||||
dependency.addIdentifier(i);
|
||||
identifierAdded = true;
|
||||
}
|
||||
}
|
||||
return identifierAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -592,7 +599,12 @@ public class CPEAnalyzer implements Analyzer {
|
||||
/**
|
||||
* A best guess for the CPE.
|
||||
*/
|
||||
BEST_GUESS
|
||||
BEST_GUESS,
|
||||
/**
|
||||
* The entire vendor/product group must be added (without a guess at version) because there is a CVE with a VS
|
||||
* that only specifies vendor/product.
|
||||
*/
|
||||
BROAD_MATCH
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.central.CentralSearch;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Analyzer which will attempt to locate a dependency, and the GAV information, by querying Central for the dependency's
|
||||
* SHA-1 digest.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralAnalyzer.class.getName());
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Central Analyzer";
|
||||
|
||||
/**
|
||||
* The phase in which this analyzer runs.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
/**
|
||||
* The types of files on which this will work.
|
||||
*/
|
||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
|
||||
|
||||
/**
|
||||
* The analyzer should be disabled if there are errors, so this is a flag to determine if such an error has
|
||||
* occurred.
|
||||
*/
|
||||
private boolean errorFlag = false;
|
||||
|
||||
/**
|
||||
* The searcher itself.
|
||||
*/
|
||||
private CentralSearch searcher;
|
||||
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
|
||||
/**
|
||||
* Determine whether to enable this analyzer or not.
|
||||
*
|
||||
* @return whether the analyzer should be enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this analyzer is enabled.
|
||||
*
|
||||
* @return <code>true</code> if the analyzer is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
private boolean checkEnabled() {
|
||||
boolean retval = false;
|
||||
|
||||
try {
|
||||
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
||||
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
||||
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
||||
LOGGER.info("Enabling the Central analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("Central analyzer disabled");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling the Central analyzer");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the analyzer once before any analysis is performed.
|
||||
*
|
||||
* @throws Exception if there's an error during initialization
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
LOGGER.fine("Initializing Central analyzer");
|
||||
LOGGER.fine(String.format("Central analyzer enabled: %s", isEnabled()));
|
||||
if (isEnabled()) {
|
||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||
LOGGER.fine(String.format("Central Analyzer URL: %s", searchUrl));
|
||||
searcher = new CentralSearch(new URL(searchUrl));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analyzer's name.
|
||||
*
|
||||
* @return the name of the analyzer
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key.
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_CENTRAL_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase under which the analyzer runs.
|
||||
*
|
||||
* @return the phase under which the analyzer runs
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extensions for which this Analyzer runs.
|
||||
*
|
||||
* @return the extensions for which this Analyzer runs
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the analysis.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine
|
||||
* @throws AnalysisException when there's an exception during analysis
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (errorFlag || !isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final List<MavenArtifact> mas = searcher.searchSha1(dependency.getSha1sum());
|
||||
final Confidence confidence = mas.size() > 1 ? Confidence.HIGH : Confidence.HIGHEST;
|
||||
for (MavenArtifact ma : mas) {
|
||||
LOGGER.fine(String.format("Central analyzer found artifact (%s) for dependency (%s)", ma.toString(), dependency.getFileName()));
|
||||
dependency.addAsEvidence("central", ma, confidence);
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
LOGGER.info(String.format("invalid sha1-hash on %s", dependency.getFileName()));
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
LOGGER.fine(String.format("Artifact not found in repository: '%s", dependency.getFileName()));
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.log(Level.FINE, "Could not connect to Central search", ioe);
|
||||
errorFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
while (subIterator.hasNext()) {
|
||||
final Dependency nextDependency = subIterator.next();
|
||||
if (hashesMatch(dependency, nextDependency)) {
|
||||
if (isCore(dependency, nextDependency)) {
|
||||
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
@@ -390,4 +390,43 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which path is shortest; if path lengths are equal then we use compareTo of the string method to
|
||||
* determine if the first path is smaller.
|
||||
*
|
||||
* @param left the first path to compare
|
||||
* @param right the second path to compare
|
||||
* @return <code>true</code> if the leftPath is the shortest; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean firstPathIsShortest(String left, String right) {
|
||||
final String leftPath = left.replace('\\', '/');
|
||||
final String rightPath = right.replace('\\', '/');
|
||||
|
||||
final int leftCount = countChar(leftPath, '/');
|
||||
final int rightCount = countChar(rightPath, '/');
|
||||
if (leftCount == rightCount) {
|
||||
return leftPath.compareTo(rightPath) <= 0;
|
||||
} else {
|
||||
return leftCount < rightCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of times the character is present in the string.
|
||||
*
|
||||
* @param string the string to count the characters in
|
||||
* @param c the character to count
|
||||
* @return the number of times the character is present in the string
|
||||
*/
|
||||
private int countChar(String string, char c) {
|
||||
int count = 0;
|
||||
final int max = string.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (c == string.charAt(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,12 +86,46 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
removeJreEntries(dependency);
|
||||
removeBadMatches(dependency);
|
||||
removeBadSpringMatches(dependency);
|
||||
removeWrongVersionMatches(dependency);
|
||||
removeSpuriousCPE(dependency);
|
||||
removeDuplicativeEntriesFromJar(dependency, engine);
|
||||
addFalseNegativeCPEs(dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes inaccurate matches on springframework CPEs.
|
||||
*
|
||||
* @param dependency the dependency to test for and remove known inaccurate CPE matches
|
||||
*/
|
||||
private void removeBadSpringMatches(Dependency dependency) {
|
||||
String mustContain = null;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".contains(i.getType())) {
|
||||
if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||
final int endPoint = i.getValue().indexOf(":", 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mustContain != null) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
if ("cpe".contains(i.getType())
|
||||
&& i.getValue() != null
|
||||
&& i.getValue().startsWith("cpe:/a:springsource:")
|
||||
&& !i.getValue().toLowerCase().contains(mustContain)) {
|
||||
itr.remove();
|
||||
//dependency.getIdentifiers().remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
||||
|
||||
@@ -73,7 +73,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
|
||||
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
||||
final File f = new File(dependency.getFileName());
|
||||
final File f = dependency.getActualFile();
|
||||
String fileName = f.getName();
|
||||
|
||||
//remove file extension
|
||||
|
||||
@@ -293,13 +293,27 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
return false;
|
||||
}
|
||||
File externalPom = null;
|
||||
if (pomEntries.isEmpty()) {
|
||||
return false;
|
||||
if (dependency.getActualFilePath().matches(".*\\.m2.repository\\b.*")) {
|
||||
String pomPath = dependency.getActualFilePath();
|
||||
pomPath = pomPath.substring(0, pomPath.lastIndexOf('.')) + ".pom";
|
||||
externalPom = new File(pomPath);
|
||||
if (externalPom.isFile()) {
|
||||
pomEntries.add(pomPath);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (String path : pomEntries) {
|
||||
Properties pomProperties = null;
|
||||
try {
|
||||
pomProperties = retrievePomProperties(path, jar);
|
||||
if (externalPom == null) {
|
||||
pomProperties = retrievePomProperties(path, jar);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex);
|
||||
}
|
||||
@@ -313,11 +327,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String displayPath = String.format("%s%s%s",
|
||||
dependency.getFilePath(),
|
||||
File.separator,
|
||||
path); //.replaceAll("[\\/]", File.separator));
|
||||
path);
|
||||
final String displayName = String.format("%s%s%s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
path); //.replaceAll("[\\/]", File.separator));
|
||||
path);
|
||||
|
||||
newDependency.setFileName(displayName);
|
||||
newDependency.setFilePath(displayPath);
|
||||
@@ -325,7 +339,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
engine.getDependencies().add(newDependency);
|
||||
Collections.sort(engine.getDependencies());
|
||||
} else {
|
||||
pom = retrievePom(path, jar);
|
||||
if (externalPom == null) {
|
||||
pom = retrievePom(path, jar);
|
||||
} else {
|
||||
pom = retrievePom(externalPom);
|
||||
}
|
||||
foundSomething |= setPomEvidence(dependency, pom, pomProperties, classes);
|
||||
}
|
||||
} catch (AnalysisException ex) {
|
||||
@@ -523,6 +541,41 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the specified POM and converts it to a Model.
|
||||
*
|
||||
* @param file the pom.xml file
|
||||
* @return returns a
|
||||
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
|
||||
* {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
|
||||
*/
|
||||
private Model retrievePom(File file) throws AnalysisException {
|
||||
Model model = null;
|
||||
try {
|
||||
final FileInputStream stream = new FileInputStream(file);
|
||||
final InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
|
||||
final InputSource xml = new InputSource(reader);
|
||||
final SAXSource source = new SAXSource(xml);
|
||||
model = readPom(source);
|
||||
} catch (SecurityException ex) {
|
||||
final String msg = String.format("Unable to parse pom '%s'; invalid signature", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new AnalysisException(ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to parse pom '%s'(IO Exception)", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw new AnalysisException(ex);
|
||||
} catch (Throwable ex) {
|
||||
final String msg = String.format("Unexpected error during parsing of the pom '%s'", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw new AnalysisException(ex);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the specified POM from a jar file and converts it to a Model.
|
||||
*
|
||||
@@ -583,11 +636,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String originalGroupID = groupid;
|
||||
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||
groupid = groupid.substring(4);
|
||||
}
|
||||
foundSomething = true;
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGHEST);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
addMatchingValues(classes, groupid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, groupid, dependency.getProductEvidence());
|
||||
@@ -616,7 +666,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
foundSomething = true;
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, artifactid, dependency.getProductEvidence());
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -49,6 +49,11 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The default URL - this will be used by the CentralAnalyzer to determine whether to enable this.
|
||||
*/
|
||||
public static final String DEFAULT_URL = "https://repository.sonatype.org/service/local/";
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -74,6 +79,47 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private NexusSearch searcher;
|
||||
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
|
||||
/**
|
||||
* Determines if this analyzer is enabled
|
||||
*
|
||||
* @return <code>true</code> if the analyzer is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
private boolean checkEnabled() {
|
||||
/* Enable this analyzer ONLY if the Nexus URL has been set to something
|
||||
other than the default one (if it's the default one, we'll use the
|
||||
central one) and it's enabled by the user.
|
||||
*/
|
||||
boolean retval = false;
|
||||
try {
|
||||
if ((!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL)))
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
|
||||
LOGGER.info("Enabling Nexus analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.info("Nexus analyzer disabled, using Central instead");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling Nexus analyzer");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to enable this analyzer or not.
|
||||
*
|
||||
* @return whether the analyzer should be enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the analyzer once before any analysis is performed.
|
||||
*
|
||||
@@ -150,31 +196,12 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
||||
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) {
|
||||
dependency.getVendorEvidence().addEvidence("nexus", "groupid", ma.getGroupId(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) {
|
||||
dependency.getProductEvidence().addEvidence("nexus", "artifactid", ma.getArtifactId(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getVersion() != null && !"".equals(ma.getVersion())) {
|
||||
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
|
||||
boolean found = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".equals(i.getType()) && i.getValue().equals(ma.toString())) {
|
||||
found = true;
|
||||
i.setConfidence(Confidence.HIGHEST);
|
||||
i.setUrl(ma.getArtifactUrl());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
|
||||
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Class of methods to search Maven Central via Central.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class CentralSearch {
|
||||
|
||||
/**
|
||||
* The URL for the Central service
|
||||
*/
|
||||
private final URL rootURL;
|
||||
|
||||
/**
|
||||
* Whether to use the Proxy when making requests
|
||||
*/
|
||||
private boolean useProxy;
|
||||
|
||||
/**
|
||||
* Used for logging.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralSearch.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a NexusSearch for the given repository URL.
|
||||
*
|
||||
* @param rootURL the URL of the repository on which searches should execute. Only parameters are added to this (so
|
||||
* it should end in /select)
|
||||
*/
|
||||
public CentralSearch(URL rootURL) {
|
||||
this.rootURL = rootURL;
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
} else {
|
||||
useProxy = false;
|
||||
LOGGER.fine("Not using proxy");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the configured Central URL for the given sha1 hash. If the artifact is found, a
|
||||
* <code>MavenArtifact</code> is populated with the GAV.
|
||||
*
|
||||
* @param sha1 the SHA-1 hash string for which to search
|
||||
* @return the populated Maven GAV.
|
||||
* @throws IOException if it's unable to connect to the specified repository or if the specified artifact is not
|
||||
* found.
|
||||
*/
|
||||
public List<MavenArtifact> searchSha1(String sha1) throws IOException {
|
||||
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
||||
throw new IllegalArgumentException("Invalid SHA1 format");
|
||||
}
|
||||
|
||||
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1));
|
||||
|
||||
LOGGER.fine(String.format("Searching Central url %s", url.toString()));
|
||||
|
||||
// Determine if we need to use a proxy. The rules:
|
||||
// 1) If the proxy is set, AND the setting is set to true, use the proxy
|
||||
// 2) Otherwise, don't use the proxy (either the proxy isn't configured,
|
||||
// or proxy is specifically set to false)
|
||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
|
||||
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// JSON would be more elegant, but there's not currently a dependency
|
||||
// on JSON, so don't want to add one just for this
|
||||
conn.addRequestProperty("Accept", "application/xml");
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == 200) {
|
||||
boolean missing = false;
|
||||
try {
|
||||
final DocumentBuilder builder = DocumentBuilderFactory
|
||||
.newInstance().newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String numFound = xpath.evaluate("/response/result/@numFound", doc);
|
||||
if ("0".equals(numFound)) {
|
||||
missing = true;
|
||||
} else {
|
||||
final ArrayList<MavenArtifact> result = new ArrayList<MavenArtifact>();
|
||||
final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
|
||||
for (int i = 0; i < docs.getLength(); i++) {
|
||||
final String g = xpath.evaluate("./str[@name='g']", docs.item(i));
|
||||
LOGGER.finest(String.format("GroupId: %s", g));
|
||||
final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
|
||||
LOGGER.finest(String.format("ArtifactId: %s", a));
|
||||
final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
|
||||
LOGGER.finest(String.format("Version: %s", v));
|
||||
result.add(new MavenArtifact(g, a, v, url.toString()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Anything else is jacked up XML stuff that we really can't recover
|
||||
// from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (missing) {
|
||||
throw new FileNotFoundException("Artifact not found in Central");
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("Could not connect to Central received response code: %d %s",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
LOGGER.fine(msg);
|
||||
throw new IOException(msg);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.data.central</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* <p>
|
||||
* Contains classes related to searching Maven Central.</p>
|
||||
* <p>
|
||||
* These are used to abstract Maven Central searching away from OWASP Dependency Check so they can be reused elsewhere.</p>
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
@@ -54,6 +54,7 @@ import org.owasp.dependencycheck.utils.Pair;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class CpeMemoryIndex {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -160,7 +161,7 @@ public final class CpeMemoryIndex {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Analyzer createSearchingAnalyzer() {
|
||||
final Map fieldAnalyzers = new HashMap();
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
productSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
|
||||
@@ -29,10 +29,12 @@ import java.util.logging.Logger;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class CweDB {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CweDB.class.getName());
|
||||
|
||||
/**
|
||||
* Empty private constructor as this is a utility class.
|
||||
*/
|
||||
@@ -55,7 +57,9 @@ public final class CweDB {
|
||||
final String filePath = "data/cwe.hashmap.serialized";
|
||||
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||
oin = new ObjectInputStream(input);
|
||||
return (HashMap<String, String>) oin.readObject();
|
||||
@SuppressWarnings("unchecked")
|
||||
final HashMap<String, String> ret = (HashMap<String, String>) oin.readObject();
|
||||
return ret;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
|
||||
@@ -306,14 +306,14 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown when there is an error retrieving the data from the DB
|
||||
*/
|
||||
public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
final HashSet data = new HashSet<Pair<String, String>>();
|
||||
final Set<Pair<String, String>> data = new HashSet<Pair<String, String>>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
data.add(new Pair(rs.getString(1), rs.getString(2)));
|
||||
data.add(new Pair<String, String>(rs.getString(1), rs.getString(2)));
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||
@@ -731,7 +731,7 @@ public class CveDB {
|
||||
* @param previous a flag indicating if previous versions of the product are vulnerable
|
||||
* @return true if the identified version is affected, otherwise false
|
||||
*/
|
||||
private boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
|
||||
protected boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
|
||||
boolean affected = false;
|
||||
final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
|
||||
final DependencyVersion v = parseDependencyVersion(cpeId);
|
||||
|
||||
@@ -142,8 +142,8 @@ public class DatabaseProperties {
|
||||
*
|
||||
* @return a map of the database meta data
|
||||
*/
|
||||
public Map getMetaData() {
|
||||
final TreeMap map = new TreeMap();
|
||||
public Map<String, String> getMetaData() {
|
||||
final TreeMap<String, String> map = new TreeMap<String, String>();
|
||||
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||
final String key = (String) entry.getKey();
|
||||
if (!"version".equals(key)) {
|
||||
@@ -156,10 +156,10 @@ public class DatabaseProperties {
|
||||
map.put(key, formatted);
|
||||
} catch (Throwable ex) { //deliberately being broad in this catch clause
|
||||
LOGGER.log(Level.FINE, "Unable to parse timestamp from DB", ex);
|
||||
map.put(key, entry.getValue());
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
} else {
|
||||
map.put(key, entry.getValue());
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
package org.owasp.dependencycheck.data.update.task;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -25,6 +28,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
@@ -195,10 +200,18 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
return null;
|
||||
}
|
||||
if (url1.toExternalForm().endsWith(".xml.gz")) {
|
||||
extractGzip(first);
|
||||
}
|
||||
if (url2.toExternalForm().endsWith(".xml.gz")) {
|
||||
extractGzip(second);
|
||||
}
|
||||
|
||||
msg = String.format("Download Complete for NVD CVE - %s", nvdCveInfo.getId());
|
||||
LOGGER.log(Level.INFO, msg);
|
||||
|
||||
if (this.processorService == null) {
|
||||
return null;
|
||||
}
|
||||
final ProcessTask task = new ProcessTask(cveDB, this, settings);
|
||||
return this.processorService.submit(task);
|
||||
|
||||
@@ -237,4 +250,48 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file
|
||||
* specified.
|
||||
*
|
||||
* @param file the archive file
|
||||
* @throws FileNotFoundException thrown if the file does not exist
|
||||
* @throws IOException thrown if there is an error extracting the file.
|
||||
*/
|
||||
private void extractGzip(File file) throws FileNotFoundException, IOException {
|
||||
final String originalPath = file.getPath();
|
||||
File gzip = new File(originalPath + ".gz");
|
||||
if (gzip.isFile()) {
|
||||
gzip.delete();
|
||||
}
|
||||
if (!file.renameTo(gzip)) {
|
||||
throw new IOException("Unable to rename '" + file.getPath() + "'");
|
||||
}
|
||||
final File newfile = new File(originalPath);
|
||||
|
||||
final byte[] buffer = new byte[4096];
|
||||
|
||||
GZIPInputStream cin = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
cin = new GZIPInputStream(new FileInputStream(gzip));
|
||||
out = new FileOutputStream(newfile);
|
||||
|
||||
int len;
|
||||
while ((len = cin.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
} finally {
|
||||
if (cin != null) {
|
||||
cin.close();
|
||||
}
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (gzip.isFile()) {
|
||||
FileUtils.deleteQuietly(gzip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
|
||||
@@ -35,7 +37,7 @@ import org.owasp.dependencycheck.utils.FileUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Dependency implements Comparable<Dependency> {
|
||||
public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
@@ -315,6 +317,41 @@ public class Dependency implements Comparable<Dependency> {
|
||||
this.identifiers.add(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the maven artifact as evidence.
|
||||
*
|
||||
* @param source The source of the evidence
|
||||
* @param mavenArtifact The maven artifact
|
||||
* @param confidence The confidence level of this evidence
|
||||
*/
|
||||
public void addAsEvidence(String source, MavenArtifact mavenArtifact, Confidence confidence) {
|
||||
if (mavenArtifact.getGroupId() != null && !mavenArtifact.getGroupId().isEmpty()) {
|
||||
this.getVendorEvidence().addEvidence(source, "groupid", mavenArtifact.getGroupId(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getArtifactId() != null && !mavenArtifact.getArtifactId().isEmpty()) {
|
||||
this.getProductEvidence().addEvidence(source, "artifactid", mavenArtifact.getArtifactId(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getVersion() != null && !mavenArtifact.getVersion().isEmpty()) {
|
||||
this.getVersionEvidence().addEvidence(source, "version", mavenArtifact.getVersion(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getArtifactUrl() != null && !mavenArtifact.getArtifactUrl().isEmpty()) {
|
||||
boolean found = false;
|
||||
for (Identifier i : this.getIdentifiers()) {
|
||||
if ("maven".equals(i.getType()) && i.getValue().equals(mavenArtifact.toString())) {
|
||||
found = true;
|
||||
i.setConfidence(Confidence.HIGHEST);
|
||||
i.setUrl(mavenArtifact.getArtifactUrl());
|
||||
LOGGER.fine(String.format("Already found identifier %s. Confidence set to highest", i.getValue()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LOGGER.fine(String.format("Adding new maven identifier %s", mavenArtifact.toString()));
|
||||
this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the list of detected Identifiers for the dependency file.
|
||||
*
|
||||
@@ -323,6 +360,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void addIdentifier(Identifier identifier) {
|
||||
this.identifiers.add(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of identifiers that have been suppressed.
|
||||
*/
|
||||
@@ -440,6 +478,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public EvidenceCollection getVersionEvidence() {
|
||||
return this.versionEvidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of the JAR file.
|
||||
*/
|
||||
@@ -462,6 +501,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The license that this dependency uses.
|
||||
*/
|
||||
@@ -484,6 +524,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setLicense(String license) {
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of vulnerabilities for this dependency.
|
||||
*/
|
||||
@@ -539,6 +580,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void addVulnerability(Vulnerability vulnerability) {
|
||||
this.vulnerabilities.add(vulnerability);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of related dependencies.
|
||||
*/
|
||||
@@ -578,7 +620,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
* @return an integer representing the natural ordering
|
||||
*/
|
||||
public int compareTo(Dependency o) {
|
||||
return this.getFileName().compareToIgnoreCase(o.getFileName());
|
||||
return this.getFilePath().compareToIgnoreCase(o.getFilePath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Evidence is a piece of information about a Dependency.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Evidence implements Comparable<Evidence> {
|
||||
public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
|
||||
/**
|
||||
* Creates a new Evidence object.
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -36,7 +37,7 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class EvidenceCollection implements Iterable<Evidence> {
|
||||
public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Identifier implements Comparable<Identifier> {
|
||||
public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
|
||||
/**
|
||||
* Constructs a new Identifier with the specified data.
|
||||
|
||||
@@ -167,15 +167,28 @@ public class ReportGenerator {
|
||||
*/
|
||||
public void generateReports(String outputDir, String outputFormat) throws IOException, Exception {
|
||||
final String format = outputFormat.toUpperCase();
|
||||
final String pathToCheck = outputDir.toLowerCase();
|
||||
if (format.matches("^(XML|HTML|VULN|ALL)$")) {
|
||||
if ("XML".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.XML);
|
||||
if (pathToCheck.endsWith(".xml")) {
|
||||
generateReport("XmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.XML);
|
||||
}
|
||||
}
|
||||
if ("HTML".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.HTML);
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("HtmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.HTML);
|
||||
}
|
||||
}
|
||||
if ("VULN".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.VULN);
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("VulnReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.VULN);
|
||||
}
|
||||
}
|
||||
if ("ALL".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.ALL);
|
||||
|
||||
@@ -103,6 +103,12 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
currentText = new StringBuffer();
|
||||
if (SUPPRESS.equals(qName)) {
|
||||
rule = new SuppressionRule();
|
||||
final String base = currentAttributes.getValue("base");
|
||||
if (base != null) {
|
||||
rule.setBase(Boolean.parseBoolean(base));
|
||||
} else {
|
||||
rule.setBase(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,6 @@ import java.io.IOException;
|
||||
*/
|
||||
public class SuppressionParseException extends IOException {
|
||||
|
||||
/**
|
||||
* The serial version UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SuppressionParseException.
|
||||
*/
|
||||
@@ -50,7 +45,7 @@ public class SuppressionParseException extends IOException {
|
||||
/**
|
||||
* Creates a new SuppressionParseException.
|
||||
*
|
||||
* @param ex the cause of the download failure.
|
||||
* @param ex the cause of the parse exception
|
||||
*/
|
||||
public SuppressionParseException(Throwable ex) {
|
||||
super(ex);
|
||||
@@ -60,7 +55,7 @@ public class SuppressionParseException extends IOException {
|
||||
* Creates a new SuppressionParseException.
|
||||
*
|
||||
* @param msg a message for the exception.
|
||||
* @param ex the cause of the download failure.
|
||||
* @param ex the cause of the parse exception
|
||||
*/
|
||||
public SuppressionParseException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
|
||||
@@ -266,6 +266,30 @@ public class SuppressionRule {
|
||||
return gav != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag indicating whether or not the suppression rule is a core/base rule that should not be included in the
|
||||
* resulting report in the "suppressed" section.
|
||||
*/
|
||||
private boolean base;
|
||||
|
||||
/**
|
||||
* Get the value of base.
|
||||
*
|
||||
* @return the value of base
|
||||
*/
|
||||
public boolean isBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of base.
|
||||
*
|
||||
* @param base new value of base
|
||||
*/
|
||||
public void setBase(boolean base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a given dependency to determine if any CPE, CVE, CWE, or CVSS scores should be suppressed. If any
|
||||
* should be, they are removed from the dependency.
|
||||
@@ -300,7 +324,9 @@ public class SuppressionRule {
|
||||
final Identifier i = itr.next();
|
||||
for (PropertyType c : this.cpe) {
|
||||
if (identifierMatches("cpe", c, i)) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
}
|
||||
itr.remove();
|
||||
break;
|
||||
}
|
||||
@@ -339,7 +365,9 @@ public class SuppressionRule {
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
}
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@ public final class DBUtils {
|
||||
int id = 0;
|
||||
try {
|
||||
rs = statement.getGeneratedKeys();
|
||||
rs.next();
|
||||
if (!rs.next()) {
|
||||
throw new DatabaseException("Unable to get primary key for inserted row");
|
||||
}
|
||||
id = rs.getInt(1);
|
||||
} catch (SQLException ex) {
|
||||
throw new DatabaseException("Unable to get primary key for inserted row");
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DependencyVersion implements Iterable, Comparable<DependencyVersion
|
||||
public final void parseVersion(String version) {
|
||||
versionParts = new ArrayList<String>();
|
||||
if (version != null) {
|
||||
final Pattern rx = Pattern.compile("(\\d+|[a-z]+\\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());
|
||||
while (matcher.find()) {
|
||||
versionParts.add(matcher.group());
|
||||
@@ -189,17 +189,23 @@ public class DependencyVersion implements Iterable, Comparable<DependencyVersion
|
||||
if (version == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ret = true;
|
||||
int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
if (max > 3) {
|
||||
max = 3;
|
||||
if (Math.abs(this.versionParts.size() - version.versionParts.size()) >= 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
boolean ret = true;
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (this.versionParts.get(i) == null || !this.versionParts.get(i).equals(version.versionParts.get(i))) {
|
||||
final String thisVersion = this.versionParts.get(i);
|
||||
final String otherVersion = version.getVersionParts().get(i);
|
||||
if (i >= 3) {
|
||||
if (thisVersion.compareToIgnoreCase(otherVersion) >= 0) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
} else if (!thisVersion.equals(otherVersion)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public final class DependencyVersionUtil {
|
||||
/**
|
||||
* Regular expression to extract version numbers from file names.
|
||||
*/
|
||||
private static final Pattern RX_VERSION = Pattern.compile("\\d+(\\.\\d{1,6})+(\\.?([_-](release|beta|alpha)|[a-zA-Z_-]{1,3}\\d{1,8}))?");
|
||||
private static final Pattern RX_VERSION = Pattern.compile("\\d+(\\.\\d{1,6})+(\\.?([_-](release|beta|alpha|\\d+)|[a-zA-Z_-]{1,3}\\d{0,8}))?");
|
||||
/**
|
||||
* Regular expression to extract a single version number without periods. This is a last ditch effort just to check
|
||||
* in case we are missing a version number using the previous regex.
|
||||
|
||||
@@ -8,6 +8,7 @@ org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NvdCveAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.CentralAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NexusAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NuspecAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.AssemblyAnalyzer
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses false positives identified on spring security.
|
||||
]]></notes>
|
||||
@@ -9,7 +9,16 @@
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses false positives identified on spring security.
|
||||
]]></notes>
|
||||
<filePath regex="true">.*spring-security-[^\\/]*\.jar$</filePath>
|
||||
<cpe>cpe:/a:mod_security:mod_security</cpe>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppreses additional false positives for the xstream library that occur because spring has a copy of this library.
|
||||
com.springsource.com.thoughtworks.xstream-1.3.1.jar
|
||||
@@ -17,4 +26,40 @@
|
||||
<gav regex="true">com\.thoughtworks\.xstream:xstream:.*</gav>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on velocity tools.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.apache\.velocity:velocity-tools:.*</gav>
|
||||
<cpe>cpe:/a:apache:struts</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Sandbox is a php blog platform and should not be flagged as a CPE for java or .net dependencies.
|
||||
]]></notes>
|
||||
<filePath regex="true">.*\.(jar|dll|exe|ear|war|pom)</filePath>
|
||||
<cpe>cpe:/a:sandbox:sandbox</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on Jersey core client.
|
||||
]]></notes>
|
||||
<gav regex="true">(com\.sun\.jersey|org\.glassfish\.jersey\.core):jersey-(client|common):.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
<cpe>cpe:/a:oracle:oracle_client</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on the grizzly-framework
|
||||
]]></notes>
|
||||
<gav regex="true">org\.glassfish\.grizzly:grizzly-framework:.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on the grizzly-framework
|
||||
]]></notes>
|
||||
<gav regex="true">org\.forgerock\.opendj:opendj-ldap-sdk:.*</gav>
|
||||
<cpe>cpe:/a:ldap_project:ldap</cpe>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -40,11 +40,16 @@ data.driver_path=
|
||||
cve.url.modified.validfordays=7
|
||||
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
#cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2002
|
||||
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
#cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
|
||||
|
||||
# file type analyzer settings:
|
||||
analyzer.archive.enabled=true
|
||||
@@ -58,3 +63,7 @@ analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||
# are configured
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
# the URL for searching search.maven.org for SHA-1 and whether it's enabled
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
<xs:element name="cvssBelow" type="dc:cvssScoreType"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="base" use="optional" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
|
||||
@@ -33,8 +33,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$(".expandable").click(function (e) {
|
||||
e = e || window.event;
|
||||
$(".expandable").click(function (event) {
|
||||
e = event || window.event;
|
||||
var h = e.target || e.srcElement;
|
||||
var content = "#content" + h.id.substr(6);
|
||||
var header = "#" + h.id;
|
||||
@@ -56,6 +56,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
$(header).addClass("expandablesubsection");
|
||||
$(header).removeClass("collaspablesubsection");
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -533,24 +534,22 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<li class="scaninfo hidden"><i>$enc.html($prop.key)</i>: $enc.html($prop.value)</li>
|
||||
#end
|
||||
</ul><br/>
|
||||
Display: <a href="#" title="Click to toggle display" onclick="return toggleDisplay(this,'.notvulnerable', 'Showing Vulnerable Dependencies', 'Showing All Dependencies'); return false;">Showing Vulnerable Dependencies</a><br/><br/>
|
||||
Display: <a href="#" title="Click to toggle display" onclick="return toggleDisplay(this, '.notvulnerable', 'Showing Vulnerable Dependencies', 'Showing All Dependencies'); return false;">Showing Vulnerable Dependencies</a><br/><br/>
|
||||
#set($lnkcnt=0)
|
||||
<table class="lined">
|
||||
<tr style="text-align:left">
|
||||
<th title="The name of the dependency">Dependency</th>
|
||||
<th title="The number of related dependencies"># Related</th>
|
||||
<th title="The Common Platform Enumeration">CPE</th>
|
||||
<th title="The Maven GAV Coordinates">GAV</th>
|
||||
<th title="The highest CVE Impact">CVE Impact</th>
|
||||
<th title="The number of Common Vulnerability and Exposure (CVE) entries">CVE Count</th>
|
||||
<th title="The confidence rating dependency-check has for the identified CPE">CPE Confidence</th>
|
||||
<th title="The count of evidence used to identify the CPE">Evidence Count</th>
|
||||
<th title="The highest CVE Severity">Highest Severity</th>
|
||||
<th title="The number of Common Vulnerability and Exposure (CVE) entries">CVE Count</th>
|
||||
<th title="The confidence rating dependency-check has for the identified CPE">CPE Confidence</th>
|
||||
<th title="The count of evidence used to identify the CPE">Evidence Count</th>
|
||||
</tr>
|
||||
#foreach($dependency in $dependencies)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<tr class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
<td><a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a></td>
|
||||
<td>$dependency.getRelatedDependencies().size()</td>
|
||||
#set($mavenlink="")
|
||||
#set($cpeIdCount=0)
|
||||
#set($cpeIdConf="")
|
||||
@@ -754,7 +753,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
@@ -888,7 +887,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
git st<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
@@ -907,6 +906,6 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
## END SUPPRESSED VULNERABILITIES
|
||||
</div>
|
||||
</div>
|
||||
<div><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</div>
|
||||
<div><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -236,6 +236,6 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</p>
|
||||
<p><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
@@ -42,26 +41,6 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of scan method, of class Engine.
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testScan() throws Exception {
|
||||
String testClasses = "target/test-classes/*.zip";
|
||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Engine instance = new Engine();
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
instance.scan(testClasses);
|
||||
assertTrue(instance.getDependencies().size() > 0);
|
||||
for (Dependency d : instance.getDependencies()) {
|
||||
assertTrue("non-zip file collected " + d.getFileName(), d.getFileName().toLowerCase().endsWith(".zip"));
|
||||
}
|
||||
instance.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test running the entire engine.
|
||||
*
|
||||
@@ -70,10 +49,10 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
@Test
|
||||
public void testEngine() throws Exception {
|
||||
String testClasses = "target/test-classes";
|
||||
// boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Engine instance = new Engine();
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
instance.scan(testClasses);
|
||||
assertTrue(instance.getDependencies().size() > 0);
|
||||
instance.analyzeDependencies();
|
||||
@@ -81,8 +60,7 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
cveDB.open();
|
||||
DatabaseProperties dbProp = cveDB.getDatabaseProperties();
|
||||
cveDB.close();
|
||||
ReportGenerator rg = new ReportGenerator("DependencyCheck",
|
||||
instance.getDependencies(), instance.getAnalyzers(), dbProp);
|
||||
ReportGenerator rg = new ReportGenerator("DependencyCheck", instance.getDependencies(), instance.getAnalyzers(), dbProp);
|
||||
rg.generateReports("./target/", "ALL");
|
||||
instance.cleanup();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
ArchiveAnalyzer instance = new ArchiveAnalyzer();
|
||||
Set expResult = new HashSet<String>();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("zip");
|
||||
expResult.add("war");
|
||||
expResult.add("ear");
|
||||
|
||||
@@ -25,9 +25,11 @@ import java.util.Set;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.queryparser.classic.ParseException;
|
||||
import org.junit.Assert;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
|
||||
@@ -81,12 +83,24 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*/
|
||||
@Test
|
||||
public void testDetermineCPE_full() throws Exception {
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5");
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0");
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2");
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null);
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
|
||||
try {
|
||||
//callDetermineCPE_full("struts2-core-2.3.16.3.jar", "cpe:/a:apache:struts:2.3.16.3", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
} finally {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,25 +108,16 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs
|
||||
*/
|
||||
public void callDetermineCPE_full(String depName, String expResult) throws Exception {
|
||||
public void callDetermineCPE_full(String depName, String expResult, CPEAnalyzer instance, FileNameAnalyzer fnAnalyzer, JarAnalyzer jarAnalyzer, HintAnalyzer hAnalyzer, FalsePositiveAnalyzer fp) throws Exception {
|
||||
|
||||
File file = new File(this.getClass().getClassLoader().getResource(depName).getPath());
|
||||
|
||||
Dependency dep = new Dependency(file);
|
||||
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
fnAnalyzer.analyze(dep, null);
|
||||
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
jarAnalyzer.analyze(dep, null);
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
hAnalyzer.analyze(dep, null);
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
instance.analyze(dep, null);
|
||||
instance.close();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
fp.analyze(dep, null);
|
||||
|
||||
if (expResult != null) {
|
||||
@@ -180,6 +185,30 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
//Assert.assertTrue("Incorrect match - spring", spring.getIdentifiers().get(0).getValue().equals(expResultSpring));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of determineIdentifiers method, of class CPEAnalyzer.
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs
|
||||
*/
|
||||
@Test
|
||||
public void testDetermineIdentifiers() throws Exception {
|
||||
Dependency openssl = new Dependency();
|
||||
openssl.getVendorEvidence().addEvidence("test", "vendor", "openssl", Confidence.HIGHEST);
|
||||
openssl.getProductEvidence().addEvidence("test", "product", "openssl", Confidence.HIGHEST);
|
||||
openssl.getVersionEvidence().addEvidence("test", "version", "1.0.1c", Confidence.HIGHEST);
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
instance.determineIdentifiers(openssl, "openssl", "openssl", Confidence.HIGHEST);
|
||||
instance.close();
|
||||
|
||||
String expResult = "cpe:/a:openssl:openssl:1.0.1c";
|
||||
Identifier expIdentifier = new Identifier("cpe", expResult, expResult);
|
||||
|
||||
assertTrue(openssl.getIdentifiers().contains(expIdentifier));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of searchCPE method, of class CPEAnalyzer.
|
||||
*
|
||||
@@ -190,12 +219,12 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
String vendor = "apache software foundation";
|
||||
String product = "struts 2 core";
|
||||
String version = "2.1.2";
|
||||
String expResult = "cpe:/a:apache:struts:2.1.2";
|
||||
String expVendor = "apache";
|
||||
String expProduct = "struts";
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
|
||||
//TODO - yeah, not a very good test as the results are the same with or without weighting...
|
||||
Set<String> productWeightings = new HashSet<String>(1);
|
||||
productWeightings.add("struts2");
|
||||
|
||||
@@ -203,9 +232,16 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
vendorWeightings.add("apache");
|
||||
|
||||
List<IndexEntry> result = instance.searchCPE(vendor, product, productWeightings, vendorWeightings);
|
||||
//TODO fix this assert
|
||||
//Assert.assertEquals(expResult, result.get(0).getName());
|
||||
|
||||
instance.close();
|
||||
|
||||
boolean found = false;
|
||||
for (IndexEntry entry : result) {
|
||||
if (expVendor.equals(entry.getVendor()) && expProduct.equals(entry.getProduct())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("apache:struts was not identified", found);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +86,40 @@ public class DependencyBundlingAnalyzerTest extends BaseTest {
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFirstPathIsShortest() {
|
||||
DependencyBundlingAnalyzer instance = new DependencyBundlingAnalyzer();
|
||||
|
||||
String left = "./a/c.jar";
|
||||
String right = "./d/e/f.jar";
|
||||
boolean expResult = true;
|
||||
boolean result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./d/e/f.jar";
|
||||
expResult = true;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./d/b/c.jar";
|
||||
right = "./a/e/f.jar";
|
||||
expResult = false;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./d/f.jar";
|
||||
expResult = false;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./a/b/c.jar";
|
||||
expResult = true;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class JarAnalyzerTest extends BaseTest {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
JarAnalyzer instance = new JarAnalyzer();
|
||||
Set expResult = new HashSet();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("jar");
|
||||
expResult.add("war");
|
||||
Set result = instance.getSupportedExtensions();
|
||||
|
||||
@@ -38,7 +38,7 @@ public class JavaScriptAnalyzerTest extends BaseTest {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
|
||||
Set expResult = new HashSet<String>();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("js");
|
||||
Set result = instance.getSupportedExtensions();
|
||||
assertEquals(expResult, result);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Created by colezlaw on 10/13/14.
|
||||
*/
|
||||
public class CentralSearchTest extends BaseTest {
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralSearchTest.class.getName());
|
||||
private CentralSearch searcher;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
String centralUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||
LOGGER.fine(centralUrl);
|
||||
searcher = new CentralSearch(new URL(centralUrl));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullSha1() throws Exception { searcher.searchSha1(null); }
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMalformedSha1() throws Exception {
|
||||
searcher.searchSha1("invalid");
|
||||
}
|
||||
|
||||
// This test does generate network traffic and communicates with a host
|
||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||
// test it anyway
|
||||
@Test
|
||||
public void testValidSha1() throws Exception {
|
||||
List<MavenArtifact> ma = searcher.searchSha1("9977a8d04e75609cf01badc4eb6a9c7198c4c5ea");
|
||||
assertEquals("Incorrect group", "org.apache.maven.plugins", ma.get(0).getGroupId());
|
||||
assertEquals("Incorrect artifact", "maven-compiler-plugin", ma.get(0).getArtifactId());
|
||||
assertEquals("Incorrect version", "3.1", ma.get(0).getVersion());
|
||||
}
|
||||
|
||||
// This test does generate network traffic and communicates with a host
|
||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||
// test it anyway
|
||||
@Test(expected = FileNotFoundException.class)
|
||||
public void testMissingSha1() throws Exception {
|
||||
searcher.searchSha1("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
|
||||
}
|
||||
|
||||
// This test should give us multiple results back from Central
|
||||
@Test
|
||||
public void testMultipleReturns() throws Exception {
|
||||
List<MavenArtifact> ma = searcher.searchSha1("94A9CE681A42D0352B3AD22659F67835E560D107");
|
||||
assertTrue(ma.size() > 1);
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,11 @@ package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -72,4 +74,21 @@ public class CveDBIntegrationTest extends BaseDBTestCase {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of isAffected method, of class CveDB.
|
||||
*/
|
||||
@Test
|
||||
public void testIsAffected() throws Exception {
|
||||
String vendor = "openssl";
|
||||
String product = "openssl";
|
||||
DependencyVersion identifiedVersion = new DependencyVersion("1.0.1o");
|
||||
String cpeId = "cpe:/a:openssl:openssl:1.0.1e";
|
||||
String previous = "y";
|
||||
|
||||
CveDB instance = new CveDB();
|
||||
assertFalse(instance.isAffected(vendor, product, identifiedVersion, cpeId, previous));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update.task;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class DownloadTaskTest {
|
||||
|
||||
public DownloadTaskTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Settings.initialize();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Settings.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of call method, of class DownloadTask.
|
||||
*/
|
||||
@Test
|
||||
public void testCall() throws Exception {
|
||||
NvdCveInfo cve = new NvdCveInfo();
|
||||
cve.setId("modified");
|
||||
cve.setNeedsUpdate(true);
|
||||
cve.setUrl(Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL));
|
||||
cve.setOldSchemaVersionUrl(Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL));
|
||||
ExecutorService processExecutor = null;
|
||||
CveDB cveDB = null;
|
||||
DownloadTask instance = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());;
|
||||
Future<ProcessTask> result = instance.call();
|
||||
assertNull(result);
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,12 @@ import java.util.Set;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -152,7 +154,7 @@ public class DependencyTest {
|
||||
public void testGetMd5sum() {
|
||||
File file = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
|
||||
Dependency instance = new Dependency(file);
|
||||
// assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum());
|
||||
//assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum());
|
||||
String expResult = "C30B57142E1CCBC1EFD5CD15F307358F";
|
||||
String result = instance.getMd5sum();
|
||||
assertEquals(expResult, result);
|
||||
@@ -294,4 +296,34 @@ public class DependencyTest {
|
||||
EvidenceCollection result = instance.getVersionEvidence();
|
||||
assertTrue(true); //this is just a getter setter pair.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addAsEvidence method, of class Dependency.
|
||||
*/
|
||||
@Test
|
||||
public void testAddAsEvidence() {
|
||||
Dependency instance = new Dependency();
|
||||
MavenArtifact mavenArtifact = new MavenArtifact("group", "artifact", "version", "url");
|
||||
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
|
||||
assertTrue(instance.getEvidence().contains(Confidence.HIGH));
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "version").isEmpty());
|
||||
assertFalse(instance.getIdentifiers().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addAsEvidence method, of class Dependency.
|
||||
*/
|
||||
@Test
|
||||
public void testAddAsEvidenceWithEmptyArtefact() {
|
||||
Dependency instance = new Dependency();
|
||||
MavenArtifact mavenArtifact = new MavenArtifact(null, null, null, null);
|
||||
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
|
||||
assertFalse(instance.getEvidence().contains(Confidence.HIGH));
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "version").isEmpty());
|
||||
assertTrue(instance.getIdentifiers().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,15 @@ public class SuppressionHandlerTest {
|
||||
|
||||
xmlReader.parse(in);
|
||||
|
||||
List result = handler.getSuppressionRules();
|
||||
List<SuppressionRule> result = handler.getSuppressionRules();
|
||||
assertTrue(result.size() > 3);
|
||||
int baseCount = 0;
|
||||
for (SuppressionRule r : result) {
|
||||
if (r.isBase()) {
|
||||
baseCount++;
|
||||
}
|
||||
}
|
||||
assertTrue(baseCount > 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,17 @@ public class SuppressionRuleTest {
|
||||
List<String> result = instance.getCve();
|
||||
assertEquals(cve, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of base property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testBase() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
assertFalse(instance.isBase());
|
||||
instance.setBase(true);
|
||||
assertTrue(instance.isBase());
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Ignored duplicate tests, left in, as empty tests, so IDE doesn't re-generate them">
|
||||
@@ -424,33 +435,33 @@ public class SuppressionRuleTest {
|
||||
instance.setSha1(sha1);
|
||||
instance.addCwe("287");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
dependency.setSha1sum(sha1);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cvss
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCvssBelow(5f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCvssBelow(8f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cve
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCve("CVE-2012-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCve("CVE-2013-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cpe
|
||||
instance = new SuppressionRule();
|
||||
@@ -468,18 +479,21 @@ public class SuppressionRuleTest {
|
||||
instance.setFilePath(pt);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
|
||||
instance = new SuppressionRule();
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:microsoft:.net_framework");
|
||||
instance.addCpe(pt);
|
||||
assertTrue(dependency.getIdentifiers().size() == 3);
|
||||
instance.setBase(true);
|
||||
assertEquals(3, dependency.getIdentifiers().size());
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 3);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -134,14 +134,14 @@ public class DependencyVersionTest {
|
||||
@Test
|
||||
public void testMatchesAtLeastThreeLevels() {
|
||||
|
||||
DependencyVersion instance = new DependencyVersion("1.2.3.4");
|
||||
DependencyVersion version = new DependencyVersion("1.2.3.5");
|
||||
DependencyVersion instance = new DependencyVersion("2.3.16.3");
|
||||
DependencyVersion version = new DependencyVersion("2.3.16.4");
|
||||
//true tests
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("1.2");
|
||||
version = new DependencyVersion("2.3");
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
//false tests
|
||||
version = new DependencyVersion("1.2.2.5");
|
||||
version = new DependencyVersion("2.3.16.1");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("2");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
@@ -165,6 +165,14 @@ public class DependencyVersionTest {
|
||||
version = new DependencyVersion("1.2.3.1");
|
||||
assertEquals(-1, instance.compareTo(version));
|
||||
|
||||
instance = new DependencyVersion("1.0.1n");
|
||||
version = new DependencyVersion("1.0.1m");
|
||||
assertEquals(1, instance.compareTo(version));
|
||||
version = new DependencyVersion("1.0.1n");
|
||||
assertEquals(0, instance.compareTo(version));
|
||||
version = new DependencyVersion("1.0.1o");
|
||||
assertEquals(-1, instance.compareTo(version));
|
||||
|
||||
DependencyVersion[] dv = new DependencyVersion[7];
|
||||
dv[0] = new DependencyVersion("2.1.3");
|
||||
dv[1] = new DependencyVersion("2.1.3.r2");
|
||||
|
||||
@@ -54,13 +54,13 @@ public class DependencyVersionUtilTest {
|
||||
* Test of parseVersion method, of class DependencyVersionUtil.
|
||||
*/
|
||||
@Test
|
||||
public void testParseVersionFromFileName() {
|
||||
public void testParseVersion() {
|
||||
final String[] fileName = {"something-0.9.5.jar", "lib2-1.1.jar", "lib1.5r4-someflag-R26.jar",
|
||||
"lib-1.2.5-dev-20050313.jar", "testlib_V4.4.0.jar", "lib-core-2.0.0-RC1-SNAPSHOT.jar",
|
||||
"lib-jsp-2.0.1_R114940.jar", "dev-api-2.3.11_R121413.jar", "lib-api-3.7-SNAPSHOT.jar",
|
||||
"-", "", "1.3-beta", "6"};
|
||||
"-", "", "1.3-beta", "6", "openssl1.0.1c", "jsf-impl-2.2.8-02.jar"};
|
||||
final String[] expResult = {"0.9.5", "1.1", "1.5.r4", "1.2.5", "4.4.0", "2.0.0.rc1",
|
||||
"2.0.1.r114940", "2.3.11.r121413", "3.7", "-", null, "1.3.beta", "6"};
|
||||
"2.0.1.r114940", "2.3.11.r121413", "3.7", "-", null, "1.3.beta", "6", "1.0.1c", "2.2.8.02"};
|
||||
|
||||
for (int i = 0; i < fileName.length; i++) {
|
||||
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName[i]);
|
||||
|
||||
@@ -47,11 +47,16 @@ cpe.meta.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-di
|
||||
cve.url.modified.validfordays=7
|
||||
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2014
|
||||
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
#cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
#cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
|
||||
|
||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||
analyzer.nexus.enabled=true
|
||||
@@ -59,3 +64,7 @@ analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||
# are configured
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
# the URL for searching search.maven.org for SHA-1 and whether it's enabled
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<filePath>c:\path\to\some.jar</filePath>
|
||||
<cpe>cpe:/a:csv:csv:1.0</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses any jboss:jboss cpe for any test.jar in any directory.
|
||||
]]></notes>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-jenkins</artifactId>
|
||||
|
||||
@@ -22,7 +22,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* This file is part of dependency-check-maven.
|
||||
*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.Component;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.reporting.MavenReport;
|
||||
import org.apache.maven.reporting.MavenReportException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is an abstract reporting mojo that enables report aggregation. Some of the code in the this class was copied
|
||||
* from the CoberturaReportMojo (http://mojo.codehaus.org/cobertura-maven-plugin/, version 2.6). The authors of the
|
||||
* CoberturaReportMojo were <a href="will.gwaltney@sas.com">Will Gwaltney</a> and
|
||||
* <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>. There working example of how to do report aggregation was
|
||||
* invaluable.</p>
|
||||
* <p>
|
||||
* An important point about using this abstract class is that it is intended for one to write some form of serialized
|
||||
* data (via the {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#writeDataFile() }; note that the
|
||||
* <code>writeDataFile()</code> function is called automatically after either {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeNonAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } or {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } are called. When <code>executeAggregateReport()</code> is implemented, one can call {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#getChildDataFiles()
|
||||
* } to obtain a list of the data files to aggregate.</p>
|
||||
*
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class ReportAggregationMojo extends AbstractMojo implements MavenReport {
|
||||
|
||||
/**
|
||||
* The Maven Project Object.
|
||||
*/
|
||||
@Component
|
||||
private MavenProject project;
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportAggregationMojo.class.getName());
|
||||
|
||||
/**
|
||||
* List of Maven project of the current build
|
||||
*/
|
||||
@Parameter(readonly = true, required = true, property = "reactorProjects")
|
||||
private List<MavenProject> reactorProjects;
|
||||
|
||||
/**
|
||||
* Generate aggregate reports in multi-module projects.
|
||||
*/
|
||||
@Parameter(property = "aggregate", defaultValue = "false")
|
||||
private boolean aggregate;
|
||||
|
||||
/**
|
||||
* Sets whether or not the external report format should be used.
|
||||
*/
|
||||
@Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
|
||||
private String dataFileName;
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check report. This generally maps to
|
||||
* "target/site".
|
||||
*/
|
||||
@Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true)
|
||||
private File reportOutputDirectory;
|
||||
|
||||
/**
|
||||
* Sets the Reporting output directory.
|
||||
*
|
||||
* @param directory the output directory
|
||||
*/
|
||||
@Override
|
||||
public void setReportOutputDirectory(File directory) {
|
||||
reportOutputDirectory = directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory.
|
||||
*
|
||||
* @return the output directory
|
||||
*/
|
||||
@Override
|
||||
public File getReportOutputDirectory() {
|
||||
return reportOutputDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory for the given project.
|
||||
*
|
||||
* @param project the Maven project to get the output directory for
|
||||
* @return the output directory for the given project
|
||||
*/
|
||||
public File getReportOutputDirectory(MavenProject project) {
|
||||
final Object o = project.getContextValue(getOutputDirectoryContextKey());
|
||||
if (o != null && o instanceof File) {
|
||||
return (File) o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is an external report. This method always returns true.
|
||||
*
|
||||
* @return <code>true</code>
|
||||
*/
|
||||
@Override
|
||||
public final boolean isExternalReport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The collection of child projects.
|
||||
*/
|
||||
private final Map<MavenProject, Set<MavenProject>> projectChildren = new HashMap<MavenProject, Set<MavenProject>>();
|
||||
|
||||
/**
|
||||
* Called before execute; allows for any setup that is needed. If this is overridden you must call
|
||||
* </code>super.preExecute()</code>.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void preExecute() throws MojoExecutionException, MojoFailureException {
|
||||
buildAggregateInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mojo is being executed.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected abstract void performExecute() throws MojoExecutionException, MojoFailureException;
|
||||
|
||||
/**
|
||||
* Runs after the mojo has executed. This implementation will call <code>writeDataFile()</code>. As such, it is
|
||||
* important that if this method is overriden that <code>super.postExecute()</code> is called.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void postExecute() throws MojoExecutionException, MojoFailureException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key
|
||||
* is used in the <code>MavenProject.(set|get)ContextValue</code>.
|
||||
*
|
||||
* @return the key used to store the path to the data file
|
||||
*/
|
||||
protected String getDataFileContextKey() {
|
||||
return "dependency-check-path-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the output directory. When generating the report in the
|
||||
* <code>executeAggregateReport()</code> the output directory should be obtained by using this key.
|
||||
*
|
||||
* @return the key used to store the path to the output directory
|
||||
*/
|
||||
protected String getOutputDirectoryContextKey() {
|
||||
return "dependency-output-dir-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called by Maven to execute the mojo.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
public final void execute() throws MojoExecutionException, MojoFailureException {
|
||||
try {
|
||||
preExecute();
|
||||
performExecute();
|
||||
} finally {
|
||||
postExecute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs prior to the site report generation.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void preGenerate() throws MavenReportException {
|
||||
buildAggregateInfo();
|
||||
|
||||
project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes after the site report has been generated.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void postGenerate() throws MavenReportException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the non aggregate report.
|
||||
*
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeNonAggregateReport(Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the aggregate Site Report.
|
||||
*
|
||||
* @param project the maven project used to generate the aggregate report
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeAggregateReport(MavenProject project, Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
* @deprecated use {@link #generate(org.apache.maven.doxia.sink.Sink, java.util.Locale) instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
|
||||
generate((Sink) sink, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
public final void generate(Sink sink, Locale locale) throws MavenReportException {
|
||||
try {
|
||||
preGenerate();
|
||||
if (canGenerateNonAggregateReport()) {
|
||||
executeNonAggregateReport(locale);
|
||||
}
|
||||
|
||||
if (canGenerateAggregateReport()) {
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
if (!isMultiModule(proj)) {
|
||||
continue;
|
||||
}
|
||||
executeAggregateReport(proj, locale);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
postGenerate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo can generate a non-aggregate report for this project.
|
||||
*
|
||||
* @return <code>true</code> if a non-aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateNonAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns whether or not we can generate any aggregate reports at this time.
|
||||
*
|
||||
* @return <code>true</code> if an aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns the name of the data file that contains the serialized data.
|
||||
*
|
||||
* @return the name of the data file that contains the serialized data
|
||||
*/
|
||||
protected String getDataFileName() {
|
||||
return dataFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data file to disk in the target directory.
|
||||
*
|
||||
* @return the File object referencing the data file that was written
|
||||
*/
|
||||
protected abstract File writeDataFile();
|
||||
|
||||
/**
|
||||
* Collects the information needed for building aggregate reports.
|
||||
*/
|
||||
private void buildAggregateInfo() {
|
||||
// build parent-child map
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
Set<MavenProject> depList = projectChildren.get(proj.getParent());
|
||||
if (depList == null) {
|
||||
depList = new HashSet<MavenProject>();
|
||||
projectChildren.put(proj.getParent(), depList);
|
||||
}
|
||||
depList.add(proj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren() {
|
||||
return getAllChildren(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @param parentProject the parent project to collect the child project references
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren(MavenProject parentProject) {
|
||||
final Set<MavenProject> children = projectChildren.get(parentProject);
|
||||
if (children == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<MavenProject> result = new ArrayList<MavenProject>();
|
||||
for (MavenProject child : children) {
|
||||
if (isMultiModule(child)) {
|
||||
result.addAll(getAllChildren(child));
|
||||
} else {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of data files that were produced by the direct children of the given MavenProject.
|
||||
*
|
||||
* @param project the Maven project to obtain the child data files from
|
||||
* @return a list of the data files
|
||||
*/
|
||||
protected List<File> getAllChildDataFiles(MavenProject project) {
|
||||
final List<MavenProject> children = getAllChildren(project);
|
||||
return getDataFiles(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any existing output files from the given list of projects.
|
||||
*
|
||||
* @param projects the list of projects to obtain the output files from
|
||||
* @return a list of output files
|
||||
*/
|
||||
protected List<File> getDataFiles(List<MavenProject> projects) {
|
||||
final List<File> files = new ArrayList<File>();
|
||||
for (MavenProject proj : projects) {
|
||||
final Object path = project.getContextValue(getDataFileContextKey());
|
||||
if (path == null) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - aggregate data file was not generated",
|
||||
proj.getName());
|
||||
LOGGER.warning(msg);
|
||||
} else {
|
||||
final File outputFile = new File((String) path);
|
||||
if (outputFile.exists()) {
|
||||
files.add(outputFile);
|
||||
} else {
|
||||
if (!isMultiModule(project)) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - missing data file '%s'",
|
||||
proj.getName(), outputFile.getPath());
|
||||
LOGGER.warning(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the project has pom packaging
|
||||
*
|
||||
* @param mavenProject Project to test
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule(MavenProject mavenProject) {
|
||||
return "pom".equals(mavenProject.getPackaging());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the current project has pom packaging
|
||||
*
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule() {
|
||||
return isMultiModule(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current project is the last project in a multi-module build. If the maven build is not a
|
||||
* multi-module project then this will always return true.
|
||||
*
|
||||
* @return <code>true</code> if the current project is the last project in a multi-module build; otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
protected boolean isLastProject() {
|
||||
return project.equals(reactorProjects.get(reactorProjects.size() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo is configured to perform report aggregation.
|
||||
*
|
||||
* @return <code>true</code> if report aggregation is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
public boolean isAggregate() {
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the current project. This method is used instead of auto-binding the project via component
|
||||
* annotation in concrete implementations of this. If the child has a <code>@Component MavenProject project;</code>
|
||||
* defined then the abstract class (i.e. this class) will not have access to the current project (just the way Maven
|
||||
* works with the binding).
|
||||
*
|
||||
* @return returns a reference to the current project
|
||||
*/
|
||||
protected MavenProject getProject() {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* This file is part of dependency-check-maven.
|
||||
*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
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.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Reference;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
|
||||
/**
|
||||
* A utility class that encapsulates the report generation for dependency-check-maven.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
final class ReportingUtil {
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportingUtil.class.getName());
|
||||
|
||||
/**
|
||||
* Empty private constructor for this utility class.
|
||||
*/
|
||||
private ReportingUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the reports for a given dependency-check engine.
|
||||
*
|
||||
* @param engine a dependency-check engine
|
||||
* @param outDirectory the directory to write the reports to
|
||||
* @param projectName the name of the project that a report is being generated for
|
||||
* @param format the format of the report to generate
|
||||
*/
|
||||
static void generateExternalReports(Engine engine, File outDirectory, String projectName, String format) {
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator r = new ReportGenerator(projectName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
try {
|
||||
r.generateReports(outDirectory.getCanonicalPath(), format);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a dependency-check report using the Maven Site format.
|
||||
*
|
||||
* @param engine the engine used to scan the dependencies
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
static void generateMavenSiteReport(final Engine engine, Sink sink, String projectName) {
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
|
||||
writeSiteReportHeader(sink, projectName);
|
||||
writeSiteReportTOC(sink, dependencies);
|
||||
|
||||
int cnt = 0;
|
||||
for (Dependency d : dependencies) {
|
||||
writeSiteReportDependencyHeader(sink, d);
|
||||
cnt = writeSiteReportDependencyEvidenceUsed(d, cnt, sink);
|
||||
cnt = writeSiteReportDependencyRelatedDependencies(d, cnt, sink);
|
||||
writeSiteReportDependencyIdentifiers(d, sink);
|
||||
writeSiteReportDependencyVulnerabilities(d, sink, cnt);
|
||||
}
|
||||
sink.body_();
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="various writeXXXXX methods to generate the Site Report">
|
||||
/**
|
||||
* Writes the vulnerabilities to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
*/
|
||||
private static void writeSiteReportDependencyVulnerabilities(Dependency d, Sink sink, int collapsibleHeaderCount) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getVulnerabilities() != null && !d.getVulnerabilities().isEmpty()) {
|
||||
for (Vulnerability v : d.getVulnerabilities()) {
|
||||
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + URLEncoder.encode(v.getName(), "US-ASCII"));
|
||||
sink.text(v.getName());
|
||||
sink.link_();
|
||||
sink.bold_();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(v.getName());
|
||||
sink.bold_();
|
||||
sink.lineBreak();
|
||||
sink.text("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + v.getName());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text("Severity: ");
|
||||
if (v.getCvssScore() < 4.0) {
|
||||
sink.text("Low");
|
||||
} else {
|
||||
if (v.getCvssScore() >= 7.0) {
|
||||
sink.text("High");
|
||||
} else {
|
||||
sink.text("Medium");
|
||||
}
|
||||
}
|
||||
sink.lineBreak();
|
||||
sink.text("CVSS Score: " + v.getCvssScore());
|
||||
if (v.getCwe() != null && !v.getCwe().isEmpty()) {
|
||||
sink.lineBreak();
|
||||
sink.text("CWE: ");
|
||||
sink.text(v.getCwe());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text(v.getDescription());
|
||||
if (v.getReferences() != null && !v.getReferences().isEmpty()) {
|
||||
sink.list();
|
||||
for (Reference ref : v.getReferences()) {
|
||||
sink.listItem();
|
||||
sink.text(ref.getSource());
|
||||
sink.text(" - ");
|
||||
sink.link(ref.getUrl());
|
||||
sink.text(ref.getName());
|
||||
sink.link_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.paragraph_();
|
||||
if (v.getVulnerableSoftware() != null && !v.getVulnerableSoftware().isEmpty()) {
|
||||
sink.paragraph();
|
||||
|
||||
cnt += 1;
|
||||
sink.rawText("Vulnerable Software <a href=\"javascript:toggleElement(this, 'vulnSoft" + cnt + "')\">[-]</a>");
|
||||
sink.rawText("<div id=\"vulnSoft" + cnt + "\" style=\"display:block\">");
|
||||
sink.list();
|
||||
for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
|
||||
sink.listItem();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + URLEncoder.encode(vs.getName(), "US-ASCII"));
|
||||
sink.text(vs.getName());
|
||||
sink.link_();
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(vs.getName());
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
sink.text(" (http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + vs.getName() + ")");
|
||||
}
|
||||
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the identifiers to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyIdentifiers(Dependency d, Sink sink) {
|
||||
if (d.getIdentifiers() != null && !d.getIdentifiers().isEmpty()) {
|
||||
sink.sectionTitle4();
|
||||
sink.text("Identifiers");
|
||||
sink.sectionTitle4_();
|
||||
sink.list();
|
||||
for (Identifier i : d.getIdentifiers()) {
|
||||
sink.listItem();
|
||||
sink.text(i.getType());
|
||||
sink.text(": ");
|
||||
if (i.getUrl() != null && i.getUrl().length() > 0) {
|
||||
sink.link(i.getUrl());
|
||||
sink.text(i.getValue());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(i.getValue());
|
||||
}
|
||||
if (i.getDescription() != null && i.getDescription().length() > 0) {
|
||||
sink.lineBreak();
|
||||
sink.text(i.getDescription());
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the related dependencies to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyRelatedDependencies(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getRelatedDependencies() != null && !d.getRelatedDependencies().isEmpty()) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Related Dependencies <a href=\"javascript:toggleElement(this, 'related" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"related" + cnt + "\" style=\"display:none\">");
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
sink.listItem();
|
||||
sink.text(r.getFileName());
|
||||
sink.list();
|
||||
writeListItem(sink, "File Path: " + r.getFilePath());
|
||||
writeListItem(sink, "SHA1: " + r.getSha1sum());
|
||||
writeListItem(sink, "MD5: " + r.getMd5sum());
|
||||
sink.list_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the evidence used to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyEvidenceUsed(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
final Set<Evidence> evidence = d.getEvidenceForDisplay();
|
||||
if (evidence != null && evidence.size() > 0) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Evidence Collected <a href=\"javascript:toggleElement(this, 'evidence" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"evidence" + cnt + "\" style=\"display:none\">");
|
||||
sink.table();
|
||||
sink.tableRow();
|
||||
writeTableHeaderCell(sink, "Source");
|
||||
writeTableHeaderCell(sink, "Name");
|
||||
writeTableHeaderCell(sink, "Value");
|
||||
sink.tableRow_();
|
||||
for (Evidence e : evidence) {
|
||||
sink.tableRow();
|
||||
writeTableCell(sink, e.getSource());
|
||||
writeTableCell(sink, e.getName());
|
||||
writeTableCell(sink, e.getValue());
|
||||
sink.tableRow_();
|
||||
}
|
||||
sink.table_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the dependency header to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyHeader(Sink sink, Dependency d) {
|
||||
sink.sectionTitle2();
|
||||
sink.anchor("sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.anchor_();
|
||||
sink.sectionTitle2_();
|
||||
if (d.getDescription() != null && d.getDescription().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("Description: ");
|
||||
sink.bold_();
|
||||
sink.text(d.getDescription());
|
||||
sink.paragraph_();
|
||||
}
|
||||
if (d.getLicense() != null && d.getLicense().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("License: ");
|
||||
sink.bold_();
|
||||
if (d.getLicense().startsWith("http://") && !d.getLicense().contains(" ")) {
|
||||
sink.link(d.getLicense());
|
||||
sink.text(d.getLicense());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(d.getLicense());
|
||||
}
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list item to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeListItem(Sink sink, String text) {
|
||||
sink.listItem();
|
||||
sink.text(text);
|
||||
sink.listItem_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableCell(Sink sink, String text) {
|
||||
sink.tableCell();
|
||||
sink.text(text);
|
||||
sink.tableCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table header cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableHeaderCell(Sink sink, String text) {
|
||||
sink.tableHeaderCell();
|
||||
sink.text(text);
|
||||
sink.tableHeaderCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the TOC for the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param dependencies the dependencies that are being reported on
|
||||
*/
|
||||
private static void writeSiteReportTOC(Sink sink, final List<Dependency> dependencies) {
|
||||
sink.list();
|
||||
for (Dependency d : dependencies) {
|
||||
sink.listItem();
|
||||
sink.link("#sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.link_();
|
||||
if (!d.getVulnerabilities().isEmpty()) {
|
||||
sink.rawText(" <font style=\"color:red\">•</font>");
|
||||
}
|
||||
if (!d.getRelatedDependencies().isEmpty()) {
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
writeListItem(sink, r.getFileName());
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the site report header.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
private static void writeSiteReportHeader(Sink sink, String projectName) {
|
||||
sink.head();
|
||||
sink.title();
|
||||
sink.text("Dependency-Check Report: " + projectName);
|
||||
sink.title_();
|
||||
sink.head_();
|
||||
sink.body();
|
||||
sink.rawText("<script type=\"text/javascript\">");
|
||||
sink.rawText("function toggleElement(el, targetId) {");
|
||||
sink.rawText("if (el.innerText == '[+]') {");
|
||||
sink.rawText(" el.innerText = '[-]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='block';");
|
||||
sink.rawText("} else {");
|
||||
sink.rawText(" el.innerText = '[+]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='none';");
|
||||
sink.rawText("}");
|
||||
|
||||
sink.rawText("}");
|
||||
sink.rawText("</script>");
|
||||
sink.section1();
|
||||
sink.sectionTitle1();
|
||||
sink.text("Project: " + projectName);
|
||||
sink.sectionTitle1_();
|
||||
sink.date();
|
||||
final Date now = new Date();
|
||||
sink.text(DateFormat.getDateTimeInstance().format(now));
|
||||
sink.date_();
|
||||
sink.section1_();
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
}
|
||||
@@ -4,8 +4,8 @@ The following properties can be set on the dependency-check-maven plugin.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
aggregate | Sets whether report aggregation will be performed for multi-module site reports. This option only affects the report generation when configured within the reporting section. | false
|
||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
||||
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
||||
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
|
||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
@@ -23,38 +23,44 @@ Note, that specific analyzers will automatically disable themselves if no file
|
||||
types that they support are detected - so specifically disabling them may not
|
||||
be needed.
|
||||
|
||||
Property | Description | Default Value
|
||||
------------------------|------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
Property | Description | Default Value
|
||||
------------------------|---------------------------------------------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus Pro Server URL. If not set the Nexus Analyzer will be disabled. |
|
||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems |
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
||||
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|-------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2. | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year. | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
connectionTimeout | Sets the URL Connection Timeout used when downloading external data. |
|
||||
dataDirectory | Sets the data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||
connectionString | The connection string used to connect to the database. |
|
||||
databaseUser | The username used when connecting to the database. |
|
||||
databasePassword | The password used when connecting to the database. |
|
||||
|
||||
metaFileName | Sets the name of the file to use for storing the metadata about the project. | dependency-check.ser
|
||||
|
||||
Proxy Configuration
|
||||
====================
|
||||
Use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to configure a proxy server.
|
||||
Use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to configure a proxy server. If multiple proxies
|
||||
are configured in the Maven settings file you must tell dependency-check which proxy to use with the following property:
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------------------|------------------
|
||||
mavenSettingsProxyId | The id for the proxy, configured via settings.xml, that dependency-check should use. |
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ Create the DependencyCheck-report.html in the target directory
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -41,11 +43,48 @@ Create the DependencyCheck-report.html in the target directory
|
||||
```
|
||||
|
||||
$H$H$H Example 2:
|
||||
Create an aggregated dependency-check report within the site
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<reporting>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration>
|
||||
<aggregate>true</aggregate>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>check</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
</plugin>
|
||||
...
|
||||
</plugins>
|
||||
...
|
||||
</reporting>
|
||||
...
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 3:
|
||||
Create the DependencyCheck-report.html and fail the build for CVSS greater then 8
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -71,44 +110,14 @@ Create the DependencyCheck-report.html and fail the build for CVSS greater then
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 3:
|
||||
Create the dependency-check report within the site
|
||||
|
||||
```xml
|
||||
<project>
|
||||
<build>
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<configuration>
|
||||
<reportPlugins>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration>
|
||||
<externalReport>false</externalReport>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
...
|
||||
</plugins>
|
||||
...
|
||||
</build>
|
||||
...
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 4:
|
||||
Create the DependencyCheck-report.html and skip artifacts no bundled in distribution (Provided and Runtime scope)
|
||||
Create the DependencyCheck-report.html and skip artifacts not bundled in distribution (Provided and Runtime scope)
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -140,7 +149,9 @@ Create the DependencyCheck-report.html and use internal mirroring of CVE content
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
|
||||
@@ -21,7 +21,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
@@ -249,6 +249,9 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/org/owasp/dependencycheck/org/apache/**/*.java</exclude>
|
||||
</excludes>
|
||||
<rulesets>
|
||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||
@@ -261,6 +264,9 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.owasp.dependencycheck.utils.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant;
|
||||
|
||||
/**
|
||||
* Signals an error condition during a build
|
||||
*/
|
||||
public class BuildException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -5419014565354664240L;
|
||||
|
||||
/** Location in the build file where the exception occurred */
|
||||
private Location location = Location.UNKNOWN_LOCATION;
|
||||
|
||||
/**
|
||||
* Constructs a build exception with no descriptive information.
|
||||
*/
|
||||
public BuildException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given descriptive message.
|
||||
*
|
||||
* @param message A description of or information about the exception.
|
||||
* Should not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given message and exception as
|
||||
* a root cause.
|
||||
*
|
||||
* @param message A description of or information about the exception.
|
||||
* Should not be <code>null</code> unless a cause is specified.
|
||||
* @param cause The exception that might have caused this one.
|
||||
* May be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given message and exception as
|
||||
* a root cause and a location in a file.
|
||||
*
|
||||
* @param msg A description of or information about the exception.
|
||||
* Should not be <code>null</code> unless a cause is specified.
|
||||
* @param cause The exception that might have caused this one.
|
||||
* May be <code>null</code>.
|
||||
* @param location The location in the project file where the error
|
||||
* occurred. Must not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String msg, Throwable cause, Location location) {
|
||||
this(msg, cause);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given exception as a root cause.
|
||||
*
|
||||
* @param cause The exception that might have caused this one.
|
||||
* Should not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given descriptive message and a
|
||||
* location in a file.
|
||||
*
|
||||
* @param message A description of or information about the exception.
|
||||
* Should not be <code>null</code>.
|
||||
* @param location The location in the project file where the error
|
||||
* occurred. Must not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String message, Location location) {
|
||||
super(message);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given exception as
|
||||
* a root cause and a location in a file.
|
||||
*
|
||||
* @param cause The exception that might have caused this one.
|
||||
* Should not be <code>null</code>.
|
||||
* @param location The location in the project file where the error
|
||||
* occurred. Must not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(Throwable cause, Location location) {
|
||||
this(cause);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nested exception, if any.
|
||||
*
|
||||
* @return the nested exception, or <code>null</code> if no
|
||||
* exception is associated with this one
|
||||
* @deprecated Use {@link #getCause} instead.
|
||||
*/
|
||||
public Throwable getException() {
|
||||
return getCause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the error and the error message.
|
||||
*
|
||||
* @return the location of the error and the error message
|
||||
*/
|
||||
public String toString() {
|
||||
return location.toString() + getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file location where the error occurred.
|
||||
*
|
||||
* @param location The file location where the error occurred.
|
||||
* Must not be <code>null</code>.
|
||||
*/
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file location where the error occurred.
|
||||
*
|
||||
* @return the file location where the error occurred.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* An interface used to describe the actions required of any type of
|
||||
* directory scanner.
|
||||
*
|
||||
*/
|
||||
public interface FileScanner {
|
||||
/**
|
||||
* Adds default exclusions to the current exclusions set.
|
||||
*/
|
||||
void addDefaultExcludes();
|
||||
|
||||
/**
|
||||
* Returns the base directory to be scanned.
|
||||
* This is the directory which is scanned recursively.
|
||||
*
|
||||
* @return the base directory to be scanned
|
||||
*/
|
||||
File getBasedir();
|
||||
|
||||
/**
|
||||
* Returns the names of the directories which matched at least one of the
|
||||
* include patterns and at least one of the exclude patterns.
|
||||
* The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the directories which matched at least one of the
|
||||
* include patterns and at least one of the exclude patterns.
|
||||
*/
|
||||
String[] getExcludedDirectories();
|
||||
|
||||
/**
|
||||
* Returns the names of the files which matched at least one of the
|
||||
* include patterns and at least one of the exclude patterns.
|
||||
* The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the files which matched at least one of the
|
||||
* include patterns and at least one of the exclude patterns.
|
||||
*
|
||||
*/
|
||||
String[] getExcludedFiles();
|
||||
|
||||
/**
|
||||
* Returns the names of the directories which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
* The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the directories which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
*/
|
||||
String[] getIncludedDirectories();
|
||||
|
||||
/**
|
||||
* Returns the names of the files which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
* The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the files which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
*/
|
||||
String[] getIncludedFiles();
|
||||
|
||||
/**
|
||||
* Returns the names of the directories which matched none of the include
|
||||
* patterns. The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the directories which matched none of the include
|
||||
* patterns.
|
||||
*/
|
||||
String[] getNotIncludedDirectories();
|
||||
|
||||
/**
|
||||
* Returns the names of the files which matched none of the include
|
||||
* patterns. The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the files which matched none of the include
|
||||
* patterns.
|
||||
*/
|
||||
String[] getNotIncludedFiles();
|
||||
|
||||
/**
|
||||
* Scans the base directory for files which match at least one include
|
||||
* pattern and don't match any exclude patterns.
|
||||
*
|
||||
* @exception IllegalStateException if the base directory was set
|
||||
* incorrectly (i.e. if it is <code>null</code>, doesn't exist,
|
||||
* or isn't a directory).
|
||||
*/
|
||||
void scan() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Sets the base directory to be scanned. This is the directory which is
|
||||
* scanned recursively. All '/' and '\' characters should be replaced by
|
||||
* <code>File.separatorChar</code>, so the separator used need not match
|
||||
* <code>File.separatorChar</code>.
|
||||
*
|
||||
* @param basedir The base directory to scan.
|
||||
* Must not be <code>null</code>.
|
||||
*/
|
||||
void setBasedir(String basedir);
|
||||
|
||||
/**
|
||||
* Sets the base directory to be scanned. This is the directory which is
|
||||
* scanned recursively.
|
||||
*
|
||||
* @param basedir The base directory for scanning.
|
||||
* Should not be <code>null</code>.
|
||||
*/
|
||||
void setBasedir(File basedir);
|
||||
|
||||
/**
|
||||
* Sets the list of exclude patterns to use.
|
||||
*
|
||||
* @param excludes A list of exclude patterns.
|
||||
* May be <code>null</code>, indicating that no files
|
||||
* should be excluded. If a non-<code>null</code> list is
|
||||
* given, all elements must be non-<code>null</code>.
|
||||
*/
|
||||
void setExcludes(String[] excludes);
|
||||
|
||||
/**
|
||||
* Sets the list of include patterns to use.
|
||||
*
|
||||
* @param includes A list of include patterns.
|
||||
* May be <code>null</code>, indicating that all files
|
||||
* should be included. If a non-<code>null</code>
|
||||
* list is given, all elements must be
|
||||
* non-<code>null</code>.
|
||||
*/
|
||||
void setIncludes(String[] includes);
|
||||
|
||||
/**
|
||||
* Sets whether or not the file system should be regarded as case sensitive.
|
||||
*
|
||||
* @param isCaseSensitive whether or not the file system should be
|
||||
* regarded as a case sensitive one
|
||||
*/
|
||||
void setCaseSensitive(boolean isCaseSensitive);
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.util.FileUtils;
|
||||
import org.xml.sax.Locator;
|
||||
|
||||
/**
|
||||
* Stores the location of a piece of text within a file (file name,
|
||||
* line number and column number). Note that the column number is
|
||||
* currently ignored.
|
||||
*
|
||||
*/
|
||||
public class Location implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Name of the file. */
|
||||
private final String fileName;
|
||||
/** Line number within the file. */
|
||||
private final int lineNumber;
|
||||
/** Column number within the file. */
|
||||
private final int columnNumber;
|
||||
|
||||
/** Location to use when one is needed but no information is available */
|
||||
public static final Location UNKNOWN_LOCATION = new Location();
|
||||
|
||||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
|
||||
|
||||
/**
|
||||
* Creates an "unknown" location.
|
||||
*/
|
||||
private Location() {
|
||||
this(null, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a location consisting of a file name but no line number or
|
||||
* column number.
|
||||
*
|
||||
* @param fileName The name of the file. May be <code>null</code>,
|
||||
* in which case the location is equivalent to
|
||||
* {@link #UNKNOWN_LOCATION UNKNOWN_LOCATION}.
|
||||
*/
|
||||
public Location(String fileName) {
|
||||
this(fileName, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a location from the SAX locator using the system ID as
|
||||
* the filename.
|
||||
*
|
||||
* @param loc Must not be <code>null</code>.
|
||||
*
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public Location(Locator loc) {
|
||||
this(loc.getSystemId(), loc.getLineNumber(), loc.getColumnNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a location consisting of a file name, line number and
|
||||
* column number.
|
||||
*
|
||||
* @param fileName The name of the file. May be <code>null</code>,
|
||||
* in which case the location is equivalent to
|
||||
* {@link #UNKNOWN_LOCATION UNKNOWN_LOCATION}.
|
||||
*
|
||||
* @param lineNumber Line number within the file. Use 0 for unknown
|
||||
* positions within a file.
|
||||
* @param columnNumber Column number within the line.
|
||||
*/
|
||||
public Location(String fileName, int lineNumber, int columnNumber) {
|
||||
if (fileName != null && fileName.startsWith("file:")) {
|
||||
this.fileName = FILE_UTILS.fromURI(fileName);
|
||||
} else {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
this.lineNumber = lineNumber;
|
||||
this.columnNumber = columnNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the filename portion of the location
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the line number
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column number
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public int getColumnNumber() {
|
||||
return columnNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name, line number, a colon and a trailing space.
|
||||
* An error message can be appended easily. For unknown locations, an
|
||||
* empty string is returned.
|
||||
*
|
||||
* @return a String of the form <code>"fileName:lineNumber: "</code>
|
||||
* if both file name and line number are known,
|
||||
* <code>"fileName: "</code> if only the file name is known,
|
||||
* and the empty string for unknown locations.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
if (fileName != null) {
|
||||
buf.append(fileName);
|
||||
|
||||
if (lineNumber != 0) {
|
||||
buf.append(":");
|
||||
buf.append(lineNumber);
|
||||
}
|
||||
|
||||
buf.append(": ");
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality operation.
|
||||
* @param other the object to compare to.
|
||||
* @return true if the other object contains the same information
|
||||
* as this object.
|
||||
* @since Ant 1.6.3
|
||||
*/
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(other.getClass() == getClass())) {
|
||||
return false;
|
||||
}
|
||||
return toString().equals(other.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash operation.
|
||||
* @return a hash code value for this location.
|
||||
* @since Ant 1.6.3
|
||||
*/
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.taskdefs.condition.Os;
|
||||
|
||||
/**
|
||||
* A Path tokenizer takes a path and returns the components that make up
|
||||
* that path.
|
||||
*
|
||||
* The path can use path separators of either ':' or ';' and file separators
|
||||
* of either '/' or '\'.
|
||||
*
|
||||
*/
|
||||
public class PathTokenizer {
|
||||
/**
|
||||
* A tokenizer to break the string up based on the ':' or ';' separators.
|
||||
*/
|
||||
private StringTokenizer tokenizer;
|
||||
|
||||
/**
|
||||
* A String which stores any path components which have been read ahead
|
||||
* due to DOS filesystem compensation.
|
||||
*/
|
||||
private String lookahead = null;
|
||||
|
||||
/**
|
||||
* A boolean that determines if we are running on Novell NetWare, which
|
||||
* exhibits slightly different path name characteristics (multi-character
|
||||
* volume / drive names)
|
||||
*/
|
||||
private boolean onNetWare = Os.isFamily("netware");
|
||||
|
||||
/**
|
||||
* Flag to indicate whether or not we are running on a platform with a
|
||||
* DOS style filesystem
|
||||
*/
|
||||
private boolean dosStyleFilesystem;
|
||||
|
||||
/**
|
||||
* Constructs a path tokenizer for the specified path.
|
||||
*
|
||||
* @param path The path to tokenize. Must not be <code>null</code>.
|
||||
*/
|
||||
public PathTokenizer(String path) {
|
||||
if (onNetWare) {
|
||||
// For NetWare, use the boolean=true mode, so we can use delimiter
|
||||
// information to make a better decision later.
|
||||
tokenizer = new StringTokenizer(path, ":;", true);
|
||||
} else {
|
||||
// on Windows and Unix, we can ignore delimiters and still have
|
||||
// enough information to tokenize correctly.
|
||||
tokenizer = new StringTokenizer(path, ":;", false);
|
||||
}
|
||||
dosStyleFilesystem = File.pathSeparatorChar == ';';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if there are more path elements available from this tokenizer's
|
||||
* path. If this method returns <code>true</code>, then a subsequent call
|
||||
* to nextToken will successfully return a token.
|
||||
*
|
||||
* @return <code>true</code> if and only if there is at least one token
|
||||
* in the string after the current position; <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean hasMoreTokens() {
|
||||
if (lookahead != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return tokenizer.hasMoreTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next path element from this tokenizer.
|
||||
*
|
||||
* @return the next path element from this tokenizer.
|
||||
*
|
||||
* @exception NoSuchElementException if there are no more elements in this
|
||||
* tokenizer's path.
|
||||
*/
|
||||
public String nextToken() throws NoSuchElementException {
|
||||
String token = null;
|
||||
if (lookahead != null) {
|
||||
token = lookahead;
|
||||
lookahead = null;
|
||||
} else {
|
||||
token = tokenizer.nextToken().trim();
|
||||
}
|
||||
|
||||
if (!onNetWare) {
|
||||
if (token.length() == 1 && Character.isLetter(token.charAt(0))
|
||||
&& dosStyleFilesystem
|
||||
&& tokenizer.hasMoreTokens()) {
|
||||
// we are on a dos style system so this path could be a drive
|
||||
// spec. We look at the next token
|
||||
String nextToken = tokenizer.nextToken().trim();
|
||||
if (nextToken.startsWith("\\") || nextToken.startsWith("/")) {
|
||||
// we know we are on a DOS style platform and the next path
|
||||
// starts with a slash or backslash, so we know this is a
|
||||
// drive spec
|
||||
token += ":" + nextToken;
|
||||
} else {
|
||||
// store the token just read for next time
|
||||
lookahead = nextToken;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we are on NetWare, tokenizing is handled a little differently,
|
||||
// due to the fact that NetWare has multiple-character volume names.
|
||||
if (token.equals(File.pathSeparator) || token.equals(":")) {
|
||||
// ignore ";" and get the next token
|
||||
token = tokenizer.nextToken().trim();
|
||||
}
|
||||
|
||||
if (tokenizer.hasMoreTokens()) {
|
||||
// this path could be a drive spec, so look at the next token
|
||||
String nextToken = tokenizer.nextToken().trim();
|
||||
|
||||
// make sure we aren't going to get the path separator next
|
||||
if (!nextToken.equals(File.pathSeparator)) {
|
||||
if (nextToken.equals(":")) {
|
||||
if (!token.startsWith("/") && !token.startsWith("\\")
|
||||
&& !token.startsWith(".")
|
||||
&& !token.startsWith("..")) {
|
||||
// it indeed is a drive spec, get the next bit
|
||||
String oneMore = tokenizer.nextToken().trim();
|
||||
if (!oneMore.equals(File.pathSeparator)) {
|
||||
token += ":" + oneMore;
|
||||
} else {
|
||||
token += ":";
|
||||
lookahead = oneMore;
|
||||
}
|
||||
}
|
||||
// implicit else: ignore the ':' since we have either a
|
||||
// UNIX or a relative path
|
||||
} else {
|
||||
// store the token just read for next time
|
||||
lookahead = nextToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant;
|
||||
|
||||
/**
|
||||
* Base class for components of a project, including tasks and data types. Provides common facilities.
|
||||
*
|
||||
*/
|
||||
public abstract class ProjectComponent implements Cloneable {
|
||||
|
||||
// // CheckStyle:VisibilityModifier OFF - bc
|
||||
// /**
|
||||
// * Project object of this component.
|
||||
// * @deprecated since 1.6.x.
|
||||
// * You should not be directly accessing this variable directly.
|
||||
// * You should access project object via the getProject()
|
||||
// * or setProject() accessor/mutators.
|
||||
// */
|
||||
// protected Project project;
|
||||
/**
|
||||
* Location within the build file of this task definition.
|
||||
*
|
||||
* @deprecated since 1.6.x. You should not be accessing this variable directly. Please use the
|
||||
* {@link #getLocation()} method.
|
||||
*/
|
||||
protected Location location = Location.UNKNOWN_LOCATION;
|
||||
|
||||
/**
|
||||
* Description of this component, if any.
|
||||
*
|
||||
* @deprecated since 1.6.x. You should not be accessing this variable directly.
|
||||
*/
|
||||
protected String description;
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
|
||||
/**
|
||||
* Sole constructor.
|
||||
*/
|
||||
public ProjectComponent() {
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets the project object of this component. This method is used by
|
||||
// * Project when a component is added to it so that the component has
|
||||
// * access to the functions of the project. It should not be used
|
||||
// * for any other purpose.
|
||||
// *
|
||||
// * @param project Project in whose scope this component belongs.
|
||||
// * Must not be <code>null</code>.
|
||||
// */
|
||||
// public void setProject(Project project) {
|
||||
// this.project = project;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns the project to which this component belongs.
|
||||
// *
|
||||
// * @return the components's project.
|
||||
// */
|
||||
// public Project getProject() {
|
||||
// return project;
|
||||
// }
|
||||
/**
|
||||
* Returns the file/location where this task was defined.
|
||||
*
|
||||
* @return the file/location where this task was defined. Should not return <code>null</code>.
|
||||
* Location.UNKNOWN_LOCATION is used for unknown locations.
|
||||
*
|
||||
* @see Location#UNKNOWN_LOCATION
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file/location where this task was defined.
|
||||
*
|
||||
* @param location The file/location where this task was defined. Should not be <code>null</code>--use
|
||||
* Location.UNKNOWN_LOCATION if the location isn't known.
|
||||
*
|
||||
* @see Location#UNKNOWN_LOCATION
|
||||
*/
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a description of the current action. This may be used for logging purposes.
|
||||
*
|
||||
* @param desc Description of the current action. May be <code>null</code>, indicating that no description is
|
||||
* available.
|
||||
*
|
||||
*/
|
||||
public void setDescription(String desc) {
|
||||
description = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description of the current action.
|
||||
*
|
||||
* @return the description of the current action, or <code>null</code> if no description is available.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message with the default (INFO) priority.
|
||||
*
|
||||
* @param msg The message to be logged. Should not be <code>null</code>.
|
||||
*/
|
||||
public void log(String msg) {
|
||||
// log(msg, Project.MSG_INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message with the given priority.
|
||||
*
|
||||
* @param msg The message to be logged. Should not be <code>null</code>.
|
||||
* @param msgLevel the message priority at which this message is to be logged.
|
||||
*/
|
||||
public void log(String msg, int msgLevel) {
|
||||
// if (getProject() != null) {
|
||||
// getProject().log(msg, msgLevel);
|
||||
// } else {
|
||||
// // 'reasonable' default, if the component is used without
|
||||
// // a Project ( for example as a standalone Bean ).
|
||||
// // Most ant components can be used this way.
|
||||
// if (msgLevel <= Project.MSG_INFO) {
|
||||
// System.err.println(msg);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @since Ant 1.7
|
||||
* @return a shallow copy of this projectcomponent.
|
||||
* @throws CloneNotSupportedException does not happen, but is declared to allow subclasses to do so.
|
||||
*/
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
ProjectComponent pc = (ProjectComponent) super.clone();
|
||||
pc.setLocation(getLocation());
|
||||
//pc.setProject(getProject());
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.launch;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.CharacterIterator;
|
||||
import java.text.StringCharacterIterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.util.FileUtils;
|
||||
|
||||
// CheckStyle:LineLengthCheck OFF - urls are long!
|
||||
/**
|
||||
* The Locator is a utility class which is used to find certain items
|
||||
* in the environment.
|
||||
*
|
||||
* It is used at boot time in the launcher, and cannot make use of any of Ant's other classes.
|
||||
*
|
||||
* This is a surprisingly brittle piece of code, and has had lots of bugs filed against it.
|
||||
* {@link <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=42275">running ant off a network share can cause Ant to fail</a>}
|
||||
* {@link <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=8031">use File.toURI().toURL().toExternalForm()</a>}
|
||||
* {@link <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=42222">Locator implementation not encoding URI strings properly: spaces in paths</a>}
|
||||
* It also breaks Eclipse 3.3 Betas
|
||||
* {@link <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=183283">Exception if installation path has spaces</a>}
|
||||
*
|
||||
* Be very careful when making changes to this class, as a break will upset a lot of people.
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
// CheckStyle:LineLengthCheck ON - urls are long!
|
||||
public final class Locator {
|
||||
|
||||
private static final int NIBBLE = 4;
|
||||
private static final int NIBBLE_MASK = 0xF;
|
||||
|
||||
private static final int ASCII_SIZE = 128;
|
||||
|
||||
private static final int BYTE_SIZE = 256;
|
||||
|
||||
private static final int WORD = 16;
|
||||
|
||||
private static final int SPACE = 0x20;
|
||||
private static final int DEL = 0x7F;
|
||||
|
||||
/**
|
||||
* encoding used to represent URIs
|
||||
*/
|
||||
public static final String URI_ENCODING = "UTF-8";
|
||||
// stolen from org.apache.xerces.impl.XMLEntityManager#getUserDir()
|
||||
// of the Xerces-J team
|
||||
// which ASCII characters need to be escaped
|
||||
private static boolean[] gNeedEscaping = new boolean[ASCII_SIZE];
|
||||
// the first hex character if a character needs to be escaped
|
||||
private static char[] gAfterEscaping1 = new char[ASCII_SIZE];
|
||||
// the second hex character if a character needs to be escaped
|
||||
private static char[] gAfterEscaping2 = new char[ASCII_SIZE];
|
||||
private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
/** Error string used when an invalid uri is seen */
|
||||
public static final String ERROR_NOT_FILE_URI
|
||||
= "Can only handle valid file: URIs, not ";
|
||||
|
||||
// initialize the above 3 arrays
|
||||
static {
|
||||
for (int i = 0; i < SPACE; i++) {
|
||||
gNeedEscaping[i] = true;
|
||||
gAfterEscaping1[i] = gHexChs[i >> NIBBLE];
|
||||
gAfterEscaping2[i] = gHexChs[i & NIBBLE_MASK];
|
||||
}
|
||||
gNeedEscaping[DEL] = true;
|
||||
gAfterEscaping1[DEL] = '7';
|
||||
gAfterEscaping2[DEL] = 'F';
|
||||
char[] escChs = {' ', '<', '>', '#', '%', '"', '{', '}',
|
||||
'|', '\\', '^', '~', '[', ']', '`'};
|
||||
int len = escChs.length;
|
||||
char ch;
|
||||
for (int i = 0; i < len; i++) {
|
||||
ch = escChs[i];
|
||||
gNeedEscaping[ch] = true;
|
||||
gAfterEscaping1[ch] = gHexChs[ch >> NIBBLE];
|
||||
gAfterEscaping2[ch] = gHexChs[ch & NIBBLE_MASK];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Not instantiable
|
||||
*/
|
||||
private Locator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the directory or jar file the class has been loaded from.
|
||||
*
|
||||
* @param c the class whose location is required.
|
||||
* @return the file or jar with the class or null if we cannot
|
||||
* determine the location.
|
||||
*
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public static File getClassSource(Class<?> c) {
|
||||
String classResource = c.getName().replace('.', '/') + ".class";
|
||||
return getResourceSource(c.getClassLoader(), classResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the directory or jar a given resource has been loaded from.
|
||||
*
|
||||
* @param c the classloader to be consulted for the source.
|
||||
* @param resource the resource whose location is required.
|
||||
*
|
||||
* @return the file with the resource source or null if
|
||||
* we cannot determine the location.
|
||||
*
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public static File getResourceSource(ClassLoader c, String resource) {
|
||||
if (c == null) {
|
||||
c = Locator.class.getClassLoader();
|
||||
}
|
||||
URL url = null;
|
||||
if (c == null) {
|
||||
url = ClassLoader.getSystemResource(resource);
|
||||
} else {
|
||||
url = c.getResource(resource);
|
||||
}
|
||||
if (url != null) {
|
||||
String u = url.toString();
|
||||
try {
|
||||
if (u.startsWith("jar:file:")) {
|
||||
return new File(fromJarURI(u));
|
||||
} else if (u.startsWith("file:")) {
|
||||
int tail = u.indexOf(resource);
|
||||
String dirName = u.substring(0, tail);
|
||||
return new File(fromURI(dirName));
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
//unable to determine the URI for reasons unknown.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a file path from a <code>file:</code> URI.
|
||||
*
|
||||
* <p>Will be an absolute path if the given URI is absolute.</p>
|
||||
*
|
||||
* <p>Prior to Java 1.4,<!-- TODO is JDK version actually relevant? -->
|
||||
* swallows '%' that are not followed by two characters.</p>
|
||||
*
|
||||
* See <a href="http://www.w3.org/TR/xml11/#dt-sysid">dt-sysid</a>
|
||||
* which makes some mention of how
|
||||
* characters not supported by URI Reference syntax should be escaped.
|
||||
*
|
||||
* @param uri the URI designating a file in the local filesystem.
|
||||
* @return the local file system path for the file.
|
||||
* @throws IllegalArgumentException if the URI is malformed or not a legal file: URL
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public static String fromURI(String uri) {
|
||||
return fromURIJava13(uri);
|
||||
// #buzilla8031: first try Java 1.4.
|
||||
// TODO should use java.net.URI now that we can rely on 1.4...
|
||||
// but check for UNC-related regressions, e.g. #42275
|
||||
// (and remember that \\server\share\file -> file:////server/share/file
|
||||
// rather than -> file://server/share/file as it should;
|
||||
// fixed only in JDK 7's java.nio.file.Path.toUri)
|
||||
// return fromUriJava14(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Java1.4+ code to extract the path from the URI.
|
||||
* @param uri
|
||||
* @return null if a conversion was not possible
|
||||
*/
|
||||
/* currently unused:
|
||||
private static String fromUriJava14(String uri) {
|
||||
// Also check for properly formed URIs. Ant formerly recommended using
|
||||
// nonsense URIs such as "file:./foo.xml" in XML includes. You shouldn't
|
||||
// do that (just "foo.xml" is correct) but for compatibility we special-case
|
||||
// things when the path is not absolute, and fall back to the old parsing behavior.
|
||||
if (uri.startsWith("file:/")) {
|
||||
try {
|
||||
File f = new File(URI.create(encodeURI(uri)));
|
||||
//bug #42227 forgot to decode before returning
|
||||
return decodeUri(f.getAbsolutePath());
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Bad URI, pass this on.
|
||||
// no, this is downgraded to a warning after various
|
||||
// JRE bugs surfaced. Hand off
|
||||
// to our built in code on a failure
|
||||
//throw new IllegalArgumentException(
|
||||
// "Bad URI " + uri + ":" + e.getMessage(), e);
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// Unexpected exception? Should not happen.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param uri uri to expand
|
||||
* @return the decoded URI
|
||||
* @since Ant1.7.1
|
||||
*/
|
||||
private static String fromURIJava13(String uri) {
|
||||
// Fallback method for Java 1.3 or earlier.
|
||||
|
||||
URL url = null;
|
||||
try {
|
||||
url = new URL(uri);
|
||||
} catch (MalformedURLException emYouEarlEx) {
|
||||
// Ignore malformed exception
|
||||
}
|
||||
if (url == null || !("file".equals(url.getProtocol()))) {
|
||||
throw new IllegalArgumentException(ERROR_NOT_FILE_URI + uri);
|
||||
}
|
||||
StringBuffer buf = new StringBuffer(url.getHost());
|
||||
if (buf.length() > 0) {
|
||||
buf.insert(0, File.separatorChar).insert(0, File.separatorChar);
|
||||
}
|
||||
String file = url.getFile();
|
||||
int queryPos = file.indexOf('?');
|
||||
buf.append((queryPos < 0) ? file : file.substring(0, queryPos));
|
||||
|
||||
uri = buf.toString().replace('/', File.separatorChar);
|
||||
|
||||
if (File.pathSeparatorChar == ';' && uri.startsWith("\\") && uri.length() > 2
|
||||
&& Character.isLetter(uri.charAt(1)) && uri.lastIndexOf(':') > -1) {
|
||||
uri = uri.substring(1);
|
||||
}
|
||||
String path = null;
|
||||
try {
|
||||
path = decodeUri(uri);
|
||||
//consider adding the current directory. This is not done when
|
||||
//the path is a UNC name
|
||||
String cwd = System.getProperty("user.dir");
|
||||
int posi = cwd.indexOf(':');
|
||||
boolean pathStartsWithFileSeparator = path.startsWith(File.separator);
|
||||
boolean pathStartsWithUNC = path.startsWith("" + File.separator + File.separator);
|
||||
if ((posi > 0) && pathStartsWithFileSeparator && !pathStartsWithUNC) {
|
||||
path = cwd.substring(0, posi + 1) + path;
|
||||
}
|
||||
} catch (UnsupportedEncodingException exc) {
|
||||
// not sure whether this is clean, but this method is
|
||||
// declared not to throw exceptions.
|
||||
throw new IllegalStateException(
|
||||
"Could not convert URI " + uri + " to path: "
|
||||
+ exc.getMessage());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crack a JAR URI.
|
||||
* This method is public for testing; we may delete it without any warning -it is not part of Ant's stable API.
|
||||
* @param uri uri to expand; contains jar: somewhere in it
|
||||
* @return the decoded URI
|
||||
* @since Ant1.7.1
|
||||
*/
|
||||
public static String fromJarURI(String uri) {
|
||||
int pling = uri.indexOf("!/");
|
||||
String jarName = uri.substring("jar:".length(), pling);
|
||||
return fromURI(jarName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an Uri with % characters.
|
||||
* The URI is escaped
|
||||
* @param uri String with the uri possibly containing % characters.
|
||||
* @return The decoded Uri
|
||||
* @throws UnsupportedEncodingException if UTF-8 is not available
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public static String decodeUri(String uri) throws UnsupportedEncodingException {
|
||||
if (uri.indexOf('%') == -1) {
|
||||
return uri;
|
||||
}
|
||||
ByteArrayOutputStream sb = new ByteArrayOutputStream(uri.length());
|
||||
CharacterIterator iter = new StringCharacterIterator(uri);
|
||||
for (char c = iter.first(); c != CharacterIterator.DONE;
|
||||
c = iter.next()) {
|
||||
if (c == '%') {
|
||||
char c1 = iter.next();
|
||||
if (c1 != CharacterIterator.DONE) {
|
||||
int i1 = Character.digit(c1, WORD);
|
||||
char c2 = iter.next();
|
||||
if (c2 != CharacterIterator.DONE) {
|
||||
int i2 = Character.digit(c2, WORD);
|
||||
sb.write((char) ((i1 << NIBBLE) + i2));
|
||||
}
|
||||
}
|
||||
} else if (c >= 0x0000 && c < 0x0080) {
|
||||
sb.write(c);
|
||||
} else { // #50543
|
||||
byte[] bytes = String.valueOf(c).getBytes(URI_ENCODING);
|
||||
sb.write(bytes, 0, bytes.length);
|
||||
}
|
||||
}
|
||||
return sb.toString(URI_ENCODING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an Uri with % characters.
|
||||
* The URI is escaped
|
||||
* @param path String to encode.
|
||||
* @return The encoded string, according to URI norms
|
||||
* @throws UnsupportedEncodingException if UTF-8 is not available
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public static String encodeURI(String path) throws UnsupportedEncodingException {
|
||||
int i = 0;
|
||||
int len = path.length();
|
||||
int ch = 0;
|
||||
StringBuffer sb = null;
|
||||
for (; i < len; i++) {
|
||||
ch = path.charAt(i);
|
||||
// if it's not an ASCII character, break here, and use UTF-8 encoding
|
||||
if (ch >= ASCII_SIZE) {
|
||||
break;
|
||||
}
|
||||
if (gNeedEscaping[ch]) {
|
||||
if (sb == null) {
|
||||
sb = new StringBuffer(path.substring(0, i));
|
||||
}
|
||||
sb.append('%');
|
||||
sb.append(gAfterEscaping1[ch]);
|
||||
sb.append(gAfterEscaping2[ch]);
|
||||
// record the fact that it's escaped
|
||||
} else if (sb != null) {
|
||||
sb.append((char) ch);
|
||||
}
|
||||
}
|
||||
|
||||
// we saw some non-ascii character
|
||||
if (i < len) {
|
||||
if (sb == null) {
|
||||
sb = new StringBuffer(path.substring(0, i));
|
||||
}
|
||||
// get UTF-8 bytes for the remaining sub-string
|
||||
byte[] bytes = null;
|
||||
byte b;
|
||||
bytes = path.substring(i).getBytes(URI_ENCODING);
|
||||
len = bytes.length;
|
||||
|
||||
// for each byte
|
||||
for (i = 0; i < len; i++) {
|
||||
b = bytes[i];
|
||||
// for non-ascii character: make it positive, then escape
|
||||
if (b < 0) {
|
||||
ch = b + BYTE_SIZE;
|
||||
sb.append('%');
|
||||
sb.append(gHexChs[ch >> NIBBLE]);
|
||||
sb.append(gHexChs[ch & NIBBLE_MASK]);
|
||||
} else if (gNeedEscaping[b]) {
|
||||
sb.append('%');
|
||||
sb.append(gAfterEscaping1[b]);
|
||||
sb.append(gAfterEscaping2[b]);
|
||||
} else {
|
||||
sb.append((char) b);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb == null ? path : sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a File to a URL.
|
||||
* File.toURL() does not encode characters like #.
|
||||
* File.toURI() has been introduced in java 1.4, so
|
||||
* Ant cannot use it (except by reflection) <!-- TODO no longer true -->
|
||||
* FileUtils.toURI() cannot be used by Locator.java
|
||||
* Implemented this way.
|
||||
* File.toURL() adds file: and changes '\' to '/' for dos OSes
|
||||
* encodeURI converts characters like ' ' and '#' to %DD
|
||||
* @param file the file to convert
|
||||
* @return URL the converted File
|
||||
* @throws MalformedURLException on error
|
||||
* @deprecated since 1.9, use {@link FileUtils#getFileURL(File)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static URL fileToURL(File file)
|
||||
throws MalformedURLException {
|
||||
return new URL(file.toURI().toASCIIString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the File necessary to load the Sun compiler tools. If the classes
|
||||
* are available to this class, then no additional URL is required and
|
||||
* null is returned. This may be because the classes are explicitly in the
|
||||
* class path or provided by the JVM directly.
|
||||
*
|
||||
* @return the tools jar as a File if required, null otherwise.
|
||||
*/
|
||||
public static File getToolsJar() {
|
||||
// firstly check if the tools jar is already in the classpath
|
||||
boolean toolsJarAvailable = false;
|
||||
try {
|
||||
// just check whether this throws an exception
|
||||
Class.forName("com.sun.tools.javac.Main");
|
||||
toolsJarAvailable = true;
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
Class.forName("sun.tools.javac.Main");
|
||||
toolsJarAvailable = true;
|
||||
} catch (Exception e2) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (toolsJarAvailable) {
|
||||
return null;
|
||||
}
|
||||
// couldn't find compiler - try to find tools.jar
|
||||
// based on java.home setting
|
||||
String libToolsJar
|
||||
= File.separator + "lib" + File.separator + "tools.jar";
|
||||
String javaHome = System.getProperty("java.home");
|
||||
File toolsJar = new File(javaHome + libToolsJar);
|
||||
if (toolsJar.exists()) {
|
||||
// Found in java.home as given
|
||||
return toolsJar;
|
||||
}
|
||||
if (javaHome.toLowerCase(Locale.ENGLISH).endsWith(File.separator + "jre")) {
|
||||
javaHome = javaHome.substring(
|
||||
0, javaHome.length() - "/jre".length());
|
||||
toolsJar = new File(javaHome + libToolsJar);
|
||||
}
|
||||
if (!toolsJar.exists()) {
|
||||
System.out.println("Unable to locate tools.jar. "
|
||||
+ "Expected to find it in " + toolsJar.getPath());
|
||||
return null;
|
||||
}
|
||||
return toolsJar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of URLs representing all of the jar files in the
|
||||
* given location. If the location is a file, it is returned as the only
|
||||
* element of the array. If the location is a directory, it is scanned for
|
||||
* jar files.
|
||||
*
|
||||
* @param location the location to scan for Jars.
|
||||
*
|
||||
* @return an array of URLs for all jars in the given location.
|
||||
*
|
||||
* @exception MalformedURLException if the URLs for the jars cannot be
|
||||
* formed.
|
||||
*/
|
||||
public static URL[] getLocationURLs(File location)
|
||||
throws MalformedURLException {
|
||||
return getLocationURLs(location, new String[]{".jar"});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of URLs representing all of the files of a given set of
|
||||
* extensions in the given location. If the location is a file, it is
|
||||
* returned as the only element of the array. If the location is a
|
||||
* directory, it is scanned for matching files.
|
||||
*
|
||||
* @param location the location to scan for files.
|
||||
* @param extensions an array of extension that are to match in the
|
||||
* directory search.
|
||||
*
|
||||
* @return an array of URLs of matching files.
|
||||
* @exception MalformedURLException if the URLs for the files cannot be
|
||||
* formed.
|
||||
*/
|
||||
public static URL[] getLocationURLs(File location,
|
||||
final String[] extensions)
|
||||
throws MalformedURLException {
|
||||
URL[] urls = new URL[0];
|
||||
|
||||
if (!location.exists()) {
|
||||
return urls;
|
||||
}
|
||||
if (!location.isDirectory()) {
|
||||
urls = new URL[1];
|
||||
String path = location.getPath();
|
||||
String littlePath = path.toLowerCase(Locale.ENGLISH);
|
||||
for (int i = 0; i < extensions.length; ++i) {
|
||||
if (littlePath.endsWith(extensions[i])) {
|
||||
urls[0] = fileToURL(location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
File[] matches = location.listFiles(
|
||||
new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
String littleName = name.toLowerCase(Locale.ENGLISH);
|
||||
for (int i = 0; i < extensions.length; ++i) {
|
||||
if (littleName.endsWith(extensions[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
urls = new URL[matches.length];
|
||||
for (int i = 0; i < matches.length; ++i) {
|
||||
urls[i] = fileToURL(matches[i]);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.org.apache.tools.ant.launch</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* This is a copy of classes within Apache Ant. The DirectoryScanner
|
||||
* is needed by dependency-check. However, we did not want to make
|
||||
* Ant a dependency. As such, a few files were copied and slightly
|
||||
* modified to remove any references to the Ant Project class.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.launch;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.org.apache.tools.ant</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* This is a copy of classes within Apache Ant. The DirectoryScanner
|
||||
* is needed by dependency-check. However, we did not want to make
|
||||
* Ant a dependency. As such, a few files were copied and slightly
|
||||
* modified to remove any references to the Ant Project class.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant;
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.taskdefs.condition;
|
||||
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.BuildException;
|
||||
|
||||
/**
|
||||
* Interface for conditions to use inside the <condition> task.
|
||||
*
|
||||
*/
|
||||
public interface Condition {
|
||||
/**
|
||||
* Is this condition true?
|
||||
* @return true if the condition is true
|
||||
* @exception BuildException if an error occurs
|
||||
*/
|
||||
boolean eval() throws BuildException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.taskdefs.condition;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.BuildException;
|
||||
|
||||
/**
|
||||
* Condition that tests the OS type.
|
||||
*
|
||||
* @since Ant 1.4
|
||||
*/
|
||||
public class Os implements Condition {
|
||||
private static final String OS_NAME =
|
||||
System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
|
||||
private static final String OS_ARCH =
|
||||
System.getProperty("os.arch").toLowerCase(Locale.ENGLISH);
|
||||
private static final String OS_VERSION =
|
||||
System.getProperty("os.version").toLowerCase(Locale.ENGLISH);
|
||||
private static final String PATH_SEP =
|
||||
System.getProperty("path.separator");
|
||||
|
||||
/**
|
||||
* OS family to look for
|
||||
*/
|
||||
private String family;
|
||||
/**
|
||||
* Name of OS
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* version of OS
|
||||
*/
|
||||
private String version;
|
||||
/**
|
||||
* OS architecture
|
||||
*/
|
||||
private String arch;
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_WINDOWS = "windows";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_9X = "win9x";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_NT = "winnt";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_OS2 = "os/2";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_NETWARE = "netware";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_DOS = "dos";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_MAC = "mac";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_TANDEM = "tandem";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_UNIX = "unix";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_VMS = "openvms";
|
||||
/**
|
||||
* OS family that can be tested for. {@value}
|
||||
*/
|
||||
public static final String FAMILY_ZOS = "z/os";
|
||||
/** OS family that can be tested for. {@value} */
|
||||
public static final String FAMILY_OS400 = "os/400";
|
||||
|
||||
/**
|
||||
* OpenJDK is reported to call MacOS X "Darwin"
|
||||
* @see https://issues.apache.org/bugzilla/show_bug.cgi?id=44889
|
||||
* @see https://issues.apache.org/jira/browse/HADOOP-3318
|
||||
*/
|
||||
private static final String DARWIN = "darwin";
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
*/
|
||||
public Os() {
|
||||
//default
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that sets the family attribute
|
||||
* @param family a String value
|
||||
*/
|
||||
public Os(String family) {
|
||||
setFamily(family);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS family type
|
||||
*
|
||||
* @param f The OS family type desired<br>
|
||||
* Possible values:<br>
|
||||
* <ul>
|
||||
* <li>dos</li>
|
||||
* <li>mac</li>
|
||||
* <li>netware</li>
|
||||
* <li>os/2</li>
|
||||
* <li>tandem</li>
|
||||
* <li>unix</li>
|
||||
* <li>windows</li>
|
||||
* <li>win9x</li>
|
||||
* <li>z/os</li>
|
||||
* <li>os/400</li>
|
||||
* </ul>
|
||||
*/
|
||||
public void setFamily(String f) {
|
||||
family = f.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS name
|
||||
*
|
||||
* @param name The OS name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS architecture
|
||||
*
|
||||
* @param arch The OS architecture
|
||||
*/
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS version
|
||||
*
|
||||
* @param version The OS version
|
||||
*/
|
||||
public void setVersion(String version) {
|
||||
this.version = version.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the type of
|
||||
* that set in setFamily.
|
||||
* @return true if the os matches.
|
||||
* @throws BuildException if there is an error.
|
||||
* @see Os#setFamily(String)
|
||||
*/
|
||||
public boolean eval() throws BuildException {
|
||||
return isOs(family, name, arch, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS family.
|
||||
* @param family the family to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.5
|
||||
*/
|
||||
public static boolean isFamily(String family) {
|
||||
return isOs(family, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS name.
|
||||
*
|
||||
* @param name the OS name to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isName(String name) {
|
||||
return isOs(null, name, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS architecture.
|
||||
*
|
||||
* @param arch the OS architecture to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isArch(String arch) {
|
||||
return isOs(null, null, arch, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS version.
|
||||
*
|
||||
* @param version the OS version to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isVersion(String version) {
|
||||
return isOs(null, null, null, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS family, name, architecture and version
|
||||
*
|
||||
* @param family The OS family
|
||||
* @param name The OS name
|
||||
* @param arch The OS architecture
|
||||
* @param version The OS version
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isOs(String family, String name, String arch,
|
||||
String version) {
|
||||
boolean retValue = false;
|
||||
|
||||
if (family != null || name != null || arch != null
|
||||
|| version != null) {
|
||||
|
||||
boolean isFamily = true;
|
||||
boolean isName = true;
|
||||
boolean isArch = true;
|
||||
boolean isVersion = true;
|
||||
|
||||
if (family != null) {
|
||||
|
||||
//windows probing logic relies on the word 'windows' in
|
||||
//the OS
|
||||
boolean isWindows = OS_NAME.indexOf(FAMILY_WINDOWS) > -1;
|
||||
boolean is9x = false;
|
||||
boolean isNT = false;
|
||||
if (isWindows) {
|
||||
//there are only four 9x platforms that we look for
|
||||
is9x = (OS_NAME.indexOf("95") >= 0
|
||||
|| OS_NAME.indexOf("98") >= 0
|
||||
|| OS_NAME.indexOf("me") >= 0
|
||||
//wince isn't really 9x, but crippled enough to
|
||||
//be a muchness. Ant doesnt run on CE, anyway.
|
||||
|| OS_NAME.indexOf("ce") >= 0);
|
||||
isNT = !is9x;
|
||||
}
|
||||
if (family.equals(FAMILY_WINDOWS)) {
|
||||
isFamily = isWindows;
|
||||
} else if (family.equals(FAMILY_9X)) {
|
||||
isFamily = isWindows && is9x;
|
||||
} else if (family.equals(FAMILY_NT)) {
|
||||
isFamily = isWindows && isNT;
|
||||
} else if (family.equals(FAMILY_OS2)) {
|
||||
isFamily = OS_NAME.indexOf(FAMILY_OS2) > -1;
|
||||
} else if (family.equals(FAMILY_NETWARE)) {
|
||||
isFamily = OS_NAME.indexOf(FAMILY_NETWARE) > -1;
|
||||
} else if (family.equals(FAMILY_DOS)) {
|
||||
isFamily = PATH_SEP.equals(";") && !isFamily(FAMILY_NETWARE);
|
||||
} else if (family.equals(FAMILY_MAC)) {
|
||||
isFamily = OS_NAME.indexOf(FAMILY_MAC) > -1
|
||||
|| OS_NAME.indexOf(DARWIN) > -1;
|
||||
} else if (family.equals(FAMILY_TANDEM)) {
|
||||
isFamily = OS_NAME.indexOf("nonstop_kernel") > -1;
|
||||
} else if (family.equals(FAMILY_UNIX)) {
|
||||
isFamily = PATH_SEP.equals(":")
|
||||
&& !isFamily(FAMILY_VMS)
|
||||
&& (!isFamily(FAMILY_MAC) || OS_NAME.endsWith("x")
|
||||
|| OS_NAME.indexOf(DARWIN) > -1);
|
||||
} else if (family.equals(FAMILY_ZOS)) {
|
||||
isFamily = OS_NAME.indexOf(FAMILY_ZOS) > -1
|
||||
|| OS_NAME.indexOf("os/390") > -1;
|
||||
} else if (family.equals(FAMILY_OS400)) {
|
||||
isFamily = OS_NAME.indexOf(FAMILY_OS400) > -1;
|
||||
} else if (family.equals(FAMILY_VMS)) {
|
||||
isFamily = OS_NAME.indexOf(FAMILY_VMS) > -1;
|
||||
} else {
|
||||
throw new BuildException(
|
||||
"Don\'t know how to detect os family \""
|
||||
+ family + "\"");
|
||||
}
|
||||
}
|
||||
if (name != null) {
|
||||
isName = name.equals(OS_NAME);
|
||||
}
|
||||
if (arch != null) {
|
||||
isArch = arch.equals(OS_ARCH);
|
||||
}
|
||||
if (version != null) {
|
||||
isVersion = version.equals(OS_VERSION);
|
||||
}
|
||||
retValue = isFamily && isName && isArch && isVersion;
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.org.apache.tools.ant.taskdefs.condition</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* This is a copy of classes within Apache Ant. The DirectoryScanner
|
||||
* is needed by dependency-check. However, we did not want to make
|
||||
* Ant a dependency. As such, a few files were copied and slightly
|
||||
* modified to remove any references to the Ant Project class.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.taskdefs.condition;
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types;
|
||||
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.BuildException;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.ProjectComponent;
|
||||
|
||||
/**
|
||||
* Base class for those classes that can appear inside the build file as stand alone data types.
|
||||
*
|
||||
* <p>
|
||||
* This class handles the common description attribute and provides a default implementation for reference handling and
|
||||
* checking for circular references that is appropriate for types that can not be nested inside elements of the same
|
||||
* type (i.e. <patternset> but not <path>).</p>
|
||||
*
|
||||
*/
|
||||
public abstract class DataType extends ProjectComponent implements Cloneable {
|
||||
// CheckStyle:VisibilityModifier OFF
|
||||
|
||||
/**
|
||||
* Value to the refid attribute.
|
||||
*
|
||||
* @deprecated since 1.7. The user should not be directly referencing variable. Please use {@link #getRefid}
|
||||
* instead.
|
||||
*/
|
||||
protected Reference ref;
|
||||
|
||||
/**
|
||||
* Are we sure we don't hold circular references?
|
||||
*
|
||||
* <p>
|
||||
* Subclasses are responsible for setting this value to false if we'd need to investigate this condition (usually
|
||||
* because a child element has been added that is a subclass of DataType).</p>
|
||||
*
|
||||
* @deprecated since 1.7. The user should not be directly referencing variable. Please use {@link #setChecked} or
|
||||
* {@link #isChecked} instead.
|
||||
*/
|
||||
protected boolean checked = true;
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
|
||||
/**
|
||||
* Has the refid attribute of this element been set?
|
||||
*
|
||||
* @return true if the refid attribute has been set
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return ref != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the refid attribute.
|
||||
*
|
||||
* <p>
|
||||
* Subclasses may need to check whether any other attributes have been set as well or child elements have been
|
||||
* created and thus override this method. if they do the must call <code>super.setRefid</code>.</p>
|
||||
*
|
||||
* @param ref the reference to use
|
||||
*/
|
||||
public void setRefid(final Reference ref) {
|
||||
this.ref = ref;
|
||||
checked = false;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Gets as descriptive as possible a name used for this datatype instance.
|
||||
// *
|
||||
// * @return <code>String</code> name.
|
||||
// */
|
||||
// protected String getDataTypeName() {
|
||||
// return ComponentHelper.getElementName(getProject(), this, true);
|
||||
// }
|
||||
// /**
|
||||
// * Convenience method.
|
||||
// * @since Ant 1.7
|
||||
// */
|
||||
// protected void dieOnCircularReference() {
|
||||
// dieOnCircularReference(getProject());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Convenience method.
|
||||
// * @param p the Ant Project instance against which to resolve references.
|
||||
// * @since Ant 1.7
|
||||
// */
|
||||
// protected void dieOnCircularReference(Project p) {
|
||||
// if (checked || !isReference()) {
|
||||
// return;
|
||||
// }
|
||||
// dieOnCircularReference(new IdentityStack<Object>(this), p);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Check to see whether any DataType we hold references to is
|
||||
// * included in the Stack (which holds all DataType instances that
|
||||
// * directly or indirectly reference this instance, including this
|
||||
// * instance itself).
|
||||
// *
|
||||
// * <p>If one is included, throw a BuildException created by {@link
|
||||
// * #circularReference circularReference}.</p>
|
||||
// *
|
||||
// * <p>This implementation is appropriate only for a DataType that
|
||||
// * cannot hold other DataTypes as children.</p>
|
||||
// *
|
||||
// * <p>The general contract of this method is that it shouldn't do
|
||||
// * anything if {@link #checked <code>checked</code>} is true and
|
||||
// * set it to true on exit.</p>
|
||||
// * @param stack the stack of references to check.
|
||||
// * @param project the project to use to dereference the references.
|
||||
// * @throws BuildException on error.
|
||||
// */
|
||||
// protected void dieOnCircularReference(final Stack<Object> stack,
|
||||
// final Project project)
|
||||
// throws BuildException {
|
||||
//
|
||||
// if (checked || !isReference()) {
|
||||
// return;
|
||||
// }
|
||||
// Object o = ref.getReferencedObject(project);
|
||||
//
|
||||
// if (o instanceof DataType) {
|
||||
// IdentityStack<Object> id = IdentityStack.getInstance(stack);
|
||||
//
|
||||
// if (id.contains(o)) {
|
||||
// throw circularReference();
|
||||
// } else {
|
||||
// id.push(o);
|
||||
// ((DataType) o).dieOnCircularReference(id, project);
|
||||
// id.pop();
|
||||
// }
|
||||
// }
|
||||
// checked = true;
|
||||
// }
|
||||
// /**
|
||||
// * Allow DataTypes outside org.apache.tools.ant.types to indirectly call dieOnCircularReference on nested DataTypes.
|
||||
// *
|
||||
// * @param dt the DataType to check.
|
||||
// * @param stk the stack of references to check.
|
||||
// * @param p the project to use to dereference the references.
|
||||
// * @throws BuildException on error.
|
||||
// * @since Ant 1.7
|
||||
// */
|
||||
// public static void invokeCircularReferenceCheck(DataType dt, Stack<Object> stk,
|
||||
// Project p) {
|
||||
// dt.dieOnCircularReference(stk, p);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Allow DataTypes outside org.apache.tools.ant.types to indirectly call dieOnCircularReference on nested DataTypes.
|
||||
// *
|
||||
// * <p>
|
||||
// * Pushes dt on the stack, runs dieOnCircularReference and pops it again.</p>
|
||||
// *
|
||||
// * @param dt the DataType to check.
|
||||
// * @param stk the stack of references to check.
|
||||
// * @param p the project to use to dereference the references.
|
||||
// * @throws BuildException on error.
|
||||
// * @since Ant 1.8.0
|
||||
// */
|
||||
// public static void pushAndInvokeCircularReferenceCheck(DataType dt,
|
||||
// Stack<Object> stk,
|
||||
// Project p) {
|
||||
// stk.push(dt);
|
||||
// dt.dieOnCircularReference(stk, p);
|
||||
// stk.pop();
|
||||
// }
|
||||
// /**
|
||||
// * Performs the check for circular references and returns the referenced object.
|
||||
// *
|
||||
// * @return the dereferenced object.
|
||||
// * @throws BuildException if the reference is invalid (circular ref, wrong class, etc).
|
||||
// * @since Ant 1.7
|
||||
// */
|
||||
// protected Object getCheckedRef() {
|
||||
// return getCheckedRef(getProject());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Performs the check for circular references and returns the referenced object.
|
||||
// *
|
||||
// * @param p the Ant Project instance against which to resolve references.
|
||||
// * @return the dereferenced object.
|
||||
// * @throws BuildException if the reference is invalid (circular ref, wrong class, etc).
|
||||
// * @since Ant 1.7
|
||||
// */
|
||||
// protected Object getCheckedRef(Project p) {
|
||||
// return getCheckedRef(getClass(), getDataTypeName(), p);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Performs the check for circular references and returns the referenced object.
|
||||
// *
|
||||
// * @param requiredClass the class that this reference should be a subclass of.
|
||||
// * @param dataTypeName the name of the datatype that the reference should be (error message use only).
|
||||
// * @return the dereferenced object.
|
||||
// * @throws BuildException if the reference is invalid (circular ref, wrong class, etc).
|
||||
// */
|
||||
// protected <T> T getCheckedRef(final Class<T> requiredClass,
|
||||
// final String dataTypeName) {
|
||||
// return getCheckedRef(requiredClass, dataTypeName, getProject());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Performs the check for circular references and returns the referenced object. This version allows the fallback
|
||||
// * Project instance to be specified.
|
||||
// *
|
||||
// * @param requiredClass the class that this reference should be a subclass of.
|
||||
// * @param dataTypeName the name of the datatype that the reference should be (error message use only).
|
||||
// * @param project the fallback Project instance for dereferencing.
|
||||
// * @return the dereferenced object.
|
||||
// * @throws BuildException if the reference is invalid (circular ref, wrong class, etc), or if <code>project</code>
|
||||
// * is <code>null</code>.
|
||||
// * @since Ant 1.7
|
||||
// */
|
||||
// protected <T> T getCheckedRef(final Class<T> requiredClass,
|
||||
// final String dataTypeName, final Project project) {
|
||||
// if (project == null) {
|
||||
// throw new BuildException("No Project specified");
|
||||
// }
|
||||
// dieOnCircularReference(project);
|
||||
// Object o = ref.getReferencedObject(project);
|
||||
// if (!(requiredClass.isAssignableFrom(o.getClass()))) {
|
||||
// log("Class " + o.getClass() + " is not a subclass of " + requiredClass,
|
||||
// Project.MSG_VERBOSE);
|
||||
// String msg = ref.getRefId() + " doesn\'t denote a " + dataTypeName;
|
||||
// throw new BuildException(msg);
|
||||
// }
|
||||
// @SuppressWarnings("unchecked")
|
||||
// final T result = (T) o;
|
||||
// return result;
|
||||
// }
|
||||
/**
|
||||
* Creates an exception that indicates that refid has to be the only attribute if it is set.
|
||||
*
|
||||
* @return the exception to throw
|
||||
*/
|
||||
protected BuildException tooManyAttributes() {
|
||||
return new BuildException("You must not specify more than one "
|
||||
+ "attribute when using refid");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an exception that indicates that this XML element must not have child elements if the refid attribute is
|
||||
* set.
|
||||
*
|
||||
* @return the exception to throw
|
||||
*/
|
||||
protected BuildException noChildrenAllowed() {
|
||||
return new BuildException("You must not specify nested elements "
|
||||
+ "when using refid");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an exception that indicates the user has generated a loop of data types referencing each other.
|
||||
*
|
||||
* @return the exception to throw
|
||||
*/
|
||||
protected BuildException circularReference() {
|
||||
return new BuildException("This data type contains a circular "
|
||||
+ "reference.");
|
||||
}
|
||||
|
||||
/**
|
||||
* The flag that is used to indicate that circular references have been checked.
|
||||
*
|
||||
* @return true if circular references have been checked
|
||||
*/
|
||||
protected boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that is used to indicate that circular references have been checked.
|
||||
*
|
||||
* @param checked if true, if circular references have been checked
|
||||
*/
|
||||
protected void setChecked(final boolean checked) {
|
||||
this.checked = checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the reference set on this object
|
||||
*
|
||||
* @return the reference or null
|
||||
*/
|
||||
public Reference getRefid() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* check that it is ok to set attributes, i.e that no reference is defined
|
||||
*
|
||||
* @since Ant 1.6
|
||||
* @throws BuildException if not allowed
|
||||
*/
|
||||
protected void checkAttributesAllowed() {
|
||||
if (isReference()) {
|
||||
throw tooManyAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check that it is ok to add children, i.e that no reference is defined
|
||||
*
|
||||
* @since Ant 1.6
|
||||
* @throws BuildException if not allowed
|
||||
*/
|
||||
protected void checkChildrenAllowed() {
|
||||
if (isReference()) {
|
||||
throw noChildrenAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic DataType toString().
|
||||
*
|
||||
* @return this DataType formatted as a String.
|
||||
*/
|
||||
public String toString() {
|
||||
String d = getDescription();
|
||||
//return d == null ? getDataTypeName() : getDataTypeName() + " " + d;
|
||||
return d == null ? "DataType" : d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since Ant 1.7
|
||||
* @return a shallow copy of this DataType.
|
||||
* @throws CloneNotSupportedException if there is a problem.
|
||||
*/
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
DataType dt = (DataType) super.clone();
|
||||
dt.setDescription(getDescription());
|
||||
if (getRefid() != null) {
|
||||
dt.setRefid(getRefid());
|
||||
}
|
||||
dt.setChecked(isChecked());
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types;
|
||||
|
||||
/**
|
||||
* Class to hold a reference to another object in the project.
|
||||
*
|
||||
*/
|
||||
public class Reference {
|
||||
|
||||
private String refid;
|
||||
//private Project project;
|
||||
|
||||
/**
|
||||
* Create a reference.
|
||||
*
|
||||
* @deprecated since 1.7. Please use {@link Reference#Reference(Project,String)} instead.
|
||||
*/
|
||||
public Reference() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reference to a named ID.
|
||||
*
|
||||
* @param id the name of this reference
|
||||
* @deprecated since 1.7. Please use {@link Reference#Reference(Project,String)} instead.
|
||||
*/
|
||||
public Reference(String id) {
|
||||
setRefId(id);
|
||||
}
|
||||
//
|
||||
// /**
|
||||
// * Create a reference to a named ID in a particular project.
|
||||
// * @param p the project this reference is associated with
|
||||
// * @param id the name of this reference
|
||||
// * @since Ant 1.6.3
|
||||
// */
|
||||
// public Reference(Project p, String id) {
|
||||
// setRefId(id);
|
||||
// setProject(p);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Set the reference id. Should not normally be necessary; use {@link Reference#Reference(Project, String)}.
|
||||
*
|
||||
* @param id the reference id to use
|
||||
*/
|
||||
public void setRefId(String id) {
|
||||
refid = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reference id of this reference.
|
||||
*
|
||||
* @return the reference id
|
||||
*/
|
||||
public String getRefId() {
|
||||
return refid;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Set the associated project. Should not normally be necessary;
|
||||
// * use {@link Reference#Reference(Project,String)}.
|
||||
// * @param p the project to use
|
||||
// * @since Ant 1.6.3
|
||||
// */
|
||||
// public void setProject(Project p) {
|
||||
// this.project = p;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Get the associated project, if any; may be null.
|
||||
// * @return the associated project
|
||||
// * @since Ant 1.6.3
|
||||
// */
|
||||
// public Project getProject() {
|
||||
// return project;
|
||||
// }
|
||||
// /**
|
||||
// * Resolve the reference, using the associated project if
|
||||
// * it set, otherwise use the passed in project.
|
||||
// * @param fallback the fallback project to use if the project attribute of
|
||||
// * reference is not set.
|
||||
// * @return the dereferenced object.
|
||||
// * @throws BuildException if the reference cannot be dereferenced.
|
||||
// */
|
||||
// public Object getReferencedObject(Project fallback) throws BuildException {
|
||||
// if (refid == null) {
|
||||
// throw new BuildException("No reference specified");
|
||||
// }
|
||||
//
|
||||
// Object o = project == null ? fallback.getReference(refid) : project.getReference(refid);
|
||||
// if (o == null) {
|
||||
// throw new BuildException("Reference " + refid + " not found.");
|
||||
// }
|
||||
// return o;
|
||||
// }
|
||||
// /**
|
||||
// * Resolve the reference, looking in the associated project.
|
||||
// * @see Project#getReference
|
||||
// * @return the dereferenced object.
|
||||
// * @throws BuildException if the project is null or the reference cannot be dereferenced
|
||||
// * @since Ant 1.6.3
|
||||
// */
|
||||
// public Object getReferencedObject() throws BuildException {
|
||||
// if (project == null) {
|
||||
// throw new BuildException("No project set on reference to " + refid);
|
||||
// }
|
||||
// return getReferencedObject(project);
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.types.resources.FileProvider;
|
||||
|
||||
/**
|
||||
* Describes a "File-like" resource (File, ZipEntry, etc.).
|
||||
*
|
||||
* This class is meant to be used by classes needing to record path and date/time information about a file, a zip entry
|
||||
* or some similar resource (URL, archive in a version control repository, ...).
|
||||
*
|
||||
* @since Ant 1.5.2
|
||||
* @see org.apache.tools.ant.types.resources.Touchable
|
||||
*/
|
||||
public class Resource extends DataType implements Comparable<Resource>, ResourceCollection {
|
||||
|
||||
/**
|
||||
* Constant unknown size
|
||||
*/
|
||||
public static final long UNKNOWN_SIZE = -1;
|
||||
|
||||
/**
|
||||
* Constant unknown datetime for getLastModified
|
||||
*/
|
||||
public static final long UNKNOWN_DATETIME = 0L;
|
||||
|
||||
/**
|
||||
* Magic number
|
||||
*/
|
||||
protected static final int MAGIC = getMagicNumber("Resource".getBytes());
|
||||
|
||||
private static final int NULL_NAME = getMagicNumber("null name".getBytes());
|
||||
|
||||
/**
|
||||
* Create a "magic number" for use in hashCode calculations.
|
||||
*
|
||||
* @param seed byte[] to seed with.
|
||||
* @return a magic number as int.
|
||||
*/
|
||||
protected static int getMagicNumber(byte[] seed) {
|
||||
return new BigInteger(seed).intValue();
|
||||
}
|
||||
|
||||
private String name = null;
|
||||
private Boolean exists = null;
|
||||
private Long lastmodified = null;
|
||||
private Boolean directory = null;
|
||||
private Long size = null;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public Resource() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Only sets the name.
|
||||
*
|
||||
* <p>
|
||||
* This is a dummy, used for not existing resources.</p>
|
||||
*
|
||||
* @param name relative path of the resource. Expects "/" to be used as the directory separator.
|
||||
*/
|
||||
public Resource(String name) {
|
||||
this(name, false, 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name, lastmodified flag, and exists flag.
|
||||
*
|
||||
* @param name relative path of the resource. Expects "/" to be used as the directory separator.
|
||||
* @param exists if true, this resource exists.
|
||||
* @param lastmodified the last modification time of this resource.
|
||||
*/
|
||||
public Resource(String name, boolean exists, long lastmodified) {
|
||||
this(name, exists, lastmodified, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name, lastmodified flag, exists flag, and directory flag.
|
||||
*
|
||||
* @param name relative path of the resource. Expects "/" to be used as the directory separator.
|
||||
* @param exists if true the resource exists
|
||||
* @param lastmodified the last modification time of the resource
|
||||
* @param directory if true, this resource is a directory
|
||||
*/
|
||||
public Resource(String name, boolean exists, long lastmodified, boolean directory) {
|
||||
this(name, exists, lastmodified, directory, UNKNOWN_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name, lastmodified flag, exists flag, directory flag, and size.
|
||||
*
|
||||
* @param name relative path of the resource. Expects "/" to be used as the directory separator.
|
||||
* @param exists if true the resource exists
|
||||
* @param lastmodified the last modification time of the resource
|
||||
* @param directory if true, this resource is a directory
|
||||
* @param size the size of this resource.
|
||||
*/
|
||||
public Resource(String name, boolean exists, long lastmodified, boolean directory, long size) {
|
||||
this.name = name;
|
||||
setName(name);
|
||||
setExists(exists);
|
||||
setLastModified(lastmodified);
|
||||
setDirectory(directory);
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name attribute will contain the path of a file relative to the root directory of its fileset or the recorded path
|
||||
* of a zip entry.
|
||||
*
|
||||
* <p>
|
||||
* example for a file with fullpath /var/opt/adm/resource.txt in a file set with root dir /var/opt it will be
|
||||
* adm/resource.txt.</p>
|
||||
*
|
||||
* <p>
|
||||
* "/" will be used as the directory separator.</p>
|
||||
*
|
||||
* @return the name of this resource.
|
||||
*/
|
||||
public String getName() {
|
||||
//return isReference() ? ((Resource) getCheckedRef()).getName() : name;
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this Resource.
|
||||
*
|
||||
* @param name relative path of the resource. Expects "/" to be used as the directory separator.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
checkAttributesAllowed();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The exists attribute tells whether a resource exists.
|
||||
*
|
||||
* @return true if this resource exists.
|
||||
*/
|
||||
public boolean isExists() {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).isExists();
|
||||
// }
|
||||
//default true:
|
||||
return exists == null || exists.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the exists attribute.
|
||||
*
|
||||
* @param exists if true, this resource exists.
|
||||
*/
|
||||
public void setExists(boolean exists) {
|
||||
checkAttributesAllowed();
|
||||
this.exists = exists ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the modification time in milliseconds since 01.01.1970 (the "epoch").
|
||||
*
|
||||
* @return the modification time, if that is meaningful (e.g. for a file resource which exists); 0 if the resource
|
||||
* does not exist, to mirror the behavior of {@link java.io.File#lastModified}; or 0 if the notion of modification
|
||||
* time is meaningless for this class of resource (e.g. an inline string)
|
||||
*/
|
||||
public long getLastModified() {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).getLastModified();
|
||||
// }
|
||||
if (!isExists() || lastmodified == null) {
|
||||
return UNKNOWN_DATETIME;
|
||||
}
|
||||
long result = lastmodified.longValue();
|
||||
return result < UNKNOWN_DATETIME ? UNKNOWN_DATETIME : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last modification attribute.
|
||||
*
|
||||
* @param lastmodified the modification time in milliseconds since 01.01.1970.
|
||||
*/
|
||||
public void setLastModified(long lastmodified) {
|
||||
checkAttributesAllowed();
|
||||
this.lastmodified = new Long(lastmodified);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the resource is a directory.
|
||||
*
|
||||
* @return boolean flag indicating if the resource is a directory.
|
||||
*/
|
||||
public boolean isDirectory() {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).isDirectory();
|
||||
// }
|
||||
//default false:
|
||||
return directory != null && directory.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directory attribute.
|
||||
*
|
||||
* @param directory if true, this resource is a directory.
|
||||
*/
|
||||
public void setDirectory(boolean directory) {
|
||||
checkAttributesAllowed();
|
||||
this.directory = directory ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of this Resource.
|
||||
*
|
||||
* @param size the size, as a long.
|
||||
* @since Ant 1.6.3
|
||||
*/
|
||||
public void setSize(long size) {
|
||||
checkAttributesAllowed();
|
||||
this.size = new Long(size > UNKNOWN_SIZE ? size : UNKNOWN_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Resource.
|
||||
*
|
||||
* @return the size, as a long, 0 if the Resource does not exist (for compatibility with java.io.File), or
|
||||
* UNKNOWN_SIZE if not known.
|
||||
* @since Ant 1.6.3
|
||||
*/
|
||||
public long getSize() {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).getSize();
|
||||
// }
|
||||
return isExists()
|
||||
? (size != null ? size.longValue() : UNKNOWN_SIZE)
|
||||
: 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone this Resource.
|
||||
*
|
||||
* @return copy of this.
|
||||
*/
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"CloneNotSupportedException for a Resource caught. "
|
||||
+ "Derived classes must support cloning.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to a comparison of names.
|
||||
*
|
||||
* @param other the object to compare to.
|
||||
* @return a negative integer, zero, or a positive integer as this Resource is less than, equal to, or greater than
|
||||
* the specified Resource.
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public int compareTo(Resource other) {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).compareTo(other);
|
||||
// }
|
||||
return toString().compareTo(other.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement basic Resource equality.
|
||||
*
|
||||
* @param other the object to check against.
|
||||
* @return true if the specified Object is equal to this Resource.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public boolean equals(Object other) {
|
||||
// if (isReference()) {
|
||||
// return getCheckedRef().equals(other);
|
||||
// }
|
||||
return other != null && other.getClass().equals(getClass())
|
||||
&& compareTo((Resource) other) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hash code for this Resource.
|
||||
*
|
||||
* @return hash code as int.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public int hashCode() {
|
||||
// if (isReference()) {
|
||||
// return getCheckedRef().hashCode();
|
||||
// }
|
||||
String name = getName();
|
||||
return MAGIC * (name == null ? NULL_NAME : name.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an InputStream for the Resource.
|
||||
*
|
||||
* @return an InputStream containing this Resource's content.
|
||||
* @throws IOException if unable to provide the content of this Resource as a stream.
|
||||
* @throws UnsupportedOperationException if InputStreams are not supported for this Resource type.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).getInputStream();
|
||||
// }
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an OutputStream for the Resource.
|
||||
*
|
||||
* @return an OutputStream to which content can be written.
|
||||
* @throws IOException if unable to provide the content of this Resource as a stream.
|
||||
* @throws UnsupportedOperationException if OutputStreams are not supported for this Resource type.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).getOutputStream();
|
||||
// }
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fulfill the ResourceCollection contract.
|
||||
*
|
||||
* @return an Iterator of Resources.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public Iterator<Resource> iterator() {
|
||||
//return isReference() ? ((Resource) getCheckedRef()).iterator()
|
||||
// : new Iterator<Resource>() {
|
||||
return new Iterator<Resource>() {
|
||||
private boolean done = false;
|
||||
|
||||
public boolean hasNext() {
|
||||
return !done;
|
||||
}
|
||||
|
||||
public Resource next() {
|
||||
if (done) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
done = true;
|
||||
return Resource.this;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fulfill the ResourceCollection contract.
|
||||
*
|
||||
* @return the size of this ResourceCollection.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public int size() {
|
||||
//return isReference() ? ((Resource) getCheckedRef()).size() : 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fulfill the ResourceCollection contract.
|
||||
*
|
||||
* @return whether this Resource is a FileProvider.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public boolean isFilesystemOnly() {
|
||||
// return (isReference() && ((Resource) getCheckedRef()).isFilesystemOnly())
|
||||
// || this.as(FileProvider.class) != null;
|
||||
return this.as(FileProvider.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation of this Resource.
|
||||
*
|
||||
* @return this Resource formatted as a String.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public String toString() {
|
||||
// if (isReference()) {
|
||||
// return getCheckedRef().toString();
|
||||
// }
|
||||
String n = getName();
|
||||
return n == null ? "(anonymous)" : n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long String representation of this Resource. This typically should be the value of <code>toString()</code>
|
||||
* prefixed by a type description.
|
||||
*
|
||||
* @return this Resource formatted as a long String.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public final String toLongString() {
|
||||
// return isReference() ? ((Resource) getCheckedRef()).toLongString()
|
||||
// : getDataTypeName() + " \"" + toString() + '"';
|
||||
return toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the base version.
|
||||
*
|
||||
* @param r the Reference to set.
|
||||
*/
|
||||
public void setRefid(Reference r) {
|
||||
if (name != null
|
||||
|| exists != null
|
||||
|| lastmodified != null
|
||||
|| directory != null
|
||||
|| size != null) {
|
||||
throw tooManyAttributes();
|
||||
}
|
||||
super.setRefid(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this resource that implements the interface given as the argument or null if there is no such
|
||||
* view.
|
||||
*
|
||||
* <p>
|
||||
* This allows extension interfaces to be added to resources without growing the number of permutations of
|
||||
* interfaces decorators/adapters need to implement.</p>
|
||||
*
|
||||
* <p>
|
||||
* This implementation of the method will return the current instance itself if it can be assigned to the given
|
||||
* class.</p>
|
||||
*
|
||||
* @since Ant 1.8.0
|
||||
*/
|
||||
public <T> T as(Class<T> clazz) {
|
||||
return clazz.isAssignableFrom(getClass()) ? clazz.cast(this) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types;
|
||||
|
||||
import java.util.Iterator;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.types.resources.FileProvider;
|
||||
|
||||
/**
|
||||
* Interface describing a collection of Resources.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public interface ResourceCollection extends Iterable<Resource> {
|
||||
|
||||
/**
|
||||
* Gets the contents of this collection.
|
||||
* @return all resources in the collection
|
||||
*/
|
||||
Iterator<Resource> iterator();
|
||||
|
||||
/**
|
||||
* Learn the number of contained Resources.
|
||||
* @return number of elements as int.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Indicate whether this ResourceCollection is composed entirely of
|
||||
* Resources accessible via local filesystem conventions. If true,
|
||||
* all resources returned from this collection should
|
||||
* respond with a {@link FileProvider} when asked via {@link Resource#as}.
|
||||
* @return whether this is a filesystem-only resource collection.
|
||||
*/
|
||||
boolean isFilesystemOnly();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types;
|
||||
|
||||
/**
|
||||
* this interface should be implemented by classes (Scanners) needing
|
||||
* to deliver information about resources.
|
||||
*
|
||||
* @since Ant 1.5.2
|
||||
*/
|
||||
public interface ResourceFactory {
|
||||
|
||||
/**
|
||||
* Query a resource (file, zipentry, ...) by name
|
||||
*
|
||||
* @param name relative path of the resource about which
|
||||
* information is sought. Expects "/" to be used as the
|
||||
* directory separator.
|
||||
* @return instance of Resource; the exists attribute of Resource
|
||||
* will tell whether the sought resource exists
|
||||
*/
|
||||
Resource getResource(String name);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.org.apache.tools.ant.types</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* This is a copy of classes within Apache Ant. The DirectoryScanner
|
||||
* is needed by dependency-check. However, we did not want to make
|
||||
* Ant a dependency. As such, a few files were copied and slightly
|
||||
* modified to remove any references to the Ant Project class.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types;
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by "appendable" resources.
|
||||
* @since Ant 1.8
|
||||
*/
|
||||
public interface Appendable {
|
||||
|
||||
/**
|
||||
* Get an appending OutputStream.
|
||||
* @return OutputStream
|
||||
* @throws IOException if anything goes wrong
|
||||
*/
|
||||
OutputStream getAppendOutputStream() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.resources;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* This is an interface that resources that can provide a file should implement.
|
||||
* This is a refactoring of {@link FileResource}, to allow other resources
|
||||
* to act as sources of files (and to make components that only support
|
||||
* file-based resources from only support FileResource resources.
|
||||
* @since Ant 1.8
|
||||
*/
|
||||
public interface FileProvider {
|
||||
/**
|
||||
* Get the file represented by this Resource.
|
||||
* @return the file.
|
||||
*/
|
||||
File getFile();
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.BuildException;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.types.Reference;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.types.Resource;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.types.ResourceFactory;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.util.FileUtils;
|
||||
|
||||
/**
|
||||
* A Resource representation of a File.
|
||||
*
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public class FileResource extends Resource implements Touchable, FileProvider,
|
||||
ResourceFactory, Appendable {
|
||||
|
||||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
|
||||
private static final int NULL_FILE
|
||||
= Resource.getMagicNumber("null file".getBytes());
|
||||
|
||||
private File file;
|
||||
private File baseDir;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public FileResource() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileResource using the specified basedir and relative name.
|
||||
*
|
||||
* @param b the basedir as File.
|
||||
* @param name the relative filename.
|
||||
*/
|
||||
public FileResource(File b, String name) {
|
||||
this.baseDir = b;
|
||||
this.file = FILE_UTILS.resolveFile(b, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileResource from a File.
|
||||
*
|
||||
* @param f the File represented.
|
||||
*/
|
||||
public FileResource(File f) {
|
||||
setFile(f);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Create a new FileResource.
|
||||
// * @param p Project
|
||||
// * @param f File represented
|
||||
// * @since Ant 1.8
|
||||
// */
|
||||
// public FileResource(Project p, File f) {
|
||||
// this(f);
|
||||
// setProject(p);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Constructor for Ant attribute introspection.
|
||||
// * @param p the Project against which to resolve <code>s</code>.
|
||||
// * @param s the absolute or Project-relative filename as a String.
|
||||
// * @see org.apache.tools.ant.IntrospectionHelper
|
||||
// */
|
||||
// public FileResource(Project p, String s) {
|
||||
// this(p, p.resolveFile(s));
|
||||
// }
|
||||
/**
|
||||
* Set the File for this FileResource.
|
||||
*
|
||||
* @param f the File to be represented.
|
||||
*/
|
||||
public void setFile(File f) {
|
||||
checkAttributesAllowed();
|
||||
file = f;
|
||||
if (f != null && (getBaseDir() == null || !FILE_UTILS.isLeadingPath(getBaseDir(), f))) {
|
||||
setBaseDir(f.getParentFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file represented by this FileResource.
|
||||
*
|
||||
* @return the File.
|
||||
*/
|
||||
public File getFile() {
|
||||
// if (isReference()) {
|
||||
// return ((FileResource) getCheckedRef()).getFile();
|
||||
// }
|
||||
// dieOnCircularReference();
|
||||
synchronized (this) {
|
||||
if (file == null) {
|
||||
//try to resolve file set via basedir/name property setters:
|
||||
File d = getBaseDir();
|
||||
String n = super.getName();
|
||||
if (n != null) {
|
||||
setFile(FILE_UTILS.resolveFile(d, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the basedir for this FileResource.
|
||||
*
|
||||
* @param b the basedir as File.
|
||||
*/
|
||||
public void setBaseDir(File b) {
|
||||
checkAttributesAllowed();
|
||||
baseDir = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the basedir to which the name is relative.
|
||||
*
|
||||
* @return the basedir as File.
|
||||
*/
|
||||
public File getBaseDir() {
|
||||
// if (isReference()) {
|
||||
// return ((FileResource) getCheckedRef()).getBaseDir();
|
||||
// }
|
||||
// dieOnCircularReference();
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the super version.
|
||||
*
|
||||
* @param r the Reference to set.
|
||||
*/
|
||||
public void setRefid(Reference r) {
|
||||
if (file != null || baseDir != null) {
|
||||
throw tooManyAttributes();
|
||||
}
|
||||
super.setRefid(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this FileResource. If the basedir is set, the name will be relative to that. Otherwise the
|
||||
* basename only will be returned.
|
||||
*
|
||||
* @return the name of this resource.
|
||||
*/
|
||||
public String getName() {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).getName();
|
||||
// }
|
||||
File b = getBaseDir();
|
||||
return b == null ? getNotNullFile().getName()
|
||||
: FILE_UTILS.removeLeadingPath(b, getNotNullFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Learn whether this file exists.
|
||||
*
|
||||
* @return true if this resource exists.
|
||||
*/
|
||||
public boolean isExists() {
|
||||
// return isReference() ? ((Resource) getCheckedRef()).isExists()
|
||||
// : getNotNullFile().exists();
|
||||
return getNotNullFile().exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the modification time in milliseconds since 01.01.1970 .
|
||||
*
|
||||
* @return 0 if the resource does not exist.
|
||||
*/
|
||||
public long getLastModified() {
|
||||
// return isReference()
|
||||
// ? ((Resource) getCheckedRef()).getLastModified()
|
||||
// : getNotNullFile().lastModified();
|
||||
return getNotNullFile().lastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Learn whether the resource is a directory.
|
||||
*
|
||||
* @return boolean flag indicating if the resource is a directory.
|
||||
*/
|
||||
public boolean isDirectory() {
|
||||
// return isReference() ? ((Resource) getCheckedRef()).isDirectory()
|
||||
// : getNotNullFile().isDirectory();
|
||||
return getNotNullFile().isDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Resource.
|
||||
*
|
||||
* @return the size, as a long, 0 if the Resource does not exist.
|
||||
*/
|
||||
public long getSize() {
|
||||
// return isReference() ? ((Resource) getCheckedRef()).getSize()
|
||||
// : getNotNullFile().length();
|
||||
return getNotNullFile().length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an InputStream for reading the contents of this Resource.
|
||||
*
|
||||
* @return an InputStream object.
|
||||
* @throws IOException if an error occurs.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
// return isReference()
|
||||
// ? ((Resource) getCheckedRef()).getInputStream()
|
||||
// : new FileInputStream(getNotNullFile());
|
||||
return new FileInputStream(getNotNullFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an OutputStream for the Resource.
|
||||
*
|
||||
* @return an OutputStream to which content can be written.
|
||||
* @throws IOException if unable to provide the content of this Resource as a stream.
|
||||
* @throws UnsupportedOperationException if OutputStreams are not supported for this Resource type.
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
// if (isReference()) {
|
||||
// return ((FileResource) getCheckedRef()).getOutputStream();
|
||||
// }
|
||||
return getOutputStream(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public OutputStream getAppendOutputStream() throws IOException {
|
||||
// if (isReference()) {
|
||||
// return ((FileResource) getCheckedRef()).getAppendOutputStream();
|
||||
// }
|
||||
return getOutputStream(true);
|
||||
}
|
||||
|
||||
private OutputStream getOutputStream(boolean append) throws IOException {
|
||||
File f = getNotNullFile();
|
||||
if (f.exists()) {
|
||||
if (f.isFile() && !append) {
|
||||
f.delete();
|
||||
}
|
||||
} else {
|
||||
File p = f.getParentFile();
|
||||
if (p != null && !(p.exists())) {
|
||||
p.mkdirs();
|
||||
}
|
||||
}
|
||||
return append ? new FileOutputStream(f.getAbsolutePath(), true) : new FileOutputStream(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this FileResource to another Resource.
|
||||
*
|
||||
* @param another the other Resource against which to compare.
|
||||
* @return a negative integer, zero, or a positive integer as this FileResource is less than, equal to, or greater
|
||||
* than the specified Resource.
|
||||
*/
|
||||
public int compareTo(Resource another) {
|
||||
// if (isReference()) {
|
||||
// return ((Resource) getCheckedRef()).compareTo(another);
|
||||
// }
|
||||
if (this.equals(another)) {
|
||||
return 0;
|
||||
}
|
||||
FileProvider otherFP = another.as(FileProvider.class);
|
||||
if (otherFP != null) {
|
||||
File f = getFile();
|
||||
if (f == null) {
|
||||
return -1;
|
||||
}
|
||||
File of = otherFP.getFile();
|
||||
if (of == null) {
|
||||
return 1;
|
||||
}
|
||||
return f.compareTo(of);
|
||||
}
|
||||
return super.compareTo(another);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare another Object to this FileResource for equality.
|
||||
*
|
||||
* @param another the other Object to compare.
|
||||
* @return true if another is a FileResource representing the same file.
|
||||
*/
|
||||
public boolean equals(Object another) {
|
||||
if (this == another) {
|
||||
return true;
|
||||
}
|
||||
// if (isReference()) {
|
||||
// return getCheckedRef().equals(another);
|
||||
// }
|
||||
if (another == null || !(another.getClass().equals(getClass()))) {
|
||||
return false;
|
||||
}
|
||||
FileResource otherfr = (FileResource) another;
|
||||
return getFile() == null
|
||||
? otherfr.getFile() == null
|
||||
: getFile().equals(otherfr.getFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hash code for this Resource.
|
||||
*
|
||||
* @return hash code as int.
|
||||
*/
|
||||
public int hashCode() {
|
||||
// if (isReference()) {
|
||||
// return getCheckedRef().hashCode();
|
||||
// }
|
||||
return MAGIC * (getFile() == null ? NULL_FILE : getFile().hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation of this Resource.
|
||||
*
|
||||
* @return this FileResource formatted as a String.
|
||||
*/
|
||||
public String toString() {
|
||||
// if (isReference()) {
|
||||
// return getCheckedRef().toString();
|
||||
// }
|
||||
if (file == null) {
|
||||
return "(unbound file resource)";
|
||||
}
|
||||
String absolutePath = file.getAbsolutePath();
|
||||
return FILE_UTILS.normalize(absolutePath).getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fulfill the ResourceCollection contract.
|
||||
*
|
||||
* @return whether this Resource is a FileResource.
|
||||
*/
|
||||
public boolean isFilesystemOnly() {
|
||||
// if (isReference()) {
|
||||
// return ((FileResource) getCheckedRef()).isFilesystemOnly();
|
||||
// }
|
||||
// dieOnCircularReference();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Touchable interface.
|
||||
*
|
||||
* @param modTime new last modification time.
|
||||
*/
|
||||
public void touch(long modTime) {
|
||||
// if (isReference()) {
|
||||
// ((FileResource) getCheckedRef()).touch(modTime);
|
||||
// return;
|
||||
// }
|
||||
if (!getNotNullFile().setLastModified(modTime)) {
|
||||
//log("Failed to change file modification time", Project.MSG_WARN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file represented by this FileResource, ensuring it is not null.
|
||||
*
|
||||
* @return the not-null File.
|
||||
* @throws BuildException if file is null.
|
||||
*/
|
||||
protected File getNotNullFile() {
|
||||
if (getFile() == null) {
|
||||
throw new BuildException("file attribute is null!");
|
||||
}
|
||||
// dieOnCircularReference();
|
||||
return getFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new resource that matches a relative or absolute path. If the current instance has a compatible baseDir
|
||||
* attribute, it is copied.
|
||||
*
|
||||
* @param path relative/absolute path to a resource
|
||||
* @return a new resource of type FileResource
|
||||
* @throws BuildException if desired
|
||||
* @since Ant1.8
|
||||
*/
|
||||
public Resource getResource(String path) {
|
||||
File newfile = FILE_UTILS.resolveFile(getFile(), path);
|
||||
FileResource fileResource = new FileResource(newfile);
|
||||
if (FILE_UTILS.isLeadingPath(getBaseDir(), newfile)) {
|
||||
fileResource.setBaseDir(getBaseDir());
|
||||
}
|
||||
return fileResource;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.resources;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by "touchable" resources;
|
||||
* that is, those whose modification time can be altered.
|
||||
* @since Ant 1.7
|
||||
*/
|
||||
public interface Touchable {
|
||||
/**
|
||||
* Method called to "touch" the resource.
|
||||
* @param modTime the time to set the modified "field" of the resource,
|
||||
* measured in milliseconds since the epoch.
|
||||
*/
|
||||
void touch(long modTime);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.org.apache.tools.ant.types.resources</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* This is a copy of classes within Apache Ant. The DirectoryScanner
|
||||
* is needed by dependency-check. However, we did not want to make
|
||||
* Ant a dependency. As such, a few files were copied and slightly
|
||||
* modified to remove any references to the Ant Project class.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.resources;
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.selectors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.BuildException;
|
||||
|
||||
/**
|
||||
* This is the interface to be used by all selectors.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface FileSelector {
|
||||
|
||||
/**
|
||||
* Method that each selector will implement to create their
|
||||
* selection behaviour. If there is a problem with the setup
|
||||
* of a selector, it can throw a BuildException to indicate
|
||||
* the problem.
|
||||
*
|
||||
* @param basedir A java.io.File object for the base directory
|
||||
* @param filename The name of the file to check
|
||||
* @param file A File object for this filename
|
||||
* @return whether the file should be selected or not
|
||||
* @exception BuildException if the selector was not configured correctly
|
||||
*/
|
||||
boolean isSelected(File basedir, String filename, File file)
|
||||
throws BuildException;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.selectors;
|
||||
|
||||
/**
|
||||
* An interface used to describe the actions required by any type of
|
||||
* directory scanner that supports Selectors.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface SelectorScanner {
|
||||
/**
|
||||
* Sets the selectors the scanner should use.
|
||||
*
|
||||
* @param selectors the list of selectors
|
||||
*/
|
||||
void setSelectors(FileSelector[] selectors);
|
||||
|
||||
/**
|
||||
* Directories which were selected out of a scan.
|
||||
*
|
||||
* @return list of directories not selected
|
||||
*/
|
||||
String[] getDeselectedDirectories();
|
||||
|
||||
/**
|
||||
* Files which were selected out of a scan.
|
||||
*
|
||||
* @return list of files not selected
|
||||
*/
|
||||
String[] getDeselectedFiles();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,695 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.selectors;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.types.Resource;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.util.FileUtils;
|
||||
|
||||
/**
|
||||
* <p>This is a utility class used by selectors and DirectoryScanner. The
|
||||
* functionality more properly belongs just to selectors, but unfortunately
|
||||
* DirectoryScanner exposed these as protected methods. Thus we have to
|
||||
* support any subclasses of DirectoryScanner that may access these methods.
|
||||
* </p>
|
||||
* <p>This is a Singleton.</p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public final class SelectorUtils {
|
||||
|
||||
/**
|
||||
* The pattern that matches an arbitrary number of directories.
|
||||
* @since Ant 1.8.0
|
||||
*/
|
||||
public static final String DEEP_TREE_MATCH = "**";
|
||||
|
||||
private static final SelectorUtils instance = new SelectorUtils();
|
||||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
|
||||
|
||||
/**
|
||||
* Private Constructor
|
||||
*/
|
||||
private SelectorUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the instance of the Singleton.
|
||||
* @return singleton instance
|
||||
*/
|
||||
public static SelectorUtils getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
* <p>
|
||||
* This is not a general purpose test and should only be used if you
|
||||
* can live with false positives. For example, <code>pattern=**\a</code>
|
||||
* and <code>str=b</code> will yield <code>true</code>.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
*
|
||||
* @return whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
*/
|
||||
public static boolean matchPatternStart(String pattern, String str) {
|
||||
return matchPatternStart(pattern, str, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
* <p>
|
||||
* This is not a general purpose test and should only be used if you
|
||||
* can live with false positives. For example, <code>pattern=**\a</code>
|
||||
* and <code>str=b</code> will yield <code>true</code>.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
*
|
||||
* @return whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
*/
|
||||
public static boolean matchPatternStart(String pattern, String str,
|
||||
boolean isCaseSensitive) {
|
||||
// When str starts with a File.separator, pattern has to start with a
|
||||
// File.separator.
|
||||
// When pattern starts with a File.separator, str has to start with a
|
||||
// File.separator.
|
||||
if (str.startsWith(File.separator)
|
||||
!= pattern.startsWith(File.separator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] patDirs = tokenizePathAsArray(pattern);
|
||||
String[] strDirs = tokenizePathAsArray(str);
|
||||
return matchPatternStart(patDirs, strDirs, isCaseSensitive);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
* <p>
|
||||
* This is not a general purpose test and should only be used if you
|
||||
* can live with false positives. For example, <code>pattern=**\a</code>
|
||||
* and <code>str=b</code> will yield <code>true</code>.
|
||||
*
|
||||
* @param patDirs The tokenized pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param strDirs The tokenized path to match. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
*
|
||||
* @return whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
*/
|
||||
static boolean matchPatternStart(String[] patDirs, String[] strDirs,
|
||||
boolean isCaseSensitive) {
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = patDirs.length - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strDirs.length - 1;
|
||||
|
||||
// up to first '**'
|
||||
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
String patDir = patDirs[patIdxStart];
|
||||
if (patDir.equals(DEEP_TREE_MATCH)) {
|
||||
break;
|
||||
}
|
||||
if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
|
||||
return false;
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
|
||||
// CheckStyle:SimplifyBooleanReturnCheck OFF
|
||||
// Check turned off as the code needs the comments for the various
|
||||
// code paths.
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// String is exhausted
|
||||
return true;
|
||||
} else if (patIdxStart > patIdxEnd) {
|
||||
// String not exhausted, but pattern is. Failure.
|
||||
return false;
|
||||
} else {
|
||||
// pattern now holds ** while string is not exhausted
|
||||
// this will generate false positives but we can live with that.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches a given pattern.
|
||||
*
|
||||
* If you need to call this method multiple times with the same
|
||||
* pattern you should rather use TokenizedPath
|
||||
*
|
||||
* @see TokenizedPath
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
*
|
||||
* @return <code>true</code> if the pattern matches against the string,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean matchPath(String pattern, String str) {
|
||||
String[] patDirs = tokenizePathAsArray(pattern);
|
||||
return matchPath(patDirs, tokenizePathAsArray(str), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches a given pattern.
|
||||
*
|
||||
* If you need to call this method multiple times with the same
|
||||
* pattern you should rather use TokenizedPattern
|
||||
*
|
||||
* @see TokenizedPattern
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
*
|
||||
* @return <code>true</code> if the pattern matches against the string,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean matchPath(String pattern, String str,
|
||||
boolean isCaseSensitive) {
|
||||
String[] patDirs = tokenizePathAsArray(pattern);
|
||||
return matchPath(patDirs, tokenizePathAsArray(str), isCaseSensitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Core implementation of matchPath. It is isolated so that it
|
||||
* can be called from TokenizedPattern.
|
||||
*/
|
||||
static boolean matchPath(String[] tokenizedPattern, String[] strDirs,
|
||||
boolean isCaseSensitive) {
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = tokenizedPattern.length - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strDirs.length - 1;
|
||||
|
||||
// up to first '**'
|
||||
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
String patDir = tokenizedPattern[patIdxStart];
|
||||
if (patDir.equals(DEEP_TREE_MATCH)) {
|
||||
break;
|
||||
}
|
||||
if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
|
||||
return false;
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// String is exhausted
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (patIdxStart > patIdxEnd) {
|
||||
// String not exhausted, but pattern is. Failure.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// up to last '**'
|
||||
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
String patDir = tokenizedPattern[patIdxEnd];
|
||||
if (patDir.equals(DEEP_TREE_MATCH)) {
|
||||
break;
|
||||
}
|
||||
if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
|
||||
return false;
|
||||
}
|
||||
patIdxEnd--;
|
||||
strIdxEnd--;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// String is exhausted
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
int patIdxTmp = -1;
|
||||
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
|
||||
if (tokenizedPattern[i].equals(DEEP_TREE_MATCH)) {
|
||||
patIdxTmp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (patIdxTmp == patIdxStart + 1) {
|
||||
// '**/**' situation, so skip one
|
||||
patIdxStart++;
|
||||
continue;
|
||||
}
|
||||
// Find the pattern between padIdxStart & padIdxTmp in str between
|
||||
// strIdxStart & strIdxEnd
|
||||
int patLength = (patIdxTmp - patIdxStart - 1);
|
||||
int strLength = (strIdxEnd - strIdxStart + 1);
|
||||
int foundIdx = -1;
|
||||
strLoop:
|
||||
for (int i = 0; i <= strLength - patLength; i++) {
|
||||
for (int j = 0; j < patLength; j++) {
|
||||
String subPat = tokenizedPattern[patIdxStart + j + 1];
|
||||
String subStr = strDirs[strIdxStart + i + j];
|
||||
if (!match(subPat, subStr, isCaseSensitive)) {
|
||||
continue strLoop;
|
||||
}
|
||||
}
|
||||
|
||||
foundIdx = strIdxStart + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (foundIdx == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
patIdxStart = patIdxTmp;
|
||||
strIdxStart = foundIdx + patLength;
|
||||
}
|
||||
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern.
|
||||
* The pattern may contain two special characters:<br>
|
||||
* '*' means zero or more characters<br>
|
||||
* '?' means one and only one character
|
||||
*
|
||||
* @param pattern The pattern to match against.
|
||||
* Must not be <code>null</code>.
|
||||
* @param str The string which must be matched against the pattern.
|
||||
* Must not be <code>null</code>.
|
||||
*
|
||||
* @return <code>true</code> if the string matches against the pattern,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean match(String pattern, String str) {
|
||||
return match(pattern, str, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern.
|
||||
* The pattern may contain two special characters:<br>
|
||||
* '*' means zero or more characters<br>
|
||||
* '?' means one and only one character
|
||||
*
|
||||
* @param pattern The pattern to match against.
|
||||
* Must not be <code>null</code>.
|
||||
* @param str The string which must be matched against the pattern.
|
||||
* Must not be <code>null</code>.
|
||||
* @param caseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
*
|
||||
*
|
||||
* @return <code>true</code> if the string matches against the pattern,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean match(String pattern, String str,
|
||||
boolean caseSensitive) {
|
||||
char[] patArr = pattern.toCharArray();
|
||||
char[] strArr = str.toCharArray();
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = patArr.length - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strArr.length - 1;
|
||||
char ch;
|
||||
|
||||
boolean containsStar = false;
|
||||
for (int i = 0; i < patArr.length; i++) {
|
||||
if (patArr[i] == '*') {
|
||||
containsStar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containsStar) {
|
||||
// No '*'s, so we make a shortcut
|
||||
if (patIdxEnd != strIdxEnd) {
|
||||
return false; // Pattern and string do not have the same size
|
||||
}
|
||||
for (int i = 0; i <= patIdxEnd; i++) {
|
||||
ch = patArr[i];
|
||||
if (ch != '?') {
|
||||
if (different(caseSensitive, ch, strArr[i])) {
|
||||
return false; // Character mismatch
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; // String matches against pattern
|
||||
}
|
||||
|
||||
if (patIdxEnd == 0) {
|
||||
return true; // Pattern contains only '*', which matches anything
|
||||
}
|
||||
|
||||
// Process characters before first star
|
||||
while (true) {
|
||||
ch = patArr[patIdxStart];
|
||||
if (ch == '*' || strIdxStart > strIdxEnd) {
|
||||
break;
|
||||
}
|
||||
if (ch != '?') {
|
||||
if (different(caseSensitive, ch, strArr[strIdxStart])) {
|
||||
return false; // Character mismatch
|
||||
}
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// All characters in the string are used. Check if only '*'s are
|
||||
// left in the pattern. If so, we succeeded. Otherwise failure.
|
||||
return allStars(patArr, patIdxStart, patIdxEnd);
|
||||
}
|
||||
|
||||
// Process characters after last star
|
||||
while (true) {
|
||||
ch = patArr[patIdxEnd];
|
||||
if (ch == '*' || strIdxStart > strIdxEnd) {
|
||||
break;
|
||||
}
|
||||
if (ch != '?') {
|
||||
if (different(caseSensitive, ch, strArr[strIdxEnd])) {
|
||||
return false; // Character mismatch
|
||||
}
|
||||
}
|
||||
patIdxEnd--;
|
||||
strIdxEnd--;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// All characters in the string are used. Check if only '*'s are
|
||||
// left in the pattern. If so, we succeeded. Otherwise failure.
|
||||
return allStars(patArr, patIdxStart, patIdxEnd);
|
||||
}
|
||||
|
||||
// process pattern between stars. padIdxStart and patIdxEnd point
|
||||
// always to a '*'.
|
||||
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
int patIdxTmp = -1;
|
||||
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
|
||||
if (patArr[i] == '*') {
|
||||
patIdxTmp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (patIdxTmp == patIdxStart + 1) {
|
||||
// Two stars next to each other, skip the first one.
|
||||
patIdxStart++;
|
||||
continue;
|
||||
}
|
||||
// Find the pattern between padIdxStart & padIdxTmp in str between
|
||||
// strIdxStart & strIdxEnd
|
||||
int patLength = (patIdxTmp - patIdxStart - 1);
|
||||
int strLength = (strIdxEnd - strIdxStart + 1);
|
||||
int foundIdx = -1;
|
||||
strLoop:
|
||||
for (int i = 0; i <= strLength - patLength; i++) {
|
||||
for (int j = 0; j < patLength; j++) {
|
||||
ch = patArr[patIdxStart + j + 1];
|
||||
if (ch != '?') {
|
||||
if (different(caseSensitive, ch,
|
||||
strArr[strIdxStart + i + j])) {
|
||||
continue strLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foundIdx = strIdxStart + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (foundIdx == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
patIdxStart = patIdxTmp;
|
||||
strIdxStart = foundIdx + patLength;
|
||||
}
|
||||
|
||||
// All characters in the string are used. Check if only '*'s are left
|
||||
// in the pattern. If so, we succeeded. Otherwise failure.
|
||||
return allStars(patArr, patIdxStart, patIdxEnd);
|
||||
}
|
||||
|
||||
private static boolean allStars(char[] chars, int start, int end) {
|
||||
for (int i = start; i <= end; ++i) {
|
||||
if (chars[i] != '*') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean different(
|
||||
boolean caseSensitive, char ch, char other) {
|
||||
return caseSensitive
|
||||
? ch != other
|
||||
: Character.toUpperCase(ch) != Character.toUpperCase(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks a path up into a Vector of path elements, tokenizing on
|
||||
* <code>File.separator</code>.
|
||||
*
|
||||
* @param path Path to tokenize. Must not be <code>null</code>.
|
||||
*
|
||||
* @return a Vector of path elements from the tokenized path
|
||||
*/
|
||||
public static Vector<String> tokenizePath(String path) {
|
||||
return tokenizePath(path, File.separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks a path up into a Vector of path elements, tokenizing on
|
||||
*
|
||||
* @param path Path to tokenize. Must not be <code>null</code>.
|
||||
* @param separator the separator against which to tokenize.
|
||||
*
|
||||
* @return a Vector of path elements from the tokenized path
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public static Vector<String> tokenizePath(String path, String separator) {
|
||||
Vector<String> ret = new Vector<String>();
|
||||
if (FileUtils.isAbsolutePath(path)) {
|
||||
String[] s = FILE_UTILS.dissect(path);
|
||||
ret.add(s[0]);
|
||||
path = s[1];
|
||||
}
|
||||
StringTokenizer st = new StringTokenizer(path, separator);
|
||||
while (st.hasMoreTokens()) {
|
||||
ret.addElement(st.nextToken());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #tokenizePath tokenizePath} but hopefully faster.
|
||||
*/
|
||||
/*package*/ static String[] tokenizePathAsArray(String path) {
|
||||
String root = null;
|
||||
if (FileUtils.isAbsolutePath(path)) {
|
||||
String[] s = FILE_UTILS.dissect(path);
|
||||
root = s[0];
|
||||
path = s[1];
|
||||
}
|
||||
char sep = File.separatorChar;
|
||||
int start = 0;
|
||||
int len = path.length();
|
||||
int count = 0;
|
||||
for (int pos = 0; pos < len; pos++) {
|
||||
if (path.charAt(pos) == sep) {
|
||||
if (pos != start) {
|
||||
count++;
|
||||
}
|
||||
start = pos + 1;
|
||||
}
|
||||
}
|
||||
if (len != start) {
|
||||
count++;
|
||||
}
|
||||
String[] l = new String[count + ((root == null) ? 0 : 1)];
|
||||
|
||||
if (root != null) {
|
||||
l[0] = root;
|
||||
count = 1;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
start = 0;
|
||||
for (int pos = 0; pos < len; pos++) {
|
||||
if (path.charAt(pos) == sep) {
|
||||
if (pos != start) {
|
||||
String tok = path.substring(start, pos);
|
||||
l[count++] = tok;
|
||||
}
|
||||
start = pos + 1;
|
||||
}
|
||||
}
|
||||
if (len != start) {
|
||||
String tok = path.substring(start);
|
||||
l[count/*++*/] = tok;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns dependency information on these two files. If src has been
|
||||
* modified later than target, it returns true. If target doesn't exist,
|
||||
* it likewise returns true. Otherwise, target is newer than src and
|
||||
* is not out of date, thus the method returns false. It also returns
|
||||
* false if the src file doesn't even exist, since how could the
|
||||
* target then be out of date.
|
||||
*
|
||||
* @param src the original file
|
||||
* @param target the file being compared against
|
||||
* @param granularity the amount in seconds of slack we will give in
|
||||
* determining out of dateness
|
||||
* @return whether the target is out of date
|
||||
*/
|
||||
public static boolean isOutOfDate(File src, File target, int granularity) {
|
||||
if (!src.exists()) {
|
||||
return false;
|
||||
}
|
||||
if (!target.exists()) {
|
||||
return true;
|
||||
}
|
||||
if ((src.lastModified() - granularity) > target.lastModified()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns dependency information on these two resources. If src has been
|
||||
* modified later than target, it returns true. If target doesn't exist,
|
||||
* it likewise returns true. Otherwise, target is newer than src and
|
||||
* is not out of date, thus the method returns false. It also returns
|
||||
* false if the src file doesn't even exist, since how could the
|
||||
* target then be out of date.
|
||||
*
|
||||
* @param src the original resource
|
||||
* @param target the resource being compared against
|
||||
* @param granularity the int amount in seconds of slack we will give in
|
||||
* determining out of dateness
|
||||
* @return whether the target is out of date
|
||||
*/
|
||||
public static boolean isOutOfDate(Resource src, Resource target,
|
||||
int granularity) {
|
||||
return isOutOfDate(src, target, (long) granularity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns dependency information on these two resources. If src has been
|
||||
* modified later than target, it returns true. If target doesn't exist,
|
||||
* it likewise returns true. Otherwise, target is newer than src and
|
||||
* is not out of date, thus the method returns false. It also returns
|
||||
* false if the src file doesn't even exist, since how could the
|
||||
* target then be out of date.
|
||||
*
|
||||
* @param src the original resource
|
||||
* @param target the resource being compared against
|
||||
* @param granularity the long amount in seconds of slack we will give in
|
||||
* determining out of dateness
|
||||
* @return whether the target is out of date
|
||||
*/
|
||||
public static boolean isOutOfDate(Resource src, Resource target, long granularity) {
|
||||
long sourceLastModified = src.getLastModified();
|
||||
long targetLastModified = target.getLastModified();
|
||||
return src.isExists()
|
||||
&& (sourceLastModified == Resource.UNKNOWN_DATETIME
|
||||
|| targetLastModified == Resource.UNKNOWN_DATETIME
|
||||
|| (sourceLastModified - granularity) > targetLastModified);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Flattens" a string by removing all whitespace (space, tab, linefeed,
|
||||
* carriage return, and formfeed). This uses StringTokenizer and the
|
||||
* default set of tokens as documented in the single argument constructor.
|
||||
*
|
||||
* @param input a String to remove all whitespace.
|
||||
* @return a String that has had all whitespace removed.
|
||||
*/
|
||||
public static String removeWhitespace(String input) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
if (input != null) {
|
||||
StringTokenizer st = new StringTokenizer(input);
|
||||
while (st.hasMoreTokens()) {
|
||||
result.append(st.nextToken());
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a string contains stars or question marks
|
||||
* @param input a String which one wants to test for containing wildcard
|
||||
* @return true if the string contains at least a star or a question mark
|
||||
*/
|
||||
public static boolean hasWildcards(String input) {
|
||||
return (input.indexOf('*') != -1 || input.indexOf('?') != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes from a pattern all tokens to the right containing wildcards
|
||||
* @param input the input string
|
||||
* @return the leftmost part of the pattern without wildcards
|
||||
*/
|
||||
public static String rtrimWildcardTokens(String input) {
|
||||
return new TokenizedPattern(input).rtrimWildcardTokens().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.selectors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.BuildException;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.util.FileUtils;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.util.SymbolicLinkUtils;
|
||||
|
||||
/**
|
||||
* Container for a path that has been split into its components.
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public class TokenizedPath {
|
||||
|
||||
/**
|
||||
* Instance that holds no tokens at all.
|
||||
*/
|
||||
public static final TokenizedPath EMPTY_PATH =
|
||||
new TokenizedPath("", new String[0]);
|
||||
|
||||
/** Helper. */
|
||||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
|
||||
/** Helper. */
|
||||
private static final SymbolicLinkUtils SYMLINK_UTILS =
|
||||
SymbolicLinkUtils.getSymbolicLinkUtils();
|
||||
/** iterations for case-sensitive scanning. */
|
||||
private static final boolean[] CS_SCAN_ONLY = new boolean[] {true};
|
||||
/** iterations for non-case-sensitive scanning. */
|
||||
private static final boolean[] CS_THEN_NON_CS = new boolean[] {true, false};
|
||||
|
||||
private final String path;
|
||||
private final String[] tokenizedPath;
|
||||
|
||||
/**
|
||||
* Initialize the TokenizedPath by parsing it.
|
||||
* @param path The path to tokenize. Must not be
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public TokenizedPath(String path) {
|
||||
this(path, SelectorUtils.tokenizePathAsArray(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new path as a child of another path.
|
||||
*
|
||||
* @param parent the parent path
|
||||
* @param child the child, must not contain the file separator
|
||||
*/
|
||||
public TokenizedPath(TokenizedPath parent, String child) {
|
||||
if (parent.path.length() > 0
|
||||
&& parent.path.charAt(parent.path.length() - 1)
|
||||
!= File.separatorChar) {
|
||||
path = parent.path + File.separatorChar + child;
|
||||
} else {
|
||||
path = parent.path + child;
|
||||
}
|
||||
tokenizedPath = new String[parent.tokenizedPath.length + 1];
|
||||
System.arraycopy(parent.tokenizedPath, 0, tokenizedPath, 0,
|
||||
parent.tokenizedPath.length);
|
||||
tokenizedPath[parent.tokenizedPath.length] = child;
|
||||
}
|
||||
|
||||
/* package */ TokenizedPath(String path, String[] tokens) {
|
||||
this.path = path;
|
||||
this.tokenizedPath = tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The original path String
|
||||
*/
|
||||
public String toString() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* The depth (or length) of a path.
|
||||
*/
|
||||
public int depth() {
|
||||
return tokenizedPath.length;
|
||||
}
|
||||
|
||||
/* package */ String[] getTokens() {
|
||||
return tokenizedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* From <code>base</code> traverse the filesystem in order to find
|
||||
* a file that matches the given name.
|
||||
*
|
||||
* @param base base File (dir).
|
||||
* @param cs whether to scan case-sensitively.
|
||||
* @return File object that points to the file in question or null.
|
||||
*/
|
||||
public File findFile(File base, final boolean cs) {
|
||||
String[] tokens = tokenizedPath;
|
||||
if (FileUtils.isAbsolutePath(path)) {
|
||||
if (base == null) {
|
||||
String[] s = FILE_UTILS.dissect(path);
|
||||
base = new File(s[0]);
|
||||
tokens = SelectorUtils.tokenizePathAsArray(s[1]);
|
||||
} else {
|
||||
File f = FILE_UTILS.normalize(path);
|
||||
String s = FILE_UTILS.removeLeadingPath(base, f);
|
||||
if (s.equals(f.getAbsolutePath())) {
|
||||
//removing base from path yields no change; path
|
||||
//not child of base
|
||||
return null;
|
||||
}
|
||||
tokens = SelectorUtils.tokenizePathAsArray(s);
|
||||
}
|
||||
}
|
||||
return findFile(base, tokens, cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we have to traverse a symlink when trying to reach path from
|
||||
* basedir?
|
||||
* @param base base File (dir).
|
||||
*/
|
||||
public boolean isSymlink(File base) {
|
||||
for (int i = 0; i < tokenizedPath.length; i++) {
|
||||
try {
|
||||
if ((base != null
|
||||
&& SYMLINK_UTILS.isSymbolicLink(base, tokenizedPath[i]))
|
||||
||
|
||||
(base == null
|
||||
&& SYMLINK_UTILS.isSymbolicLink(tokenizedPath[i]))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
base = new File(base, tokenizedPath[i]);
|
||||
} catch (java.io.IOException ioe) {
|
||||
String msg = "IOException caught while checking "
|
||||
+ "for links, couldn't get canonical path!";
|
||||
// will be caught and redirected to Ant's logging system
|
||||
System.err.println(msg);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* true if the original paths are equal.
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof TokenizedPath
|
||||
&& path.equals(((TokenizedPath) o).path);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return path.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* From <code>base</code> traverse the filesystem in order to find
|
||||
* a file that matches the given stack of names.
|
||||
*
|
||||
* @param base base File (dir) - must not be null.
|
||||
* @param pathElements array of path elements (dirs...file).
|
||||
* @param cs whether to scan case-sensitively.
|
||||
* @return File object that points to the file in question or null.
|
||||
*/
|
||||
private static File findFile(File base, final String[] pathElements,
|
||||
final boolean cs) {
|
||||
for (int current = 0; current < pathElements.length; current++) {
|
||||
if (!base.isDirectory()) {
|
||||
return null;
|
||||
}
|
||||
String[] files = base.list();
|
||||
if (files == null) {
|
||||
throw new BuildException("IO error scanning directory "
|
||||
+ base.getAbsolutePath());
|
||||
}
|
||||
boolean found = false;
|
||||
boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS;
|
||||
for (int i = 0; !found && i < matchCase.length; i++) {
|
||||
for (int j = 0; !found && j < files.length; j++) {
|
||||
if (matchCase[i]
|
||||
? files[j].equals(pathElements[current])
|
||||
: files[j].equalsIgnoreCase(pathElements[current])) {
|
||||
base = new File(base, files[j]);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return pathElements.length == 0 && !base.isDirectory() ? null : base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TokenizedPattern from the same tokens that make up
|
||||
* this path.
|
||||
*/
|
||||
public TokenizedPattern toPattern() {
|
||||
return new TokenizedPattern(path, tokenizedPath);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.selectors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Provides reusable path pattern matching. PathPattern is preferable
|
||||
* to equivalent SelectorUtils methods if you need to execute multiple
|
||||
* matching with the same pattern because here the pattern itself will
|
||||
* be parsed only once.
|
||||
* @see SelectorUtils#matchPath(String, String)
|
||||
* @see SelectorUtils#matchPath(String, String, boolean)
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public class TokenizedPattern {
|
||||
|
||||
/**
|
||||
* Instance that holds no tokens at all.
|
||||
*/
|
||||
public static final TokenizedPattern EMPTY_PATTERN =
|
||||
new TokenizedPattern("", new String[0]);
|
||||
|
||||
private final String pattern;
|
||||
private final String[] tokenizedPattern;
|
||||
|
||||
/**
|
||||
* Initialize the PathPattern by parsing it.
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public TokenizedPattern(String pattern) {
|
||||
this(pattern, SelectorUtils.tokenizePathAsArray(pattern));
|
||||
}
|
||||
|
||||
TokenizedPattern(String pattern, String[] tokens) {
|
||||
this.pattern = pattern;
|
||||
this.tokenizedPattern = tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches a given pattern.
|
||||
*
|
||||
* @param path The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
*
|
||||
* @return <code>true</code> if the pattern matches against the string,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean matchPath(TokenizedPath path, boolean isCaseSensitive) {
|
||||
return SelectorUtils.matchPath(tokenizedPattern, path.getTokens(),
|
||||
isCaseSensitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not this pattern matches the start of
|
||||
* a path.
|
||||
*/
|
||||
public boolean matchStartOf(TokenizedPath path,
|
||||
boolean caseSensitive) {
|
||||
return SelectorUtils.matchPatternStart(tokenizedPattern,
|
||||
path.getTokens(), caseSensitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The pattern String
|
||||
*/
|
||||
public String toString() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* true if the original patterns are equal.
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof TokenizedPattern
|
||||
&& pattern.equals(((TokenizedPattern) o).pattern);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return pattern.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* The depth (or length) of a pattern.
|
||||
*/
|
||||
public int depth() {
|
||||
return tokenizedPattern.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the tokenized pattern contain the given string?
|
||||
*/
|
||||
public boolean containsPattern(String pat) {
|
||||
for (int i = 0; i < tokenizedPattern.length; i++) {
|
||||
if (tokenizedPattern[i].equals(pat)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new TokenizedPath where all tokens of this pattern to
|
||||
* the right containing wildcards have been removed
|
||||
* @return the leftmost part of the pattern without wildcards
|
||||
*/
|
||||
public TokenizedPath rtrimWildcardTokens() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int newLen = 0;
|
||||
for (; newLen < tokenizedPattern.length; newLen++) {
|
||||
if (SelectorUtils.hasWildcards(tokenizedPattern[newLen])) {
|
||||
break;
|
||||
}
|
||||
if (newLen > 0
|
||||
&& sb.charAt(sb.length() - 1) != File.separatorChar) {
|
||||
sb.append(File.separator);
|
||||
}
|
||||
sb.append(tokenizedPattern[newLen]);
|
||||
}
|
||||
if (newLen == 0) {
|
||||
return TokenizedPath.EMPTY_PATH;
|
||||
}
|
||||
String[] newPats = new String[newLen];
|
||||
System.arraycopy(tokenizedPattern, 0, newPats, 0, newLen);
|
||||
return new TokenizedPath(sb.toString(), newPats);
|
||||
}
|
||||
|
||||
/**
|
||||
* true if the last token equals the given string.
|
||||
*/
|
||||
public boolean endsWith(String s) {
|
||||
return tokenizedPattern.length > 0
|
||||
&& tokenizedPattern[tokenizedPattern.length - 1].equals(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pattern without the last token of this pattern.
|
||||
*/
|
||||
public TokenizedPattern withoutLastToken() {
|
||||
if (tokenizedPattern.length == 0) {
|
||||
throw new IllegalStateException("cant strip a token from nothing");
|
||||
} else if (tokenizedPattern.length == 1) {
|
||||
return EMPTY_PATTERN;
|
||||
} else {
|
||||
String toStrip = tokenizedPattern[tokenizedPattern.length - 1];
|
||||
int index = pattern.lastIndexOf(toStrip);
|
||||
String[] tokens = new String[tokenizedPattern.length - 1];
|
||||
System.arraycopy(tokenizedPattern, 0, tokens, 0,
|
||||
tokenizedPattern.length - 1);
|
||||
return new TokenizedPattern(pattern.substring(0, index), tokens);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.org.apache.tools.ant.types.selectors</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* This is a copy of classes within Apache Ant. The DirectoryScanner
|
||||
* is needed by dependency-check. However, we did not want to make
|
||||
* Ant a dependency. As such, a few files were copied and slightly
|
||||
* modified to remove any references to the Ant Project class.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.types.selectors;
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Vector;
|
||||
|
||||
// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
|
||||
|
||||
/**
|
||||
* A set of helper methods related to collection manipulation.
|
||||
*
|
||||
* @since Ant 1.5
|
||||
*/
|
||||
public class CollectionUtils {
|
||||
|
||||
/**
|
||||
* Collections.emptyList() is Java5+.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Deprecated
|
||||
public static final List EMPTY_LIST = Collections.EMPTY_LIST;
|
||||
|
||||
/**
|
||||
* Please use Vector.equals() or List.equals().
|
||||
* @param v1 the first vector.
|
||||
* @param v2 the second vector.
|
||||
* @return true if the vectors are equal.
|
||||
* @since Ant 1.5
|
||||
* @deprecated since 1.6.x.
|
||||
*/
|
||||
public static boolean equals(Vector<?> v1, Vector<?> v2) {
|
||||
if (v1 == v2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (v1 == null || v2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return v1.equals(v2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dictionary does not have an equals.
|
||||
* Please use Map.equals().
|
||||
*
|
||||
* <p>Follows the equals contract of Java 2's Map.</p>
|
||||
* @param d1 the first directory.
|
||||
* @param d2 the second directory.
|
||||
* @return true if the directories are equal.
|
||||
* @since Ant 1.5
|
||||
* @deprecated since 1.6.x.
|
||||
*/
|
||||
public static boolean equals(Dictionary<?, ?> d1, Dictionary<?, ?> d2) {
|
||||
if (d1 == d2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (d1 == null || d2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d1.size() != d2.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Enumeration<?> e1 = d1.keys();
|
||||
while (e1.hasMoreElements()) {
|
||||
Object key = e1.nextElement();
|
||||
Object value1 = d1.get(key);
|
||||
Object value2 = d2.get(key);
|
||||
if (value2 == null || !value1.equals(value2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// don't need the opposite check as the Dictionaries have the
|
||||
// same size, so we've also covered all keys of d2 already.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comma separated list of all values held in the given
|
||||
* collection.
|
||||
*
|
||||
* @since Ant 1.8.0
|
||||
*/
|
||||
public static String flattenToString(Collection<?> c) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (Object o : c) {
|
||||
if (sb.length() != 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(o);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dictionary does not know the putAll method. Please use Map.putAll().
|
||||
* @param m1 the to directory.
|
||||
* @param m2 the from directory.
|
||||
* @since Ant 1.6
|
||||
* @deprecated since 1.6.x.
|
||||
*/
|
||||
public static <K, V> void putAll(Dictionary<? super K, ? super V> m1, Dictionary<? extends K, ? extends V> m2) {
|
||||
for (Enumeration<? extends K> it = m2.keys(); it.hasMoreElements();) {
|
||||
K key = it.nextElement();
|
||||
m1.put(key, m2.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An empty enumeration.
|
||||
* @since Ant 1.6
|
||||
*/
|
||||
public static final class EmptyEnumeration<E> implements Enumeration<E> {
|
||||
/** Constructor for the EmptyEnumeration */
|
||||
public EmptyEnumeration() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false always.
|
||||
*/
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return nothing.
|
||||
* @throws NoSuchElementException always.
|
||||
*/
|
||||
public E nextElement() throws NoSuchElementException {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append one enumeration to another.
|
||||
* Elements are evaluated lazily.
|
||||
* @param e1 the first enumeration.
|
||||
* @param e2 the subsequent enumeration.
|
||||
* @return an enumeration representing e1 followed by e2.
|
||||
* @since Ant 1.6.3
|
||||
*/
|
||||
public static <E> Enumeration<E> append(Enumeration<E> e1, Enumeration<E> e2) {
|
||||
return new CompoundEnumeration<E>(e1, e2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the specified Iterator to the Enumeration interface.
|
||||
* @param iter the Iterator to adapt.
|
||||
* @return an Enumeration.
|
||||
*/
|
||||
public static <E> Enumeration<E> asEnumeration(final Iterator<E> iter) {
|
||||
return new Enumeration<E>() {
|
||||
public boolean hasMoreElements() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
public E nextElement() {
|
||||
return iter.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the specified Enumeration to the Iterator interface.
|
||||
* @param e the Enumeration to adapt.
|
||||
* @return an Iterator.
|
||||
*/
|
||||
public static <E> Iterator<E> asIterator(final Enumeration<E> e) {
|
||||
return new Iterator<E>() {
|
||||
public boolean hasNext() {
|
||||
return e.hasMoreElements();
|
||||
}
|
||||
public E next() {
|
||||
return e.nextElement();
|
||||
}
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection containing all elements of the iterator.
|
||||
*
|
||||
* @since Ant 1.8.0
|
||||
*/
|
||||
public static <T> Collection<T> asCollection(final Iterator<? extends T> iter) {
|
||||
List<T> l = new ArrayList<T>();
|
||||
while (iter.hasNext()) {
|
||||
l.add(iter.next());
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
private static final class CompoundEnumeration<E> implements Enumeration<E> {
|
||||
|
||||
private final Enumeration<E> e1, e2;
|
||||
|
||||
public CompoundEnumeration(Enumeration<E> e1, Enumeration<E> e2) {
|
||||
this.e1 = e1;
|
||||
this.e2 = e2;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return e1.hasMoreElements() || e2.hasMoreElements();
|
||||
}
|
||||
|
||||
public E nextElement() throws NoSuchElementException {
|
||||
if (e1.hasMoreElements()) {
|
||||
return e1.nextElement();
|
||||
} else {
|
||||
return e2.nextElement();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts how often the given Object occurs in the given
|
||||
* collection using equals() for comparison.
|
||||
*
|
||||
* @since Ant 1.8.0
|
||||
*/
|
||||
public static int frequency(Collection<?> c, Object o) {
|
||||
// same as Collections.frequency introduced with JDK 1.5
|
||||
int freq = 0;
|
||||
if (c != null) {
|
||||
for (Iterator<?> i = c.iterator(); i.hasNext(); ) {
|
||||
Object test = i.next();
|
||||
if (o == null ? test == null : o.equals(test)) {
|
||||
freq++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user