initial release

This commit is contained in:
Jeremy Long
2012-09-08 01:26:38 -04:00
parent d5caab764a
commit ed600f1759
20 changed files with 474 additions and 428 deletions

12
README
View File

@@ -1,14 +1,18 @@
About: About:
DependencyCheck is a simple utility that attempts to determine if there is a Common Product Enumeration (CPE) identifier for a given project dependency. If found, it will generate a report linking to the associated CVE entries. DependencyCheck is a simple utility that attempts to determine if there is a
Common Product Enumeration (CPE) identifier for a given project dependency.
If found, it will generate a report linking to the associated CVE entries.
Usage: Usage:
Still under development: mvn package site Still under development: mvn package site
java -jar dependencycheck-0.1.jar -h
TODO: TODO:
Add CVE download/indexing and CPE lookup. Add CVE download/indexing and CPE lookup.
Finish report generation. Finish report generation (xml).
Fix/finish the CLI. Consider utilizing the OSVDB in addition to CPE/CVE.
Author: Jeremy Long (jeremy.long@gmail.com) Author: Jeremy Long (jeremy.long@gmail.com)
Copyright (c) 2012 Jeremy Long. All Rights Reserved. Copyright (c) 2012 Jeremy Long. All Rights Reserved.

56
pom.xml
View File

@@ -16,13 +16,14 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>. along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
--> -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.codesecure</groupId> <groupId>org.codesecure</groupId>
<artifactId>DependencyCheck</artifactId> <artifactId>DependencyCheck</artifactId>
<version>1.0-SNAPSHOT</version> <version>0.1</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>DependencyCheck</name> <name>DependencyCheck</name>
@@ -34,6 +35,11 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<email>jeremy.long@gmail.com</email> <email>jeremy.long@gmail.com</email>
</developer> </developer>
</developers> </developers>
<scm>
<connection>scm:git:git@github.com:jeremylong/DependencyCheck.git</connection>
<url>scm:git:git@github.com:jeremylong/DependencyCheck.git</url>
<developerConnection>scm:git:git@github.com:jeremylong/DependencyCheck.git</developerConnection>
</scm>
<licenses> <licenses>
<license> <license>
<name>GNU General Public License version 3</name> <name>GNU General Public License version 3</name>
@@ -44,6 +50,25 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<build> <build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.gif</exclude>
<exclude>**/*.js</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@@ -54,7 +79,9 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<version>2.5.1</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -153,15 +180,15 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<workingDirectory>target</workingDirectory> <workingDirectory>target</workingDirectory>
</property> </property>
<property> <property>
<name>index.cpe</name> <name>cve</name>
<value>${project.build.directory}/store/cpe</value> <value>${project.build.directory}/store/cve</value>
</property> </property>
<property> <property>
<name>index.osvdb</name> <name>osvdb</name>
<value>${project.build.directory}/store/osvdb</value> <value>${project.build.directory}/store/osvdb</value>
</property> </property>
<property> <property>
<name>index.cpe</name> <name>cpe</name>
<value>${project.build.directory}/store/cpe</value> <value>${project.build.directory}/store/cpe</value>
</property> </property>
</systemProperties> </systemProperties>
@@ -392,5 +419,24 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<classifier>javadoc</classifier> <classifier>javadoc</classifier>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
<classifier>javadoc</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
<classifier>sources</classifier>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -1,14 +1,32 @@
package org.codesecure.dependencycheck; package org.codesecure.dependencycheck;
/*
* This file is part of DependencyCheck.
*
* DependencyCheck is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DependencyCheck is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DependencyCheck. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.codesecure.dependencycheck.data.cpe.CPEQuery; import org.codesecure.dependencycheck.data.cpe.CPEQuery;
import org.codesecure.dependencycheck.data.cpe.Index;
import org.codesecure.dependencycheck.data.cpe.xml.Importer; import org.codesecure.dependencycheck.data.cpe.xml.Importer;
import org.codesecure.dependencycheck.reporting.ReportGenerator; import org.codesecure.dependencycheck.reporting.ReportGenerator;
import org.codesecure.dependencycheck.scanner.Dependency; import org.codesecure.dependencycheck.scanner.Dependency;
@@ -34,9 +52,8 @@ import org.xml.sax.SAXException;
* *
* Copyright (c) 2012 Jeremy Long. All Rights Reserved. * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/ */
/** /**
* * The command line interface for the DependencyCheck application.
* *
* @author Jeremy Long (jeremy.long@gmail.com) * @author Jeremy Long (jeremy.long@gmail.com)
*/ */
@@ -50,7 +67,12 @@ public class App {
App app = new App(); App app = new App();
app.run(args); app.run(args);
} }
/**
* main CLI entry-point into the application.
*
* @param args the command line arguments
*/
public void run(String[] args) { public void run(String[] args) {
CliParser cli = new CliParser(); CliParser cli = new CliParser();
try { try {
@@ -62,18 +84,32 @@ public class App {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
return; return;
} }
if (cli.isGetVersion()) { if (cli.isGetVersion()) {
cli.printVersionInfo(); cli.printVersionInfo();
} else if (cli.isLoadCPE()) { } else if (cli.isLoadCPE()) {
loadCPE(cli.getCpeFile()); loadCPE(cli.getCpeFile());
} else if (cli.isRunScan()) { } else if (cli.isRunScan()) {
if (cli.isAutoUpdate()) {
Index cpeI = new Index();
try {
cpeI.updateIndexFromWeb();
} catch (Exception ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
}
}
runScan(cli.getReportDirectory(), cli.getApplicationName(), cli.getScanFiles()); runScan(cli.getReportDirectory(), cli.getApplicationName(), cli.getScanFiles());
} else { } else {
cli.printHelp(); cli.printHelp();
} }
} }
/**
* Loads the specified CPE.XML file into Lucene Index.
* @param cpePath
*/
private void loadCPE(String cpePath) { private void loadCPE(String cpePath) {
try { try {
Importer.importXML(cpePath); Importer.importXML(cpePath);
@@ -85,6 +121,13 @@ public class App {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
} }
} }
/**
* Scans the specified directories and writes the dependency reports to the reportDirectory.
* @param reportDirectory the path to the directory where the reports will be written.
* @param applicationName the application name for the report.
* @param files the files/directories to scan.
*/
private void runScan(String reportDirectory, String applicationName, String[] files) { private void runScan(String reportDirectory, String applicationName, String[] files) {
try { try {
Scanner scanner = new Scanner(); Scanner scanner = new Scanner();
@@ -106,13 +149,11 @@ public class App {
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
} }
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
} catch (org.apache.lucene.queryParser.ParseException ex) { } catch (org.apache.lucene.queryParser.ParseException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
} }
} }
} }

