Update NVD CVE timestamp checking

Former-commit-id: 5764a3ce90b6963d4476f581b712bc9df0c1a7cb
This commit is contained in:
Jeremy Long
2012-12-30 08:53:14 -05:00
parent 40e4f9cd90
commit d4f097cfbc
8 changed files with 298 additions and 519 deletions

View File

@@ -1,351 +0,0 @@
package org.codesecure.dependencycheck.data.cpe.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 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.codesecure.dependencycheck.data.cpe.Entry;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A SAX Handler that will parse the CPE XML Listing.
*
* @author Jeremy Long (jeremy.long@gmail.com)
*/
public class CPEHandler 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 registered 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.parseName(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(CPEHandler.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(CPEHandler.class.getName()).log(Level.SEVERE, null, ex);
throw new SAXException(ex);
} catch (IOException ex) {
Logger.getLogger(CPEHandler.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 + "'");
// }
}
// <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
/**
* 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);
}
}
// </editor-fold>
}

View File

@@ -24,28 +24,24 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import org.codesecure.dependencycheck.data.CachedWebDataSource;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.lucene.index.CorruptIndexException;
import org.codesecure.dependencycheck.data.nvdcve.Index;
import org.codesecure.dependencycheck.data.UpdateException;
import org.codesecure.dependencycheck.utils.DownloadFailedException;
import org.codesecure.dependencycheck.utils.Downloader;
import org.codesecure.dependencycheck.utils.FileUtils;
import org.codesecure.dependencycheck.utils.InvalidSettingException;
import org.codesecure.dependencycheck.utils.Settings;
/**
@@ -283,7 +279,12 @@ public class IndexUpdater extends Index implements CachedWebDataSource {
} catch (InvalidDataException ex) {
Logger.getLogger(IndexUpdater.class.getName()).log(Level.SEVERE, null, ex);
throw new DownloadFailedException("Unable to retrieve valid timestamp from nvd cve downloads page", ex);
} catch (InvalidSettingException ex) {
Logger.getLogger(IndexUpdater.class.getName()).log(Level.SEVERE, null, ex);
throw new DownloadFailedException("Invalid settings", ex);
}
if (currentlyPublished == null) {
throw new DownloadFailedException("Unable to retrieve valid timestamp from nvd cve downloads page");
}
@@ -401,139 +402,176 @@ public class IndexUpdater extends Index implements CachedWebDataSource {
* Retrieves the timestamps from the NVD CVE meta data file.
*
* @return the timestamp from the currently published nvdcve downloads page
* @throws MalformedURLException is thrown if the URL for the NVD CCE Meta
* @throws MalformedURLException thrown if the URL for the NVD CCE Meta
* data is incorrect.
* @throws DownloadFailedException is thrown if there is an error
* @throws DownloadFailedException thrown if there is an error
* downloading the nvd cve meta data file
* @throws InvalidDataException is thrown if there is an exception parsing
* @throws InvalidDataException thrown if there is an exception parsing
* the timestamps
* @throws InvalidSettingException thrown if the settings are invalid
*/
protected Map<String, NvdCveUrl> retrieveCurrentTimestampsFromWeb() throws MalformedURLException, DownloadFailedException, InvalidDataException {
protected Map<String, NvdCveUrl> retrieveCurrentTimestampsFromWeb()
throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
Map<String, NvdCveUrl> map = new HashMap<String, NvdCveUrl>();
String retrieveUrl = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
File tmp = null;
try {
tmp = File.createTempFile("cve", "meta");
URL url = new URL(Settings.getString(Settings.KEYS.CVE_META_URL));
Downloader.fetchFile(url, tmp);
String html = readFile(tmp);
NvdCveUrl item = new NvdCveUrl();
item.setNeedsUpdate(false); //the others default to true, to make life easier later this should default to false.
item.id = "modified";
item.timestamp = Downloader.getLastModified(new URL(retrieveUrl));
map.put("modified", item);
String retrieveUrl = Settings.getString(Settings.KEYS.CVE_MODIFIED_URL);
NvdCveUrl cve = createNvdCveUrl("modified", retrieveUrl, html);
cve.setNeedsUpdate(false); //the others default to true, to make life easier later this should default to false.
map.put("modified", cve);
int max = Settings.getInt(Settings.KEYS.CVE_URL_COUNT);
for (int i = 1; i <= max; i++) {
retrieveUrl = Settings.getString(Settings.KEYS.CVE_BASE_URL + i);
String key = Integer.toString(i);
cve = createNvdCveUrl(key, retrieveUrl, html);
map.put(key, cve);
}
} catch (IOException ex) {
throw new DownloadFailedException("Unable to create temporary file for NVD CVE Meta File download.", ex);
} finally {
try {
if (tmp != null && tmp.exists()) {
tmp.delete();
}
} finally {
if (tmp != null && tmp.exists()) {
tmp.deleteOnExit();
}
}
int max = Settings.getInt(Settings.KEYS.CVE_URL_COUNT);
for (int i = 1; i <= max; i++) {
retrieveUrl = Settings.getString(Settings.KEYS.CVE_BASE_URL + Settings.KEYS.CVE_SCHEMA_2_0 + i);
item = new NvdCveUrl();
item.id = Integer.toString(i);
item.url = retrieveUrl;
item.timestamp = Downloader.getLastModified(new URL(retrieveUrl));
map.put(item.id, item);
}
return map;
}
/**
* Creates a new NvdCveUrl object from the provide id, url, and text/html
* from the NVD CVE downloads page.
*
* @param id the name of this NVD CVE Url
* @param retrieveUrl the URL to download the file from
* @param text a bit of HTML from the NVD CVE downloads page that contains
* the URL and the last updated timestamp.
* @return a shiny new NvdCveUrl object.
* @throws InvalidDataException is thrown if the timestamp could not be
* extracted from the provided text.
*/
private NvdCveUrl createNvdCveUrl(String id, String retrieveUrl, String text) throws InvalidDataException {
Pattern pattern = Pattern.compile(Pattern.quote(retrieveUrl) + ".+?\\<br");
Matcher m = pattern.matcher(text);
NvdCveUrl item = new NvdCveUrl();
item.id = id;
item.url = retrieveUrl;
if (m.find()) {
String line = m.group();
int pos = line.indexOf("Updated:");
if (pos > 0) {
pos += 9;
try {
String timestampstr = line.substring(pos, line.length() - 3).replace("at ", "");
long timestamp = getEpochTimeFromDateTime(timestampstr);
item.setTimestamp(timestamp);
} catch (NumberFormatException ex) {
throw new InvalidDataException("NVD CVE Meta file does not contain a valid timestamp for '" + retrieveUrl + "'.", ex);
}
} else {
throw new InvalidDataException("NVD CVE Meta file does not contain the updated timestamp for '" + retrieveUrl + "'.");
}
} else {
throw new InvalidDataException("NVD CVE Meta file does not contain the url for '" + retrieveUrl + "'.");
}
return item;
}
/**
* Parses a timestamp in the format of "MM/dd/yy hh:mm" into a calendar
* object and returns the epoch time. Note, this removes the millisecond
* portion of the epoch time so all numbers returned should end in 000.
*
* @param timestamp a string in the format of "MM/dd/yy hh:mm"
* @return a Calendar object.
* @throws NumberFormatException if the timestamp was parsed incorrectly.
*/
private long getEpochTimeFromDateTime(String timestamp) throws NumberFormatException {
Calendar c = new GregorianCalendar();
int month = Integer.parseInt(timestamp.substring(0, 2));
int date = Integer.parseInt(timestamp.substring(3, 5));
int year = 2000 + Integer.parseInt(timestamp.substring(6, 8));
int hourOfDay = Integer.parseInt(timestamp.substring(9, 11));
int minute = Integer.parseInt(timestamp.substring(12, 14));
c.set(year, month, date, hourOfDay, minute, 0);
long t = c.getTimeInMillis();
t = (t / 1000) * 1000;
return t;
}
/**
* Reads a file into a string.
*
* @param file the file to be read.
* @return the contents of the file.
* @throws IOException is thrown if an IOExcpetion occurs.
*/
private String readFile(File file) throws IOException {
InputStreamReader stream = new InputStreamReader(new FileInputStream(file), "UTF-8");
StringBuilder str = new StringBuilder((int) file.length());
try {
char[] buf = new char[8096];
int read = stream.read(buf, 0, 8096);
while (read > 0) {
str.append(buf, 0, read);
read = stream.read(buf, 0, 8096);
}
} finally {
stream.close();
}
return str.toString();
}
//<editor-fold defaultstate="collapsed" desc="old dead code">
// /**
// * Retrieves the timestamps from the NVD CVE meta data file.
// *
// * @return the timestamp from the currently published nvdcve downloads page
// * @throws MalformedURLException is thrown if the URL for the NVD CCE Meta
// * data is incorrect.
// * @throws DownloadFailedException is thrown if there is an error
// * downloading the nvd cve meta data file
// * @throws InvalidDataException is thrown if there is an exception parsing
// * the timestamps
// */
// protected Map<String, NvdCveUrl> retrieveCurrentTimestampsFromWeb() throws MalformedURLException, DownloadFailedException, InvalidDataException {
// Map<String, NvdCveUrl> map = new HashMap<String, NvdCveUrl>();
//
// File tmp = null;
// try {
// tmp = File.createTempFile("cve", "meta");
// URL url = new URL(Settings.getString(Settings.KEYS.CVE_META_URL));
// Downloader.fetchFile(url, tmp);
// String html = readFile(tmp);
//
// String retrieveUrl = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
// NvdCveUrl cve = createNvdCveUrl("modified", retrieveUrl, html);
// cve.setNeedsUpdate(false); //the others default to true, to make life easier later this should default to false.
// map.put("modified", cve);
// int max = Settings.getInt(Settings.KEYS.CVE_URL_COUNT);
// for (int i = 1; i <= max; i++) {
// retrieveUrl = Settings.getString(Settings.KEYS.CVE_BASE_URL + Settings.KEYS.CVE_SCHEMA_2_0 + i);
// String key = Integer.toString(i);
// cve = createNvdCveUrl(key, retrieveUrl, html);
// map.put(key, cve);
// }
// } catch (IOException ex) {
// throw new DownloadFailedException("Unable to create temporary file for NVD CVE Meta File download.", ex);
// } finally {
// try {
// if (tmp != null && tmp.exists()) {
// tmp.delete();
// }
// } finally {
// if (tmp != null && tmp.exists()) {
// tmp.deleteOnExit();
// }
// }
// }
// return map;
// }
//
// /**
// * Creates a new NvdCveUrl object from the provide id, url, and text/html
// * from the NVD CVE downloads page.
// *
// * @param id the name of this NVD CVE Url
// * @param retrieveUrl the URL to download the file from
// * @param text a bit of HTML from the NVD CVE downloads page that contains
// * the URL and the last updated timestamp.
// * @return a shiny new NvdCveUrl object.
// * @throws InvalidDataException is thrown if the timestamp could not be
// * extracted from the provided text.
// */
// private NvdCveUrl createNvdCveUrl(String id, String retrieveUrl, String text) throws InvalidDataException {
// Pattern pattern = Pattern.compile(Pattern.quote(retrieveUrl) + ".+?\\<br");
// Matcher m = pattern.matcher(text);
// NvdCveUrl item = new NvdCveUrl();
// item.id = id;
// item.url = retrieveUrl;
// if (m.find()) {
// String line = m.group();
// int pos = line.indexOf("Updated:");
// if (pos > 0) {
// pos += 9;
// try {
// String timestampstr = line.substring(pos, line.length() - 3).replace("at ", "");
// long timestamp = getEpochTimeFromDateTime(timestampstr);
// item.setTimestamp(timestamp);
// } catch (NumberFormatException ex) {
// throw new InvalidDataException("NVD CVE Meta file does not contain a valid timestamp for '" + retrieveUrl + "'.", ex);
// }
// } else {
// throw new InvalidDataException("NVD CVE Meta file does not contain the updated timestamp for '" + retrieveUrl + "'.");
// }
// } else {
// throw new InvalidDataException("NVD CVE Meta file does not contain the url for '" + retrieveUrl + "'.");
// }
// return item;
// }
//
// /**
// * Parses a timestamp in the format of "MM/dd/yy hh:mm" into a calendar
// * object and returns the epoch time. Note, this removes the millisecond
// * portion of the epoch time so all numbers returned should end in 000.
// *
// * @param timestamp a string in the format of "MM/dd/yy hh:mm"
// * @return a Calendar object.
// * @throws NumberFormatException if the timestamp was parsed incorrectly.
// */
// private long getEpochTimeFromDateTime(String timestamp) throws NumberFormatException {
// Calendar c = new GregorianCalendar();
// int month = Integer.parseInt(timestamp.substring(0, 2));
// int date = Integer.parseInt(timestamp.substring(3, 5));
// int year = 2000 + Integer.parseInt(timestamp.substring(6, 8));
// int hourOfDay = Integer.parseInt(timestamp.substring(9, 11));
// int minute = Integer.parseInt(timestamp.substring(12, 14));
// c.set(year, month, date, hourOfDay, minute, 0);
// long t = c.getTimeInMillis();
// t = (t / 1000) * 1000;
// return t;
// }
//
// /**
// * Reads a file into a string.
// *
// * @param file the file to be read.
// * @return the contents of the file.
// * @throws IOException is thrown if an IOExcpetion occurs.
// */
// private String readFile(File file) throws IOException {
// InputStreamReader stream = new InputStreamReader(new FileInputStream(file), "UTF-8");
// StringBuilder str = new StringBuilder((int) file.length());
// try {
// char[] buf = new char[8096];
// int read = stream.read(buf, 0, 8096);
// while (read > 0) {
// str.append(buf, 0, read);
// read = stream.read(buf, 0, 8096);
// }
// } finally {
// stream.close();
// }
// return str.toString();
// }
//</editor-fold>
/**
* A pojo that contains the Url and timestamp of the current NvdCve XML
* files.
*/
protected class NvdCveUrl {
protected static class NvdCveUrl {
/**
* an id.

View File

@@ -97,22 +97,8 @@ public class Downloader {
*/
public static void fetchFile(URL url, File outputPath, boolean unzip) throws DownloadFailedException {
HttpURLConnection conn = null;
Proxy proxy = null;
String proxyUrl = Settings.getString(Settings.KEYS.PROXY_URL);
try {
if (proxyUrl != null) {
int proxyPort = Settings.getInt(Settings.KEYS.PROXY_PORT);
SocketAddress addr = new InetSocketAddress(proxyUrl, proxyPort);
proxy = new Proxy(Proxy.Type.HTTP, addr);
conn = (HttpURLConnection) url.openConnection(proxy);
} else {
conn = (HttpURLConnection) url.openConnection();
}
if (Settings.getString(Settings.KEYS.CONNECTION_TIMEOUT) != null) {
int timeout = Settings.getInt(Settings.KEYS.CONNECTION_TIMEOUT);
conn.setConnectTimeout(timeout);
}
conn = Downloader.getConnection(url);
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
conn.connect();
} catch (IOException ex) {
@@ -148,13 +134,13 @@ public class Downloader {
throw new DownloadFailedException("Error saving downloaded file.", ex);
} finally {
if (writer != null) {
try {
writer.close();
writer = null;
} catch (Exception ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the writter in Downloader.", ex);
}
try {
writer.close();
writer = null;
} catch (Exception ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the writter in Downloader.", ex);
}
}
if (reader != null) {
try {
@@ -162,8 +148,8 @@ public class Downloader {
reader = null;
} catch (Exception ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the reader in Downloader.", ex);
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the reader in Downloader.", ex);
}
}
try {
@@ -173,4 +159,72 @@ public class Downloader {
}
}
}
/**
* Makes an HTTP Head request to retrieve the last modified date of the given URL.
*
* @param url the URL to retrieve the timestamp from
* @return an epoch timestamp
* @throws DownloadFailedException is thrown if an exception occurs making the HTTP request
*/
public static long getLastModified(URL url) throws DownloadFailedException {
HttpURLConnection conn = null;
long timestamp = 0;
try {
conn = Downloader.getConnection(url);
conn.setRequestMethod("HEAD");
conn.connect();
timestamp = conn.getLastModified();
} catch (Exception ex) {
throw new DownloadFailedException("Error making HTTP HEAD request.", ex);
} finally {
if (conn != null) {
try {
conn.disconnect();
} finally {
conn = null;
}
}
}
return timestamp;
}
/**
* Utility method to get an HttpURLConnectoin. If the app is configured to
* use a proxy this method will retrieve the proxy settings and use them
* when setting up the connection.
*
* @param url the url to connect to
* @return an HttpURLConnection
* @throws DownloadFailedException thrown if there is an exception
*/
private static HttpURLConnection getConnection(URL url) throws DownloadFailedException {
HttpURLConnection conn = null;
Proxy proxy = null;
String proxyUrl = Settings.getString(Settings.KEYS.PROXY_URL);
try {
if (proxyUrl != null) {
int proxyPort = Settings.getInt(Settings.KEYS.PROXY_PORT);
SocketAddress addr = new InetSocketAddress(proxyUrl, proxyPort);
proxy = new Proxy(Proxy.Type.HTTP, addr);
conn = (HttpURLConnection) url.openConnection(proxy);
} else {
conn = (HttpURLConnection) url.openConnection();
}
if (Settings.getString(Settings.KEYS.CONNECTION_TIMEOUT) != null) {
int timeout = Settings.getInt(Settings.KEYS.CONNECTION_TIMEOUT);
conn.setConnectTimeout(timeout);
}
} catch (IOException ex) {
try {
if (conn != null) {
conn.disconnect();
}
} finally {
conn = null;
}
throw new DownloadFailedException("Error getting connection.", ex);
}
return conn;
}
}

View File

@@ -70,9 +70,14 @@ public class Settings {
public static final String CVE_META_URL = "cve.url.meta";
/**
* The properties key for the URL to retrieve the recently modified and
* added CVE entries (last 8 days).
* added CVE entries (last 8 days) using the 2.0 schema.
*/
public static final String CVE_MODIFIED_URL = "cve.url.modified";
public static final String CVE_MODIFIED_20_URL = "cve.url-2.0.modified";
/**
* The properties key for the URL to retrieve the recently modified and
* added CVE entries (last 8 days) using the 1.2 schema.
*/
public static final String CVE_MODIFIED_12_URL = "cve.url-1.2.modified";
/**
* The properties key for the URL to retrieve the recently modified and
* added CVE entries (last 8 days).
@@ -86,9 +91,19 @@ public class Settings {
public static final String CVE_URL_COUNT = "cve.url.count";
/**
* The properties key for the "base" property key for the CVE URLs (e.g.
* cve.url.1, cve.url.2, cve.url.n).
* cve.url-2.0.1, cve.url-1.2.2, cve.url.n).
*/
public static final String CVE_BASE_URL = "cve.url.";
public static final String CVE_BASE_URL = "cve.url-";
/**
* The properties key for the CVE schema version 1.2
*/
public static final String CVE_SCHEMA_1_2 = "1.2.";
/**
* The properties key for the CVE schema version 2.0
*/
public static final String CVE_SCHEMA_2_0 = "2.0.";
/**
* The properties key for the proxy url.
*/

View File

@@ -7,12 +7,15 @@ cpe=data/cpe
cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.xml.gz
# the path to the cpe meta data file.
cpe.meta.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.meta
# the path to the lucene index to store the nvd cve data
cve=data/cve
# the path to the nvd cve "meta" page where the timestamps for the last update files can be found.
cve.url.meta=http://nvd.nist.gov/download.cfm
#cve.url.meta=http://nvd.nist.gov/download.cfm
# the path to the modified nvd cve xml file.
cve.url.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
# the number of days that the modified nvd cve data holds data for. We don't need
# to update the other files if we are within this timespan. Per NIST this file
@@ -20,15 +23,29 @@ cve.url.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xm
cve.url.modified.validfordays=7
# the number of cve.urls
cve.url.count=11
# the paths to the various nvd cve files.
cve.url.1=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2002.xml
cve.url.2=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2003.xml
cve.url.3=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2004.xml
cve.url.4=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2005.xml
cve.url.5=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2006.xml
cve.url.6=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2007.xml
cve.url.7=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2008.xml
cve.url.8=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2009.xml
cve.url.9=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2010.xml
cve.url.10=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2011.xml
cve.url.11=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2012.xml
# the paths to the various nvd cve files (schema version 2.0)
cve.url-2.0.1=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2002.xml
cve.url-2.0.2=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2003.xml
cve.url-2.0.3=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2004.xml
cve.url-2.0.4=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2005.xml
cve.url-2.0.5=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2006.xml
cve.url-2.0.6=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2007.xml
cve.url-2.0.7=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2008.xml
cve.url-2.0.8=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2009.xml
cve.url-2.0.9=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2010.xml
cve.url-2.0.10=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2011.xml
cve.url-2.0.11=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2012.xml
# the paths to the various nvd cve files (schema version 1.2).
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
cve.url-1.2.1=http://nvd.nist.gov/download/nvdcve-2002.xml
cve.url-1.2.2=http://nvd.nist.gov/download/nvdcve-2003.xml
cve.url-1.2.3=http://nvd.nist.gov/download/nvdcve-2004.xml
cve.url-1.2.4=http://nvd.nist.gov/download/nvdcve-2005.xml
cve.url-1.2.5=http://nvd.nist.gov/download/nvdcve-2006.xml
cve.url-1.2.6=http://nvd.nist.gov/download/nvdcve-2007.xml
cve.url-1.2.7=http://nvd.nist.gov/download/nvdcve-2008.xml
cve.url-1.2.8=http://nvd.nist.gov/download/nvdcve-2009.xml
cve.url-1.2.9=http://nvd.nist.gov/download/nvdcve-2010.xml
cve.url-1.2.10=http://nvd.nist.gov/download/nvdcve-2011.xml
cve.url-1.2.11=http://nvd.nist.gov/download/nvdcve-2012.xml

View File

@@ -5,8 +5,6 @@
package org.codesecure.dependencycheck.dependency;
import java.io.File;
import org.codesecure.dependencycheck.dependency.Dependency;
import org.codesecure.dependencycheck.dependency.Evidence;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;

View File

@@ -10,6 +10,7 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
@@ -58,4 +59,12 @@ public class DownloaderIntegrationTest {
Downloader.fetchFile(url, outputPath, false);
}
@Test
public void testGetLastModified() throws Exception {
System.out.println("getLastModified");
URL url = new URL("http://nvd.nist.gov/download/nvdcve-2012.xml");
long timestamp = Downloader.getLastModified(url);
assertTrue("timestamp equal to zero?", timestamp>0);
}
}

View File

@@ -6,7 +6,6 @@ package org.codesecure.dependencycheck.utils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import junit.framework.TestCase;
import org.junit.Test;