Compare commits

...

12 Commits

Author SHA1 Message Date
Jeremy Long
76899996c2 version 0.2.3.2
Former-commit-id: 474018fefa56379cb88cfd232c4a88e8ce9b15af
2012-12-22 06:16:46 -05:00
Jeremy Long
283dcae297 added find bugs and fixed some bugs
Former-commit-id: 2266d86317f4fb20b7d3262b41b14d962916078f
2012-12-22 06:15:39 -05:00
Jeremy Long
566f36e577 continued removal of cpe.xml - it is incomplete for our purpose
Former-commit-id: 83d10942664962f0f530b4694a96c1f4f2783d43
2012-12-22 04:30:26 -05:00
Jeremy Long
6e23fd7251 bug fixes
Former-commit-id: 770436e4eff1f331b122eecd16081194987ba3f9
2012-12-20 21:39:02 -05:00
Jeremy Long
a16bcfbc10 upgrade to lucene 4.0
Former-commit-id: 0822d5816b603d8017b2fe8aa2a592aa3263c51c
2012-12-16 21:26:30 -05:00
Jeremy Long
2fcc325af7 bug fixes
Former-commit-id: 02eac4d4a7073e140181c39fa8137b37f86e5f74
2012-12-02 22:22:25 -05:00
Jeremy Long
5334cf7def fixed reported bug
Former-commit-id: 0f4d2380d45811e2c181996651ed1541376a3cb6
2012-11-20 20:11:08 -05:00
Jeremy Long
a8a85a5947 Cleaned up reporting
Former-commit-id: ba7c493381c4a5d9b1078e8f8c8a44f3ffc119f3
2012-11-17 07:57:55 -05:00
Jeremy Long
a6faadcc74 v0.2.3
Former-commit-id: 03939984b22675d4aaa73aad4803dd2aa4751638
2012-11-12 14:50:04 -05:00
Jeremy Long
1e7b45c00b updated to use directory of jar instead of working directory to store data
Former-commit-id: 5090e57e59d022d0824bf5a7fdcbedfc0bff027e
2012-11-12 14:48:39 -05:00
Jeremy Long
9f21ea6a9d general updates
Former-commit-id: edac8a6df87e1793f94ebdad615ed424acb27d90
2012-11-12 13:36:44 -05:00
Jeremy Long
99c056e7f5 location of data files is no longer the working directory, rather the location of the JAR file itself
Former-commit-id: 320077664c9c65f5b5f6dd7acb5c923da8869167
2012-11-12 12:19:39 -05:00
43 changed files with 815 additions and 383 deletions

View File

@@ -7,10 +7,10 @@ If found, it will generate a report linking to the associated CVE entries.
Usage: Usage:
$ mvn package $ mvn package
$ cd target $ cd target
$ java -jar DependencyCheck-0.2.2.jar -h $ java -jar DependencyCheck-0.2.3.2.jar -h
$ java -jar DependencyCheck-0.2.2.jar -a Testing -out . -scan ./test-classes/org.mortbay.jetty.jar -scan ./test-classes/struts2-core-2.1.2.jar -scan ./lib $ java -jar DependencyCheck-0.2.3.2.jar -a Testing -out . -scan ./test-classes/org.mortbay.jetty.jar -scan ./test-classes/struts2-core-2.1.2.jar -scan ./lib
Then load the resulting 'Testing.html' into your favorite browser. Then load the resulting 'DependencyCheck-Report.html' into your favorite browser.
Author: Jeremy Long (jeremy.long@gmail.com) Author: Jeremy Long (jeremy.long@gmail.com)

62
pom.xml
View File

@@ -23,7 +23,7 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<groupId>org.codesecure</groupId> <groupId>org.codesecure</groupId>
<artifactId>DependencyCheck</artifactId> <artifactId>DependencyCheck</artifactId>
<version>0.2.2</version> <version>0.2.3.2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>DependencyCheck</name> <name>DependencyCheck</name>
@@ -100,7 +100,7 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version> <version>2.8.1</version>
<configuration> <configuration>
<bottom>Copyright &#169; 2012 Jeremy Long. All Rights Reserved.</bottom> <bottom>Copyright&#169; 2012 Jeremy Long. All Rights Reserved.</bottom>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@@ -206,13 +206,21 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<value>${project.build.directory}/cobertura/cobertura.ser</value> <value>${project.build.directory}/cobertura/cobertura.ser</value>
<workingDirectory>target</workingDirectory> <workingDirectory>target</workingDirectory>
</property> </property>
<property> <!--<property>
<name>cve</name> <name>cve</name>
<value>${project.build.directory}/data/cve</value> <value>${project.build.directory}/data/cve</value>
</property> </property>
<property> <property>
<name>cpe</name> <name>cpe</name>
<value>${project.build.directory}/data/cpe</value> <value>${project.build.directory}/data/cpe</value>
</property>-->
<property>
<name>cve</name>
<value>target/data/cve</value>
</property>
<property>
<name>cpe</name>
<value>target/data/cpe</value>
</property> </property>
</systemProperties> </systemProperties>
<excludes> <excludes>
@@ -224,6 +232,21 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<version>2.12.4</version> <version>2.12.4</version>
<configuration>
<systemProperties>
<property>
<name>cve</name>
<value>target/data/cve</value>
</property>
<property>
<name>cpe</name>
<value>target/data/cpe</value>
</property>
</systemProperties>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@@ -308,6 +331,11 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
</excludes> </excludes>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>taglist-maven-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
@@ -338,11 +366,17 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<reportSet> <reportSet>
<id>integration-tests</id> <id>integration-tests</id>
<reports> <reports>
<report>report-only</report>
<report>failsafe-report-only</report> <report>failsafe-report-only</report>
</reports> </reports>
</reportSet> </reportSet>
</reportSets> </reportSets>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.2</version>
</plugin>
</reportPlugins> </reportPlugins>
</configuration> </configuration>
</plugin> </plugin>
@@ -365,7 +399,18 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<dependency> <dependency>
<groupId>org.apache.lucene</groupId> <groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId> <artifactId>lucene-core</artifactId>
<version>3.5.0</version> <version>4.0.0</version>
<!--<version>3.5.0</version>-->
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>4.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
@@ -427,5 +472,14 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<artifactId>hawtdb</artifactId> <artifactId>hawtdb</artifactId>
<version>1.6</version> <version>1.6</version>
</dependency>--> </dependency>-->
<!-- The following dependencies are only scanned during integration testing -->
<!--<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>2.5.5</version>
<scope>test</scope>
</dependency>-->
</dependencies> </dependencies>
</project> </project>

View File