View File

@@ -61,7 +61,7 @@ public class CPEQuery {
* utilized within the CPE Names. * utilized within the CPE Names.
*/ */
static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 _-]"; static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 _-]";
/* A string representation of a regular expression used to remove all but /* A string representation of a regular expression used to remove all but
* alpha characters. * alpha characters.
*/ */
static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*"; static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
@@ -191,15 +191,15 @@ public class CPEQuery {
do { do {
List<Entry> entries = searchCPE(vendors, titles, versions, dependency.getTitleEvidence().getWeighting(), List<Entry> entries = searchCPE(vendors, titles, versions, dependency.getTitleEvidence().getWeighting(),
dependency.getVendorEvidence().getWeighting()); dependency.getVendorEvidence().getWeighting());
if (entries.size()>0) { if (entries.size() > 0) {
List<String> verified = verifyEntries(entries, dependency); List<String> verified = verifyEntries(entries, dependency);
if (verified.size() > 0) { if (verified.size() > 0) {
found = true; found = true;
dependency.setCPEs(verified); dependency.setCPEs(verified);
} }
} }
if (!found) { if (!found) {
int round = cnt % 3; int round = cnt % 3;
if (round == 0) { if (round == 0) {
@@ -320,7 +320,7 @@ public class CPEQuery {
*/ */
protected String buildSearch(String vendor, String product, String version, protected String buildSearch(String vendor, String product, String version,
List<String> vendorWeighting, List<String> produdctWeightings) { List<String> vendorWeighting, List<String> produdctWeightings) {
StringBuilder sb = new StringBuilder(vendor.length() + product.length() StringBuilder sb = new StringBuilder(vendor.length() + product.length()
+ version.length() + Fields.PRODUCT.length() + Fields.VERSION.length() + version.length() + Fields.PRODUCT.length() + Fields.VERSION.length()
+ Fields.VENDOR.length() + STRING_BUILDER_BUFFER); + Fields.VENDOR.length() + STRING_BUILDER_BUFFER);
@@ -335,7 +335,7 @@ public class CPEQuery {
if (!appendWeightedSearch(sb, Fields.VENDOR, vendor.toLowerCase(), vendorWeighting)) { if (!appendWeightedSearch(sb, Fields.VENDOR, vendor.toLowerCase(), vendorWeighting)) {
return null; return null;
} }
sb.append(Fields.VERSION).append(":("); sb.append(Fields.VERSION).append(":(");
if (sb.indexOf("^") > 0) { if (sb.indexOf("^") > 0) {
//if we have a weighting on something else, reduce the weighting on the version a lot //if we have a weighting on something else, reduce the weighting on the version a lot
@@ -369,7 +369,7 @@ public class CPEQuery {
sb.append(" ").append(field).append(":( "); sb.append(" ").append(field).append(":( ");
String cleanText = cleanseText(searchText); String cleanText = cleanseText(searchText);
if ("".equals(cleanText)) { if ("".equals(cleanText)) {
return false; return false;
} }
@@ -408,7 +408,7 @@ public class CPEQuery {
private String cleanseText(String text) { private String cleanseText(String text) {
return text.replaceAll(CLEANSE_CHARACTER_RX, " "); return text.replaceAll(CLEANSE_CHARACTER_RX, " ");
} }
/** /**
* Compares two strings after lower casing them and removing the non-alpha * Compares two strings after lower casing them and removing the non-alpha
* characters. * characters.

View File

@@ -19,10 +19,16 @@ package org.codesecure.dependencycheck.data.cpe;
*/ */
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL; import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
@@ -38,6 +44,8 @@ import org.apache.lucene.util.Version;
import org.codesecure.dependencycheck.utils.Downloader; import org.codesecure.dependencycheck.utils.Downloader;
import org.codesecure.dependencycheck.utils.Settings; import org.codesecure.dependencycheck.utils.Settings;
import org.codesecure.dependencycheck.data.cpe.xml.Importer; import org.codesecure.dependencycheck.data.cpe.xml.Importer;
import org.joda.time.DateTime;
import org.joda.time.Days;
/** /**
* The Index class is used to utilize and maintain the CPE Index. * The Index class is used to utilize and maintain the CPE Index.
@@ -46,6 +54,14 @@ import org.codesecure.dependencycheck.data.cpe.xml.Importer;
*/ */
public class Index { public class Index {
/**
* Te name of the properties file containing the timestamp of the last update.
*/
private static final String UPDATE_PROPERTIES_FILE = "lastupdated.prop";
/**
* The properties file key for the last updated field.
*/
private static final String LAST_UPDATED = "lastupdated";
/** /**
* The Lucene directory containing the index. * The Lucene directory containing the index.
*/ */
@@ -124,10 +140,47 @@ public class Index {
outputPath = File.createTempFile("cpe", ".xml"); outputPath = File.createTempFile("cpe", ".xml");
Downloader.fetchFile(url, outputPath); Downloader.fetchFile(url, outputPath);
Importer.importXML(outputPath.toString()); Importer.importXML(outputPath.toString());
writeLastUpdatedPropertyFile();
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
} finally { } finally {
outputPath.delete(); boolean deleted = false;
try {
deleted = outputPath.delete();
} finally {
if (!deleted) {
outputPath.deleteOnExit();
}
}
}
}
}
private void writeLastUpdatedPropertyFile() {
DateTime now = new DateTime();
String dir = Settings.getString(Settings.KEYS.CPE_INDEX);
File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
Properties prop = new Properties();
prop.put(this.LAST_UPDATED, String.valueOf(now.getMillis()));
OutputStream os = null;
try {
os = new FileOutputStream(cpeProp);
OutputStreamWriter out = new OutputStreamWriter(os);
prop.store(out, dir);
} catch (FileNotFoundException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
os.flush();
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
}
try {
os.close();
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
} }
} }
} }
@@ -138,6 +191,43 @@ public class Index {
* @return whether or not the CPE Index needs to be updated. * @return whether or not the CPE Index needs to be updated.
*/ */
public boolean updateNeeded() { public boolean updateNeeded() {
return true; boolean needed = false;
String lastUpdated = null;
String dir = Settings.getString(Settings.KEYS.CPE_INDEX);
File f = new File(dir);
if (!f.exists()) {
needed = true;
} else {
File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
if (!cpeProp.exists()) {
needed = true;
} else {
Properties prop = new Properties();
FileInputStream is = null;
try {
is = new FileInputStream(cpeProp);
prop.load(is);
lastUpdated = prop.getProperty(this.LAST_UPDATED);
} catch (FileNotFoundException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
}
try {
long lastupdate = Long.parseLong(lastUpdated);
DateTime last = new DateTime(lastupdate);
DateTime now = new DateTime();
Days d = Days.daysBetween(last, now);
int days = d.getDays();
int freq = Settings.getInt(Settings.KEYS.CPE_DOWNLOAD_FREQUENCY);
if (days >= freq) {
needed = true;
}
} catch (NumberFormatException ex) {
needed = true;
}
}
}
return needed;
} }
} }

View File

@@ -39,6 +39,25 @@ public class Importer {
private Importer() { private Importer() {
} }
/**
* Imports the CPE XML File into the Lucene Index.
*
* @param file containing the path to the CPE XML file.
* @throws ParserConfigurationException is thrown if the parser is misconfigured.
* @throws SAXException is thrown when there is a SAXException.
* @throws IOException is thrown when there is an IOException.
*/
public static void importXML(File file) throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
CPEHandler handler = new CPEHandler();
Indexer indexer = new Indexer();
indexer.open();
handler.registerSaveDelegate(indexer);
saxParser.parse(file, handler);
indexer.close();
}
/** /**
* Imports the CPE XML File into the Lucene Index. * Imports the CPE XML File into the Lucene Index.
* *
@@ -48,14 +67,7 @@ public class Importer {
* @throws IOException is thrown when there is an IOException. * @throws IOException is thrown when there is an IOException.
*/ */
public static void importXML(String path) throws ParserConfigurationException, SAXException, IOException { public static void importXML(String path) throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
CPEHandler handler = new CPEHandler();
Indexer indexer = new Indexer();
indexer.open();
handler.registerSaveDelegate(indexer);
File f = new File(path); File f = new File(path);
saxParser.parse(f, handler); Importer.importXML(f);
indexer.close();
} }
} }

View File

@@ -27,7 +27,6 @@ import java.io.InputStreamReader;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context; import org.apache.velocity.context.Context;
import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.RuntimeConstants;
@@ -42,20 +41,28 @@ import org.codesecure.dependencycheck.scanner.Dependency;
*/ */
public class ReportGenerator { public class ReportGenerator {
/**
* Generates the Dependency Reports for the identified dependencies.
*
* @param outputDir the path where the reports should be written.
* @param applicationName the name of the application that was scanned.
* @param dependencies a list of dependencies to include in the report.
* @throws IOException is thrown when the template file does not exist.
* @throws Exception is thrown if there is an error writting out the reports.
*/
public void generateReports(String outputDir, String applicationName, List<Dependency> dependencies) throws IOException, Exception { public void generateReports(String outputDir, String applicationName, List<Dependency> dependencies) throws IOException, Exception {
Map<String, Object> properties = new HashMap<String, Object>(); Map<String, Object> properties = new HashMap<String, Object>();
properties.put("dependencies",dependencies); properties.put("dependencies", dependencies);
properties.put("applicationName", applicationName); properties.put("applicationName", applicationName);
String reportName = applicationName.replaceAll("[^a-zA-Z0-9-_ \\.]+", ""); String reportName = applicationName.replaceAll("[^a-zA-Z0-9-_ \\.]+", "");
String filename = outputDir + File.separatorChar + reportName; String filename = outputDir + File.separatorChar + reportName;
generateReport("HtmlReport",filename+".html",properties); generateReport("HtmlReport", filename + ".html", properties);
//generateReport("XmlReport",filename+".xml",properties); //generateReport("XmlReport",filename + ".xml",properties);
} }
/** /**
* much of this code is from http://stackoverflow.com/questions/2931516/loading-velocity-template-inside-a-jar-file * much of this code is from http://stackoverflow.com/questions/2931516/loading-velocity-template-inside-a-jar-file
* @param templateName the name of the template to load. * @param templateName the name of the template to load.
@@ -64,23 +71,23 @@ public class ReportGenerator {
* @throws IOException is thrown when the template file does not exist. * @throws IOException is thrown when the template file does not exist.
* @throws Exception is thrown when an exception occurs. * @throws Exception is thrown when an exception occurs.
*/ */
protected void generateReport(String templateName, String outFileName, protected void generateReport(String templateName, String outFileName,
Map<String, Object> properties) throws IOException, Exception { Map<String, Object> properties) throws IOException, Exception {
VelocityEngine ve = new VelocityEngine(); VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
ToolManager manager = new ToolManager(); ToolManager manager = new ToolManager();
Context context = manager.createContext(); Context context = manager.createContext();
EasyFactoryConfiguration config = new EasyFactoryConfiguration(); EasyFactoryConfiguration config = new EasyFactoryConfiguration();
config.addDefaultTools(); config.addDefaultTools();
config.toolbox("application") config.toolbox("application")
.tool("esc","org.apache.velocity.tools.generic.EscapeTool") .tool("esc", "org.apache.velocity.tools.generic.EscapeTool")
.tool("org.apache.velocity.tools.generic.DateTool"); .tool("org.apache.velocity.tools.generic.DateTool");
manager.configure(config); manager.configure(config);
ve.init(); ve.init();
final String templatePath = "templates/" + templateName + ".vsl"; final String templatePath = "templates/" + templateName + ".vsl";
@@ -91,19 +98,19 @@ public class ReportGenerator {
InputStreamReader reader = new InputStreamReader(input); InputStreamReader reader = new InputStreamReader(input);
BufferedWriter writer = null; BufferedWriter writer = null;
//VelocityContext context = new VelocityContext(); //VelocityContext context = new VelocityContext();
//load the data into the context //load the data into the context
if (properties != null) { if (properties != null) {
for (Map.Entry<String, Object> property : properties.entrySet()) { for (Map.Entry<String, Object> property : properties.entrySet()) {
context.put(property.getKey(), property.getValue()); context.put(property.getKey(), property.getValue());
} }
} }
try { try {
writer = new BufferedWriter(new FileWriter(new File(outFileName))); writer = new BufferedWriter(new FileWriter(new File(outFileName)));
if (!ve.evaluate(context, writer, templatePath, reader)) { if (!ve.evaluate(context, writer, templatePath, reader)) {
throw new Exception("Failed to convert the template into html."); throw new Exception("Failed to convert the template into html.");
} }
@@ -112,12 +119,12 @@ public class ReportGenerator {
try { try {
writer.close(); writer.close();
} catch (Exception ex) { } catch (Exception ex) {
//ignore this error.
} }
try { try {
reader.close(); reader.close();
} catch (Exception ex) { } catch (Exception ex) {
//ignore this error.
} }
} }
} }

View File

@@ -0,0 +1,12 @@
/**
* <html>
* <head>
* <title>org.codesecure.dependencycheck.reporting</title>
* </head>
* <body>
* Contains classes used to generate reports.
* </body>
* </html>
*/
package org.codesecure.dependencycheck.reporting;

View File

@@ -65,13 +65,16 @@ public class Dependency {
*/ */
protected EvidenceCollection versionEvidence = null; protected EvidenceCollection versionEvidence = null;
/**
* Constructs a new Dependency object.
*/
public Dependency() { public Dependency() {
vendorEvidence = new EvidenceCollection(); vendorEvidence = new EvidenceCollection();
titleEvidence = new EvidenceCollection(); titleEvidence = new EvidenceCollection();
versionEvidence = new EvidenceCollection(); versionEvidence = new EvidenceCollection();
cpes = new ArrayList<String>(); cpes = new ArrayList<String>();
} }
/** /**
* Returns the file name of the JAR. * Returns the file name of the JAR.
* *
@@ -180,8 +183,8 @@ public class Dependency {
public EvidenceCollection getEvidence() { public EvidenceCollection getEvidence() {
return EvidenceCollection.mergeUsed(this.titleEvidence, this.vendorEvidence, this.versionEvidence); return EvidenceCollection.mergeUsed(this.titleEvidence, this.vendorEvidence, this.versionEvidence);
} }
/** /**
* Returns the evidence used to identify this dependency. * Returns the evidence used to identify this dependency.
* *

View File

@@ -234,5 +234,5 @@ public class EvidenceCollection implements Iterable<Evidence> {
} }
return sb.toString(); return sb.toString();
} }
} }

View File

@@ -51,22 +51,23 @@ public class JarAnalyzer implements Analyzer {
private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core
private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation
private enum STRING_STATE { private enum STRING_STATE {
ALPHA, ALPHA,
NUMBER, NUMBER,
OTHER OTHER
} }
private STRING_STATE determineState(char c) { private STRING_STATE determineState(char c) {
if (c>='0' && c<='9' || c=='.') { if (c >= '0' && c <= '9' || c == '.') {
return STRING_STATE.NUMBER; return STRING_STATE.NUMBER;
} else if (c>='a' && c<='z') { } else if (c >= 'a' && c <= 'z') {
return STRING_STATE.ALPHA; return STRING_STATE.ALPHA;
} else { } else {
return STRING_STATE.OTHER; return STRING_STATE.OTHER;
} }
} }
/** /**
* Loads a specified JAR file and collects information from the manifest and * Loads a specified JAR file and collects information from the manifest and
* checksums to identify the correct CPE information. * checksums to identify the correct CPE information.
@@ -82,19 +83,17 @@ public class JarAnalyzer implements Analyzer {
String fileName = file.getName(); String fileName = file.getName();
dependency.setFileName(fileName); dependency.setFileName(fileName);
dependency.setFilePath(file.getCanonicalPath()); dependency.setFilePath(file.getCanonicalPath());
String fileNameEvidence = fileName.substring(0,fileName.length()-4) String fileNameEvidence = fileName.substring(0, fileName.length() - 4)
.toLowerCase() .toLowerCase().replace('-', ' ').replace('_', ' ');
.replace('-', ' ')
.replace('_', ' ');
StringBuilder sb = new StringBuilder(fileNameEvidence.length()); StringBuilder sb = new StringBuilder(fileNameEvidence.length());
STRING_STATE state = determineState(fileNameEvidence.charAt(0)); STRING_STATE state = determineState(fileNameEvidence.charAt(0));
for(int i=0;i<fileNameEvidence.length();i++) { for (int i = 0; i < fileNameEvidence.length(); i++) {
char c = fileNameEvidence.charAt(i); char c = fileNameEvidence.charAt(i);
STRING_STATE new_state = determineState(c); STRING_STATE newState = determineState(c);
if (new_state != state) { if (newState != state) {
sb.append(' '); sb.append(' ');
state = new_state; state = newState;
} }
sb.append(c); sb.append(c);
} }
@@ -106,7 +105,7 @@ public class JarAnalyzer implements Analyzer {
fileNameEvidence, Evidence.Confidence.HIGH); fileNameEvidence, Evidence.Confidence.HIGH);
dependency.getVersionEvidence().addEvidence("jar", "file name", dependency.getVersionEvidence().addEvidence("jar", "file name",
fileNameEvidence, Evidence.Confidence.HIGH); fileNameEvidence, Evidence.Confidence.HIGH);
String md5 = null; String md5 = null;
String sha1 = null; String sha1 = null;
try { try {

View File

@@ -87,7 +87,7 @@ public class Scanner {
break; break;
} }
} }
if (implmnts) { if (implmnts) {
this.analyzers.put(extension, (Analyzer) analyzer.newInstance()); this.analyzers.put(extension, (Analyzer) analyzer.newInstance());
} else { } else {

View File

@@ -103,7 +103,7 @@ public final class CliParser {
//TODO - need a new exception type here, this isn't really a parseexception. //TODO - need a new exception type here, this isn't really a parseexception.
throw new ParseException("Scan cannot be run without specifying a directory to write the reports to via the 'out' argument."); throw new ParseException("Scan cannot be run without specifying a directory to write the reports to via the 'out' argument.");
} else { } else {
String p = line.getOptionValue(ArgumentName.OUT,""); String p = line.getOptionValue(ArgumentName.OUT, "");
File f = new File(p); File f = new File(p);
if ("".equals(p) || !(f.exists() && f.isDirectory())) { if ("".equals(p) || !(f.exists() && f.isDirectory())) {
//TODO - need a new exception type here, this isn't really a parseexception. //TODO - need a new exception type here, this isn't really a parseexception.
@@ -151,22 +151,29 @@ public final class CliParser {
*/ */
@SuppressWarnings("static-access") @SuppressWarnings("static-access")
private Options createCommandLineOptions() { private Options createCommandLineOptions() {
Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false, "print this message"); Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION, false, "print the version information and exit"); "print this message");
Option appname = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APPNAME).withDescription("the name of the application being scanned").create(ArgumentName.APPNAME_SHORT);
Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN).withDescription("the path to scan").create(ArgumentName.SCAN_SHORT); Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
false, "print the version information and exit");
Option load = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.CPE).withDescription("load the CPE xml file").create(ArgumentName.CPE_SHORT); Option noupdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
false, "disables the automatic updating of the CPE data.");
Option appname = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APPNAME)
.withDescription("the name of the application being scanned").create(ArgumentName.APPNAME_SHORT);
Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
.withDescription("the path to scan - this option can be specified multiple times.").create(ArgumentName.SCAN_SHORT);
Option load = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.CPE)
.withDescription("load the CPE xml file").create(ArgumentName.CPE_SHORT);
Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
.withDescription("the folder to write reports to.").create(ArgumentName.OUT_SHORT);
Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT).withDescription("the folder to write reports to.").create(ArgumentName.OUT_SHORT);
//TODO add the ability to load a properties file to override the defaults... //TODO add the ability to load a properties file to override the defaults...
//TODO add the ability to load the CVE entries.
//TODO add a switch to auto-update CVE entries.
//TODO add a switch to auto-update CPE entries.
OptionGroup og = new OptionGroup(); OptionGroup og = new OptionGroup();
og.addOption(path); og.addOption(path);
og.addOption(load); og.addOption(load);
@@ -177,6 +184,7 @@ public final class CliParser {
opts.addOption(appname); opts.addOption(appname);
opts.addOption(version); opts.addOption(version);
opts.addOption(help); opts.addOption(help);
opts.addOption(noupdate);
return opts; return opts;
} }
@@ -222,10 +230,14 @@ public final class CliParser {
*/ */
public void printHelp() { public void printHelp() {
HelpFormatter formatter = new HelpFormatter(); HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("DependencyCheck", options, true); formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
"\n" + Settings.getString("application.name", "DependencyCheck") +
" can be used to identify if there are any known CVE vulnerabilities in libraries utillized by an application." +
" " + Settings.getString("application.name", "DependencyCheck") + " will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.\n",
options, "", true);
} }
/** /**
* Retrieves the file command line parameter(s) specified for the 'cpe' argument. * Retrieves the file command line parameter(s) specified for the 'cpe' argument.
* *
@@ -234,7 +246,7 @@ public final class CliParser {
public String getCpeFile() { public String getCpeFile() {
return line.getOptionValue(ArgumentName.CPE); return line.getOptionValue(ArgumentName.CPE);
} }
/** /**
* Retrieves the file command line parameter(s) specified for the 'scan' argument. * Retrieves the file command line parameter(s) specified for the 'scan' argument.
* *
@@ -242,12 +254,21 @@ public final class CliParser {
*/ */
public String[] getScanFiles() { public String[] getScanFiles() {
return line.getOptionValues(ArgumentName.SCAN); return line.getOptionValues(ArgumentName.SCAN);
} }
/**
* returns the directory to write the reports to specified on the command line.
* @return the path to the reports directory.
*/
public String getReportDirectory() { public String getReportDirectory() {
return line.getOptionValue(ArgumentName.OUT); return line.getOptionValue(ArgumentName.OUT);
} }
/**
* Returns the application name specified on the command line.
* @return the applicatoin name.
*/
public String getApplicationName() { public String getApplicationName() {
return line.getOptionValue(ArgumentName.APPNAME); return line.getOptionValue(ArgumentName.APPNAME);
} }
@@ -257,49 +278,83 @@ public final class CliParser {
* <li>Implementation-Version: ${pom.version}</li></ul> * <li>Implementation-Version: ${pom.version}</li></ul>
*/ */
public void printVersionInfo() { public void printVersionInfo() {
String version = "DependencyCheck version unknown"; String version = String.format("%s version %s",
Settings.getString("application.name", "DependencyCheck"),
URLClassLoader cl = (URLClassLoader) this.getClass().getClassLoader(); Settings.getString("application.version", "Unknown"));
InputStream is = null;
try {
URL url = cl.findResource("META-INF/MANIFEST.MF");
is = url.openStream();
Manifest manifest = new Manifest(is);
Attributes atts = manifest.getMainAttributes();
version = atts.getValue(Attributes.Name.IMPLEMENTATION_TITLE)
+ " version "
+ atts.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
} catch (IOException ex) {
Logger.getLogger(CliParser.class.getName()).log(Level.WARNING, null, ex);
} finally {
try {
is.close();
is = null;
} catch (Throwable ex) {
Logger.getLogger(CliParser.class.getName()).log(Level.FINEST, null, ex);
}
}
System.out.println(version); System.out.println(version);
} }
/**
* Checks if the auto update feature has been disabled. If it has been disabled
* via the command line this will return false.
*
* @return if auto-update is allowed.
*/
public boolean isAutoUpdate() {
return (line != null) ? !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE) : false;
}
/** /**
* A collection of static final strings that represent the possible command * A collection of static final strings that represent the possible command
* line arguments. * line arguments.
*/ */
public static class ArgumentName { public static class ArgumentName {
/**
* The long CLI argument name specifing the directory/file to scan
*/
public static final String SCAN = "scan"; public static final String SCAN = "scan";
public static final String CPE = "cpe"; /**
public static final String OUT = "out"; * The short CLI argument name specifing the directory/file to scan
public static final String APPNAME = "app"; */
public static final String VERSION = "version";
public static final String HELP = "help";
public static final String SCAN_SHORT = "s"; public static final String SCAN_SHORT = "s";
/**
* The long CLI argument name specifing the path to the CPE.XML file to import
*/
public static final String CPE = "cpe";
/**
* The short CLI argument name specifing the path to the CPE.XML file to import
*/
public static final String CPE_SHORT = "c"; public static final String CPE_SHORT = "c";
/**
* The long CLI argument name specifing that the CPE/CVE/etc. data should not be automatically updated.
*/
public static final String DISABLE_AUTO_UPDATE = "noupdate";
/**
* The short CLI argument name specifing that the CPE/CVE/etc. data should not be automatically updated.
*/
public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
/**
* The long CLI argument name specifing the directory to write the reports to.
*/
public static final String OUT = "out";
/**
* The short CLI argument name specifing the directory to write the reports to.
*/
public static final String OUT_SHORT = "o"; public static final String OUT_SHORT = "o";
public static final String VERSION_SHORT = "v"; /**
public static final String HELP_SHORT = "h"; * The long CLI argument name specifing the name of the application to be scanned.
*/
public static final String APPNAME = "app";
/**
* The short CLI argument name specifing the name of the application to be scanned.
*/
public static final String APPNAME_SHORT = "a"; public static final String APPNAME_SHORT = "a";
/**
* The long CLI argument name asking for help.
*/
public static final String HELP = "help";
/**
* The short CLI argument name asking for help.
*/
public static final String HELP_SHORT = "h";
/**
* The long CLI argument name asking for the version.
*/
public static final String VERSION_SHORT = "v";
/**
* The short CLI argument name asking for the version.
*/
public static final String VERSION = "version";
} }
} }

