bug fixes/enhancements

This commit is contained in:
Jeremy Long
2012-09-10 12:25:15 -04:00
parent dbc10e53e4
commit 4147801074
10 changed files with 216 additions and 82 deletions

6
README
View File

@@ -4,9 +4,11 @@ Common Product Enumeration (CPE) identifier for a given project dependency.
If found, it will generate a report linking to the associated CVE entries. If found, it will generate a report linking to the associated CVE entries.
Usage: Usage:
Still under development: mvn package site $ mvn package
$ cd target
$ java -jar dependencycheck-0.1.jar -h
$ java -jar DependencyCheck-0.1.jar -a Testing -out . -scan ./test-classes/org.mortbay.jetty.jar -scan struts2-core-2.1.2.jar -scan ./lib
java -jar dependencycheck-0.1.jar -h
TODO: TODO:
Add CVE download/indexing and CPE lookup. Add CVE download/indexing and CPE lookup.

View File

@@ -21,6 +21,8 @@ package org.codesecure.dependencycheck.data.cpe;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
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;
@@ -37,7 +39,9 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version; import org.apache.lucene.util.Version;
import org.codesecure.dependencycheck.data.LuceneUtils; import org.codesecure.dependencycheck.data.LuceneUtils;
import org.codesecure.dependencycheck.scanner.Dependency; import org.codesecure.dependencycheck.scanner.Dependency;
import org.codesecure.dependencycheck.scanner.Evidence;
import org.codesecure.dependencycheck.scanner.Evidence.Confidence; import org.codesecure.dependencycheck.scanner.Evidence.Confidence;
import org.codesecure.dependencycheck.scanner.EvidenceCollection;
/** /**
* CPEQuery is a utility class that takes a project dependency and attempts * CPEQuery is a utility class that takes a project dependency and attempts
@@ -60,7 +64,7 @@ public class CPEQuery {
* A string representation of a regular expression defining characters * A string representation of a regular expression defining characters
* utilized within the CPE Names. * utilized within the CPE Names.
*/ */
static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 _-]"; 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.
*/ */
@@ -166,22 +170,25 @@ public class CPEQuery {
* @param dependency the dependency to search for CPE entries on. * @param dependency the dependency to search for CPE entries on.
* @throws CorruptIndexException is thrown when the Lucene index is corrupt. * @throws CorruptIndexException is thrown when the Lucene index is corrupt.
* @throws IOException is thrown when an IOException occurs. * @throws IOException is thrown when an IOException occurs.
* @throws ParseException is thrown when the Lucene query cannot be parsed. * @throws ParseException is thrown when the Lucene query cannot be parsed.
*/ */
public void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException { public void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
Confidence vendorConf = Confidence.HIGH; Confidence vendorConf = Confidence.HIGH;
Confidence titleConf = Confidence.HIGH; Confidence titleConf = Confidence.HIGH;
Confidence versionConf = Confidence.HIGH; Confidence versionConf = Confidence.HIGH;
String vendors = dependency.getVendorEvidence().toString(vendorConf); String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), vendorConf);
//dependency.getVendorEvidence().toString(vendorConf);
// if ("".equals(vendors)) { // if ("".equals(vendors)) {
// vendors = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; // vendors = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX;
// } // }
String titles = dependency.getTitleEvidence().toString(titleConf); String titles = addEvidenceWithoutDuplicateTerms("", dependency.getTitleEvidence(), titleConf);
///dependency.getTitleEvidence().toString(titleConf);
// if ("".equals(titles)) { // if ("".equals(titles)) {
// titles = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; // titles = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX;
// } // }
String versions = dependency.getVersionEvidence().toString(versionConf); String versions = addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), versionConf);
//dependency.getVersionEvidence().toString(versionConf);
// if ("".equals(versions)) { // if ("".equals(versions)) {
// versions = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; // versions = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX;
// } // }
@@ -205,7 +212,8 @@ public class CPEQuery {
if (round == 0) { if (round == 0) {
vendorConf = reduceConfidence(vendorConf); vendorConf = reduceConfidence(vendorConf);
if (dependency.getVendorEvidence().contains(vendorConf)) { if (dependency.getVendorEvidence().contains(vendorConf)) {
vendors += " " + dependency.getVendorEvidence().toString(vendorConf); //vendors += " " + dependency.getVendorEvidence().toString(vendorConf);
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), vendorConf);
} else { } else {
cnt += 1; cnt += 1;
round += 1; round += 1;
@@ -214,7 +222,8 @@ public class CPEQuery {
if (round == 1) { if (round == 1) {
titleConf = reduceConfidence(titleConf); titleConf = reduceConfidence(titleConf);
if (dependency.getTitleEvidence().contains(titleConf)) { if (dependency.getTitleEvidence().contains(titleConf)) {
titles += " " + dependency.getTitleEvidence().toString(titleConf); //titles += " " + dependency.getTitleEvidence().toString(titleConf);
titles = addEvidenceWithoutDuplicateTerms(titles, dependency.getTitleEvidence(), titleConf);
} else { } else {
cnt += 1; cnt += 1;
round += 1; round += 1;
@@ -223,7 +232,8 @@ public class CPEQuery {
if (round == 2) { if (round == 2) {
versionConf = reduceConfidence(versionConf); versionConf = reduceConfidence(versionConf);
if (dependency.getVersionEvidence().contains(versionConf)) { if (dependency.getVersionEvidence().contains(versionConf)) {
versions += " " + dependency.getVersionEvidence().toString(versionConf); //versions += " " + dependency.getVersionEvidence().toString(versionConf);
versions = addEvidenceWithoutDuplicateTerms(versions, dependency.getVersionEvidence(), versionConf);
} }
} }
@@ -232,6 +242,33 @@ public class CPEQuery {
} while (!found && (++cnt) < 9); } while (!found && (++cnt) < 9);
} }
/**
* Returns the text created by concatonating the text and the values from the
* EvidenceCollection (filtered for a specific confidence). This attempts to
* prevent duplicate terms from being added.<br/<br/>
* Note, if the evidence is longer then 200 characters it will be truncated.
*
* @param text the base text.
* @param ec an EvidenceCollection
* @param confidenceFilter a Confidence level to filter the evidence by.
* @return
*/
private String addEvidenceWithoutDuplicateTerms(final String text, final EvidenceCollection ec, Confidence confidenceFilter) {
String txt = (text == null) ? "" : text;
StringBuilder sb = new StringBuilder(txt.length() + (20 * ec.size()));
for (Evidence e : ec.iterator(confidenceFilter)) {
String value = e.getValue();
if (sb.indexOf(value)<0) {
if (value.length()>200) {
sb.append(value.substring(0,200));
} else {
sb.append(value).append(' ');
}
}
}
return sb.toString();
}
/** /**
* Reduces the given confidence by one level. This returns LOW if the confidence * Reduces the given confidence by one level. This returns LOW if the confidence
* passed in is not HIGH. * passed in is not HIGH.
@@ -282,7 +319,7 @@ public class CPEQuery {
* @throws ParseException when the generated query is not valid. * @throws ParseException when the generated query is not valid.
*/ */
protected List<Entry> searchCPE(String vendor, String product, String version, protected List<Entry> searchCPE(String vendor, String product, String version,
List<String> vendorWeightings, List<String> productWeightings) Set<String> vendorWeightings, Set<String> productWeightings)
throws CorruptIndexException, IOException, ParseException { throws CorruptIndexException, IOException, ParseException {
ArrayList<Entry> ret = new ArrayList<Entry>(MAX_QUERY_RESULTS); ArrayList<Entry> ret = new ArrayList<Entry>(MAX_QUERY_RESULTS);
@@ -319,7 +356,7 @@ public class CPEQuery {
* @return the Lucene query. * @return the Lucene query.
*/ */
protected String buildSearch(String vendor, String product, String version, protected String buildSearch(String vendor, String product, String version,
List<String> vendorWeighting, List<String> produdctWeightings) { Set<String> vendorWeighting, Set<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()
@@ -364,7 +401,7 @@ public class CPEQuery {
* importance when searching. * importance when searching.
* @return if the append was successful. * @return if the append was successful.
*/ */
private boolean appendWeightedSearch(StringBuilder sb, String field, String searchText, List<String> weightedText) { private boolean appendWeightedSearch(StringBuilder sb, String field, String searchText, Set<String> weightedText) {
//TODO add a mutator or special analyzer that combines words next to each other and adds them as a key. //TODO add a mutator or special analyzer that combines words next to each other and adds them as a key.
sb.append(" ").append(field).append(":( "); sb.append(" ").append(field).append(":( ");
@@ -377,8 +414,9 @@ public class CPEQuery {
if (weightedText == null || weightedText.isEmpty()) { if (weightedText == null || weightedText.isEmpty()) {
LuceneUtils.appendEscapedLuceneQuery(sb, cleanText); LuceneUtils.appendEscapedLuceneQuery(sb, cleanText);
} else { } else {
String[] text = cleanText.split("\\s"); StringTokenizer tokens = new StringTokenizer(cleanText);
for (String word : text) { while (tokens.hasMoreElements()) {
String word = tokens.nextToken();
String temp = null; String temp = null;
for (String weighted : weightedText) { for (String weighted : weightedText) {
String weightedStr = cleanseText(weighted); String weightedStr = cleanseText(weighted);

View File

@@ -25,12 +25,14 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
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.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.KeywordAnalyzer; import org.apache.lucene.analysis.KeywordAnalyzer;
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper; import org.apache.lucene.analysis.PerFieldAnalyzerWrapper;
@@ -44,8 +46,10 @@ 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.codesecure.dependencycheck.utils.DownloadFailedException;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Days; import org.joda.time.Days;
import org.xml.sax.SAXException;
/** /**
* The Index class is used to utilize and maintain the CPE Index. * The Index class is used to utilize and maintain the CPE Index.
@@ -130,9 +134,12 @@ public class Index {
* Downloads the latest CPE XML file from the web and imports it into * Downloads the latest CPE XML file from the web and imports it into
* the current CPE Index. * the current CPE Index.
* *
* @throws Exception is thrown if an exception occurs. * @throws MalformedURLException is thrown if the URL for the CPE is malformed.
* @throws ParserConfigurationException is thrown if the parser is misconfigured.
* @throws SAXException is thrown if there is an error parsing the CPE XML.
* @throws IOException is thrown if a temporary file could not be created.
*/ */
public void updateIndexFromWeb() throws Exception { public void updateIndexFromWeb() throws MalformedURLException, ParserConfigurationException, SAXException, IOException {
if (updateNeeded()) { if (updateNeeded()) {
URL url = new URL(Settings.getString(Settings.KEYS.CPE_URL)); URL url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
File outputPath = null; File outputPath = null;
@@ -141,7 +148,8 @@ public class Index {
Downloader.fetchFile(url, outputPath); Downloader.fetchFile(url, outputPath);
Importer.importXML(outputPath.toString()); Importer.importXML(outputPath.toString());
writeLastUpdatedPropertyFile(); writeLastUpdatedPropertyFile();
} catch (Exception ex) {
} catch (DownloadFailedException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
} finally { } finally {
boolean deleted = false; boolean deleted = false;
@@ -209,9 +217,9 @@ public class Index {
prop.load(is); prop.load(is);
lastUpdated = prop.getProperty(this.LAST_UPDATED); lastUpdated = prop.getProperty(this.LAST_UPDATED);
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex);
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex);
} }
try { try {
long lastupdate = Long.parseLong(lastUpdated); long lastupdate = Long.parseLong(lastUpdated);

View File

@@ -68,6 +68,9 @@ public class Importer {
*/ */
public static void importXML(String path) throws ParserConfigurationException, SAXException, IOException { public static void importXML(String path) throws ParserConfigurationException, SAXException, IOException {
File f = new File(path); File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
Importer.importXML(f); Importer.importXML(f);
} }
} }

View File

@@ -29,6 +29,7 @@ public class Evidence {
* The confidence that the evidence is "high" quality. * The confidence that the evidence is "high" quality.
*/ */
public enum Confidence { public enum Confidence {
/** /**
* High confidence evidence. * High confidence evidence.
*/ */
@@ -174,4 +175,47 @@ public class Evidence {
public void setConfidence(Confidence confidence) { public void setConfidence(Confidence confidence) {
this.confidence = confidence; this.confidence = confidence;
} }
/**
* Implements the hashCode for Evidence.
* @return hash code.
*/
@Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 67 * hash + (this.source != null ? this.source.hashCode() : 0);
hash = 67 * hash + (this.value != null ? this.value.hashCode() : 0);
hash = 67 * hash + (this.confidence != null ? this.confidence.hashCode() : 0);
return hash;
}
/**
* Implements equals for Evidence.
* @param that an object to check the equality of.
* @return whether the two objects are equal.
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (!(that instanceof Evidence)) {
return false;
}
Evidence e = (Evidence) that;
return testEquality(name, e.name) && testEquality(source, e.source) && testEquality(value, e.value)
&& (confidence == null ? e.confidence == null : confidence == e.confidence);
}
/**
* Simple equality test for use within the equals method. This does a case insensitive compare.
* @param l a string to compare.
* @param r another string to compare.
* @return whether the two strings are the same.
*/
private boolean testEquality(String l, String r) {
return l == null ? r == null : l.equalsIgnoreCase(r);
}
} }

View File

@@ -18,9 +18,9 @@ package org.codesecure.dependencycheck.scanner;
* Copyright (c) 2012 Jeremy Long. All Rights Reserved. * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/ */
import java.util.ArrayList; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.Set;
import org.codesecure.dependencycheck.utils.Filter; import org.codesecure.dependencycheck.utils.Filter;
/** /**
@@ -85,15 +85,15 @@ public class EvidenceCollection implements Iterable<Evidence> {
return EvidenceCollection.LOW_CONFIDENCE.filter(this.list); return EvidenceCollection.LOW_CONFIDENCE.filter(this.list);
} }
} }
private List<Evidence> list = null; private Set<Evidence> list = null;
private List<String> weightedStrings = null; private Set<String> weightedStrings = null;
/** /**
* Creates a new EvidenceCollection. * Creates a new EvidenceCollection.
*/ */
public EvidenceCollection() { public EvidenceCollection() {
list = new ArrayList<Evidence>(); list = new HashSet<Evidence>();
weightedStrings = new ArrayList<String>(); weightedStrings = new HashSet<String>();
} }
/** /**
@@ -133,18 +133,16 @@ public class EvidenceCollection implements Iterable<Evidence> {
* @param str to add to the weighting collection. * @param str to add to the weighting collection.
*/ */
public void addWeighting(String str) { public void addWeighting(String str) {
if (!weightedStrings.contains(str)) { weightedStrings.add(str);
weightedStrings.add(str);
}
} }
/** /**
* Returns a list of Weightings - a list of terms that are believed to be of * Returns a set of Weightings - a list of terms that are believed to be of
* higher confidence when also found in another location. * higher confidence when also found in another location.
* *
* @return List<String> * @return Set<String>
*/ */
public List<String> getWeighting() { public Set<String> getWeighting() {
return weightedStrings; return weightedStrings;
} }
@@ -208,19 +206,27 @@ public class EvidenceCollection implements Iterable<Evidence> {
} }
return ret; return ret;
} }
// Removed because this wasn't working right (the function returned the right data, but
/** // the use of the results was flawed.
* Returns a string of evidence 'values' for a given confidence. // /**
* @param confidence the confidence filter applied to the toString method. // * Returns a string of evidence 'values' for a given confidence.
* @return a string containing the evidence. // * @param confidence the confidence filter applied to the toString method.
*/ // * @return a string containing the evidence.
public String toString(Evidence.Confidence confidence) { // */
StringBuilder sb = new StringBuilder(); // public String toString(Evidence.Confidence confidence) {
for (Evidence e : this.iterator(confidence)) { // StringBuilder sb = new StringBuilder();
sb.append(e.getValue()).append(' '); // for (Evidence e : this.iterator(confidence)) {
} // String str = e.getValue();
return sb.toString(); // //TODO this is a cheap hack, need to prevent the same string from hitting multiple times...
} // // consider changing the evidencecollection.add to prevent the same "value" for a lower
// // confidence from being added? Might not work due to minor differences in the items in the manifest.
// // might need to actually use a StringTokenizer here and only add single words no in the list.
// if (sb.indexOf(str)<0) {
// sb.append(str).append(' ');
// }
// }
// return sb.toString();
// }
/** /**
* Returns a string of evidence 'values'. * Returns a string of evidence 'values'.
@@ -235,4 +241,11 @@ public class EvidenceCollection implements Iterable<Evidence> {
return sb.toString(); return sb.toString();
} }
/**
* Returns the number of elements in the EvidenceCollection.
* @return the number of elements in the collection.
*/
public int size() {
return list.size();
}
} }

View File

@@ -22,7 +22,9 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.jar.Attributes; import java.util.jar.Attributes;
import java.util.jar.JarFile; import java.util.jar.JarFile;
@@ -47,6 +49,20 @@ import org.codesecure.dependencycheck.utils.Checksum;
*/ */
public class JarAnalyzer implements Analyzer { public class JarAnalyzer implements Analyzer {
private static List<String> IGNORE_LIST;
public JarAnalyzer() {
IGNORE_LIST = new ArrayList<String>();
IGNORE_LIST.add("built-by");
IGNORE_LIST.add("created-by");
IGNORE_LIST.add("license");
IGNORE_LIST.add("build-jdk");
IGNORE_LIST.add("ant-version");
IGNORE_LIST.add("import-package");
IGNORE_LIST.add("export-package");
IGNORE_LIST.add("sealed");
IGNORE_LIST.add("manifest-version");
}
/** /**
* item in some manifest, should be considered medium confidence. * item in some manifest, should be considered medium confidence.
*/ */
@@ -69,6 +85,7 @@ public class JarAnalyzer implements Analyzer {
* read in one character at a time. * read in one character at a time.
*/ */
private enum STRING_STATE { private enum STRING_STATE {
ALPHA, ALPHA,
NUMBER, NUMBER,
PERIOD, PERIOD,
@@ -364,20 +381,23 @@ public class JarAnalyzer implements Analyzer {
vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
} else { } else {
key = key.toLowerCase(); key = key.toLowerCase();
if (key.contains("version")) {
versionEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); if (!IGNORE_LIST.contains(key)) {
} else if (key.contains("title")) { if (key.contains("version")) {
titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); versionEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
} else if (key.contains("vendor")) { } else if (key.contains("title")) {
vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
} else if (key.contains("name")) { } else if (key.contains("vendor")) {
titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else if (key.contains("name")) {
} else { titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
titleEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW); } else {
if (value.matches(".*\\d.*")) { titleEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW);
versionEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW);
if (value.matches(".*\\d.*")) {
versionEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW);
}
} }
} }
} }

View File

@@ -45,9 +45,9 @@ public class Downloader {
* Retrieves a file from a given URL and saves it to the outputPath. * Retrieves a file from a given URL and saves it to the outputPath.
* @param url the URL of the file to download. * @param url the URL of the file to download.
* @param outputPath the path to the save the file to. * @param outputPath the path to the save the file to.
* @throws IOException is thrown if an IOException occurs. * @throws DownloadFailedException is thrown if there is an error downloading the file.
*/ */
public static void fetchFile(URL url, String outputPath) throws IOException { public static void fetchFile(URL url, String outputPath) throws DownloadFailedException {
File f = new File(outputPath); File f = new File(outputPath);
fetchFile(url, f); fetchFile(url, f);
} }
@@ -56,10 +56,14 @@ public class Downloader {
* Retrieves a file from a given URL and saves it to the outputPath. * Retrieves a file from a given URL and saves it to the outputPath.
* @param url the URL of the file to download. * @param url the URL of the file to download.
* @param outputPath the path to the save the file to. * @param outputPath the path to the save the file to.
* @throws IOException is thrown if an IOException occurs. * @throws DownloadFailedException is thrown if there is an error downloading the file.
*/ */
public static void fetchFile(URL url, File outputPath) throws IOException { public static void fetchFile(URL url, File outputPath) throws DownloadFailedException {
url.openConnection(); try {
url.openConnection();
} catch (IOException ex) {
throw new DownloadFailedException("Error downloading file.", ex);
}
BufferedOutputStream writer = null; BufferedOutputStream writer = null;
try { try {
InputStream reader = url.openStream(); InputStream reader = url.openStream();
@@ -70,13 +74,13 @@ public class Downloader {
writer.write(buffer, 0, bytesRead); writer.write(buffer, 0, bytesRead);
} }
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.SEVERE, null, ex); throw new DownloadFailedException("Error saving downloaded file.", ex);
} finally { } finally {
try { try {
writer.close(); writer.close();
writer = null; writer = null;
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.WARNING, Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the writter in Downloader.", ex); "Error closing the writter in Downloader.", ex);
} }
} }

View File

@@ -6,8 +6,9 @@ package org.codesecure.dependencycheck.data.cpe;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.ParseException;
import org.codesecure.dependencycheck.data.BaseIndexTestCase; import org.codesecure.dependencycheck.data.BaseIndexTestCase;
@@ -52,10 +53,10 @@ public class CPEQueryTest extends BaseIndexTestCase {
assertEquals(expResult, result.get(0).getName()); assertEquals(expResult, result.get(0).getName());
//TODO - yeah, not a very good test as the results are the same with or without weighting... //TODO - yeah, not a very good test as the results are the same with or without weighting...
List<String> productWeightings = new ArrayList<String>(1); Set<String> productWeightings = new HashSet<String>(1);
productWeightings.add("struts2"); productWeightings.add("struts2");
List<String> vendorWeightings = new ArrayList<String>(1); Set<String> vendorWeightings = new HashSet<String>(1);
vendorWeightings.add("apache"); vendorWeightings.add("apache");
result = instance.searchCPE(vendor, product, version,productWeightings,vendorWeightings); result = instance.searchCPE(vendor, product, version,productWeightings,vendorWeightings);
@@ -82,10 +83,10 @@ public class CPEQueryTest extends BaseIndexTestCase {
@Test @Test
public void testBuildSearch() throws IOException, CorruptIndexException, ParseException { public void testBuildSearch() throws IOException, CorruptIndexException, ParseException {
System.out.println("buildSearch"); System.out.println("buildSearch");
List<String> productWeightings = new ArrayList<String>(1); Set<String> productWeightings = new HashSet<String>(1);
productWeightings.add("struts2"); productWeightings.add("struts2");
List<String> vendorWeightings = new ArrayList<String>(1); Set<String> vendorWeightings = new HashSet<String>(1);
vendorWeightings.add("apache"); vendorWeightings.add("apache");
String vendor = "apache software foundation"; String vendor = "apache software foundation";
@@ -191,10 +192,10 @@ public class CPEQueryTest extends BaseIndexTestCase {
instance.open(); instance.open();
//TODO - yeah, not a very good test as the results are the same with or without weighting... //TODO - yeah, not a very good test as the results are the same with or without weighting...
List<String> productWeightings = new ArrayList<String>(1); Set<String> productWeightings = new HashSet<String>(1);
productWeightings.add("struts2"); productWeightings.add("struts2");
List<String> vendorWeightings = new ArrayList<String>(1); Set<String> vendorWeightings = new HashSet<String>(1);
vendorWeightings.add("apache"); vendorWeightings.add("apache");
List<Entry> result = instance.searchCPE(vendor, product, version,productWeightings,vendorWeightings); List<Entry> result = instance.searchCPE(vendor, product, version,productWeightings,vendorWeightings);

View File

@@ -50,21 +50,22 @@ public class ScannerTest extends BaseIndexTestCase{
* @throws Exception is thrown when an exception occurs. * @throws Exception is thrown when an exception occurs.
*/ */
@Test @Test
//TODO remove the throws exception, this needs to be much more grainular.
public void testScan() throws Exception { public void testScan() throws Exception {
System.out.println("scan"); System.out.println("scan");
String path = "./src/test/resources"; String path = "./src/test/resources";
Scanner instance = new Scanner(); Scanner instance = new Scanner();
instance.scan(path); instance.scan(path);
assertTrue(instance.getDependencies().size()>0); assertTrue(instance.getDependencies().size()>0);
// CPEQuery query = new CPEQuery(); CPEQuery query = new CPEQuery();
// query.open(); query.open();
// List<Dependency> dependencies = instance.getDependencies(); List<Dependency> dependencies = instance.getDependencies();
// for (Dependency d : dependencies) { for (Dependency d : dependencies) {
// query.determineCPE(d); query.determineCPE(d);
// } }
// query.close(); query.close();
// ReportGenerator rg = new ReportGenerator(); ReportGenerator rg = new ReportGenerator();
// rg.generateReports("./target/", "DependencyCheck", instance.getDependencies()); rg.generateReports("./target/", "DependencyCheck", instance.getDependencies());
} }