From a9cf6b595d4a03d4250684538485ba33aa73b1d7 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Mon, 17 Sep 2012 22:22:11 -0400 Subject: [PATCH] prepared for CVE data by refactoring CPE code --- .../dependencycheck/data/AbstractIndex.java | 196 +++++++++ .../dependencycheck/data/WebDataIndex.java | 45 +++ .../dependencycheck/data/cpe/CPEQuery.java | 84 ++-- .../dependencycheck/data/cpe/Index.java | 47 +-- .../dependencycheck/data/cpe/Indexer.java | 5 + .../data/cpe/xml/Importer.java | 4 +- .../dependencycheck/data/cve/Entry.java | 380 ++++++++++++++++++ .../dependencycheck/data/cve/Fields.java | 53 +++ .../dependencycheck/data/cve/Index.java | 255 ++++++++++++ .../dependencycheck/data/cve/Indexer.java | 100 +++++ .../data/cve/package-info.java | 12 + .../data/cve/xml/CVEHandler.java | 350 ++++++++++++++++ .../data/cve/xml/EntrySaveDelegate.java | 42 ++ .../data/cve/xml/Importer.java | 76 ++++ .../data/cve/xml/package-info.java | 12 + .../dependencycheck/scanner/Dependency.java | 18 +- .../dependencycheck/scanner/JarAnalyzer.java | 60 +-- .../dependencycheck/data/cpe/IndexTest.java | 11 +- .../data/cpe/IndexTestCase.java | 33 -- .../reporting/ReportGeneratorTest.java | 16 +- .../scanner/JarAnalyzerTest.java | 2 +- 21 files changed, 1614 insertions(+), 187 deletions(-) create mode 100644 src/main/java/org/codesecure/dependencycheck/data/AbstractIndex.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/WebDataIndex.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/Entry.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/Fields.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/Index.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/Indexer.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/package-info.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/xml/CVEHandler.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/xml/EntrySaveDelegate.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/xml/Importer.java create mode 100644 src/main/java/org/codesecure/dependencycheck/data/cve/xml/package-info.java delete mode 100644 src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTestCase.java diff --git a/src/main/java/org/codesecure/dependencycheck/data/AbstractIndex.java b/src/main/java/org/codesecure/dependencycheck/data/AbstractIndex.java new file mode 100644 index 000000000..4d9a9c97c --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/AbstractIndex.java @@ -0,0 +1,196 @@ +package org.codesecure.dependencycheck.data; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.index.CorruptIndexException; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.LockObtainFailedException; +import org.apache.lucene.util.Version; + +/** + * The base Index for other index objects. Implements the open and close methods. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public abstract class AbstractIndex { + + /** + * The Lucene directory containing the index. + */ + protected Directory directory = null; + /** + * The IndexWriter for the Lucene index. + */ + protected IndexWriter indexWriter = null; + /** + * The Lucene IndexReader. + */ + private IndexReader indexReader = null; + /** + * The Lucene IndexSearcher. + */ + private IndexSearcher indexSearcher = null; + + /** + * The Lucene Analyzer. + */ + private Analyzer analyzer = null; + + /** + * Indicates whether or not the Lucene Index is open. + */ + private boolean indexOpen = false; + + /** + * Opens the CPE Index. + * @throws IOException is thrown if an IOException occurs opening the index. + */ + public void open() throws IOException { + directory = this.getDirectory(); + analyzer = this.getAnalyzer(); //new StandardAnalyzer(Version.LUCENE_35); + indexOpen = true; + } + + /** + * Closes the CPE Index. + */ + public void close() { + if (indexWriter != null) { + try { + indexWriter.commit(); + } catch (CorruptIndexException ex) { + Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException ex) { + Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex); + } + try { + indexWriter.close(true); + } catch (CorruptIndexException ex) { + Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException ex) { + Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex); + } finally { + indexWriter = null; + } + } + if (indexSearcher != null) { + try { + indexSearcher.close(); + } catch (IOException ex) { + Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex); + } finally { + indexSearcher = null; + } + } + + if (analyzer != null) { + analyzer.close(); + analyzer = null; + } + try { + directory.close(); + } catch (IOException ex) { + Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex); + } finally { + directory = null; + } + indexOpen = false; + } + + /** + * Returns the status of the data source - is the index open. + * @return true or false. + */ + public boolean isOpen() { + return indexOpen; + } + /** + * Opens the Lucene Index Writer. + * + * @throws CorruptIndexException is thrown if the Lucene index is corrupt. + * @throws IOException is thrown if an IOException occurs opening the index. + */ + public void openIndexWriter() throws CorruptIndexException, IOException { + if (!isOpen()) { + open(); + } + IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_35, analyzer); + indexWriter = new IndexWriter(directory, conf); + } + + /** + * Retrieves the IndexWriter for the Lucene Index. + * + * @return an IndexWriter. + * @throws CorruptIndexException is thrown if the Lucene Index is corrupt. + * @throws LockObtainFailedException is thrown if there is an exception obtaining a lock on the Lucene index. + * @throws IOException is thrown if an IOException occurs opening the index. + */ + public IndexWriter getIndexWriter() throws CorruptIndexException, LockObtainFailedException, IOException { + if (indexWriter == null) { + openIndexWriter(); + } + return indexWriter; + } + + public void openIndexReader() throws CorruptIndexException, IOException { + if (!isOpen()) { + open(); + } + indexReader = IndexReader.open(directory, true); + } + + public IndexSearcher getIndexSearcher() throws CorruptIndexException, IOException { + if (indexReader == null) { + openIndexReader(); + } + if (indexSearcher == null) { + indexSearcher = new IndexSearcher(indexReader); + } + return indexSearcher; + } + + public Analyzer getAnalyzer() { + if (analyzer == null) { + analyzer = createAnalyzer(); + } + return analyzer; + } + + /** + * Gets the directory that contains the Lucene Index. + * @return a Lucene Directory. + * @throws IOException is thrown when an IOException occurs. + */ + public abstract Directory getDirectory() throws IOException; + /** + * Creates the Lucene Analyzer used when indexing and searching the index. + * @return a Lucene Analyzer. + */ + public abstract Analyzer createAnalyzer(); + +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/WebDataIndex.java b/src/main/java/org/codesecure/dependencycheck/data/WebDataIndex.java new file mode 100644 index 000000000..91da6d142 --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/WebDataIndex.java @@ -0,0 +1,45 @@ +package org.codesecure.dependencycheck.data; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + + +import java.io.IOException; +import java.net.MalformedURLException; +import javax.xml.parsers.ParserConfigurationException; +import org.xml.sax.SAXException; + +/** + * Defines an Index who's data is retrieved from the Internet. This data can + * be downloaded and the index updated. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public interface WebDataIndex { + + /** + * Determines if an update to the current index is needed, if it is the new + * data is downloaded from the Internet and imported into the current Lucene Index. + * + * @throws MalformedURLException is thrown if the URL for the CPE is malformed. + * @throws ParserConfigurationException is thrown if the parser is misconfigured. + * @throws SAXException is thrown if there is an error parsing the CPE XML. + * @throws IOException is thrown if a temporary file could not be created. + */ + public void updateIndexFromWeb() throws MalformedURLException, ParserConfigurationException, SAXException, IOException; +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEQuery.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEQuery.java index 4acc36e56..dbf4b98d1 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEQuery.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEQuery.java @@ -75,29 +75,17 @@ public class CPEQuery { */ static final int STRING_BUILDER_BUFFER = 20; /** - * The Lucene IndexReader. + * The CPE Index. */ - private IndexReader indexReader = null; + protected Index cpe = null; /** * The Lucene IndexSearcher. */ private IndexSearcher indexSearcher = null; - /** - * The Lucene directory. - */ - private Directory directory = null; - /** - * The Lucene Analyzer. - */ - private Analyzer analyzer = null; /** * The Lucene QueryParser. */ private QueryParser queryParser = null; - /** - * Indicates whether or not the Lucene Index is open. - */ - private boolean indexOpen = false; /** * Opens the data source. @@ -105,41 +93,21 @@ public class CPEQuery { * @throws IOException when the Lucene directory to be querried does not exist or is corrupt. */ public void open() throws IOException { - directory = Index.getDirectory(); - indexReader = IndexReader.open(directory, true); - indexSearcher = new IndexSearcher(indexReader); - analyzer = Index.createAnalyzer(); //use the same analyzer as used when indexing + cpe = new Index(); + cpe.open(); + indexSearcher = cpe.getIndexSearcher(); + Analyzer analyzer = cpe.getAnalyzer(); //TITLE is the default field because it contains venddor, product, and version all in one. queryParser = new QueryParser(Version.LUCENE_35, Fields.TITLE, analyzer); - indexOpen = true; } /** * Closes the data source. */ public void close() { - analyzer.close(); - analyzer = null; queryParser = null; - try { - indexSearcher.close(); - } catch (IOException ex) { - Logger.getLogger(CPEQuery.class.getName()).log(Level.SEVERE, null, ex); - } indexSearcher = null; - try { - indexReader.close(); - } catch (IOException ex) { - Logger.getLogger(CPEQuery.class.getName()).log(Level.SEVERE, null, ex); - } - indexReader = null; - try { - directory.close(); - } catch (IOException ex) { - Logger.getLogger(CPEQuery.class.getName()).log(Level.SEVERE, null, ex); - } - directory = null; - indexOpen = false; + cpe.close(); } /** @@ -147,7 +115,7 @@ public class CPEQuery { * @return true or false. */ public boolean isOpen() { - return indexOpen; + return (cpe == null) ? false : cpe.isOpen(); } /** @@ -157,7 +125,7 @@ public class CPEQuery { @Override protected void finalize() throws Throwable { super.finalize(); - if (indexOpen) { + if (isOpen()) { close(); } } @@ -174,7 +142,7 @@ public class CPEQuery { */ public void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException { Confidence vendorConf = Confidence.HIGH; - Confidence titleConf = Confidence.HIGH; + Confidence productConf = Confidence.HIGH; Confidence versionConf = Confidence.HIGH; String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), vendorConf); @@ -182,10 +150,10 @@ public class CPEQuery { // if ("".equals(vendors)) { // vendors = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; // } - String titles = addEvidenceWithoutDuplicateTerms("", dependency.getTitleEvidence(), titleConf); - ///dependency.getTitleEvidence().toString(titleConf); -// if ("".equals(titles)) { -// titles = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; + 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); //dependency.getVersionEvidence().toString(versionConf); @@ -196,7 +164,7 @@ public class CPEQuery { boolean found = false; int cnt = 0; do { - List entries = searchCPE(vendors, titles, versions, dependency.getTitleEvidence().getWeighting(), + List entries = searchCPE(vendors, products, versions, dependency.getProductEvidence().getWeighting(), dependency.getVendorEvidence().getWeighting()); if (entries.size() > 0) { @@ -220,10 +188,10 @@ public class CPEQuery { } } if (round == 1) { - titleConf = reduceConfidence(titleConf); - if (dependency.getTitleEvidence().contains(titleConf)) { - //titles += " " + dependency.getTitleEvidence().toString(titleConf); - titles = addEvidenceWithoutDuplicateTerms(titles, dependency.getTitleEvidence(), titleConf); + productConf = reduceConfidence(productConf); + if (dependency.getProductEvidence().contains(productConf)) { + //products += " " + dependency.getProductEvidence().toString(productConf); + products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), productConf); } else { cnt += 1; round += 1; @@ -289,7 +257,7 @@ public class CPEQuery { * with the supplied vendor, product, and version. * * @param vendor the text used to search the vendor field. - * @param product the text used to search the title field. + * @param product the text used to search the product field. * @param version the text used to search the version field. * @return a list of possible CPE values. * @throws CorruptIndexException when the Lucene index is corrupt. @@ -309,10 +277,10 @@ public class CPEQuery { * this data is used to add weighting factors to the search.

* * @param vendor the text used to search the vendor field. - * @param product the text used to search the title field. + * @param product the text used to search the product field. * @param version the text used to search the version field. * @param vendorWeightings a list of strings to use to add weighting factors to the vendor field. - * @param productWeightings Adds a list of strings that will be used to add weighting factors to the title search. + * @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search. * @return a list of possible CPE values. * @throws CorruptIndexException when the Lucene index is corrupt. * @throws IOException when the Lucene index is not found. @@ -347,11 +315,11 @@ public class CPEQuery { * data is used to add weighting factors to the search string generated.

* * @param vendor text to search the vendor field. - * @param product text to search the title field. + * @param product text to search the product field. * @param version text to search the version field. * @param vendorWeighting a list of strings to apply to the vendor * to boost the terms weight. - * @param produdctWeightings a list of strings to apply to the product/title + * @param produdctWeightings a list of strings to apply to the product * to boost the terms weight. * @return the Lucene query. */ @@ -473,7 +441,7 @@ public class CPEQuery { /** * Takes a list of entries and a dependency. If the entry has terms that were * used (i.e. this CPE entry wasn't identified because the version matched - * but the product and title did not) then the CPE Entry is returned in a list + * but the product names did not) then the CPE Entry is returned in a list * of possible CPE Entries. * * @param entries a list of CPE entries. @@ -483,7 +451,7 @@ public class CPEQuery { private List verifyEntries(final List entries, final Dependency dependency) { List verified = new ArrayList(); for (Entry e : entries) { - if (dependency.getTitleEvidence().containsUsedString(e.getProduct()) + if (dependency.getProductEvidence().containsUsedString(e.getProduct()) && dependency.getVendorEvidence().containsUsedString(e.getVendor())) { //TODO - determine if this is right? Should we be carrying too much about the // version at this point? Likely need to implement the versionAnalyzer.... diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java index ff592f3d4..795e1c588 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java @@ -44,6 +44,8 @@ import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; +import org.codesecure.dependencycheck.data.AbstractIndex; +import org.codesecure.dependencycheck.data.WebDataIndex; import org.codesecure.dependencycheck.utils.Downloader; import org.codesecure.dependencycheck.utils.Settings; import org.codesecure.dependencycheck.data.cpe.xml.Importer; @@ -55,48 +57,17 @@ import org.xml.sax.SAXException; * * @author Jeremy Long (jeremy.long@gmail.com) */ -public class Index { +public class Index extends AbstractIndex implements WebDataIndex { /** - * Te name of the properties file containing the timestamp of the last update. + * The name of the properties file containing the timestamp of the last update. */ private static final String UPDATE_PROPERTIES_FILE = "lastupdated.prop"; /** * The properties file key for the last updated field. */ private static final String LAST_UPDATED = "lastupdated"; - /** - * The Lucene directory containing the index. - */ - protected Directory directory = null; - /** - * The IndexWriter for the Lucene index. - */ - protected IndexWriter indexWriter = null; - /** - * Opens the CPE Index. - * @throws IOException is thrown if an IOException occurs opening the index. - */ - public void open() throws IOException { - directory = Index.getDirectory(); - - Analyzer analyzer = Index.createAnalyzer(); //new StandardAnalyzer(Version.LUCENE_35); - IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_35, analyzer); - indexWriter = new IndexWriter(directory, conf); - } - - /** - * Closes the CPE Index. - * - * @throws CorruptIndexException is thrown if the index is corrupt. - * @throws IOException is thrown if an IOException occurs closing the index. - */ - public void close() throws CorruptIndexException, IOException { - indexWriter.commit(); - indexWriter.close(true); - directory.close(); - } /** * Returns the directory that holds the CPE Index. @@ -104,12 +75,12 @@ public class Index { * @return the Directory containing the CPE Index. * @throws IOException is thrown if an IOException occurs. */ - public static Directory getDirectory() throws IOException { + public Directory getDirectory() throws IOException { String fileName = Settings.getString(Settings.KEYS.CPE_INDEX); File path = new File(fileName); - Directory directory = FSDirectory.open(path); + Directory dir = FSDirectory.open(path); - return directory; + return dir; } /** @@ -117,11 +88,11 @@ public class Index { * * @return the CPE Analyzer. */ - public static Analyzer createAnalyzer() { + @SuppressWarnings("unchecked") + public Analyzer createAnalyzer() { Map fieldAnalyzers = new HashMap(); fieldAnalyzers.put(Fields.VERSION, new KeywordAnalyzer()); - //new WhitespaceAnalyzer(Version.LUCENE_35)); // PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper( new StandardAnalyzer(Version.LUCENE_35), fieldAnalyzers); diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/Indexer.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/Indexer.java index e26d82c9c..5b0de7064 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/Indexer.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/Indexer.java @@ -25,6 +25,10 @@ import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.FieldInfo.IndexOptions; import org.apache.lucene.index.Term; import org.codesecure.dependencycheck.data.LuceneUtils; +import org.codesecure.dependencycheck.data.cpe.Entry; +import org.codesecure.dependencycheck.data.cpe.Fields; +import org.codesecure.dependencycheck.data.cpe.Index; +import org.codesecure.dependencycheck.data.cpe.xml.EntrySaveDelegate; import org.codesecure.dependencycheck.data.cpe.xml.EntrySaveDelegate; /** @@ -97,4 +101,5 @@ public class Indexer extends Index implements EntrySaveDelegate { return doc; } + } diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Importer.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Importer.java index a90eb7d1d..54dfb0464 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Importer.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Importer.java @@ -18,12 +18,12 @@ package org.codesecure.dependencycheck.data.cpe.xml; * Copyright (c) 2012 Jeremy Long. All Rights Reserved. */ +import org.codesecure.dependencycheck.data.cpe.Indexer; import java.io.File; import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import org.codesecure.dependencycheck.data.cpe.Indexer; import org.xml.sax.SAXException; /** @@ -53,7 +53,7 @@ public class Importer { SAXParser saxParser = factory.newSAXParser(); CPEHandler handler = new CPEHandler(); Indexer indexer = new Indexer(); - indexer.open(); + indexer.openIndexWriter(); handler.registerSaveDelegate(indexer); saxParser.parse(file, handler); indexer.close(); diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/Entry.java b/src/main/java/org/codesecure/dependencycheck/data/cve/Entry.java new file mode 100644 index 000000000..2ec95c33b --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/Entry.java @@ -0,0 +1,380 @@ +package org.codesecure.dependencycheck.data.cve; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.lucene.document.Document; + +/** + * A single CVE entry from the cve.xml files downloaded from + * http://nvd.nist.gov/cpe.cfm. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public class Entry { + + /** + * This parse method does not fully convert a Lucene Document into a CPE Entry; + * it only sets the Entry.Name. + * + * @param doc a Lucene Document. + * @return a CPE Entry. + */ + public static Entry parse(Document doc) { + Entry entry = new Entry(); + try { + entry.setName(doc.get(Fields.NAME)); + entry.setTitle(doc.get(Fields.TITLE)); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(Entry.class.getName()).log(Level.SEVERE, null, ex); + 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; + } + /** + * The title of the CPE + */ + 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 name of the CPE entry. + */ + protected String name; + + /** + * Get the value of name + * + * @return the value of name + */ + public String getName() { + return name; + } + + /** + * Set the value of name and calls parseName to obtain the vendor:product:version:revision + * + * @param name new value of name + * @throws UnsupportedEncodingException should never be thrown... + */ + public void setName(String name) throws UnsupportedEncodingException { + this.name = name; + parseName(); + } + /** + * The status of the CPE Entry. + */ + protected String status; + + /** + * Get the value of status + * + * @return the value of status + */ + public String getStatus() { + return status; + } + + /** + * Set the value of status + * + * @param status new value of status + */ + public void setStatus(String status) { + this.status = status; + } + /** + * The modification date of the CPE Entry. + */ + protected Date modificationDate; + + /** + * Get the value of modificationDate + * + * @return the value of modificationDate + */ + public Date getModificationDate() { + return modificationDate; + } + + /** + * Set the value of modificationDate + * + * @param modificationDate new value of modificationDate + */ + public void setModificationDate(Date modificationDate) { + this.modificationDate = modificationDate; + } + + /** + * Set the value of modificationDate + * + * Expected format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z' + * + * @param modificationDate new value of modificationDate + * @throws ParseException is thrown when a parse exception occurs. + */ + public void setModificationDate(String modificationDate) throws ParseException { + + String formatStr = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + Date tempDate = null; + SimpleDateFormat sdf = new SimpleDateFormat(formatStr); + sdf.setLenient(true); + tempDate = sdf.parse(modificationDate); + + this.modificationDate = tempDate; + } + /** + * The nvdId. + */ + protected String nvdId; + + /** + * Get the value of nvdId + * + * @return the value of nvdId + */ + public String getNvdId() { + return nvdId; + } + + /** + * Set the value of nvdId + * + * @param nvdId new value of nvdId + */ + public void setNvdId(String nvdId) { + this.nvdId = nvdId; + } + /** + * The vendor name. + */ + protected String vendor; + + /** + * Get the value of vendor + * + * @return the value of vendor + */ + public String getVendor() { + return vendor; + } + + /** + * Set the value of vendor + * + * @param vendor new value of vendor + */ + public void setVendor(String vendor) { + this.vendor = vendor; + } + /** + * The product name. + */ + protected String product; + + /** + * Get the value of product + * + * @return the value of product + */ + public String getProduct() { + return product; + } + + /** + * Set the value of product + * + * @param product new value of product + */ + public void setProduct(String product) { + this.product = product; + } + /** + * The product version. + */ + protected String version; + + /** + * Get the value of version + * + * @return the value of version + */ + public String getVersion() { + return version; + } + + /** + * Set the value of version + * + * @param version new value of version + */ + public void setVersion(String version) { + this.version = version; + } + /** + * The product revision. + */ + protected String revision; + + /** + * Get the value of revision + * + * @return the value of revision + */ + public String getRevision() { + return revision; + } + + /** + * Set the value of revision + * + * @param revision new value of revision + */ + public void setRevision(String revision) { + this.revision = revision; + } + /** + * If the CPE Entry is well known (i.e. based off a hash) + */ + protected boolean wellKnown = false; + + /** + * Get the value of wellKnown + * + * @return the value of wellKnown + */ + public boolean isWellKnown() { + return wellKnown; + } + + /** + * Set the value of wellKnown + * + * @param wellKnown new value of wellKnown + */ + public void setWellKnown(boolean wellKnown) { + this.wellKnown = wellKnown; + } + /** + * The search score. + */ + protected float searchScore; + + /** + * Get the value of searchScore + * + * @return the value of searchScore + */ + public float getSearchScore() { + return searchScore; + } + + /** + * Set the value of searchScore + * + * @param searchScore new value of searchScore + */ + public void setSearchScore(float searchScore) { + this.searchScore = searchScore; + } + + /** + *

Parses a name attribute value, from the cpe.xml, into its + * corresponding parts: vendor, product, version, revision.

+ *

Example:

+ *    cpe:/a:apache:struts:1.1:rc2 + * + *

Results in:

+ *
    + *
  • Vendor: apache
  • + *
  • Product: struts
  • + *
  • Version: 1.1
  • + *
  • Revision: rc2
  • + *
+ * + * @throws UnsupportedEncodingException should never be thrown... + */ + private void parseName() throws UnsupportedEncodingException { + if (name != null && name.length() > 7) { + String[] data = name.substring(7).split(":"); + if (data.length >= 1) { + vendor = URLDecoder.decode(data[0], "UTF-8"); + if (data.length >= 2) { + product = URLDecoder.decode(data[1], "UTF-8"); + if (data.length >= 3) { + version = URLDecoder.decode(data[2], "UTF-8"); + if (data.length >= 4) { + revision = URLDecoder.decode(data[3], "UTF-8"); + } + //ignore edition and language fields.. don't really see them used in the a: + } + } + } + } + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Entry other = (Entry) obj; + if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 83 * hash + (this.name != null ? this.name.hashCode() : 0); + return hash; + } +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/Fields.java b/src/main/java/org/codesecure/dependencycheck/data/cve/Fields.java new file mode 100644 index 000000000..eb0082395 --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/Fields.java @@ -0,0 +1,53 @@ +package org.codesecure.dependencycheck.data.cve; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + +/** + * Fields is a collection of field names used within the Lucene index for CPE + * entries. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public abstract class Fields { + /** + * The key for the name field. + */ + public static final String NAME = "name"; + /** + * The key for the vendor field. + */ + 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. + */ + public static final String PRODUCT = "product"; + /** + * The key for the title field. This is a field combining vendor, product, and version. + */ + public static final String TITLE = "title"; + /** + * The key for the nvdId field. + */ + public static final String NVDID = "nvdid"; +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/Index.java b/src/main/java/org/codesecure/dependencycheck/data/cve/Index.java new file mode 100644 index 000000000..9bed884bf --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/Index.java @@ -0,0 +1,255 @@ +package org.codesecure.dependencycheck.data.cve; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.parsers.ParserConfigurationException; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.KeywordAnalyzer; +import org.apache.lucene.analysis.PerFieldAnalyzerWrapper; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.util.Version; +import org.codesecure.dependencycheck.data.AbstractIndex; +import org.codesecure.dependencycheck.data.WebDataIndex; +import org.codesecure.dependencycheck.utils.Downloader; +import org.codesecure.dependencycheck.utils.Settings; +import org.codesecure.dependencycheck.data.cpe.xml.Importer; +import org.codesecure.dependencycheck.utils.DownloadFailedException; +import org.xml.sax.SAXException; + +/** + * The Index class is used to utilize and maintain the CVE Index. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public class Index extends AbstractIndex implements WebDataIndex { + + /** + * The name of the properties file containing the timestamp of the last update. + */ + private static final String UPDATE_PROPERTIES_FILE = "lastupdated.prop"; + /** + * The properties file key for the last updated field. + */ + private static final String LAST_UPDATED = "lastupdated"; + + + /** + * Returns the directory that holds the CPE Index. + * + * @return the Directory containing the CPE Index. + * @throws IOException is thrown if an IOException occurs. + */ + public Directory getDirectory() throws IOException { + String fileName = Settings.getString(Settings.KEYS.CVE_INDEX); + File path = new File(fileName); + Directory dir = FSDirectory.open(path); + + return dir; + } + + /** + * Creates an Analyzer for the CPE Index. + * + * @return the CPE Analyzer. + */ + @SuppressWarnings("unchecked") + public Analyzer createAnalyzer() { + Map fieldAnalyzers = new HashMap(); + + fieldAnalyzers.put(Fields.VERSION, new KeywordAnalyzer()); + + PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper( + new StandardAnalyzer(Version.LUCENE_35), fieldAnalyzers); + + return wrapper; + } + + /** + * Downloads the latest CPE XML file from the web and imports it into + * the current CPE Index. + * + * @throws MalformedURLException is thrown if the URL for the CPE is malformed. + * @throws ParserConfigurationException is thrown if the parser is misconfigured. + * @throws SAXException is thrown if there is an error parsing the CPE XML. + * @throws IOException is thrown if a temporary file could not be created. + */ + public void updateIndexFromWeb() throws MalformedURLException, ParserConfigurationException, SAXException, IOException { + long timeStamp = updateNeeded(); + if (timeStamp > 0) { + URL url = new URL(Settings.getString(Settings.KEYS.CPE_URL)); + File outputPath = null; + try { + outputPath = File.createTempFile("cve", ".xml"); + Downloader.fetchFile(url, outputPath, true); + Importer.importXML(outputPath.toString()); + writeLastUpdatedPropertyFile(timeStamp); + } catch (DownloadFailedException ex) { + Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); + } finally { + try { + if (outputPath != null && outputPath.exists()) { + outputPath.delete(); + } + } finally { + if (outputPath != null && outputPath.exists()) { + outputPath.deleteOnExit(); + } + } + } + } + } + + /** + * Writes a properties file containing the last updated date to the CPE directory. + * @param timeStamp the timestamp to write. + */ + private void writeLastUpdatedPropertyFile(long timeStamp) { + String dir = Settings.getString(Settings.KEYS.CPE_INDEX); + File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE); + Properties prop = new Properties(); + prop.put(Index.LAST_UPDATED, String.valueOf(timeStamp)); + OutputStream os = null; + try { + os = new FileOutputStream(cpeProp); + OutputStreamWriter out = new OutputStreamWriter(os); + prop.store(out, dir); + } catch (FileNotFoundException ex) { + Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException ex) { + Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); + } finally { + try { + os.flush(); + } catch (IOException ex) { + Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); + } + try { + os.close(); + } catch (IOException ex) { + Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + /** + * Determines if the index needs to be updated. This is done by fetching the + * cpe.meta data and checking the lastModifiedDate. If the CPE data needs to + * be refreshed this method will return the timestamp of the new CPE. If an + * update is not required this function will return 0. + * + * @return the timestamp of the currently published CPE.xml if the index needs to be updated, otherwise returns 0.. + * @throws MalformedURLException is thrown if the URL for the CPE Meta data is incorrect. + * @throws DownloadFailedException is thrown if there is an error downloading the cpe.meta data file. + */ + public long updateNeeded() throws MalformedURLException, DownloadFailedException { + long retVal = 0; + long lastUpdated = 0; + long currentlyPublishedDate = retrieveCurrentCPETimestampFromWeb(); + if (currentlyPublishedDate == 0) { + throw new DownloadFailedException("Unable to retrieve valid timestamp from cpe.meta file"); + } + + String dir = Settings.getString(Settings.KEYS.CPE_INDEX); + File f = new File(dir); + if (!f.exists()) { + retVal = currentlyPublishedDate; + } else { + File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE); + if (!cpeProp.exists()) { + retVal = currentlyPublishedDate; + } else { + Properties prop = new Properties(); + InputStream is = null; + try { + is = new FileInputStream(cpeProp); + prop.load(is); + lastUpdated = Long.parseLong(prop.getProperty(Index.LAST_UPDATED)); + } catch (FileNotFoundException ex) { + Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); + } catch (IOException ex) { + Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); + } catch (NumberFormatException ex) { + Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); + } + if (currentlyPublishedDate > lastUpdated) { + retVal = currentlyPublishedDate; + } + } + } + return retVal; + } + + /** + * Retrieves the timestamp from the CPE meta data file. + * @return the timestamp from the currently published cpe.meta. + * @throws MalformedURLException is thrown if the URL for the CPE Meta data is incorrect. + * @throws DownloadFailedException is thrown if there is an error downloading the cpe.meta data file. + */ + private long retrieveCurrentCPETimestampFromWeb() throws MalformedURLException, DownloadFailedException { + long timestamp = 0; + File tmp = null; + InputStream is = null; + try { + tmp = File.createTempFile("cpe", "meta"); + URL url = new URL(Settings.getString(Settings.KEYS.CPE_META_URL)); + Downloader.fetchFile(url, tmp); + Properties prop = new Properties(); + is = new FileInputStream(tmp); + prop.load(is); + timestamp = Long.parseLong(prop.getProperty("lastModifiedDate")); + } catch (IOException ex) { + throw new DownloadFailedException("Unable to create temporary file for CPE Meta File download.", ex); + } finally { + try { + if (is != null) { + try { + is.close(); + } catch (IOException ex) { + Logger.getLogger(Index.class.getName()).log(Level.FINEST, null, ex); + } + } + if (tmp != null && tmp.exists()) { + tmp.delete(); + } + } finally { + if (tmp != null && tmp.exists()) { + tmp.deleteOnExit(); + } + } + } + return timestamp; + } +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/Indexer.java b/src/main/java/org/codesecure/dependencycheck/data/cve/Indexer.java new file mode 100644 index 000000000..a0185df9e --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/Indexer.java @@ -0,0 +1,100 @@ +package org.codesecure.dependencycheck.data.cve; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + +import java.io.IOException; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.CorruptIndexException; +import org.apache.lucene.index.FieldInfo.IndexOptions; +import org.apache.lucene.index.Term; +import org.codesecure.dependencycheck.data.LuceneUtils; +import org.codesecure.dependencycheck.data.cve.xml.EntrySaveDelegate; + +/** + * The Indexer is used to convert a CPE Entry, retrieved from the CPE XML file, + * into a Document that is stored in the Lucene index. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public class Indexer extends Index implements EntrySaveDelegate { + + /** + * Saves a CPE Entry into the Lucene index. + * + * @param entry a CPE entry. + * @throws CorruptIndexException is thrown if the index is corrupt. + * @throws IOException is thrown if an IOException occurs. + */ + public void saveEntry(Entry entry) throws CorruptIndexException, IOException { + Document doc = convertEntryToDoc(entry); + Term term = new Term(Fields.NVDID, LuceneUtils.escapeLuceneQuery(entry.getNvdId())); + indexWriter.updateDocument(term, doc); + } + + /** + * Converst a CPE entry into a Lucene Document. + * + * @param entry a CPE Entry. + * @return a Lucene Document containing a CPE Entry. + */ + protected Document convertEntryToDoc(Entry entry) { + Document doc = new Document(); + + Field name = new Field(Fields.NAME, entry.getName(), Field.Store.YES, Field.Index.ANALYZED); + name.setIndexOptions(IndexOptions.DOCS_ONLY); + doc.add(name); + + Field nvdId = new Field(Fields.NVDID, entry.getNvdId(), Field.Store.NO, Field.Index.ANALYZED); + 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); + doc.add(vendor); + + Field product = new Field(Fields.PRODUCT, entry.getProduct(), Field.Store.NO, Field.Index.ANALYZED); + product.setIndexOptions(IndexOptions.DOCS_ONLY); + product.setBoost(5.0F); + doc.add(product); + + Field title = new Field(Fields.TITLE, entry.getTitle(), Field.Store.NO, Field.Index.ANALYZED); + title.setIndexOptions(IndexOptions.DOCS_ONLY); + //title.setBoost(1.0F); + doc.add(title); + + //TODO revision should likely be its own field + if (entry.getVersion() != null) { + Field version = null; + if (entry.getRevision() != null) { + version = new Field(Fields.VERSION, entry.getVersion() + " " + + entry.getRevision(), Field.Store.NO, Field.Index.ANALYZED); + } else { + version = new Field(Fields.VERSION, entry.getVersion(), + Field.Store.NO, Field.Index.ANALYZED); + } + version.setIndexOptions(IndexOptions.DOCS_ONLY); + version.setBoost(0.8F); + doc.add(version); + } + + return doc; + } +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/package-info.java b/src/main/java/org/codesecure/dependencycheck/data/cve/package-info.java new file mode 100644 index 000000000..7748a0137 --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/package-info.java @@ -0,0 +1,12 @@ +/** + * + * + * org.codesecure.dependencycheck.data.cve.xml + * + * + * Contains classes used to parse the CVE XML files. + * + * +*/ + +package org.codesecure.dependencycheck.data.cve; diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/xml/CVEHandler.java b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/CVEHandler.java new file mode 100644 index 000000000..d1fa366c0 --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/CVEHandler.java @@ -0,0 +1,350 @@ +package org.codesecure.dependencycheck.data.cve.xml; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + +import org.codesecure.dependencycheck.data.cve.Entry; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.text.ParseException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.lucene.index.CorruptIndexException; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A SAX Handler that will parse the CVE XML Listing. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public class CVEHandler extends DefaultHandler { + + private static final String CURRENT_SCHEMA_VERSION = "2.2"; + EntrySaveDelegate saveDelegate = null; + Entry entry = null; + boolean languageIsUS = false; + StringBuilder nodeText = null; + boolean skip = false; + Element current = new Element(); + + /** + * Register a EntrySaveDelegate object. When the last node of an entry is + * reached if a save delegate has been regsitered the save method will be invoked. + * + * @param delegate the delegate used to save an entry + */ + public void registerSaveDelegate(EntrySaveDelegate delegate) { + this.saveDelegate = delegate; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + nodeText = null; + current.setNode(qName); + if (current.isCpeItemNode()) { + entry = new Entry(); + String temp = attributes.getValue("deprecated"); + String name = attributes.getValue("name"); + skip = (temp != null && temp.equals("true")); + try { + if (!skip && name.startsWith("cpe:/a:")) { + entry.setName(name); + } else { + skip = true; + } + } catch (UnsupportedEncodingException ex) { + throw new SAXException(ex); + } + } else if (current.isTitleNode()) { + nodeText = new StringBuilder(100); + if ("en-US".equalsIgnoreCase(attributes.getValue("xml:lang"))) { + languageIsUS = true; + } else { + languageIsUS = false; + } + } else if (current.isMetaNode()) { + try { + entry.setModificationDate(attributes.getValue("modification-date")); + } catch (ParseException ex) { + Logger.getLogger(CVEHandler.class.getName()).log(Level.SEVERE, null, ex); + } + entry.setStatus(attributes.getValue("status")); + entry.setNvdId(attributes.getValue("nvd-id")); + } else if (current.isSchemaVersionNode()) { + nodeText = new StringBuilder(3); + } else if (current.isTimestampNode()) { + nodeText = new StringBuilder(24); + } +// } else if (current.isCpeListNode()) { +// //do nothing +// } else if (current.isNotesNode()) { +// //do nothing +// } else if (current.isNoteNode()) { +// //do nothing +// } else if (current.isCheckNode()) { +// //do nothing +// } else if (current.isGeneratorNode()) { +// //do nothing +// } else if (current.isProductNameNode()) { +// //do nothing +// } else if (current.isProductVersionNode()) { +// //do nothing + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + //nodeText += new String(ch, start, length); + if (nodeText != null) { + nodeText.append(ch, start, length); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + current.setNode(qName); + if (current.isCpeItemNode()) { + if (saveDelegate != null && !skip) { + try { + saveDelegate.saveEntry(entry); + } catch (CorruptIndexException ex) { + Logger.getLogger(CVEHandler.class.getName()).log(Level.SEVERE, null, ex); + throw new SAXException(ex); + } catch (IOException ex) { + Logger.getLogger(CVEHandler.class.getName()).log(Level.SEVERE, null, ex); + throw new SAXException(ex); + } + entry = null; + } + } else if (current.isTitleNode()) { + if (languageIsUS) { + entry.setTitle(nodeText.toString()); + } + } else if (current.isSchemaVersionNode() && !CURRENT_SCHEMA_VERSION.equals(nodeText.toString())) { + throw new SAXException("ERROR: Invalid Schema Version, expected: " + + CURRENT_SCHEMA_VERSION + ", file is: " + nodeText); + } +// } else if (current.isCpeListNode()) { +// //do nothing +// } else if (current.isMetaNode()) { +// //do nothing +// } else if (current.isNotesNode()) { +// //do nothing +// } else if (current.isNoteNode()) { +// //do nothing +// } else if (current.isCheckNode()) { +// //do nothing +// } else if (current.isGeneratorNode()) { +// //do nothing +// } else if (current.isProductNameNode()) { +// //do nothing +// } else if (current.isProductVersionNode()) { +// //do nothing +// else if (current.isTimestampNode()) { +// //do nothing +// } else { +// throw new SAXException("ERROR STATE: Unexpected qName '" + qName + "'"); +// } + } + + // + /** + * A simple class to maintain information about the current element while parsing + * the CPE XML. + */ + protected class Element { + + /** + * A node type in the CPE Schema 2.2 + */ + public static final String CPE_LIST = "cpe-list"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String CPE_ITEM = "cpe-item"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String TITLE = "title"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String NOTES = "notes"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String NOTE = "note"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String CHECK = "check"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String META = "meta:item-metadata"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String GENERATOR = "generator"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String PRODUCT_NAME = "product_name"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String PRODUCT_VERSION = "product_version"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String SCHEMA_VERSION = "schema_version"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String TIMESTAMP = "timestamp"; + private String node = null; + + /** + * Gets the value of node + * + * @return the value of node + */ + public String getNode() { + return this.node; + } + + /** + * Sets the value of node + * + * @param node new value of node + */ + public void setNode(String node) { + this.node = node; + } + + /** + * Checks if the handler is at the CPE_LIST node + * + * @return true or false + */ + public boolean isCpeListNode() { + return CPE_LIST.equals(node); + } + + /** + * Checks if the handler is at the CPE_ITEM node + * + * @return true or false + */ + public boolean isCpeItemNode() { + return CPE_ITEM.equals(node); + } + + /** + * Checks if the handler is at the TITLE node + * + * @return true or false + */ + public boolean isTitleNode() { + return TITLE.equals(node); + } + + /** + * Checks if the handler is at the NOTES node + * + * @return true or false + */ + public boolean isNotesNode() { + return NOTES.equals(node); + } + + /** + * Checks if the handler is at the NOTE node + * + * @return true or false + */ + public boolean isNoteNode() { + return NOTE.equals(node); + } + + /** + * Checks if the handler is at the CHECK node + * + * @return true or false + */ + public boolean isCheckNode() { + return CHECK.equals(node); + } + + /** + * Checks if the handler is at the META node + * + * @return true or false + */ + public boolean isMetaNode() { + return META.equals(node); + } + + /** + * Checks if the handler is at the GENERATOR node + * + * @return true or false + */ + public boolean isGeneratorNode() { + return GENERATOR.equals(node); + } + + /** + * Checks if the handler is at the PRODUCT_NAME node + * + * @return true or false + */ + public boolean isProductNameNode() { + return PRODUCT_NAME.equals(node); + } + + /** + * Checks if the handler is at the PRODUCT_VERSION node + * + * @return true or false + */ + public boolean isProductVersionNode() { + return PRODUCT_VERSION.equals(node); + } + + /** + * Checks if the handler is at the SCHEMA_VERSION node + * + * @return true or false + */ + public boolean isSchemaVersionNode() { + return SCHEMA_VERSION.equals(node); + } + + /** + * Checks if the handler is at the TIMESTAMP node + * + * @return true or false + */ + public boolean isTimestampNode() { + return TIMESTAMP.equals(node); + } + } + // +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/xml/EntrySaveDelegate.java b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/EntrySaveDelegate.java new file mode 100644 index 000000000..c5a263e88 --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/EntrySaveDelegate.java @@ -0,0 +1,42 @@ +package org.codesecure.dependencycheck.data.cve.xml; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + +import org.codesecure.dependencycheck.data.cve.Entry; +import java.io.IOException; +import org.apache.lucene.index.CorruptIndexException; + +/** + * + * An interface used to define the save function used when parsing the CVE XML + * file. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public interface EntrySaveDelegate { + + /** + * Saves a CVE Entry into the Lucene index. + * + * @param entry a CVE entry. + * @throws CorruptIndexException is thrown if the index is corrupt. + * @throws IOException is thrown if an IOException occurs. + */ + void saveEntry(Entry entry) throws CorruptIndexException, IOException; +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/xml/Importer.java b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/Importer.java new file mode 100644 index 000000000..c76fdd06e --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/Importer.java @@ -0,0 +1,76 @@ +package org.codesecure.dependencycheck.data.cve.xml; +/* + * This file is part of DependencyCheck. + * + * DependencyCheck is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DependencyCheck is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DependencyCheck. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ + +import org.codesecure.dependencycheck.data.cve.Indexer; +import java.io.File; +import java.io.IOException; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.xml.sax.SAXException; + +/** + * Imports a CVE XML file into the Lucene CVE Index. + * + * @author Jeremy Long (jeremy.long@gmail.com) + */ +public class Importer { + + /** + * Private constructor for utility class. + */ + private Importer() { + + } + + /** + * Imports the CPE XML File into the Lucene Index. + * + * @param file containing the path to the CPE XML file. + * @throws ParserConfigurationException is thrown if the parser is misconfigured. + * @throws SAXException is thrown when there is a SAXException. + * @throws IOException is thrown when there is an IOException. + */ + public static void importXML(File file) throws ParserConfigurationException, SAXException, IOException { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser = factory.newSAXParser(); + CVEHandler handler = new CVEHandler(); + Indexer indexer = new Indexer(); + indexer.open(); + handler.registerSaveDelegate(indexer); + saxParser.parse(file, handler); + indexer.close(); + } + /** + * Imports the CPE XML File into the Lucene Index. + * + * @param path the path to the CPE XML file. + * @throws ParserConfigurationException is thrown if the parser is misconfigured. + * @throws SAXException is thrown when there is a SAXException. + * @throws IOException is thrown when there is an IOException. + */ + public static void importXML(String path) throws ParserConfigurationException, SAXException, IOException { + File f = new File(path); + if (!f.exists()) { + f.mkdirs(); + } + Importer.importXML(f); + } +} diff --git a/src/main/java/org/codesecure/dependencycheck/data/cve/xml/package-info.java b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/package-info.java new file mode 100644 index 000000000..9256378f9 --- /dev/null +++ b/src/main/java/org/codesecure/dependencycheck/data/cve/xml/package-info.java @@ -0,0 +1,12 @@ +/** + * + * + * org.codesecure.dependencycheck.data.cve.xml + * + * + * Contains classes used to parse the CVE XML file. + * + * +*/ + +package org.codesecure.dependencycheck.data.cve.xml; diff --git a/src/main/java/org/codesecure/dependencycheck/scanner/Dependency.java b/src/main/java/org/codesecure/dependencycheck/scanner/Dependency.java index 0045a6ec5..3c7a19e1d 100644 --- a/src/main/java/org/codesecure/dependencycheck/scanner/Dependency.java +++ b/src/main/java/org/codesecure/dependencycheck/scanner/Dependency.java @@ -57,9 +57,9 @@ public class Dependency { */ protected EvidenceCollection vendorEvidence = null; /** - * A collection of title evidence. + * A collection of product evidence. */ - protected EvidenceCollection titleEvidence = null; + protected EvidenceCollection productEvidence = null; /** * A collection of version evidence. */ @@ -70,7 +70,7 @@ public class Dependency { */ public Dependency() { vendorEvidence = new EvidenceCollection(); - titleEvidence = new EvidenceCollection(); + productEvidence = new EvidenceCollection(); versionEvidence = new EvidenceCollection(); cpes = new ArrayList(); } @@ -181,7 +181,7 @@ public class Dependency { * @return an EvidenceCollection. */ public EvidenceCollection getEvidence() { - return EvidenceCollection.mergeUsed(this.titleEvidence, this.vendorEvidence, this.versionEvidence); + return EvidenceCollection.mergeUsed(this.productEvidence, this.vendorEvidence, this.versionEvidence); } @@ -191,7 +191,7 @@ public class Dependency { * @return an EvidenceCollection. */ public EvidenceCollection getEvidenceUsed() { - EvidenceCollection ec = EvidenceCollection.mergeUsed(this.titleEvidence, this.vendorEvidence, this.versionEvidence); + EvidenceCollection ec = EvidenceCollection.mergeUsed(this.productEvidence, this.vendorEvidence, this.versionEvidence); return ec; } @@ -205,12 +205,12 @@ public class Dependency { } /** - * Gets the Title Evidence. + * Gets the Product Evidence. * * @return an EvidenceCollection. */ - public EvidenceCollection getTitleEvidence() { - return this.titleEvidence; + public EvidenceCollection getProductEvidence() { + return this.productEvidence; } /** @@ -244,7 +244,7 @@ public class Dependency { if (vendorEvidence.containsUsedString(str)) { return true; } - if (titleEvidence.containsUsedString(str)) { + if (productEvidence.containsUsedString(str)) { return true; } if (versionEvidence.containsUsedString(fnd)) { diff --git a/src/main/java/org/codesecure/dependencycheck/scanner/JarAnalyzer.java b/src/main/java/org/codesecure/dependencycheck/scanner/JarAnalyzer.java index 6c99c28f9..f9138eb99 100644 --- a/src/main/java/org/codesecure/dependencycheck/scanner/JarAnalyzer.java +++ b/src/main/java/org/codesecure/dependencycheck/scanner/JarAnalyzer.java @@ -179,7 +179,7 @@ public class JarAnalyzer extends AbstractAnalyzer { } Pattern rx = Pattern.compile("\\s\\s+"); fileNameEvidence = rx.matcher(sb.toString()).replaceAll(" "); - dependency.getTitleEvidence().addEvidence("jar", "file name", + dependency.getProductEvidence().addEvidence("jar", "file name", fileNameEvidence, Evidence.Confidence.HIGH); dependency.getVendorEvidence().addEvidence("jar", "file name", fileNameEvidence, Evidence.Confidence.HIGH); @@ -276,14 +276,14 @@ public class JarAnalyzer extends AbstractAnalyzer { return; } EvidenceCollection vendor = dependency.getVendorEvidence(); - EvidenceCollection title = dependency.getTitleEvidence(); + EvidenceCollection product = dependency.getProductEvidence(); for (String s : level0.keySet()) { if (!"org".equals(s) && !"com".equals(s)) { vendor.addWeighting(s); - title.addWeighting(s); + product.addWeighting(s); vendor.addEvidence("jar", "package", s, Evidence.Confidence.LOW); - title.addEvidence("jar", "package", s, Evidence.Confidence.LOW); + product.addEvidence("jar", "package", s, Evidence.Confidence.LOW); } } for (String s : level1.keySet()) { @@ -296,9 +296,9 @@ public class JarAnalyzer extends AbstractAnalyzer { vendor.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); } else { vendor.addWeighting(parts[0]); - title.addWeighting(parts[1]); + product.addWeighting(parts[1]); vendor.addEvidence("jar", "package", parts[0], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); } } } @@ -309,18 +309,18 @@ public class JarAnalyzer extends AbstractAnalyzer { String[] parts = s.split("/"); if ("org".equals(parts[0]) || "com".equals(parts[0])) { vendor.addWeighting(parts[1]); - title.addWeighting(parts[2]); + product.addWeighting(parts[2]); vendor.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); } else { vendor.addWeighting(parts[0]); vendor.addWeighting(parts[1]); - title.addWeighting(parts[1]); - title.addWeighting(parts[2]); + product.addWeighting(parts[1]); + product.addWeighting(parts[2]); vendor.addEvidence("jar", "package", parts[0], Evidence.Confidence.LOW); vendor.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); } } } @@ -332,26 +332,26 @@ public class JarAnalyzer extends AbstractAnalyzer { if ("org".equals(parts[0]) || "com".equals(parts[0])) { vendor.addWeighting(parts[1]); vendor.addWeighting(parts[2]); - title.addWeighting(parts[2]); - title.addWeighting(parts[3]); + product.addWeighting(parts[2]); + product.addWeighting(parts[3]); vendor.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); vendor.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[3], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[3], Evidence.Confidence.LOW); } else { vendor.addWeighting(parts[0]); vendor.addWeighting(parts[1]); vendor.addWeighting(parts[2]); - title.addWeighting(parts[1]); - title.addWeighting(parts[2]); - title.addWeighting(parts[3]); + product.addWeighting(parts[1]); + product.addWeighting(parts[2]); + product.addWeighting(parts[3]); vendor.addEvidence("jar", "package", parts[0], Evidence.Confidence.LOW); vendor.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); vendor.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); - title.addEvidence("jar", "package", parts[3], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[1], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[2], Evidence.Confidence.LOW); + product.addEvidence("jar", "package", parts[3], Evidence.Confidence.LOW); } } } @@ -380,7 +380,7 @@ public class JarAnalyzer extends AbstractAnalyzer { Attributes atts = manifest.getMainAttributes(); EvidenceCollection vendorEvidence = dependency.getVendorEvidence(); - EvidenceCollection titleEvidence = dependency.getTitleEvidence(); + EvidenceCollection productEvidence = dependency.getProductEvidence(); EvidenceCollection versionEvidence = dependency.getVersionEvidence(); String source = "Manifest"; @@ -389,7 +389,7 @@ public class JarAnalyzer extends AbstractAnalyzer { String key = entry.getKey().toString(); String value = atts.getValue(key); if (key.equals(Attributes.Name.IMPLEMENTATION_TITLE.toString())) { - titleEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH); + productEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH); } else if (key.equals(Attributes.Name.IMPLEMENTATION_VERSION.toString())) { versionEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH); } else if (key.equals(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) { @@ -397,15 +397,15 @@ public class JarAnalyzer extends AbstractAnalyzer { } else if (key.equals(Attributes.Name.IMPLEMENTATION_VENDOR_ID.toString())) { vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else if (key.equals(BUNDLE_DESCRIPTION)) { - titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); + productEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else if (key.equals(BUNDLE_NAME)) { - titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); + productEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else if (key.equals(BUNDLE_VENDOR)) { vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH); } else if (key.equals(BUNDLE_VERSION)) { versionEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH); } else if (key.equals(Attributes.Name.MAIN_CLASS.toString())) { - titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); + productEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else { key = key.toLowerCase(); @@ -414,14 +414,14 @@ public class JarAnalyzer extends AbstractAnalyzer { if (key.contains("version")) { versionEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else if (key.contains("title")) { - titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); + productEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else if (key.contains("vendor")) { vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else if (key.contains("name")) { - titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); + productEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM); } else { - titleEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW); + productEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW); if (value.matches(".*\\d.*")) { versionEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW); diff --git a/src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTest.java b/src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTest.java index c88d05c66..00dba6a5e 100644 --- a/src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTest.java +++ b/src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTest.java @@ -56,13 +56,7 @@ public class IndexTest extends BaseIndexTestCase { } catch (IOException ex) { fail(ex.getMessage()); } - try { - instance.close(); - } catch (CorruptIndexException ex) { - fail(ex.getMessage()); - } catch (IOException ex) { - fail(ex.getMessage()); - } + instance.close(); } /** @@ -71,7 +65,8 @@ public class IndexTest extends BaseIndexTestCase { @Test public void testGetDirectory() throws Exception { System.out.println("getDirectory"); - Directory result = Index.getDirectory(); + Index index = new Index(); + Directory result = index.getDirectory(); String exp = "\\target\\store\\cpe"; // TODO review the generated test code and remove the default call to fail. assertTrue(result.toString().contains(exp)); diff --git a/src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTestCase.java b/src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTestCase.java deleted file mode 100644 index c35d7097a..000000000 --- a/src/test/java/org/codesecure/dependencycheck/data/cpe/IndexTestCase.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.codesecure.dependencycheck.data.cpe; - -import org.codesecure.dependencycheck.data.BaseIndexTestCase; - -/** - * - * @author jeremy - */ -public class IndexTestCase extends BaseIndexTestCase { - - public IndexTestCase(String testName) { - super(testName); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - public void testIgnoreThisClass() throws Exception { - assertTrue(true); - } - -} diff --git a/src/test/java/org/codesecure/dependencycheck/reporting/ReportGeneratorTest.java b/src/test/java/org/codesecure/dependencycheck/reporting/ReportGeneratorTest.java index 55fbae29b..35a070995 100644 --- a/src/test/java/org/codesecure/dependencycheck/reporting/ReportGeneratorTest.java +++ b/src/test/java/org/codesecure/dependencycheck/reporting/ReportGeneratorTest.java @@ -68,10 +68,10 @@ public class ReportGeneratorTest extends BaseIndexTestCase { d.addCPEentry("cpe://a:/some:cpe:1.0"); List dependencies = new ArrayList(); - d.getTitleEvidence().addEvidence("jar","filename","test", Confidence.HIGH); - d.getTitleEvidence().addEvidence("manifest","vendor","test", Confidence.HIGH); + d.getProductEvidence().addEvidence("jar","filename","test", Confidence.HIGH); + d.getProductEvidence().addEvidence("manifest","vendor","test", Confidence.HIGH); - for (Evidence e : d.getTitleEvidence().iterator(Confidence.HIGH)) { + for (Evidence e : d.getProductEvidence().iterator(Confidence.HIGH)) { String t = e.getValue(); } dependencies.add(d); @@ -82,10 +82,10 @@ public class ReportGeneratorTest extends BaseIndexTestCase { d2.addCPEentry("cpe://a:/another:cpe:1.0"); d2.addCPEentry("cpe://a:/another:cpe:1.1"); d2.addCPEentry("cpe://a:/another:cpe:1.2"); - d2.getTitleEvidence().addEvidence("jar","filename","another.jar", Confidence.HIGH); - d2.getTitleEvidence().addEvidence("manifest","vendor","Company A", Confidence.MEDIUM); + d2.getProductEvidence().addEvidence("jar","filename","another.jar", Confidence.HIGH); + d2.getProductEvidence().addEvidence("manifest","vendor","Company A", Confidence.MEDIUM); - for (Evidence e : d2.getTitleEvidence().iterator(Confidence.HIGH)) { + for (Evidence e : d2.getProductEvidence().iterator(Confidence.HIGH)) { String t = e.getValue(); } @@ -94,9 +94,9 @@ public class ReportGeneratorTest extends BaseIndexTestCase { Dependency d3 = new Dependency(); d3.setFileName("Third.jar"); d3.setFilePath("lib/Third.jar"); - d3.getTitleEvidence().addEvidence("jar","filename","third.jar", Confidence.HIGH); + d3.getProductEvidence().addEvidence("jar","filename","third.jar", Confidence.HIGH); - for (Evidence e : d3.getTitleEvidence().iterator(Confidence.HIGH)) { + for (Evidence e : d3.getProductEvidence().iterator(Confidence.HIGH)) { String t = e.getValue(); } diff --git a/src/test/java/org/codesecure/dependencycheck/scanner/JarAnalyzerTest.java b/src/test/java/org/codesecure/dependencycheck/scanner/JarAnalyzerTest.java index a0f8864dc..0f3a0abdb 100644 --- a/src/test/java/org/codesecure/dependencycheck/scanner/JarAnalyzerTest.java +++ b/src/test/java/org/codesecure/dependencycheck/scanner/JarAnalyzerTest.java @@ -59,7 +59,7 @@ public class JarAnalyzerTest { result = instance.insepct(file); boolean found = false; - for (Evidence e : result.getTitleEvidence()) { + for (Evidence e : result.getProductEvidence()) { if (e.getName().equals("package-title") && e.getValue().equals("org.mortbay.http")) { found = true; break;