View File

@@ -34,6 +34,7 @@ import java.util.logging.Logger;
*/ */
public class Settings { public class Settings {
/** /**
* The collection of keys used within the properties file. * The collection of keys used within the properties file.
*/ */
@@ -42,19 +43,23 @@ public class Settings {
/** /**
* The properties key for the path where the CPE Lucene Index will be stored. * The properties key for the path where the CPE Lucene Index will be stored.
*/ */
public static final String CPE_INDEX = "index.cpe"; public static final String CPE_INDEX = "cpe";
/** /**
* The properties key for the URL to the CPE. * The properties key for the URL to the CPE.
*/ */
public static final String CPE_URL = "index.cpe.url"; public static final String CPE_URL = "cpe.url";
/**
* The properties key for the URL to the CPE.
*/
public static final String CPE_DOWNLOAD_FREQUENCY = "cpe.downloadfrequency";
/** /**
* The properties key for the path where the CCE Lucene Index will be stored. * The properties key for the path where the CCE Lucene Index will be stored.
*/ */
public static final String CVE_INDEX = "index.cve"; public static final String CVE_INDEX = "cve";
/** /**
* The properties key for the path where the OSVDB Lucene Index will be stored. * The properties key for the path where the OSVDB Lucene Index will be stored.
*/ */
public static final String OSVDB_INDEX = "index.osvdb"; public static final String OSVDB_INDEX = "osvdb";
/** /**
* The properties key prefix for the analyzer assocations. * The properties key prefix for the analyzer assocations.
*/ */
@@ -77,6 +82,24 @@ public class Settings {
} }
} }
/**
* Returns a value from the properties file. If the value was specified as a
* system property or passed in via the -Dprop=value argument - this method
* will return the value from the system properties before the values in
* the contained configuration file.
*
* @param key the key to lookup within the properties file.
* @param defaultValue the default value for the requested property.
* @return the property from the properties file.
*/
public static String getString(String key, String defaultValue) {
String str = System.getProperty(key, instance.props.getProperty(key));
if (str==null) {
str = defaultValue;
}
return str;
}
/** /**
* Returns a value from the properties file. If the value was specified as a * Returns a value from the properties file. If the value was specified as a
* system property or passed in via the -Dprop=value argument - this method * system property or passed in via the -Dprop=value argument - this method
@@ -127,13 +150,28 @@ public class Settings {
} }
return ret; return ret;
} }
// public static boolean getBoolean(String key) { /**
// return Boolean.parseBoolean(instance.props.getProperty(key)); * Returns a integer value from the properties file. If the value was specified as a
// } * system property or passed in via the -Dprop=value argument - this method
// public static long getLong(String key) { * will return the value from the system properties before the values in
// return Long.parseLong(instance.props.getProperty(key)); * the contained configuration file.
// } *
// public static int getInt(String key) { * @param key the key to lookup within the properties file.
// return Integer.parseInt(instance.props.getProperty(key)); * @return the property from the properties file.
// } */
public static int getInt(String key) {
return Integer.parseInt(Settings.getString(key));
}
/**
* Returns a boolean value from the properties file. If the value was specified as a
* system property or passed in via the -Dprop=value argument - this method
* will return the value from the system properties before the values in
* the contained configuration file.
*
* @param key the key to lookup within the properties file.
* @return the property from the properties file.
*/
public static boolean getBoolean(String key) {
return Boolean.parseBoolean(Settings.getString(key));
}
} }