@@ -74,6 +74,7 @@ public class App {
//Preferences.systemRoot().put("java.util.logging.config.file", "log.properties"); //Preferences.systemRoot().put("java.util.logging.config.file", "log.properties");
//System.getProperties().put("java.util.logging.config.file", "configuration/log.properties"); //System.getProperties().put("java.util.logging.config.file", "configuration/log.properties");
File dir = new File("logs"); File dir = new File("logs");
if (!dir.exists()) { if (!dir.exists()) {
dir.mkdir(); dir.mkdir();
} }
@@ -157,9 +158,9 @@ public class App {
scanner.analyzeDependencies(); scanner.analyzeDependencies();
List<Dependency> dependencies = scanner.getDependencies(); List<Dependency> dependencies = scanner.getDependencies();
ReportGenerator report = new ReportGenerator(); ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers());
try { try {
report.generateReports(reportDirectory, applicationName, dependencies); report.generateReports(reportDirectory);
} 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 (Exception ex) { } catch (Exception ex) {

View File

@@ -195,7 +195,8 @@ public class Engine {
try { try {
a.initialize(); a.initialize();
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, "Exception occured initializing " + a.getName() + ".", ex); Logger.getLogger(Engine.class.getName()).log(Level.SEVERE,
"Exception occured initializing " + a.getName() + ".", ex);
try { try {
a.close(); a.close();
} catch (Exception ex1) { } catch (Exception ex1) {
@@ -254,8 +255,23 @@ public class Engine {
try { try {
source.update(); source.update();
} catch (UpdateException ex) { } catch (UpdateException ex) {
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, "Unable to update " + source.getClass().getName(), ex); Logger.getLogger(Engine.class.getName()).log(Level.SEVERE,
"Unable to update " + source.getClass().getName(), ex);
} }
} }
} }
/**
* Returns a full list of all of the analyzers. This is useful
* for reporting which analyzers where used.
* @return a list of Analyzers
*/
public List<Analyzer> getAnalyzers() {
List<Analyzer> ret = new ArrayList<Analyzer>();
for (AnalysisPhase phase : AnalysisPhase.values()) {
List<Analyzer> analyzerList = analyzers.get(phase);
ret.addAll(analyzerList);
}
return ret;
}
} }

View File

@@ -186,6 +186,7 @@ public class JarAnalyzer extends AbstractAnalyzer {
parseManifest(dependency); parseManifest(dependency);
analyzePackageNames(dependency); analyzePackageNames(dependency);
analyzePOM(dependency); analyzePOM(dependency);
addPredefinedData(dependency);
} catch (IOException ex) { } catch (IOException ex) {
throw new AnalysisException("Exception occured reading the JAR file.", ex); throw new AnalysisException("Exception occured reading the JAR file.", ex);
} catch (JAXBException ex) { } catch (JAXBException ex) {
@@ -228,7 +229,7 @@ public class JarAnalyzer extends AbstractAnalyzer {
} }
} else if (!entry.isDirectory() && "pom.properties".equals(entryName)) { } else if (!entry.isDirectory() && "pom.properties".equals(entryName)) {
if (pomProperties == null) { if (pomProperties == null) {
Reader reader = new InputStreamReader(zin); Reader reader = new InputStreamReader(zin, "UTF-8");
pomProperties = new Properties(); pomProperties = new Properties();
pomProperties.load(reader); pomProperties.load(reader);
zin.closeEntry(); zin.closeEntry();
@@ -481,6 +482,12 @@ public class JarAnalyzer extends AbstractAnalyzer {
protected void parseManifest(Dependency dependency) throws IOException { protected void parseManifest(Dependency dependency) throws IOException {
JarFile jar = new JarFile(dependency.getActualFilePath()); JarFile jar = new JarFile(dependency.getActualFilePath());
Manifest manifest = jar.getManifest(); Manifest manifest = jar.getManifest();
if (manifest == null) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE,
"Jar file '{0}' does not contain a manifest.",
dependency.getFileName());
return;
}
Attributes atts = manifest.getMainAttributes(); Attributes atts = manifest.getMainAttributes();
EvidenceCollection vendorEvidence = dependency.getVendorEvidence(); EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
@@ -615,4 +622,15 @@ public class JarAnalyzer extends AbstractAnalyzer {
sb.append(text.substring(end + 1)); sb.append(text.substring(end + 1));
return interpolateString(sb.toString(), properties); //yes yes, this should be a loop... return interpolateString(sb.toString(), properties); //yes yes, this should be a loop...
} }
private void addPredefinedData(Dependency dependency) {
Evidence spring = new Evidence("Manifest",
"Implementation-Title",
"Spring Framework",
Evidence.Confidence.HIGH);
if (dependency.getProductEvidence().getEvidence().contains(spring)) {
dependency.getVendorEvidence().addEvidence("a priori", "vendor", "SpringSource", Evidence.Confidence.HIGH);
}
}
} }

View File

@@ -27,8 +27,10 @@ import java.util.StringTokenizer;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.queryparser.classic.QueryParser;
//TODO convert to the analyzing query parser
//import org.apache.lucene.queryparser.analyzing.AnalyzingQueryParser;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreDoc;
@@ -98,8 +100,7 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal
cpe.open(); cpe.open();
indexSearcher = cpe.getIndexSearcher(); indexSearcher = cpe.getIndexSearcher();
Analyzer analyzer = cpe.getAnalyzer(); Analyzer analyzer = cpe.getAnalyzer();
//TITLE is the default field because it contains venddor, product, and version all in one. queryParser = new QueryParser(Version.LUCENE_40, Fields.NAME, analyzer);
queryParser = new QueryParser(Version.LUCENE_35, Fields.TITLE, analyzer);
} }
/** /**
@@ -149,23 +150,11 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal
Confidence versionConf = Confidence.HIGH; Confidence versionConf = Confidence.HIGH;
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), vendorConf); String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), vendorConf);
//dependency.getVendorEvidence().toString(vendorConf);
// if ("".equals(vendors)) {
// vendors = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX;
// }
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), productConf); String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), productConf);
///dependency.getProductEvidence().toString(productConf);
// if ("".equals(products)) {
// products = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX;
// }
String versions = addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), versionConf); String versions = addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), versionConf);
//dependency.getVersionEvidence().toString(versionConf);
// if ("".equals(versions)) {
// versions = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX;
// }
boolean found = false; boolean found = false;
int cnt = 0; int ctr = 0;
do { do {
List<Entry> entries = searchCPE(vendors, products, versions, dependency.getProductEvidence().getWeighting(), List<Entry> entries = searchCPE(vendors, products, versions, dependency.getProductEvidence().getWeighting(),
dependency.getVendorEvidence().getWeighting()); dependency.getVendorEvidence().getWeighting());
@@ -178,22 +167,20 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal
dependency.addIdentifier( dependency.addIdentifier(
"cpe", "cpe",
e.getName(), e.getName(),
e.getTitle(),
"http://web.nvd.nist.gov/view/vuln/search?cpe=" "http://web.nvd.nist.gov/view/vuln/search?cpe="
+ URLEncoder.encode(e.getName(), "UTF-8")); + URLEncoder.encode(e.getName(), "UTF-8"));
} }
} }
if (!found) { if (!found) {
int round = cnt % 3; int round = ctr % 3;
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); vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), vendorConf);
} else { } else {
cnt += 1; ctr += 1;
round += 1; round += 1;
} }
} }
@@ -203,7 +190,7 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal
//products += " " + dependency.getProductEvidence().toString(productConf); //products += " " + dependency.getProductEvidence().toString(productConf);
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), productConf); products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), productConf);
} else { } else {
cnt += 1; ctr += 1;
round += 1; round += 1;
} }
} }
@@ -215,7 +202,7 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal
} }
} }
} }
} while (!found && (++cnt) < 9); } while (!found && (++ctr) < 9);
} }
/** /**

View File

@@ -45,21 +45,16 @@ public class Entry {
public static Entry parse(Document doc) { public static Entry parse(Document doc) {
Entry entry = new Entry(); Entry entry = new Entry();
try { try {
entry.setName(doc.get(Fields.NAME)); entry.parseName(doc.get(Fields.NAME));
entry.setTitle(doc.get(Fields.TITLE));
} catch (UnsupportedEncodingException ex) { } catch (UnsupportedEncodingException ex) {
Logger.getLogger(Entry.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Entry.class.getName()).log(Level.SEVERE, null, ex);
entry.name = doc.get(Fields.NAME); entry.name = doc.get(Fields.NAME);
} }
// entry.vendor = doc.get(Fields.VENDOR);
// entry.version = doc.get(Fields.VERSION);
// //entry.revision = doc.get(Fields.REVISION);
// entry.product = doc.get(Fields.TITLE);
// entry.nvdId = doc.get(Fields.NVDID);
return entry; return entry;
} }
/** /**
* The title of the CPE * The title of the CPE
* @deprecated This field is no longer used
*/ */
protected String title; protected String title;
@@ -67,6 +62,7 @@ public class Entry {
* Get the value of title * Get the value of title
* *
* @return the value of title * @return the value of title
* @deprecated This field is no longer used
*/ */
public String getTitle() { public String getTitle() {
return title; return title;
@@ -76,6 +72,7 @@ public class Entry {
* Set the value of title * Set the value of title
* *
* @param title new value of title * @param title new value of title
* @deprecated This field is no longer used
*/ */
public void setTitle(String title) { public void setTitle(String title) {
this.title = title; this.title = title;
@@ -95,18 +92,16 @@ public class Entry {
} }
/** /**
* Set the value of name and calls parseName to obtain the * Set the value of name
* vendor:product:version:revision
* *
* @param name new value of name * @param name new value of name
* @throws UnsupportedEncodingException should never be thrown...
*/ */
public void setName(String name) throws UnsupportedEncodingException { public void setName(String name) {
this.name = name; this.name = name;
parseName();
} }
/** /**
* The status of the CPE Entry. * The status of the CPE Entry.
* @deprecated This field is no longer used
*/ */
protected String status; protected String status;
@@ -114,6 +109,7 @@ public class Entry {
* Get the value of status * Get the value of status
* *
* @return the value of status * @return the value of status
* @deprecated This field is no longer used
*/ */
public String getStatus() { public String getStatus() {
return status; return status;
@@ -123,31 +119,35 @@ public class Entry {
* Set the value of status * Set the value of status
* *
* @param status new value of status * @param status new value of status
* @deprecated This field is no longer used
*/ */
public void setStatus(String status) { public void setStatus(String status) {
this.status = status; this.status = status;
} }
/** /**
* The modification date of the CPE Entry. * The modification date of the CPE Entry.
* @deprecated This field is no longer used
*/ */
protected Date modificationDate; private Date modificationDate;
/** /**
* Get the value of modificationDate * Get the value of modificationDate
* *
* @return the value of modificationDate * @return the value of modificationDate
* @deprecated This field is no longer used
*/ */
public Date getModificationDate() { public Date getModificationDate() {
return modificationDate; return (Date) modificationDate.clone();
} }
/** /**
* Set the value of modificationDate * Set the value of modificationDate
* *
* @param modificationDate new value of modificationDate * @param modificationDate new value of modificationDate
* @deprecated This field is no longer used
*/ */
public void setModificationDate(Date modificationDate) { public void setModificationDate(Date modificationDate) {
this.modificationDate = modificationDate; this.modificationDate = (Date) modificationDate.clone();
} }
/** /**
@@ -157,6 +157,7 @@ public class Entry {
* *
* @param modificationDate new value of modificationDate * @param modificationDate new value of modificationDate
* @throws ParseException is thrown when a parse exception occurs. * @throws ParseException is thrown when a parse exception occurs.
* @deprecated This field is no longer used
*/ */
public void setModificationDate(String modificationDate) throws ParseException { public void setModificationDate(String modificationDate) throws ParseException {
@@ -170,6 +171,7 @@ public class Entry {
} }
/** /**
* The nvdId. * The nvdId.
* @deprecated This field is no longer used
*/ */
protected String nvdId; protected String nvdId;
@@ -177,6 +179,7 @@ public class Entry {
* Get the value of nvdId * Get the value of nvdId
* *
* @return the value of nvdId * @return the value of nvdId
* @deprecated This field is no longer used
*/ */
public String getNvdId() { public String getNvdId() {
return nvdId; return nvdId;
@@ -186,6 +189,7 @@ public class Entry {
* Set the value of nvdId * Set the value of nvdId
* *
* @param nvdId new value of nvdId * @param nvdId new value of nvdId
* @deprecated This field is no longer used
*/ */
public void setNvdId(String nvdId) { public void setNvdId(String nvdId) {
this.nvdId = nvdId; this.nvdId = nvdId;
@@ -310,15 +314,17 @@ public class Entry {
* <p>Results in:</p> <ul> <li>Vendor: apache</li> <li>Product: struts</li> * <p>Results in:</p> <ul> <li>Vendor: apache</li> <li>Product: struts</li>
* <li>Version: 1.1</li> <li>Revision: rc2</li> </ul> * <li>Version: 1.1</li> <li>Revision: rc2</li> </ul>
* *
* @param cpeName the cpe name
* @throws UnsupportedEncodingException should never be thrown... * @throws UnsupportedEncodingException should never be thrown...
*/ */
private void parseName() throws UnsupportedEncodingException { public void parseName(String cpeName) throws UnsupportedEncodingException {
if (name != null && name.length() > 7) { this.name = cpeName;
String[] data = name.substring(7).split(":"); if (cpeName != null && cpeName.length() > 7) {
String[] data = cpeName.substring(7).split(":");
if (data.length >= 1) { if (data.length >= 1) {
vendor = URLDecoder.decode(data[0], "UTF-8"); vendor = URLDecoder.decode(data[0], "UTF-8").replaceAll("[_-]", " ");
if (data.length >= 2) { if (data.length >= 2) {
product = URLDecoder.decode(data[1], "UTF-8"); product = URLDecoder.decode(data[1], "UTF-8").replaceAll("[_-]", " ");
if (data.length >= 3) { if (data.length >= 3) {
version = URLDecoder.decode(data[2], "UTF-8"); version = URLDecoder.decode(data[2], "UTF-8");
if (data.length >= 4) { if (data.length >= 4) {

View File

@@ -34,22 +34,13 @@ public abstract class Fields {
* The key for the vendor field. * The key for the vendor field.
*/ */
public static final String VENDOR = "vendor"; public static final String VENDOR = "vendor";
/**
* The key for the version field.
*/
public static final String VERSION = "version";
//public static final String REVISION = "revision";
/** /**
* The key for the product field. * The key for the product field.
*/ */
public static final String PRODUCT = "product"; public static final String PRODUCT = "product";
/** /**
* The key for the title field. This is a field combining vendor, product, * The key for the version field.
* and version.
*/ */
public static final String TITLE = "title"; public static final String VERSION = "version";
/** //public static final String REVISION = "revision";
* The key for the nvdId field.
*/
public static final String NVDID = "nvdid";
} }

View File

@@ -28,6 +28,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@@ -35,8 +36,8 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException; 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.core.KeywordAnalyzer;
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper; import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.FSDirectory;
@@ -74,13 +75,39 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
* @throws IOException is thrown if an IOException occurs. * @throws IOException is thrown if an IOException occurs.
*/ */
public Directory getDirectory() throws IOException { public Directory getDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CPE_INDEX); File path = getDataDirectory();
File path = new File(fileName);
Directory dir = FSDirectory.open(path); Directory dir = FSDirectory.open(path);
return dir; return dir;
} }
/**
* Retrieves the directory that the JAR file exists in so that
* we can ensure we always use a common data directory.
*
* @return the data directory for this index.
* @throws IOException is thrown if an IOException occurs of course...
*/
public File getDataDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CPE_INDEX);
String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create CPE Data directory");
}
}
return path;
}
/** /**
* Creates an Analyzer for the CPE Index. * Creates an Analyzer for the CPE Index.
* *
@@ -91,9 +118,10 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
Map fieldAnalyzers = new HashMap(); Map fieldAnalyzers = new HashMap();
fieldAnalyzers.put(Fields.VERSION, new KeywordAnalyzer()); fieldAnalyzers.put(Fields.VERSION, new KeywordAnalyzer());
fieldAnalyzers.put(Fields.NAME, new KeywordAnalyzer());
PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper( PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(
new StandardAnalyzer(Version.LUCENE_35), fieldAnalyzers); new StandardAnalyzer(Version.LUCENE_40), fieldAnalyzers);
return wrapper; return wrapper;
} }
@@ -104,6 +132,8 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
* *
* @throws UpdateException is thrown if there is a problem updating the * @throws UpdateException is thrown if there is a problem updating the
* index. * index.
*
* @deprecated this should no longer be used as the raw CPE hosted at NIST is not complete enough.
*/ */
public void update() throws UpdateException { public void update() throws UpdateException {
try { try {
@@ -152,31 +182,42 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
* directory. * directory.
* *
* @param timeStamp the timestamp to write. * @param timeStamp the timestamp to write.
*
* @deprecated this should no longer be used as the raw CPE hosted at NIST is not complete enough.
*/ */
private void writeLastUpdatedPropertyFile(long timeStamp) { private void writeLastUpdatedPropertyFile(long timeStamp) throws UpdateException {
String dir = Settings.getString(Settings.KEYS.CPE_INDEX); String dir;
try {
dir = getDataDirectory().getCanonicalPath();
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException("Unable to locate the last updated properties file.", ex);
}
File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE); File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
Properties prop = new Properties(); Properties prop = new Properties();
prop.put(Index.LAST_UPDATED, String.valueOf(timeStamp)); prop.put(Index.LAST_UPDATED, String.valueOf(timeStamp));
OutputStream os = null; OutputStream os = null;
OutputStreamWriter out = null;
try { try {
os = new FileOutputStream(cpeProp); os = new FileOutputStream(cpeProp);
OutputStreamWriter out = new OutputStreamWriter(os); out = new OutputStreamWriter(os, "UTF-8");
prop.store(out, dir); prop.store(out, dir);
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Index.class.getName()).log(Level.SEVERE, 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.SEVERE, null, ex);
} finally { } finally {
try { if (os != null) {
os.flush(); try {
} catch (IOException ex) { os.flush();
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) {
} Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
try { }
os.close(); try {
} catch (IOException ex) { os.close();
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
}
} }
} }
} }
@@ -193,8 +234,12 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
* is incorrect. * is incorrect.
* @throws DownloadFailedException is thrown if there is an error * @throws DownloadFailedException is thrown if there is an error
* downloading the cpe.meta data file. * downloading the cpe.meta data file.
* @throws UpdateException is thrown if there is an error locating the last updated
* properties file.
*
* @deprecated this should no longer be used as the raw CPE hosted at NIST is not complete enough.
*/ */
public long updateNeeded() throws MalformedURLException, DownloadFailedException { public long updateNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
long retVal = 0; long retVal = 0;
long lastUpdated = 0; long lastUpdated = 0;
long currentlyPublishedDate = retrieveCurrentCPETimestampFromWeb(); long currentlyPublishedDate = retrieveCurrentCPETimestampFromWeb();
@@ -202,12 +247,24 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
throw new DownloadFailedException("Unable to retrieve valid timestamp from cpe.meta file"); throw new DownloadFailedException("Unable to retrieve valid timestamp from cpe.meta file");
} }
String dir = Settings.getString(Settings.KEYS.CPE_INDEX); //String dir = Settings.getString(Settings.KEYS.CPE_INDEX);
File f = new File(dir); File f;
try {
f = getDataDirectory(); //new File(dir);
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException("Unable to locate last updated properties file.", ex);
}
if (!f.exists()) { if (!f.exists()) {
retVal = currentlyPublishedDate; retVal = currentlyPublishedDate;
} else { } else {
File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE); File cpeProp;
try {
cpeProp = new File(f.getCanonicalPath() + File.separatorChar + UPDATE_PROPERTIES_FILE);
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException("Unable to find last updated properties file.", ex);
}
if (!cpeProp.exists()) { if (!cpeProp.exists()) {
retVal = currentlyPublishedDate; retVal = currentlyPublishedDate;
} else { } else {
@@ -223,6 +280,14 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex);
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
}
}
} }
if (currentlyPublishedDate > lastUpdated) { if (currentlyPublishedDate > lastUpdated) {
retVal = currentlyPublishedDate; retVal = currentlyPublishedDate;

View File

@@ -66,7 +66,7 @@ public class CPEHandler extends DefaultHandler {
skip = (temp != null && temp.equals("true")); skip = (temp != null && temp.equals("true"));
try { try {
if (!skip && name.startsWith("cpe:/a:")) { if (!skip && name.startsWith("cpe:/a:")) {
entry.setName(name); entry.parseName(name);
} else { } else {
skip = true; skip = true;
} }

View File

@@ -21,13 +21,13 @@ package org.codesecure.dependencycheck.data.cpe.xml;
import java.io.IOException; import java.io.IOException;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.FieldInfo.IndexOptions;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.codesecure.dependencycheck.data.cpe.Entry; import org.codesecure.dependencycheck.data.cpe.Entry;
import org.codesecure.dependencycheck.data.cpe.Fields; import org.codesecure.dependencycheck.data.cpe.Fields;
import org.codesecure.dependencycheck.data.cpe.Index; import org.codesecure.dependencycheck.data.cpe.Index;
import org.codesecure.dependencycheck.data.lucene.LuceneUtils;
/** /**
* The Indexer is used to convert a CPE Entry, retrieved from the CPE XML file, * The Indexer is used to convert a CPE Entry, retrieved from the CPE XML file,
@@ -46,7 +46,8 @@ public class Indexer extends Index implements EntrySaveDelegate {
*/ */
public void saveEntry(Entry entry) throws CorruptIndexException, IOException { public void saveEntry(Entry entry) throws CorruptIndexException, IOException {
Document doc = convertEntryToDoc(entry); Document doc = convertEntryToDoc(entry);
Term term = new Term(Fields.NVDID, LuceneUtils.escapeLuceneQuery(entry.getNvdId())); //Term term = new Term(Fields.NVDID, LuceneUtils.escapeLuceneQuery(entry.getNvdId()));
Term term = new Term(Fields.NAME, entry.getName());
indexWriter.updateDocument(term, doc); indexWriter.updateDocument(term, doc);
} }
@@ -59,44 +60,30 @@ public class Indexer extends Index implements EntrySaveDelegate {
protected Document convertEntryToDoc(Entry entry) { protected Document convertEntryToDoc(Entry entry) {
Document doc = new Document(); Document doc = new Document();
Field name = new Field(Fields.NAME, entry.getName(), Field.Store.YES, Field.Index.ANALYZED); Field name = new StoredField(Fields.NAME, entry.getName());
name.setIndexOptions(IndexOptions.DOCS_ONLY);
doc.add(name); doc.add(name);
Field nvdId = new Field(Fields.NVDID, entry.getNvdId(), Field.Store.NO, Field.Index.ANALYZED); Field vendor = new TextField(Fields.VENDOR, entry.getVendor(), Field.Store.NO);
nvdId.setIndexOptions(IndexOptions.DOCS_ONLY);
doc.add(nvdId);
Field vendor = new Field(Fields.VENDOR, entry.getVendor(), Field.Store.NO, Field.Index.ANALYZED);
vendor.setIndexOptions(IndexOptions.DOCS_ONLY);
vendor.setBoost(5.0F); vendor.setBoost(5.0F);
doc.add(vendor); doc.add(vendor);
Field product = new Field(Fields.PRODUCT, entry.getProduct(), Field.Store.NO, Field.Index.ANALYZED); Field product = new TextField(Fields.PRODUCT, entry.getProduct(), Field.Store.NO);
product.setIndexOptions(IndexOptions.DOCS_ONLY);
product.setBoost(5.0F); product.setBoost(5.0F);
doc.add(product); doc.add(product);
Field title = new Field(Fields.TITLE, entry.getTitle(), Field.Store.YES, Field.Index.ANALYZED);
title.setIndexOptions(IndexOptions.DOCS_ONLY);
//title.setBoost(1.0F);
doc.add(title);
//TODO revision should likely be its own field //TODO revision should likely be its own field
if (entry.getVersion() != null) { if (entry.getVersion() != null) {
Field version = null; Field version = null;
if (entry.getRevision() != null) { if (entry.getRevision() != null) {
version = new Field(Fields.VERSION, entry.getVersion() + " " version = new TextField(Fields.VERSION, entry.getVersion() + " "
+ entry.getRevision(), Field.Store.NO, Field.Index.ANALYZED); + entry.getRevision(), Field.Store.NO);
} else { } else {
version = new Field(Fields.VERSION, entry.getVersion(), version = new TextField(Fields.VERSION, entry.getVersion(),
Field.Store.NO, Field.Index.ANALYZED); Field.Store.NO);
} }
version.setIndexOptions(IndexOptions.DOCS_ONLY);
version.setBoost(0.8F); version.setBoost(0.8F);
doc.add(version); doc.add(version);
} }
return doc; return doc;
} }
} }

View File

@@ -23,6 +23,7 @@ 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;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig;
@@ -98,13 +99,7 @@ public abstract class AbstractIndex {
} }
} }
if (indexSearcher != null) { if (indexSearcher != null) {
try { indexSearcher = null;
indexSearcher.close();
} catch (IOException ex) {
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex);
} finally {
indexSearcher = null;
}
} }
if (analyzer != null) { if (analyzer != null) {
@@ -140,7 +135,7 @@ public abstract class AbstractIndex {
if (!isOpen()) { if (!isOpen()) {
open(); open();
} }
IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_35, analyzer); IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_40, analyzer);
indexWriter = new IndexWriter(directory, conf); indexWriter = new IndexWriter(directory, conf);
} }
@@ -170,7 +165,8 @@ public abstract class AbstractIndex {
if (!isOpen()) { if (!isOpen()) {
open(); open();
} }
indexReader = IndexReader.open(directory, true); //indexReader = IndexReader.open(directory, true);
indexReader = DirectoryReader.open(directory);
} }
/** /**

View File

@@ -18,7 +18,7 @@ package org.codesecure.dependencycheck.data.lucene;
* Copyright (c) 2012 Jeremy Long. All Rights Reserved. * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/ */
import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.similarities.DefaultSimilarity;
/** /**
* *
@@ -41,7 +41,7 @@ public class DependencySimilarity extends DefaultSimilarity {
* @return 1 * @return 1
*/ */
@Override @Override
public float idf(int docFreq, int numDocs) { public float idf(long docFreq, long numDocs) {
return 1; return 1;
} }
} }

View File

@@ -21,14 +21,15 @@ package org.codesecure.dependencycheck.data.nvdcve;
import java.io.*; import java.io.*;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder;
import java.util.*; import java.util.*;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.KeywordAnalyzer; import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper; import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.FSDirectory;
@@ -39,6 +40,7 @@ import org.codesecure.dependencycheck.data.lucene.AbstractIndex;
import org.codesecure.dependencycheck.data.nvdcve.xml.Importer; import org.codesecure.dependencycheck.data.nvdcve.xml.Importer;
import org.codesecure.dependencycheck.utils.DownloadFailedException; import org.codesecure.dependencycheck.utils.DownloadFailedException;
import org.codesecure.dependencycheck.utils.Downloader; import org.codesecure.dependencycheck.utils.Downloader;
import org.codesecure.dependencycheck.utils.FileUtils;
import org.codesecure.dependencycheck.utils.Settings; import org.codesecure.dependencycheck.utils.Settings;
/** /**
@@ -48,6 +50,10 @@ import org.codesecure.dependencycheck.utils.Settings;
*/ */
public class Index extends AbstractIndex implements CachedWebDataSource { public class Index extends AbstractIndex implements CachedWebDataSource {
/**
* The current version of the index
*/
public static final String INDEX_VERSION = "1.0";
/** /**
* The name of the properties file containing the timestamp of the last * The name of the properties file containing the timestamp of the last
* update. * update.
@@ -66,18 +72,45 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
private static final String LAST_UPDATED_BASE = "lastupdated."; private static final String LAST_UPDATED_BASE = "lastupdated.";
/** /**
* Returns the directory that holds the NVD CVE Index. * Returns the directory that holds the NVD CVE Index. Note, this
* returns the path where the class or jar file exists.
* *
* @return the Directory containing the NVD CVE Index. * @return the Directory containing the NVD CVE Index.
* @throws IOException is thrown if an IOException occurs. * @throws IOException is thrown if an IOException occurs.
*/ */
public Directory getDirectory() throws IOException { public Directory getDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CVE_INDEX); File path = getDataDirectory();
File path = new File(fileName);
Directory dir = FSDirectory.open(path); Directory dir = FSDirectory.open(path);
return dir; return dir;
} }
/**
* Retrieves the directory that the JAR file exists in so that
* we can ensure we always use a common data directory.
*
* @return the data directory for this index.
* @throws IOException is thrown if an IOException occurs of course...
*/
protected File getDataDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CVE_INDEX);
String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create NVD CVE Data directory");
}
}
return path;
}
/** /**
* Creates an Analyzer for the NVD VULNERABLE_CPE Index. * Creates an Analyzer for the NVD VULNERABLE_CPE Index.
* *
@@ -91,7 +124,7 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
fieldAnalyzers.put(Fields.VULNERABLE_CPE, new KeywordAnalyzer()); fieldAnalyzers.put(Fields.VULNERABLE_CPE, new KeywordAnalyzer());
PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper( PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(
new StandardAnalyzer(Version.LUCENE_35), fieldAnalyzers); new StandardAnalyzer(Version.LUCENE_40), fieldAnalyzers);
return wrapper; return wrapper;
} }
@@ -165,11 +198,17 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
* *
* @param timeStamp the timestamp to write. * @param timeStamp the timestamp to write.
*/ */
private void writeLastUpdatedPropertyFile(Map<String, NvdCveUrl> updated) { private void writeLastUpdatedPropertyFile(Map<String, NvdCveUrl> updated) throws UpdateException {
String dir = Settings.getString(Settings.KEYS.CVE_INDEX); String dir;
try {
dir = getDataDirectory().getCanonicalPath();
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException("Unable to locate last updated properties file.", ex);
}
File cveProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE); File cveProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
Properties prop = new Properties(); Properties prop = new Properties();
prop.put("version", INDEX_VERSION);
for (NvdCveUrl cve : updated.values()) { for (NvdCveUrl cve : updated.values()) {
prop.put(LAST_UPDATED_BASE + cve.id, String.valueOf(cve.getTimestamp())); prop.put(LAST_UPDATED_BASE + cve.id, String.valueOf(cve.getTimestamp()));
} }
@@ -177,22 +216,26 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
OutputStream os = null; OutputStream os = null;
try { try {
os = new FileOutputStream(cveProp); os = new FileOutputStream(cveProp);
OutputStreamWriter out = new OutputStreamWriter(os); OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8");
prop.store(out, dir); prop.store(out, dir);
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException("Unable to find last updated properties file.", ex);
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException("Unable to update last updated properties file.", ex);
} finally { } finally {
try { if (os != null) {
os.flush(); try {
} catch (IOException ex) { os.flush();
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) {
} Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
try { }
os.close(); try {
} catch (IOException ex) { os.close();
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
}
} }
} }
} }
@@ -206,10 +249,11 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
* @return the NvdCveUrl of the files that need to be updated. * @return the NvdCveUrl of the files that need to be updated.
* @throws MalformedURLException is thrown if the URL for the NVD CVE Meta * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
* data is incorrect. * data is incorrect.
* @throws DownloadFailedException is thrown if there is an error * @throws DownloadFailedException is thrown if there is an error.
* downloading the nvd cve download data file. * downloading the nvd cve download data file.
* @throws UpdateException Is thrown if there is an issue with the last updated properties file.
*/ */
public Map<String, NvdCveUrl> updateNeeded() throws MalformedURLException, DownloadFailedException { public Map<String, NvdCveUrl> updateNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
Map<String, NvdCveUrl> currentlyPublished; Map<String, NvdCveUrl> currentlyPublished;
try { try {
@@ -221,16 +265,36 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
if (currentlyPublished == null) { if (currentlyPublished == null) {
throw new DownloadFailedException("Unable to retrieve valid timestamp from nvd cve downloads page"); throw new DownloadFailedException("Unable to retrieve valid timestamp from nvd cve downloads page");
} }
String dir = Settings.getString(Settings.KEYS.CVE_INDEX); String dir;
try {
dir = getDataDirectory().getCanonicalPath();
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException("Unable to locate last updated properties file.", ex);
}
File f = new File(dir); File f = new File(dir);
if (f.exists()) { if (f.exists()) {
File cveProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE); File cveProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
if (cveProp.exists()) { if (cveProp.exists()) {
Properties prop = new Properties(); Properties prop = new Properties();
InputStream is; InputStream is = null;
try { try {
is = new FileInputStream(cveProp); is = new FileInputStream(cveProp);
prop.load(is); prop.load(is);
if (prop.getProperty("version") == null) {
is.close();
//this is an old version of the lucene index - just delete it
FileUtils.delete(f);
//this importer also updates the CPE index and it is also using an old version
org.codesecure.dependencycheck.data.cpe.Index cpeidx = new org.codesecure.dependencycheck.data.cpe.Index();
File cpeDir = cpeidx.getDataDirectory();
FileUtils.delete(cpeDir);
return currentlyPublished;
}
long lastUpdated = Long.parseLong(prop.getProperty(Index.LAST_UPDATED_MODIFIED)); long lastUpdated = Long.parseLong(prop.getProperty(Index.LAST_UPDATED_MODIFIED));
Date now = new Date(); Date now = new Date();
int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS); int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS);
@@ -264,6 +328,14 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex);
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
}
}
} }
} }
} }
@@ -403,7 +475,7 @@ public class Index extends AbstractIndex implements CachedWebDataSource {
* @throws IOException is thrown if an IOExcpetion occurs. * @throws IOException is thrown if an IOExcpetion occurs.
*/ */
private String readFile(File file) throws IOException { private String readFile(File file) throws IOException {
FileReader stream = new FileReader(file); InputStreamReader stream = new InputStreamReader(new FileInputStream(file), "UTF-8");
StringBuilder str = new StringBuilder((int) file.length()); StringBuilder str = new StringBuilder((int) file.length());
try { try {
char[] buf = new char[8096]; char[] buf = new char[8096];

View File

@@ -20,6 +20,7 @@ package org.codesecure.dependencycheck.data.nvdcve;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -142,6 +143,9 @@ public class NvdCveAnalyzer implements org.codesecure.dependencycheck.analyzer.A
} catch (JAXBException ex) { } catch (JAXBException ex) {
Logger.getLogger(NvdCveAnalyzer.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(NvdCveAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
dependency.addAnalysisException(new AnalysisException("Unable to retrieve vulnerability data", ex)); dependency.addAnalysisException(new AnalysisException("Unable to retrieve vulnerability data", ex));
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(NvdCveAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
dependency.addAnalysisException(new AnalysisException("Unable to retrieve vulnerability data - utf-8", ex));
} }
} }
} catch (IOException ex) { } catch (IOException ex) {
@@ -198,11 +202,11 @@ public class NvdCveAnalyzer implements org.codesecure.dependencycheck.analyzer.A
this.open(); this.open();
} }
private Vulnerability parseVulnerability(String xml) throws JAXBException { private Vulnerability parseVulnerability(String xml) throws JAXBException, UnsupportedEncodingException {
JAXBContext jaxbContext = JAXBContext.newInstance(VulnerabilityType.class); JAXBContext jaxbContext = JAXBContext.newInstance(VulnerabilityType.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
ByteArrayInputStream input = new ByteArrayInputStream(xml.getBytes()); ByteArrayInputStream input = new ByteArrayInputStream(xml.getBytes("UTF-8"));
VulnerabilityType cvedata = (VulnerabilityType) unmarshaller.unmarshal(input); VulnerabilityType cvedata = (VulnerabilityType) unmarshaller.unmarshal(input);
if (cvedata == null) { if (cvedata == null) {
return null; return null;

View File

@@ -43,15 +43,17 @@ public class Importer {
*/ */
public static void importXML(File file) { public static void importXML(File file) {
NvdCveParser indexer = null; NvdCveParser indexer = null;
org.codesecure.dependencycheck.data.cpe.xml.Indexer cpeIndexer = null;
try { try {
indexer = new NvdCveParser(); indexer = new NvdCveParser();
indexer.openIndexWriter(); indexer.openIndexWriter();
//HACK - hack to ensure all CPE data is stored in the index.
cpeIndexer = new org.codesecure.dependencycheck.data.cpe.xml.Indexer();
cpeIndexer.openIndexWriter();
indexer.setCPEIndexer(cpeIndexer);
indexer.parse(file); indexer.parse(file);
} catch (CorruptIndexException ex) { } catch (CorruptIndexException ex) {
Logger.getLogger(Importer.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Importer.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) { } catch (IOException ex) {
@@ -60,6 +62,9 @@ public class Importer {
if (indexer != null) { if (indexer != null) {
indexer.close(); indexer.close();
} }
if (cpeIndexer != null) {
cpeIndexer.close();
}
} }
} }
// public static void importXML(File file) throws FileNotFoundException, IOException, JAXBException, // public static void importXML(File file) throws FileNotFoundException, IOException, JAXBException,

View File

@@ -20,6 +20,7 @@ package org.codesecure.dependencycheck.data.nvdcve.xml;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
@@ -27,8 +28,9 @@ import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller; import javax.xml.bind.Marshaller;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.FieldInfo.IndexOptions;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.codesecure.dependencycheck.data.lucene.LuceneUtils; import org.codesecure.dependencycheck.data.lucene.LuceneUtils;
import org.codesecure.dependencycheck.data.nvdcve.generated.VulnerabilityType; import org.codesecure.dependencycheck.data.nvdcve.generated.VulnerabilityType;
@@ -55,7 +57,12 @@ public class Indexer extends Index implements EntrySaveDelegate {
*/ */
public void saveEntry(VulnerabilityType vulnerability) throws CorruptIndexException, IOException { public void saveEntry(VulnerabilityType vulnerability) throws CorruptIndexException, IOException {
try { try {
Document doc = convertEntryToDoc(vulnerability); Document doc = null;
try {
doc = convertEntryToDoc(vulnerability);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(Indexer.class.getName()).log(Level.SEVERE, null, ex);
}
if (doc == null) { if (doc == null) {
return; return;
@@ -74,8 +81,9 @@ public class Indexer extends Index implements EntrySaveDelegate {
* @param vulnerability a VULNERABLE_CPE Entry. * @param vulnerability a VULNERABLE_CPE Entry.
* @return a Lucene Document containing a VULNERABLE_CPE Entry. * @return a Lucene Document containing a VULNERABLE_CPE Entry.
* @throws JAXBException is thrown when there is a JAXBException. * @throws JAXBException is thrown when there is a JAXBException.
* @throws UnsupportedEncodingException if the system doesn't support utf-8
*/ */
protected Document convertEntryToDoc(VulnerabilityType vulnerability) throws JAXBException { protected Document convertEntryToDoc(VulnerabilityType vulnerability) throws JAXBException, UnsupportedEncodingException {
boolean hasApplication = false; boolean hasApplication = false;
Document doc = new Document(); Document doc = new Document();
@@ -101,14 +109,11 @@ public class Indexer extends Index implements EntrySaveDelegate {
return null; return null;
} }
Field name = new Field(Fields.CVE_ID, vulnerability.getId(), Field.Store.NO, Field.Index.ANALYZED); Field name = new StringField(Fields.CVE_ID, vulnerability.getId(), Field.Store.NO);
name.setIndexOptions(IndexOptions.DOCS_ONLY);
doc.add(name); doc.add(name);
Field description = new Field(Fields.DESCRIPTION, vulnerability.getSummary(), Field.Store.NO, Field.Index.ANALYZED); // Field description = new Field(Fields.DESCRIPTION, vulnerability.getSummary(), Field.Store.NO, Field.Index.ANALYZED);
description.setIndexOptions(IndexOptions.DOCS_ONLY); // doc.add(description);
doc.add(description);
JAXBContext context = JAXBContext.newInstance("org.codesecure.dependencycheck.data.nvdcve.generated"); JAXBContext context = JAXBContext.newInstance("org.codesecure.dependencycheck.data.nvdcve.generated");
@@ -119,7 +124,7 @@ public class Indexer extends Index implements EntrySaveDelegate {
m.marshal(vulnerability, out); m.marshal(vulnerability, out);
Field xml = new Field(Fields.XML, out.toString(), Field.Store.YES, Field.Index.NO); Field xml = new StoredField(Fields.XML, out.toString("UTF-8"));
doc.add(xml); doc.add(xml);
return doc; return doc;
@@ -141,8 +146,7 @@ public class Indexer extends Index implements EntrySaveDelegate {
} }
private void addVulnerableCpe(String cpe, Document doc) { private void addVulnerableCpe(String cpe, Document doc) {
Field vulnerable = new Field(Fields.VULNERABLE_CPE, cpe, Field.Store.NO, Field.Index.ANALYZED); Field vulnerable = new StringField(Fields.VULNERABLE_CPE, cpe, Field.Store.NO);
vulnerable.setIndexOptions(IndexOptions.DOCS_ONLY);
doc.add(vulnerable); doc.add(vulnerable);
} }
} }

View File

@@ -20,17 +20,22 @@ package org.codesecure.dependencycheck.data.nvdcve.xml;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.index.FieldInfo.IndexOptions; import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.codesecure.dependencycheck.data.cpe.Entry;
import org.codesecure.dependencycheck.data.nvdcve.Fields; import org.codesecure.dependencycheck.data.nvdcve.Fields;
import org.codesecure.dependencycheck.data.nvdcve.Index; import org.codesecure.dependencycheck.data.nvdcve.Index;
@@ -40,6 +45,19 @@ import org.codesecure.dependencycheck.data.nvdcve.Index;
*/ */
public class NvdCveParser extends Index { public class NvdCveParser extends Index {
//HACK - this has initially been placed here as a hack because not all
// of the CPEs listed in the NVD CVE are actually in the CPE xml file
// hosted by NIST.
private org.codesecure.dependencycheck.data.cpe.xml.Indexer cpeIndexer = null;
/**
* Adds the CPE Index to add additional CPEs found by parsing the NVD CVE.
* @param indexer the CPE Indexer to write new CPEs into.
*/
public void setCPEIndexer(org.codesecure.dependencycheck.data.cpe.xml.Indexer indexer) {
this.cpeIndexer = indexer;
}
/** /**
* Parses an NVD CVE xml file using a buffered readerd. This * Parses an NVD CVE xml file using a buffered readerd. This
* method maybe more fragile then using a partial-unmarshalling SAX * method maybe more fragile then using a partial-unmarshalling SAX
@@ -49,14 +67,15 @@ public class NvdCveParser extends Index {
* @param file the reference to the NVD CVE file * @param file the reference to the NVD CVE file
*/ */
public void parse(File file) { public void parse(File file) {
FileReader fr = null; InputStreamReader fr = null;
BufferedReader br = null; BufferedReader br = null;
Pattern rxEntry = Pattern.compile("^\\s*<entry\\s*id\\=\\\"([^\\\"]+)\\\".*$"); Pattern rxEntry = Pattern.compile("^\\s*<entry\\s*id\\=\\\"([^\\\"]+)\\\".*$");
Pattern rxEntryEnd = Pattern.compile("^\\s*</entry>.*$"); Pattern rxEntryEnd = Pattern.compile("^\\s*</entry>.*$");
Pattern rxFact = Pattern.compile("^\\s*<cpe\\-lang\\:fact\\-ref name=\\\"([^\\\"]+).*$"); Pattern rxFact = Pattern.compile("^\\s*<cpe\\-lang\\:fact\\-ref name=\\\"([^\\\"]+).*$");
Pattern rxSummary = Pattern.compile("^\\s*<vuln:summary>([^\\<]+).*$"); //Pattern rxSummary = Pattern.compile("^\\s*<vuln:summary>([^\\<]+).*$");
try { try {
fr = new FileReader(file);
fr = new InputStreamReader(new FileInputStream(file), "UTF-8");
br = new BufferedReader(fr); br = new BufferedReader(fr);
StringBuilder sb = new StringBuilder(7000); StringBuilder sb = new StringBuilder(7000);
String str = null; String str = null;
@@ -105,23 +124,21 @@ public class NvdCveParser extends Index {
sb.append("id=\"").append(id).append("\">"); sb.append("id=\"").append(id).append("\">");
//sb.append(str); //need to do the above to get the correct schema generated from files. //sb.append(str); //need to do the above to get the correct schema generated from files.
Field name = new Field(Fields.CVE_ID, id, Field.Store.NO, Field.Index.ANALYZED); Field name = new StringField(Fields.CVE_ID, id, Field.Store.NO);
name.setIndexOptions(IndexOptions.DOCS_ONLY);
doc.add(name); doc.add(name);
continue; continue;
} }
Matcher matcherSummary = rxSummary.matcher(str); // Matcher matcherSummary = rxSummary.matcher(str);
if (matcherSummary.matches()) { // if (matcherSummary.matches()) {
String summary = matcherSummary.group(1); // String summary = matcherSummary.group(1);
Field description = new Field(Fields.DESCRIPTION, summary, Field.Store.NO, Field.Index.ANALYZED); // Field description = new Field(Fields.DESCRIPTION, summary, Field.Store.NO);
description.setIndexOptions(IndexOptions.DOCS_ONLY); // doc.add(description);
doc.add(description); // continue;
continue; // }
}
if (matcherEntryEnd.matches()) { if (matcherEntryEnd.matches()) {
sb.append("</vulnerabilityType>"); sb.append("</vulnerabilityType>");
Field xml = new Field(Fields.XML, sb.toString(), Field.Store.YES, Field.Index.NO); Field xml = new StoredField(Fields.XML, sb.toString());
doc.add(xml); doc.add(xml);
if (!skipEntry) { if (!skipEntry) {
@@ -146,7 +163,9 @@ public class NvdCveParser extends Index {
Logger.getLogger(NvdCveParser.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(NvdCveParser.class.getName()).log(Level.SEVERE, null, ex);
} finally { } finally {
try { try {
fr.close(); if (fr != null) {
fr.close();
}
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(NvdCveParser.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(NvdCveParser.class.getName()).log(Level.SEVERE, null, ex);
} }
@@ -164,10 +183,24 @@ public class NvdCveParser extends Index {
* Adds a CPE to the Lucene Document * Adds a CPE to the Lucene Document
* @param cpe a string representing a CPE * @param cpe a string representing a CPE
* @param doc a lucene document * @param doc a lucene document
* @throws CorruptIndexException is thrown if the CPE Index is corrupt
* @throws IOException is thrown if there is an IO Exception while writting to the CPE Index
*/ */
private void addVulnerableCpe(String cpe, Document doc) { private void addVulnerableCpe(String cpe, Document doc) throws CorruptIndexException, IOException {
Field vulnerable = new Field(Fields.VULNERABLE_CPE, cpe, Field.Store.NO, Field.Index.ANALYZED); Field vulnerable = new StringField(Fields.VULNERABLE_CPE, cpe, Field.Store.NO);
vulnerable.setIndexOptions(IndexOptions.DOCS_ONLY);
doc.add(vulnerable); doc.add(vulnerable);
//HACK - this has initially been placed here as a hack because not all
// of the CPEs listed in the NVD CVE are actually in the CPE xml file
// hosted by NIST.
Entry cpeEntry = new Entry();
try {
cpeEntry.parseName(cpe);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(NvdCveParser.class.getName()).log(Level.SEVERE, null, ex);
}
if (cpeIndexer != null) {
cpeIndexer.saveEntry(cpeEntry);
}
} }
} }

View File

@@ -19,7 +19,7 @@ package org.codesecure.dependencycheck.dependency;
*/ */
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.IOException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -238,11 +238,10 @@ public class Dependency {
* *
* @param type the type of identifier (such as CPE). * @param type the type of identifier (such as CPE).
* @param value the value of the identifier. * @param value the value of the identifier.
* @param title the title of the identifier.
* @param url the URL of the identifier. * @param url the URL of the identifier.
*/ */
public void addIdentifier(String type, String value, String title, String url) { public void addIdentifier(String type, String value, String url) {
Identifier i = new Identifier(type, value, title, url); Identifier i = new Identifier(type, value, url);
this.identifiers.add(i); this.identifiers.add(i);
} }
@@ -419,7 +418,7 @@ public class Dependency {
try { try {
md5 = Checksum.getMD5Checksum(file); md5 = Checksum.getMD5Checksum(file);
sha1 = Checksum.getSHA1Checksum(file); sha1 = Checksum.getSHA1Checksum(file);
} catch (FileNotFoundException ex) { } catch (IOException ex) {
Logger.getLogger(Dependency.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Dependency.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) { } catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Dependency.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Dependency.class.getName()).log(Level.SEVERE, null, ex);

View File

@@ -184,7 +184,7 @@ public class EvidenceCollection implements Iterable<Evidence> {
text = text.toLowerCase(); text = text.toLowerCase();
for (Evidence e : this.list) { for (Evidence e : this.list) {
if (e.used && e.value.contains(text)) { if (e.used && e.value.toLowerCase().contains(text)) {
return true; return true;
} }
} }

View File

@@ -29,13 +29,11 @@ public class Identifier {
* *
* @param type the identifier type. * @param type the identifier type.
* @param value the identifier value. * @param value the identifier value.
* @param title the identifier title.
* @param url the identifier url. * @param url the identifier url.
*/ */
Identifier(String type, String value, String title, String url) { Identifier(String type, String value, String url) {
this.type = type; this.type = type;
this.value = value; this.value = value;
this.title = title;
this.url = url; this.url = url;
} }
@@ -44,12 +42,11 @@ public class Identifier {
* *
* @param type the identifier type. * @param type the identifier type.
* @param value the identifier value. * @param value the identifier value.
* @param title the identifier title.
* @param url the identifier url. * @param url the identifier url.
* @param description the description of the identifier. * @param description the description of the identifier.
*/ */
Identifier(String type, String value, String title, String url, String description) { Identifier(String type, String value, String url, String description) {
this(type, value, title, url); this(type, value, url);
this.description = description; this.description = description;
} }
/** /**
@@ -74,28 +71,7 @@ public class Identifier {
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }
/**
* The title of the identifeir
*/
protected String title;
/**
* Get the value of title
*
* @return the value of title
*/
public String getTitle() {
return title;
}
/**
* Set the value of title
*
* @param title new value of title
*/
public void setTitle(String title) {
this.title = title;
}
/** /**
* The url for the identifeir * The url for the identifeir
*/ */

View File

@@ -18,15 +18,16 @@ package org.codesecure.dependencycheck.reporting;
* Copyright (c) 2012 Jeremy Long. All Rights Reserved. * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/ */
import java.io.BufferedWriter; import java.io.FileInputStream;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashMap; import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.app.VelocityEngine;
@@ -35,94 +36,139 @@ import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.apache.velocity.tools.ToolManager; import org.apache.velocity.tools.ToolManager;
import org.apache.velocity.tools.config.EasyFactoryConfiguration; import org.apache.velocity.tools.config.EasyFactoryConfiguration;
import org.codesecure.dependencycheck.analyzer.Analyzer;
import org.codesecure.dependencycheck.dependency.Dependency; import org.codesecure.dependencycheck.dependency.Dependency;
/** /**
* The ReportGenerator is used to, as the name implies, generate reports. Internally
* the generator uses the Velocity Templating Engine. The ReportGenerator exposes
* a list of Dependencies to the template when generating the report.
* *
* @author Jeremy Long (jeremy.long@gmail.com) * @author Jeremy Long (jeremy.long@gmail.com)
*/ */
public class ReportGenerator { public class ReportGenerator {
/**
* The Velocity Engine.
*/
private VelocityEngine engine = null;
/**
* The Velocity Engine Context.
*/
private Context context = null;
/**
* Constructs a new ReportGenerator.
*
* @param applicationName the application name being analyzed
* @param dependencies the list of dependencies
* @param analyzers the list of analyzers used.
*/
public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers) {
engine = createVelocityEngine();
context = createContext();
engine.init();
context.put("applicationName", applicationName);
context.put("dependencies", dependencies);
context.put("analyzers", analyzers);
}
/**
* Creates a new Velocity Engine.
* @return a velocity engine.
*/
private VelocityEngine createVelocityEngine() {
VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
return ve;
}
/**
* Creates a new Velocity Context initialized with escape and date tools.
* @return a Velcotiy Context.
*/
private Context createContext() {
ToolManager manager = new ToolManager();
Context c = manager.createContext();
EasyFactoryConfiguration config = new EasyFactoryConfiguration();
config.addDefaultTools();
config.toolbox("application").tool("esc", "org.apache.velocity.tools.generic.EscapeTool").tool("org.apache.velocity.tools.generic.DateTool");
manager.configure(config);
return c;
}
/** /**
* Generates the Dependency Reports for the identified dependencies. * Generates the Dependency Reports for the identified dependencies.
* *
* @param outputDir the path where the reports should be written. * @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 IOException is thrown when the template file does not exist.
* @throws Exception is thrown if there is an error writting out the * @throws Exception is thrown if there is an error writting out the
* reports. * reports.
*/ */
public void generateReports(String outputDir, String applicationName, List<Dependency> dependencies) throws IOException, Exception { public void generateReports(String outputDir) throws IOException, Exception {
generateReport("HtmlReport", outputDir + File.separator + "DependencyCheck-Report.html");
Map<String, Object> properties = new HashMap<String, Object>(); //generateReport("XmlReport", outputDir + File.separator + "DependencyCheck-Report.xml");
properties.put("dependencies", dependencies);
properties.put("applicationName", applicationName);
String reportName = applicationName.replaceAll("[^a-zA-Z0-9-_ \\.]+", "");
String filename = outputDir + File.separatorChar + reportName;
generateReport("HtmlReport", filename + ".html", properties);
//generateReport("XmlReport",filename + ".xml",properties);
} }
/** /**
* much of this code is from * Generates a report from a given Velocity Template. The template name
* http://stackoverflow.com/questions/2931516/loading-velocity-template-inside-a-jar-file * provided can be the name of a template contained in the jar file, such as
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a template file.
* *
* @param templateName the name of the template to load. * @param templateName the name of the template to load.
* @param outFileName The filename and path to write the report to. * @param outFileName the filename and path to write the report to.
* @param properties a map of properties to load into the velocity context.
* @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, public void generateReport(String templateName, String outFileName) throws IOException, Exception {
Map<String, Object> properties) throws IOException, Exception { InputStream input = null;
String templatePath = null;
VelocityEngine ve = new VelocityEngine(); File f = new File(templateName);
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); if (f.exists() && f.isFile()) {
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); try {
templatePath = templateName;
ToolManager manager = new ToolManager(); input = new FileInputStream(f);
Context context = manager.createContext(); } catch (FileNotFoundException ex) {
EasyFactoryConfiguration config = new EasyFactoryConfiguration(); Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
config.addDefaultTools(); }
config.toolbox("application").tool("esc", "org.apache.velocity.tools.generic.EscapeTool").tool("org.apache.velocity.tools.generic.DateTool"); } else {
templatePath = "templates/" + templateName + ".vsl";
manager.configure(config); input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
}
ve.init();
final String templatePath = "templates/" + templateName + ".vsl";
InputStream input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
if (input == null) { if (input == null) {
throw new IOException("Template file doesn't exist"); throw new IOException("Template file doesn't exist");
} }
InputStreamReader reader = new InputStreamReader(input); InputStreamReader reader = new InputStreamReader(input, "UTF-8");
BufferedWriter writer = null; OutputStreamWriter writer = null;
OutputStream outputStream = null;
//VelocityContext context = new VelocityContext();
//load the data into the context
if (properties != null) {
for (Map.Entry<String, Object> property : properties.entrySet()) {
context.put(property.getKey(), property.getValue());
}
}
try { try {
writer = new BufferedWriter(new FileWriter(new File(outFileName))); outputStream = new FileOutputStream(outFileName);
writer = new OutputStreamWriter(outputStream, "UTF-8");
//writer = new BufferedWriter(oswriter);
if (!ve.evaluate(context, writer, templatePath, reader)) { if (!engine.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.");
} }
writer.flush(); writer.flush();
} finally { } finally {
try { if (writer != null) {
writer.close(); try {
} catch (Exception ex) { writer.close();
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex); } catch (Exception ex) {
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception ex) {
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
}
} }
try { try {
reader.close(); reader.close();

View File

@@ -2,7 +2,6 @@ package org.codesecure.dependencycheck.utils;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.MessageDigest; import java.security.MessageDigest;
@@ -30,29 +29,30 @@ public class Checksum {
* @param algorithm the algorithm to use to calculate the checksum * @param algorithm the algorithm to use to calculate the checksum
* @param file the file to calculate the checksum for * @param file the file to calculate the checksum for
* @return the checksum * @return the checksum
* @throws FileNotFoundException when the file does not exist * @throws IOException when the file does not exist
* @throws NoSuchAlgorithmException when an algorithm is specified that does * @throws NoSuchAlgorithmException when an algorithm is specified that does
* not exist * not exist
*/ */
public static byte[] getChecksum(String algorithm, File file) throws FileNotFoundException, NoSuchAlgorithmException { public static byte[] getChecksum(String algorithm, File file) throws NoSuchAlgorithmException, IOException {
InputStream fis = new FileInputStream(file); InputStream fis = null;
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance(algorithm); MessageDigest complete = MessageDigest.getInstance(algorithm);
int numRead; int numRead;
try { try {
fis = new FileInputStream(file);
do { do {
numRead = fis.read(buffer); numRead = fis.read(buffer);
if (numRead > 0) { if (numRead > 0) {
complete.update(buffer, 0, numRead); complete.update(buffer, 0, numRead);
} }
} while (numRead != -1); } while (numRead != -1);
} catch (IOException ex) {
Logger.getLogger(Checksum.class.getName()).log(Level.SEVERE, null, ex);
} finally { } finally {
try { if (fis != null) {
fis.close(); try {
} catch (IOException ex) { fis.close();
Logger.getLogger(Checksum.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) {
Logger.getLogger(Checksum.class.getName()).log(Level.SEVERE, null, ex);
}
} }
} }
return complete.digest(); return complete.digest();
@@ -63,10 +63,10 @@ public class Checksum {
* *
* @param file the file to generate the MD5 checksum * @param file the file to generate the MD5 checksum
* @return the hex representation of the MD5 hash * @return the hex representation of the MD5 hash
* @throws FileNotFoundException when the file passed in does not exist * @throws IOException when the file passed in does not exist
* @throws NoSuchAlgorithmException when the MD5 algorithm is not available * @throws NoSuchAlgorithmException when the MD5 algorithm is not available
*/ */
public static String getMD5Checksum(File file) throws FileNotFoundException, NoSuchAlgorithmException { public static String getMD5Checksum(File file) throws IOException, NoSuchAlgorithmException {
byte[] b = getChecksum("MD5", file); byte[] b = getChecksum("MD5", file);
return getHex(b); return getHex(b);
} }
@@ -76,10 +76,10 @@ public class Checksum {
* *
* @param file the file to generate the MD5 checksum * @param file the file to generate the MD5 checksum
* @return the hex representation of the SHA1 hash * @return the hex representation of the SHA1 hash
* @throws FileNotFoundException when the file passed in does not exist * @throws IOException when the file passed in does not exist
* @throws NoSuchAlgorithmException when the SHA1 algorithm is not available * @throws NoSuchAlgorithmException when the SHA1 algorithm is not available
*/ */
public static String getSHA1Checksum(File file) throws FileNotFoundException, NoSuchAlgorithmException { public static String getSHA1Checksum(File file) throws IOException, NoSuchAlgorithmException {
byte[] b = getChecksum("SHA1", file); byte[] b = getChecksum("SHA1", file);
return getHex(b); return getHex(b);
} }

View File

@@ -93,17 +93,20 @@ public final class CliParser {
validatePathExists(getScanFiles()); validatePathExists(getScanFiles());
if (!line.hasOption(ArgumentName.OUT)) { if (!line.hasOption(ArgumentName.OUT)) {
//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.
throw new ParseException("A valid directory name must be specified for the 'out' argument."); throw new ParseException("A valid directory name must be specified for "
+ "the 'out' argument.");
} }
} }
if (!line.hasOption(ArgumentName.APPNAME)) { if (!line.hasOption(ArgumentName.APPNAME)) {
throw new ParseException("Scan cannot be run without specifying an application name via the 'app' argument."); throw new ParseException("Scan cannot be run without specifying an application "
+ "name via the 'app' argument.");
} }
} }
} }
@@ -160,15 +163,25 @@ public final class CliParser {
Option noupdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE, Option noupdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
false, "disables the automatic updating of the CPE data."); 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 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 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 load = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.CPE)
.withDescription("load the CPE xml file.")
.create(ArgumentName.CPE_SHORT);
Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP).withDescription("a property file to load.").create(ArgumentName.PROP_SHORT); Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
.withDescription("a property file to load.")
.create(ArgumentName.PROP_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...
@@ -237,7 +250,8 @@ public final class CliParser {
+ "using the -p <file> argument or by passing them in as system properties." + nl + "using the -p <file> argument or by passing them in as system properties." + nl
+ nl + " " + Settings.KEYS.PROXY_URL + "\t\t the proxy URL to use when downloading resources." + nl + " " + Settings.KEYS.PROXY_URL + "\t\t the proxy URL to use when downloading resources."
+ nl + " " + Settings.KEYS.PROXY_PORT + "\t\t the proxy port to use when downloading resources." + nl + " " + Settings.KEYS.PROXY_PORT + "\t\t the proxy port to use when downloading resources."
+ nl + " " + Settings.KEYS.CONNECTION_TIMEOUT + "\t the cconnection timeout (in milliseconds) to use" + nl + "\t\t\t when downloading resources."; + nl + " " + Settings.KEYS.CONNECTION_TIMEOUT + "\t the cconnection timeout (in milliseconds) to use"
+ nl + "\t\t\t when downloading resources.";
} }
formatter.printHelp(Settings.getString("application.name", "DependencyCheck"), formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
@@ -312,7 +326,7 @@ public final class CliParser {
* @return if auto-update is allowed. * @return if auto-update is allowed.
*/ */
public boolean isAutoUpdate() { public boolean isAutoUpdate() {
return (line != null) ? !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE) : false; return (line != null) ? !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE) : true;
} }
/** /**

View File

@@ -128,8 +128,8 @@ public class Downloader {
String encoding = conn.getContentEncoding(); String encoding = conn.getContentEncoding();
BufferedOutputStream writer = null; BufferedOutputStream writer = null;
InputStream reader = null;
try { try {
InputStream reader;
if (unzip || (encoding != null && "gzip".equalsIgnoreCase(encoding))) { if (unzip || (encoding != null && "gzip".equalsIgnoreCase(encoding))) {
reader = new GZIPInputStream(conn.getInputStream()); reader = new GZIPInputStream(conn.getInputStream());
} else if (encoding != null && "deflate".equalsIgnoreCase(encoding)) { } else if (encoding != null && "deflate".equalsIgnoreCase(encoding)) {
@@ -147,6 +147,7 @@ public class Downloader {
} catch (Exception ex) { } catch (Exception ex) {
throw new DownloadFailedException("Error saving downloaded file.", ex); throw new DownloadFailedException("Error saving downloaded file.", ex);
} finally { } finally {
if (writer != null) {
try { try {
writer.close(); writer.close();
writer = null; writer = null;
@@ -154,6 +155,17 @@ public class Downloader {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST, Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the writter in Downloader.", ex); "Error closing the writter in Downloader.", ex);
} }
}
if (reader != null) {
try {
reader.close();
reader = null;
} catch (Exception ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the reader in Downloader.", ex);
}
}
try { try {
conn.disconnect(); conn.disconnect();
} finally { } finally {

View File

@@ -18,6 +18,10 @@ package org.codesecure.dependencycheck.utils;
* Copyright (c) 2012 Jeremy Long. All Rights Reserved. * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/ */
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
/** /**
* A collection of utilities for processing information about files. * A collection of utilities for processing information about files.
* *
@@ -45,4 +49,22 @@ public class FileUtils {
} }
return ret; return ret;
} }
/**
* Deletes a file. If the File is a directory it will recursively delete
* the contents.
*
* @param file the File to delete
* @throws IOException is thrown if the file could not be deleted
*/
public static void delete(File file) throws IOException {
if (file.isDirectory()) {
for (File c : file.listFiles()) {
delete(c);
}
}
if (!file.delete()) {
throw new FileNotFoundException("Failed to delete file: " + file);
}
}
} }

View File

@@ -1,2 +1 @@
org.codesecure.dependencycheck.data.nvdcve.Index org.codesecure.dependencycheck.data.nvdcve.Index
org.codesecure.dependencycheck.data.cpe.Index

View File

@@ -20,4 +20,4 @@ java.util.logging.FileHandler.level=FINEST
# %g - generation number for rotating logs # %g - generation number for rotating logs
# %u - unique number to avoid conflicts # %u - unique number to avoid conflicts
# FileHandler writes to %h/demo0.log by default. # FileHandler writes to %h/demo0.log by default.
java.util.logging.FileHandler.pattern=./logs/DependencyCheck%g.log java.util.logging.FileHandler.pattern=./logs/DependencyCheck%u.log

View File

@@ -34,7 +34,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() { $(document).ready(function() {
$(".expandablesubsection").click(function (e) { $(".expandable").click(function (e) {
e = e || window.event; e = e || window.event;
var h = e.target || e.srcElement; var h = e.target || e.srcElement;
var content = "#content" + h.id.substr(6); var content = "#content" + h.id.substr(6);
@@ -64,7 +64,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
.hidden { .hidden {
display: none; display: none;
} }
.exandable {}
.expandablesubsection { .expandablesubsection {
cursor: pointer; cursor: pointer;
/*background-image: url(img/plus.gif);*/ /*background-image: url(img/plus.gif);*/
@@ -286,7 +286,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
Dependencies Scanned:&nbsp;$dependencies.size()<br/><br/> Dependencies Scanned:&nbsp;$dependencies.size()<br/><br/>
<div class="indent"> <div class="indent">
#foreach($dependency in $dependencies) #foreach($dependency in $dependencies)
<a href="#$esc.html($esc.url($dependency.FilePath))">$esc.html($dependency.FileName)</a><br/> #if($dependency.getVulnerabilities().size()>0)
<a href="#$esc.html($esc.url($dependency.FilePath))">$esc.html($dependency.FileName)</a>&nbsp;<b style="color:#ff0000;">&#8226;</b><br/>
#else
<a href="#$esc.html($esc.url($dependency.FilePath))">$esc.html($dependency.FileName)</a><br/>
#end
#end #end
</div> </div>
<h2>Dependencies</h2> <h2>Dependencies</h2>
@@ -308,7 +312,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
#if ( $dependency.analysisExceptions.size() != 0 ) #if ( $dependency.analysisExceptions.size() != 0 )
#set($cnt=$cnt+1) #set($cnt=$cnt+1)
<h4 id="header$cnt" class="subsectionheader expandablesubsection red">Exceptions Occured During Analysis</h4> <h4 id="header$cnt" class="subsectionheader expandable expandablesubsection red">Exceptions Occured During Analysis</h4>
<div id="content$cnt" class="subsectioncontent standardsubsection hidden"> <div id="content$cnt" class="subsectioncontent standardsubsection hidden">
<ul> <ul>
#foreach($ex in $dependency.analysisExceptions) #foreach($ex in $dependency.analysisExceptions)
@@ -336,7 +340,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
</div> </div>
#end #end
#set($cnt=$cnt+1) #set($cnt=$cnt+1)
<h4 id="header$cnt" class="subsectionheader expandablesubsection white">Evidence</h4> <h4 id="header$cnt" class="subsectionheader expandable expandablesubsection white">Evidence</h4>
<div id="content$cnt" class="subsectioncontent standardsubsection hidden"> <div id="content$cnt" class="subsectioncontent standardsubsection hidden">
<table class="lined fullwidth" border="0"> <table class="lined fullwidth" border="0">
<tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr> <tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr>
@@ -366,7 +370,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<ul> <ul>
#foreach($id in $dependency.getIdentifiers()) #foreach($id in $dependency.getIdentifiers())
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here... ##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
<li><b>$esc.html($id.type):</b>&nbsp;$esc.html($id.title)&nbsp;:&nbsp;<a href="$esc.html($id.url)" target="_blank">$esc.html($id.value)</a> <li><b>$esc.html($id.type):</b>&nbsp;<a href="$esc.html($id.url)" target="_blank">$esc.html($id.value)</a>
#if( $id.descrription ) #if( $id.descrription )
<br/>$esc.html($id.description) <br/>$esc.html($id.description)
#end #end
@@ -377,7 +381,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
</div> </div>
#if($dependency.getVulnerabilities().size()>0) #if($dependency.getVulnerabilities().size()>0)
#set($cnt=$cnt+1) #set($cnt=$cnt+1)
<h4 id="header$cnt" class="subsectionheader white">Published Vulnerabilities</h4> <h4 id="header$cnt" class="subsectionheader expandable collaspablesubsection white">Published Vulnerabilities</h4>
<div id="content$cnt" class="subsectioncontent standardsubsection"> <div id="content$cnt" class="subsectioncontent standardsubsection">
#foreach($vuln in $dependency.getVulnerabilities()) #foreach($vuln in $dependency.getVulnerabilities())
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$esc.url($vuln.name)">$esc.html($vuln.name)</a></b></p> <p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$esc.url($vuln.name)">$esc.html($vuln.name)</a></b></p>

View File

@@ -51,7 +51,8 @@ public class EngineIntegrationTest {
instance.scan(path); instance.scan(path);
assertTrue(instance.getDependencies().size() > 0); assertTrue(instance.getDependencies().size() > 0);
instance.analyzeDependencies(); instance.analyzeDependencies();
ReportGenerator rg = new ReportGenerator(); ReportGenerator rg = new ReportGenerator("DependencyCheck",
rg.generateReports("./target/", "DependencyCheck", instance.getDependencies()); instance.getDependencies(), instance.getAnalyzers());
rg.generateReports("./target/");
} }
} }

View File

@@ -63,7 +63,8 @@ public class JarAnalyzerTest {
instance.analyze(result); instance.analyze(result);
boolean found = false; boolean found = false;
for (Evidence e : result.getProductEvidence()) { for (Evidence e : result.getProductEvidence()) {
if (e.getName().equals("package-title") && e.getValue().equals("org.mortbay.http")) { if (e.getName().equalsIgnoreCase("package-title")
&& e.getValue().equalsIgnoreCase("org.mortbay.http")) {
found = true; found = true;
break; break;
} }
@@ -72,7 +73,8 @@ public class JarAnalyzerTest {
found = false; found = false;
for (Evidence e : result.getVendorEvidence()) { for (Evidence e : result.getVendorEvidence()) {
if (e.getName().equals("implementation-url") && e.getValue().equals("http://jetty.mortbay.org")) { if (e.getName().equalsIgnoreCase("implementation-url")
&& e.getValue().equalsIgnoreCase("http://jetty.mortbay.org")) {
found = true; found = true;
break; break;
} }
@@ -81,7 +83,8 @@ public class JarAnalyzerTest {
found = false; found = false;
for (Evidence e : result.getVersionEvidence()) { for (Evidence e : result.getVersionEvidence()) {
if (e.getName().equals("Implementation-Version") && e.getValue().equals("4.2.27")) { if (e.getName().equalsIgnoreCase("Implementation-Version")
&& e.getValue().equalsIgnoreCase("4.2.27")) {
found = true; found = true;
break; break;
} }

View File

@@ -9,6 +9,8 @@ import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import junit.framework.TestCase; import junit.framework.TestCase;
@@ -30,8 +32,24 @@ public abstract class BaseIndexTestCase extends TestCase {
ensureIndexExists(); ensureIndexExists();
} }
protected static File getDataDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CPE_INDEX);
String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
return path;
}
public static void ensureIndexExists() throws Exception { public static void ensureIndexExists() throws Exception {
String indexPath = Settings.getString(Settings.KEYS.CPE_INDEX); //String indexPath = Settings.getString(Settings.KEYS.CPE_INDEX);
String indexPath = getDataDirectory().getCanonicalPath();
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

@@ -10,11 +10,9 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; 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.classic.ParseException;
import org.codesecure.dependencycheck.dependency.Dependency; import org.codesecure.dependencycheck.dependency.Dependency;
import org.codesecure.dependencycheck.analyzer.JarAnalyzer; import org.codesecure.dependencycheck.analyzer.JarAnalyzer;
import org.codesecure.dependencycheck.dependency.Evidence;
import org.codesecure.dependencycheck.dependency.Evidence.Confidence;
import org.junit.Test; import org.junit.Test;
/** /**
@@ -101,10 +99,15 @@ public class CPEAnalyzerTest extends BaseIndexTestCase {
Dependency depends = new Dependency(file); Dependency depends = new Dependency(file);
jarAnalyzer.analyze(depends); jarAnalyzer.analyze(depends);
File fileSpring = new File(this.getClass().getClassLoader().getResource("spring-core-2.5.5.jar").getPath());
Dependency spring = new Dependency(fileSpring);
jarAnalyzer.analyze(spring);
CPEAnalyzer instance = new CPEAnalyzer(); CPEAnalyzer instance = new CPEAnalyzer();
instance.open(); instance.open();
String expResult = "cpe:/a:apache:struts:2.1.2"; String expResult = "cpe:/a:apache:struts:2.1.2";
instance.determineCPE(depends); instance.determineCPE(depends);
instance.determineCPE(spring);
instance.close(); instance.close();
assertTrue("Incorrect match", depends.getIdentifiers().size() == 1); assertTrue("Incorrect match", depends.getIdentifiers().size() == 1);
assertTrue("Incorrect match", depends.getIdentifiers().get(0).getValue().equals(expResult)); assertTrue("Incorrect match", depends.getIdentifiers().get(0).getValue().equals(expResult));
@@ -133,6 +136,7 @@ public class CPEAnalyzerTest extends BaseIndexTestCase {
expResult = "cpe:/a:apache:struts:2.3.1.2"; expResult = "cpe:/a:apache:struts:2.3.1.2";
result = instance.searchCPE(vendor, product, version); result = instance.searchCPE(vendor, product, version);
assertEquals(expResult, result.get(0).getName()); assertEquals(expResult, result.get(0).getName());
instance.close(); instance.close();
} }

View File

@@ -35,7 +35,7 @@ public class EntryTest extends TestCase {
String name = "cpe:/a:apache:struts:1.1:rc2"; String name = "cpe:/a:apache:struts:1.1:rc2";
Entry instance = new Entry(); Entry instance = new Entry();
instance.setName(name); instance.parseName(name);
assertEquals(name,instance.getName()); assertEquals(name,instance.getName());
assertEquals("apache", instance.getVendor()); assertEquals("apache", instance.getVendor());

View File

@@ -40,43 +40,15 @@ public class IndexIntegrationTest extends BaseIndexTestCase {
public void tearDown() { public void tearDown() {
} }
/**
* Test of open method, of class Index.
*/
@Test
public void testOpen() {
System.out.println("open");
Index instance = new Index();
try {
instance.open();
} catch (IOException ex) {
fail(ex.getMessage());
}
instance.close();
}
/**
* Test of getDirectory method, of class Index.
*/
@Test
public void testGetDirectory() throws Exception {
System.out.println("getDirectory");
Index index = new Index();
Directory result = index.getDirectory();
String exp = File.separatorChar + "target" + File.separatorChar + "data" + File.separatorChar + "cpe";
// TODO review the generated test code and remove the default call to fail.
assertTrue(result.toString().contains(exp));
}
/** /**
* Test of update method, of class Index. * Test of update method, of class Index.
*/ */
@Test @Test
public void testUpdate() throws Exception { public void testUpdate() throws Exception {
System.out.println("update"); System.out.println("update");
Index instance = new Index(); //deprecated
instance.update(); //Index instance = new Index();
//instance.update();
} }
/** /**
@@ -85,8 +57,9 @@ public class IndexIntegrationTest extends BaseIndexTestCase {
@Test @Test
public void testUpdateNeeded() throws Exception { public void testUpdateNeeded() throws Exception {
System.out.println("updateNeeded"); System.out.println("updateNeeded");
Index instance = new Index(); //deprecated
instance.updateNeeded(); //Index instance = new Index();
//instance.updateNeeded();
//if an exception is thrown this test fails. However, because it depends on the //if an exception is thrown this test fails. However, because it depends on the
// order of the tests what this will return I am just testing for the exception. // order of the tests what this will return I am just testing for the exception.
//assertTrue(expResult < result); //assertTrue(expResult < result);

View File

@@ -0,0 +1,71 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.codesecure.dependencycheck.data.cpe;
import java.io.File;
import java.io.IOException;
import org.apache.lucene.store.Directory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author Jeremy Long (jeremy.long@gmail.com)
*/
public class IndexTest extends BaseIndexTestCase {
public IndexTest(String testCase) {
super(testCase);
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of open method, of class Index.
*/
@Test
public void testOpen() {
System.out.println("open");
Index instance = new Index();
try {
instance.open();
} catch (IOException ex) {
fail(ex.getMessage());
}
instance.close();
}
/**
* Test of getDirectory method, of class Index.
*/
@Test
public void testGetDirectory() throws Exception {
System.out.println("getDirectory");
Index index = new Index();
Directory result = index.getDirectory();
String exp = File.separatorChar + "target" + File.separatorChar + "data" + File.separatorChar + "cpe";
// TODO review the generated test code and remove the default call to fail.
assertTrue(result.toString().contains(exp));
}
}

View File

@@ -10,6 +10,8 @@ import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import junit.framework.TestCase; import junit.framework.TestCase;
@@ -31,8 +33,25 @@ public abstract class BaseIndexTestCase extends TestCase {
ensureIndexExists(); ensureIndexExists();
} }
protected static File getDataDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CVE_INDEX);
String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File( "." );
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
return path;
}
public static void ensureIndexExists() throws Exception { public static void ensureIndexExists() throws Exception {
String indexPath = Settings.getString(Settings.KEYS.CVE_INDEX); //String indexPath = Settings.getString(Settings.KEYS.CVE_INDEX);
String indexPath = getDataDirectory().getCanonicalPath();
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

@@ -4,11 +4,8 @@
*/ */
package org.codesecure.dependencycheck.data.nvdcve; package org.codesecure.dependencycheck.data.nvdcve;
import java.io.File;
import java.util.Map; import java.util.Map;
import org.apache.lucene.store.Directory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.*; import org.junit.*;
/** /**
@@ -48,18 +45,6 @@ public class IndexIntegrationTest extends BaseIndexTestCase {
assertEquals(12, result.size()); assertEquals(12, result.size());
} }
/**
* Test of getDirectory method, of class Index.
*/
@Test
public void testGetDirectory() throws Exception {
System.out.println("getDirectory");
Index instance = new Index();
String exp = File.separatorChar + "target" + File.separatorChar + "data" + File.separatorChar + "cve";
Directory result = instance.getDirectory();
assertTrue(result.toString().contains(exp));
}
/** /**
* Test of update method, of class Index. * Test of update method, of class Index.
*/ */
@@ -81,5 +66,4 @@ public class IndexIntegrationTest extends BaseIndexTestCase {
//if an exception is thrown this test fails. However, because it depends on the //if an exception is thrown this test fails. However, because it depends on the
// order of the tests what this will return I am just testing for the exception. // order of the tests what this will return I am just testing for the exception.
} }
} }

View File

@@ -0,0 +1,50 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.codesecure.dependencycheck.data.nvdcve;
import java.io.File;
import org.apache.lucene.store.Directory;
import static org.junit.Assert.assertTrue;
import org.junit.*;
/**
*
* @author Jeremy
*/
public class IndexTest extends BaseIndexTestCase {
public IndexTest(String testName) {
super(testName);
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of getDirectory method, of class Index.
*/
@Test
public void testGetDirectory() throws Exception {
System.out.println("getDirectory");
Index instance = new Index();
String exp = File.separatorChar + "target" + File.separatorChar + "data" + File.separatorChar + "cve";
Directory result = instance.getDirectory();
assertTrue(result.toString().contains(exp));
}
}

View File

@@ -249,15 +249,13 @@ public class DependencyTest {
System.out.println("addIdentifier"); System.out.println("addIdentifier");
String type = "cpe"; String type = "cpe";
String value = "cpe:/a:apache:struts:2.1.2"; String value = "cpe:/a:apache:struts:2.1.2";
String title = "Apache Struts 2.1.2";
String url = "http://somewhere"; String url = "http://somewhere";
Dependency instance = new Dependency(); Dependency instance = new Dependency();
instance.addIdentifier(type, value, title, url); instance.addIdentifier(type, value, url);
assertEquals(1,instance.getIdentifiers().size()); assertEquals(1,instance.getIdentifiers().size());
Identifier i = instance.getIdentifiers().get(0); Identifier i = instance.getIdentifiers().get(0);
assertEquals(type,i.getType()); assertEquals(type,i.getType());
assertEquals(value, i.getValue()); assertEquals(value, i.getValue());
assertEquals(title, i.getTitle());
assertEquals(url, i.getUrl()); assertEquals(url, i.getUrl());
} }

View File

@@ -5,7 +5,7 @@
package org.codesecure.dependencycheck.utils; package org.codesecure.dependencycheck.utils;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.IOException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.junit.Test; import org.junit.Test;
@@ -66,7 +66,7 @@ public class ChecksumTest extends TestCase {
boolean exceptionThrown = false; boolean exceptionThrown = false;
try { try {
byte[] result = Checksum.getChecksum(algorithm, file); byte[] result = Checksum.getChecksum(algorithm, file);
} catch (FileNotFoundException ex) { } catch (IOException ex) {
exceptionThrown = true; exceptionThrown = true;
} }
assertTrue(exceptionThrown); assertTrue(exceptionThrown);

Binary file not shown.