View File

@@ -1,9 +1,10 @@
# To change this template, choose Tools | Templates application.name=${pom.name}
# and open the template in the editor. application.version=${pom.version}
index.cpe=store/cpe cpe=store/cpe
index.cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.xml cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.xml
index.cve=store/cve cpe.downloadfrequency=1
index.osvdb=store/osvdb cve=store/cve
osvdb=store/osvdb
file.extension.analyzer.association.jar=org.codesecure.dependencycheck.scanner.JarAnalyzer file.extension.analyzer.association.jar=org.codesecure.dependencycheck.scanner.JarAnalyzer

View File

@@ -20,7 +20,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
@version 1 @version 1
*# *#
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
@@ -274,7 +273,9 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
#set($cnt=0) #set($cnt=0)
#foreach($dependency in $dependencies) #foreach($dependency in $dependencies)
<h3 class="subsectionheader standardsubsection"><a name="$esc.html($dependency.FilePath)"></a>$esc.html($dependency.FileName)</h3> <h3 class="subsectionheader standardsubsection"><a name="$esc.html($dependency.FilePath)"></a>$esc.html($dependency.FileName)</h3>
<div class="subsectioncontent">File&nbsp;Path:&nbsp;$esc.html($dependency.FilePath) <div class="subsectioncontent">File&nbsp;Path:&nbsp;$esc.html($dependency.FilePath)<br/>
MD5:&nbsp;$esc.html($dependency.Md5sum)<br/>
SHA1:&nbsp;$esc.html($dependency.Sha1sum)
#set($cnt=$cnt+1) #set($cnt=$cnt+1)
<h4 id="header$cnt" class="subsectionheader expandablesubsection white">Evidence</h4> <h4 id="header$cnt" class="subsectionheader expandablesubsection white">Evidence</h4>
<div id="content$cnt" class="subsectioncontent standardsubsection hidden"> <div id="content$cnt" class="subsectioncontent standardsubsection hidden">
@@ -293,8 +294,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
Information for specific CVE entries for the idenfied CPE can be found <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$esc.url($cpevalue)" target="blank">here</a>. Information for specific CVE entries for the idenfied CPE can be found <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$esc.url($cpevalue)" target="blank">here</a>.
#* http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-0838 #* http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-0838
<a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=" target="blank">cve://a:/blah1.blah</a><br/> <a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=" target="blank">cve://a:/blah1.blah</a><br/>
<a href="cve.mitre.org" target="blank">cve://a:/blah2.blah</a><br/> *#
<a href="cve.mitre.org" target="blank">cve://a:/blah3.blah</a><br/>*#
</div> </div>
#end #end
#if($dependency.getCPEs().size()>1) #if($dependency.getCPEs().size()>1)
@@ -310,7 +310,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
#end #end
#if($dependency.getCPEs().size()==0) #if($dependency.getCPEs().size()==0)
<h4>No CPE Identifies were found for this dependency.</h4> <h4>No CPE Identifiers were found for this dependency.</h4>
#end #end
</div> </div>
#end #end

File diff suppressed because one or more lines are too long

View File

@@ -31,7 +31,7 @@ public abstract class BaseIndexTestCase extends TestCase {
} }
protected void ensureIndexExists() throws Exception { protected void ensureIndexExists() throws Exception {
String indexPath = Settings.getString("index.cpe"); String indexPath = Settings.getString("cpe");
java.io.File f = new File(indexPath); java.io.File f = new File(indexPath);
if (!f.exists()) { if (!f.exists()) {
f.mkdirs(); f.mkdirs();

View File

@@ -336,9 +336,8 @@ public class CliParserTest extends TestCase {
baos.flush(); baos.flush();
String text = (new String(baos.toByteArray())); String text = (new String(baos.toByteArray()));
String[] lines = text.split(System.getProperty("line.separator")); String[] lines = text.split(System.getProperty("line.separator"));
assertEquals("usage: DependencyCheck [-a <name>] [-c <file> | -s <path>] [-h] [-o", lines[0]); assertTrue(lines[0].startsWith("usage: "));
assertEquals(" <folder>] [-v]", lines[1]); assertTrue((lines.length>2));
assertEquals(8, lines.length);
} catch (IOException ex) { } catch (IOException ex) {
System.setOut(out); System.setOut(out);
fail("CliParser.printVersionInfo did not write anything to system.out."); fail("CliParser.printVersionInfo did not write anything to system.out.");

View File

@@ -36,15 +36,17 @@ public class DownloaderTest {
public void tearDown() { public void tearDown() {
} }
/**
* Test of fetchFile method, of class Downloader. //This test is being removed because it is a bit too slow.
* @throws Exception thrown when an excpetion occurs. // /**
*/ // * Test of fetchFile method, of class Downloader.
@Test // * @throws Exception thrown when an excpetion occurs.
public void testFetchFile_URL_String() throws Exception { // */
System.out.println("fetchFile"); // @Test
URL url = new URL(Settings.getString(Settings.KEYS.CPE_URL)); // public void testFetchFile_URL_String() throws Exception {
String outputPath = "target\\downloaded_cpe.xml"; // System.out.println("fetchFile");
Downloader.fetchFile(url, outputPath); // URL url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
} // String outputPath = "target\\downloaded_cpe.xml";
// Downloader.fetchFile(url, outputPath);
// }
} }