Coverage Report - org.owasp.dependencycheck.data.nvdcve.xml.DatabaseUpdater
 
Classes in this File Line Coverage Branch Coverage Complexity
DatabaseUpdater
0%
0/262
0%
0/76
5.789
DatabaseUpdater$NvdCveUrl
0%
0/17
N/A
5.789
 
 1  
 /*
 2  
  * This file is part of dependency-check-core.
 3  
  *
 4  
  * Dependency-check-core is free software: you can redistribute it and/or modify it
 5  
  * under the terms of the GNU General Public License as published by the Free
 6  
  * Software Foundation, either version 3 of the License, or (at your option) any
 7  
  * later version.
 8  
  *
 9  
  * Dependency-check-core is distributed in the hope that it will be useful, but
 10  
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 12  
  * details.
 13  
  *
 14  
  * You should have received a copy of the GNU General Public License along with
 15  
  * dependency-check-core. If not, see http://www.gnu.org/licenses/.
 16  
  *
 17  
  * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
 18  
  */
 19  
 package org.owasp.dependencycheck.data.nvdcve.xml;
 20  
 
 21  
 import java.io.File;
 22  
 import java.io.FileInputStream;
 23  
 import java.io.FileNotFoundException;
 24  
 import java.io.FileOutputStream;
 25  
 import java.io.IOException;
 26  
 import java.io.InputStream;
 27  
 import java.io.OutputStream;
 28  
 import java.io.OutputStreamWriter;
 29  
 import javax.xml.parsers.ParserConfigurationException;
 30  
 import org.owasp.dependencycheck.data.CachedWebDataSource;
 31  
 import java.net.MalformedURLException;
 32  
 import java.net.URL;
 33  
 import java.sql.SQLException;
 34  
 import java.util.Calendar;
 35  
 import java.util.Date;
 36  
 import java.util.HashMap;
 37  
 import java.util.List;
 38  
 import java.util.Map;
 39  
 import java.util.Properties;
 40  
 import java.util.logging.Level;
 41  
 import java.util.logging.Logger;
 42  
 import javax.xml.parsers.SAXParser;
 43  
 import javax.xml.parsers.SAXParserFactory;
 44  
 import org.owasp.dependencycheck.data.UpdateException;
 45  
 import org.owasp.dependencycheck.data.cpe.Index;
 46  
 import org.owasp.dependencycheck.data.nvdcve.CveDB;
 47  
 import org.owasp.dependencycheck.dependency.VulnerableSoftware;
 48  
 import org.owasp.dependencycheck.utils.DownloadFailedException;
 49  
 import org.owasp.dependencycheck.utils.Downloader;
 50  
 import org.owasp.dependencycheck.utils.FileUtils;
 51  
 import org.owasp.dependencycheck.utils.InvalidSettingException;
 52  
 import org.owasp.dependencycheck.utils.Settings;
 53  
 import org.xml.sax.SAXException;
 54  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
 55  
 
 56  
 /**
 57  
  *
 58  
  * @author Jeremy Long (jeremy.long@owasp.org)
 59  
  */
 60  0
 public class DatabaseUpdater implements CachedWebDataSource {
 61  
 
 62  
     /**
 63  
      * The name of the properties file containing the timestamp of the last
 64  
      * update.
 65  
      */
 66  
     private static final String UPDATE_PROPERTIES_FILE = "lastupdated.prop";
 67  
     /**
 68  
      * The properties file key for the last updated field - used to store the
 69  
      * last updated time of the Modified NVD CVE xml file.
 70  
      */
 71  
     private static final String LAST_UPDATED_MODIFIED = "lastupdated.modified";
 72  
     /**
 73  
      * Stores the last updated time for each of the NVD CVE files. These
 74  
      * timestamps should be updated if we process the modified file within 7
 75  
      * days of the last update.
 76  
      */
 77  
     private static final String LAST_UPDATED_BASE = "lastupdated.";
 78  
     /**
 79  
      * Modified key word.
 80  
      */
 81  
     public static final String MODIFIED = "modified";
 82  
     /**
 83  
      * Reference to the Cve Database.
 84  
      */
 85  0
     private CveDB cveDB = null;
 86  
     /**
 87  
      * Reference to the Cpe Index.
 88  
      */
 89  0
     private Index cpeIndex = null;
 90  
 
 91  
     /**
 92  
      * <p>Downloads the latest NVD CVE XML file from the web and imports it into
 93  
      * the current CVE Database.</p>
 94  
      *
 95  
      * @throws UpdateException is thrown if there is an error updating the
 96  
      * database
 97  
      */
 98  
     public void update() throws UpdateException {
 99  
         try {
 100  0
             final Map<String, NvdCveUrl> update = updateNeeded();
 101  0
             int maxUpdates = 0;
 102  0
             for (NvdCveUrl cve : update.values()) {
 103  0
                 if (cve.getNeedsUpdate()) {
 104  0
                     maxUpdates += 1;
 105  
                 }
 106  
             }
 107  0
             if (maxUpdates > 3) {
 108  0
                 Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
 109  
                         "NVD CVE requires several updates; this could take a couple of minutes.");
 110  
             }
 111  0
             if (maxUpdates > 0) {
 112  0
                 openDataStores();
 113  
             }
 114  0
             int count = 0;
 115  
 
 116  0
             for (NvdCveUrl cve : update.values()) {
 117  0
                 if (cve.getNeedsUpdate()) {
 118  0
                     count += 1;
 119  0
                     Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
 120  
                             "Updating NVD CVE ({0} of {1})", new Object[]{count, maxUpdates});
 121  0
                     URL url = new URL(cve.getUrl());
 122  0
                     File outputPath = null;
 123  0
                     File outputPath12 = null;
 124  
                     try {
 125  0
                         Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
 126  
                                 "Downloading {0}", cve.getUrl());
 127  
 
 128  0
                         outputPath = File.createTempFile("cve" + cve.getId() + "_", ".xml");
 129  0
                         Downloader.fetchFile(url, outputPath, false);
 130  
 
 131  0
                         url = new URL(cve.getOldSchemaVersionUrl());
 132  0
                         outputPath12 = File.createTempFile("cve_1_2_" + cve.getId() + "_", ".xml");
 133  0
                         Downloader.fetchFile(url, outputPath12, false);
 134  
 
 135  0
                         Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
 136  
                                 "Processing {0}", cve.getUrl());
 137  
 
 138  0
                         importXML(outputPath, outputPath12);
 139  
 
 140  0
                         cveDB.commit();
 141  0
                         cpeIndex.commit();
 142  
 
 143  0
                         writeLastUpdatedPropertyFile(cve);
 144  
 
 145  0
                         Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
 146  
                                 "Completed update {0} of {1}", new Object[]{count, maxUpdates});
 147  0
                     } catch (FileNotFoundException ex) {
 148  0
                         throw new UpdateException(ex);
 149  0
                     } catch (ParserConfigurationException ex) {
 150  0
                         throw new UpdateException(ex);
 151  0
                     } catch (SAXException ex) {
 152  0
                         throw new UpdateException(ex);
 153  0
                     } catch (IOException ex) {
 154  0
                         throw new UpdateException(ex);
 155  0
                     } catch (SQLException ex) {
 156  0
                         throw new UpdateException(ex);
 157  0
                     } catch (DatabaseException ex) {
 158  0
                         throw new UpdateException(ex);
 159  0
                     } catch (ClassNotFoundException ex) {
 160  0
                         throw new UpdateException(ex);
 161  
                     } finally {
 162  0
                         boolean deleted = false;
 163  
                         try {
 164  0
                             if (outputPath != null && outputPath.exists()) {
 165  0
                                 deleted = outputPath.delete();
 166  
                             }
 167  
                         } finally {
 168  0
                             if (outputPath != null && (outputPath.exists() || !deleted)) {
 169  0
                                 outputPath.deleteOnExit();
 170  
                             }
 171  
                         }
 172  
                         try {
 173  0
                             deleted = false;
 174  0
                             if (outputPath12 != null && outputPath12.exists()) {
 175  0
                                 deleted = outputPath12.delete();
 176  
                             }
 177  
                         } finally {
 178  0
                             if (outputPath12 != null && (outputPath12.exists() || !deleted)) {
 179  0
                                 outputPath12.deleteOnExit();
 180  
                             }
 181  
                         }
 182  0
                     }
 183  0
                 }
 184  
             }
 185  0
             if (maxUpdates >= 1) {
 186  0
                 ensureModifiedIsInLastUpdatedProperties(update);
 187  0
                 cveDB.cleanupDatabase();
 188  
             }
 189  0
         } catch (MalformedURLException ex) {
 190  0
             throw new UpdateException(ex);
 191  0
         } catch (DownloadFailedException ex) {
 192  0
             throw new UpdateException(ex);
 193  
         } finally {
 194  0
             closeDataStores();
 195  0
         }
 196  0
     }
 197  
 
 198  
     /**
 199  
      * Imports the NVD CVE XML File into the Lucene Index.
 200  
      *
 201  
      * @param file the file containing the NVD CVE XML
 202  
      * @param oldVersion contains the file containing the NVD CVE XML 1.2
 203  
      * @throws ParserConfigurationException is thrown if there is a parser
 204  
      * configuration exception
 205  
      * @throws SAXException is thrown if there is a SAXException
 206  
      * @throws IOException is thrown if there is a ioexception
 207  
      * @throws SQLException is thrown if there is a sql exception
 208  
      * @throws DatabaseException is thrown if there is a database exception
 209  
      * @throws ClassNotFoundException thrown if the h2 database driver cannot be
 210  
      * loaded
 211  
      */
 212  
     private void importXML(File file, File oldVersion)
 213  
             throws ParserConfigurationException, SAXException, IOException, SQLException, DatabaseException, ClassNotFoundException {
 214  
 
 215  0
         final SAXParserFactory factory = SAXParserFactory.newInstance();
 216  0
         final SAXParser saxParser = factory.newSAXParser();
 217  
 
 218  0
         final NvdCve12Handler cve12Handler = new NvdCve12Handler();
 219  0
         saxParser.parse(oldVersion, cve12Handler);
 220  0
         final Map<String, List<VulnerableSoftware>> prevVersionVulnMap = cve12Handler.getVulnerabilities();
 221  
 
 222  0
         final NvdCve20Handler cve20Handler = new NvdCve20Handler();
 223  0
         cve20Handler.setCveDB(cveDB);
 224  0
         cve20Handler.setPrevVersionVulnMap(prevVersionVulnMap);
 225  0
         cve20Handler.setCpeIndex(cpeIndex);
 226  0
         saxParser.parse(file, cve20Handler);
 227  0
     }
 228  
 
 229  
     /**
 230  
      * Closes the CVE and CPE data stores.
 231  
      */
 232  
     private void closeDataStores() {
 233  0
         if (cveDB != null) {
 234  
             try {
 235  0
                 cveDB.close();
 236  0
             } catch (Exception ignore) {
 237  0
                 Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, "Error closing the cveDB", ignore);
 238  0
             }
 239  
         }
 240  0
         if (cpeIndex != null) {
 241  
             try {
 242  0
                 cpeIndex.close();
 243  0
             } catch (Exception ignore) {
 244  0
                 Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, "Error closing the cpeIndex", ignore);
 245  0
             }
 246  
         }
 247  0
     }
 248  
 
 249  
     /**
 250  
      * Opens the CVE and CPE data stores.
 251  
      *
 252  
      * @throws UpdateException thrown if a data store cannot be opened
 253  
      */
 254  
     private void openDataStores() throws UpdateException {
 255  
         //open the cve and cpe data stores
 256  
         try {
 257  0
             cveDB = new CveDB();
 258  0
             cveDB.open();
 259  0
             cpeIndex = new Index();
 260  0
             cpeIndex.openIndexWriter();
 261  0
         } catch (IOException ex) {
 262  0
             closeDataStores();
 263  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "IO Error opening databases", ex);
 264  0
             throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
 265  0
         } catch (SQLException ex) {
 266  0
             closeDataStores();
 267  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "SQL Exception opening databases", ex);
 268  0
             throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
 269  0
         } catch (DatabaseException ex) {
 270  0
             closeDataStores();
 271  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "Database Exception opening databases", ex);
 272  0
             throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
 273  0
         } catch (ClassNotFoundException ex) {
 274  0
             closeDataStores();
 275  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "Class not found exception opening databases", ex);
 276  0
             throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
 277  0
         }
 278  0
     }
 279  
 
 280  
     //<editor-fold defaultstate="collapsed" desc="Code to read/write properties files regarding the last update dates">
 281  
     /**
 282  
      * Writes a properties file containing the last updated date to the
 283  
      * VULNERABLE_CPE directory.
 284  
      *
 285  
      * @param updatedValue the updated nvdcve entry
 286  
      * @throws UpdateException is thrown if there is an update exception
 287  
      */
 288  
     private void writeLastUpdatedPropertyFile(NvdCveUrl updatedValue) throws UpdateException {
 289  0
         if (updatedValue == null) {
 290  0
             return;
 291  
         }
 292  
         String dir;
 293  
         try {
 294  0
             dir = CveDB.getDataDirectory().getCanonicalPath();
 295  0
         } catch (IOException ex) {
 296  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "Error updating the databases propterty file.", ex);
 297  0
             throw new UpdateException("Unable to locate last updated properties file.", ex);
 298  0
         }
 299  0
         final File cveProp = new File(dir, UPDATE_PROPERTIES_FILE);
 300  0
         final Properties prop = new Properties();
 301  0
         if (cveProp.exists()) {
 302  0
             FileInputStream in = null;
 303  
             try {
 304  0
                 in = new FileInputStream(cveProp);
 305  0
                 prop.load(in);
 306  0
             } catch (Exception ignoreMe) {
 307  0
                 Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ignoreMe);
 308  
             } finally {
 309  0
                 if (in != null) {
 310  
                     try {
 311  0
                         in.close();
 312  0
                     } catch (Exception ignoreMeToo) {
 313  0
                         Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ignoreMeToo);
 314  0
                     }
 315  
                 }
 316  
             }
 317  
 
 318  
         }
 319  0
         prop.put("version", CveDB.DB_SCHEMA_VERSION);
 320  0
         prop.put(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
 321  
 
 322  0
         OutputStream os = null;
 323  0
         OutputStreamWriter out = null;
 324  
         try {
 325  0
             os = new FileOutputStream(cveProp);
 326  0
             out = new OutputStreamWriter(os, "UTF-8");
 327  0
             prop.store(out, dir);
 328  0
         } catch (FileNotFoundException ex) {
 329  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
 330  0
             throw new UpdateException("Unable to find last updated properties file.", ex);
 331  0
         } catch (IOException ex) {
 332  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
 333  0
             throw new UpdateException("Unable to update last updated properties file.", ex);
 334  
         } finally {
 335  0
             if (out != null) {
 336  
                 try {
 337  0
                     out.close();
 338  0
                 } catch (IOException ex) {
 339  0
                     Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
 340  0
                 }
 341  
             }
 342  0
             if (os != null) {
 343  
                 try {
 344  0
                     os.close();
 345  0
                 } catch (IOException ex) {
 346  0
                     Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
 347  0
                 }
 348  
             }
 349  
         }
 350  0
     }
 351  
 
 352  
     /**
 353  
      * Determines if the index needs to be updated. This is done by fetching the
 354  
      * nvd cve meta data and checking the last update date. If the data needs to
 355  
      * be refreshed this method will return the NvdCveUrl for the files that
 356  
      * need to be updated.
 357  
      *
 358  
      * @return the NvdCveUrl of the files that need to be updated.
 359  
      * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
 360  
      * data is incorrect.
 361  
      * @throws DownloadFailedException is thrown if there is an error.
 362  
      * downloading the nvd cve download data file.
 363  
      * @throws UpdateException Is thrown if there is an issue with the last
 364  
      * updated properties file.
 365  
      */
 366  
     public Map<String, NvdCveUrl> updateNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
 367  
 
 368  
         Map<String, NvdCveUrl> currentlyPublished;
 369  
         try {
 370  0
             currentlyPublished = retrieveCurrentTimestampsFromWeb();
 371  0
         } catch (InvalidDataException ex) {
 372  0
             final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
 373  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, msg, ex);
 374  0
             throw new DownloadFailedException(msg, ex);
 375  
 
 376  0
         } catch (InvalidSettingException ex) {
 377  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "Invalid setting found when retrieving timestamps", ex);
 378  0
             throw new DownloadFailedException("Invalid settings", ex);
 379  0
         }
 380  
 
 381  0
         if (currentlyPublished == null) {
 382  0
             throw new DownloadFailedException("Unable to retrieve valid timestamp from nvd cve downloads page");
 383  
         }
 384  
         String dir;
 385  
         try {
 386  0
             dir = CveDB.getDataDirectory().getCanonicalPath();
 387  0
         } catch (IOException ex) {
 388  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "CveDB data directory doesn't exist?", ex);
 389  0
             throw new UpdateException("Unable to locate last updated properties file.", ex);
 390  0
         }
 391  
 
 392  0
         final File f = new File(dir);
 393  0
         if (f.exists()) {
 394  0
             final File cveProp = new File(dir, UPDATE_PROPERTIES_FILE);
 395  0
             if (cveProp.exists()) {
 396  0
                 final Properties prop = new Properties();
 397  0
                 InputStream is = null;
 398  
                 try {
 399  0
                     is = new FileInputStream(cveProp);
 400  0
                     prop.load(is);
 401  
 
 402  0
                     boolean deleteAndRecreate = false;
 403  
                     float version;
 404  
 
 405  0
                     if (prop.getProperty("version") == null) {
 406  0
                         deleteAndRecreate = true;
 407  
                     } else {
 408  
                         try {
 409  0
                             version = Float.parseFloat(prop.getProperty("version"));
 410  0
                             final float currentVersion = Float.parseFloat(CveDB.DB_SCHEMA_VERSION);
 411  0
                             if (currentVersion > version) {
 412  0
                                 deleteAndRecreate = true;
 413  
                             }
 414  0
                         } catch (NumberFormatException ex) {
 415  0
                             deleteAndRecreate = true;
 416  0
                         }
 417  
                     }
 418  0
                     if (deleteAndRecreate) {
 419  0
                         Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO, "The database version is old. Rebuilding the database.");
 420  0
                         is.close();
 421  
                         //this is an old version of the lucene index - just delete it
 422  0
                         FileUtils.delete(f);
 423  
 
 424  
                         //this importer also updates the CPE index and it is also using an old version
 425  0
                         final Index cpeId = new Index();
 426  0
                         final File cpeDir = cpeId.getDataDirectory();
 427  0
                         FileUtils.delete(cpeDir);
 428  0
                         return currentlyPublished;
 429  
                     }
 430  
 
 431  0
                     final long lastUpdated = Long.parseLong(prop.getProperty(LAST_UPDATED_MODIFIED, "0"));
 432  0
                     final Date now = new Date();
 433  0
                     final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
 434  0
                     final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR, 2002);
 435  0
                     final int end = Calendar.getInstance().get(Calendar.YEAR);
 436  0
                     if (lastUpdated == currentlyPublished.get(MODIFIED).timestamp) {
 437  0
                         currentlyPublished.clear(); //we don't need to update anything.
 438  0
                     } else if (withinRange(lastUpdated, now.getTime(), days)) {
 439  0
                         currentlyPublished.get(MODIFIED).setNeedsUpdate(true);
 440  0
                         for (int i = start; i <= end; i++) {
 441  0
                             currentlyPublished.get(String.valueOf(i)).setNeedsUpdate(false);
 442  
                         }
 443  
                     } else { //we figure out which of the several XML files need to be downloaded.
 444  0
                         currentlyPublished.get(MODIFIED).setNeedsUpdate(false);
 445  0
                         for (int i = start; i <= end; i++) {
 446  0
                             final NvdCveUrl cve = currentlyPublished.get(String.valueOf(i));
 447  0
                             long currentTimestamp = 0;
 448  
                             try {
 449  0
                                 currentTimestamp = Long.parseLong(prop.getProperty(LAST_UPDATED_BASE + String.valueOf(i), "0"));
 450  0
                             } catch (NumberFormatException ex) {
 451  0
                                 final String msg = String.format("Error parsing '%s' '%s' from nvdcve.lastupdated",
 452  
                                         LAST_UPDATED_BASE, String.valueOf(i));
 453  0
                                 Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, msg, ex);
 454  0
                             }
 455  0
                             if (currentTimestamp == cve.getTimestamp()) {
 456  0
                                 cve.setNeedsUpdate(false); //they default to true.
 457  
                             }
 458  
                         }
 459  
                     }
 460  0
                 } catch (FileNotFoundException ex) {
 461  0
                     Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
 462  0
                 } catch (IOException ex) {
 463  0
                     Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
 464  0
                 } catch (NumberFormatException ex) {
 465  0
                     Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
 466  
                 } finally {
 467  0
                     if (is != null) {
 468  
                         try {
 469  0
                             is.close();
 470  0
                         } catch (IOException ex) {
 471  0
                             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
 472  0
                         }
 473  
                     }
 474  
                 }
 475  
             }
 476  
         }
 477  0
         return currentlyPublished;
 478  
     }
 479  
 
 480  
     /**
 481  
      * Determines if the epoch date is within the range specified of the
 482  
      * compareTo epoch time. This takes the (compareTo-date)/1000/60/60/24 to
 483  
      * get the number of days. If the calculated days is less then the range the
 484  
      * date is considered valid.
 485  
      *
 486  
      * @param date the date to be checked.
 487  
      * @param compareTo the date to compare to.
 488  
      * @param range the range in days to be considered valid.
 489  
      * @return whether or not the date is within the range.
 490  
      */
 491  
     private boolean withinRange(long date, long compareTo, int range) {
 492  0
         final double differenceInDays = (compareTo - date) / 1000.0 / 60.0 / 60.0 / 24.0;
 493  0
         return differenceInDays < range;
 494  
     }
 495  
 
 496  
     /**
 497  
      * Retrieves the timestamps from the NVD CVE meta data file.
 498  
      *
 499  
      * @return the timestamp from the currently published nvdcve downloads page
 500  
      * @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
 501  
      * is incorrect.
 502  
      * @throws DownloadFailedException thrown if there is an error downloading
 503  
      * the nvd cve meta data file
 504  
      * @throws InvalidDataException thrown if there is an exception parsing the
 505  
      * timestamps
 506  
      * @throws InvalidSettingException thrown if the settings are invalid
 507  
      */
 508  
     protected Map<String, NvdCveUrl> retrieveCurrentTimestampsFromWeb()
 509  
             throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
 510  
 
 511  0
         final Map<String, NvdCveUrl> map = new HashMap<String, NvdCveUrl>();
 512  0
         String retrieveUrl = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
 513  
 
 514  0
         NvdCveUrl item = new NvdCveUrl();
 515  0
         item.setNeedsUpdate(false); //the others default to true, to make life easier later this should default to false.
 516  0
         item.setId(MODIFIED);
 517  0
         item.setUrl(retrieveUrl);
 518  0
         item.setOldSchemaVersionUrl(Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL));
 519  
 
 520  0
         item.timestamp = Downloader.getLastModified(new URL(retrieveUrl));
 521  0
         map.put(MODIFIED, item);
 522  
 
 523  0
         final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
 524  0
         final int end = Calendar.getInstance().get(Calendar.YEAR);
 525  0
         final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
 526  0
         final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
 527  0
         for (int i = start; i <= end; i++) {
 528  0
             retrieveUrl = String.format(baseUrl20, i);
 529  0
             item = new NvdCveUrl();
 530  0
             item.setId(Integer.toString(i));
 531  0
             item.setUrl(retrieveUrl);
 532  0
             item.setOldSchemaVersionUrl(String.format(baseUrl12, i));
 533  0
             item.setTimestamp(Downloader.getLastModified(new URL(retrieveUrl)));
 534  0
             map.put(item.id, item);
 535  
         }
 536  0
         return map;
 537  
     }
 538  
 
 539  
     /**
 540  
      * Method to double check that the "modified" nvdcve file is listed and has
 541  
      * a timestamp in the last updated properties file.
 542  
      *
 543  
      * @param update a set of updated NvdCveUrl objects
 544  
      */
 545  
     private void ensureModifiedIsInLastUpdatedProperties(Map<String, NvdCveUrl> update) {
 546  
         try {
 547  0
             writeLastUpdatedPropertyFile(update.get(MODIFIED));
 548  0
         } catch (UpdateException ex) {
 549  0
             Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
 550  0
         }
 551  0
     }
 552  
 
 553  
     /**
 554  
      * A pojo that contains the Url and timestamp of the current NvdCve XML
 555  
      * files.
 556  
      */
 557  0
     protected static class NvdCveUrl {
 558  
 
 559  
         /**
 560  
          * an id.
 561  
          */
 562  
         private String id;
 563  
 
 564  
         /**
 565  
          * Get the value of id.
 566  
          *
 567  
          * @return the value of id
 568  
          */
 569  
         public String getId() {
 570  0
             return id;
 571  
         }
 572  
 
 573  
         /**
 574  
          * Set the value of id.
 575  
          *
 576  
          * @param id new value of id
 577  
          */
 578  
         public void setId(String id) {
 579  0
             this.id = id;
 580  0
         }
 581  
         /**
 582  
          * a url.
 583  
          */
 584  
         private String url;
 585  
 
 586  
         /**
 587  
          * Get the value of url.
 588  
          *
 589  
          * @return the value of url
 590  
          */
 591  
         public String getUrl() {
 592  0
             return url;
 593  
         }
 594  
 
 595  
         /**
 596  
          * Set the value of url.
 597  
          *
 598  
          * @param url new value of url
 599  
          */
 600  
         public void setUrl(String url) {
 601  0
             this.url = url;
 602  0
         }
 603  
         /**
 604  
          * The 1.2 schema URL.
 605  
          */
 606  
         private String oldSchemaVersionUrl;
 607  
 
 608  
         /**
 609  
          * Get the value of oldSchemaVersionUrl.
 610  
          *
 611  
          * @return the value of oldSchemaVersionUrl
 612  
          */
 613  
         public String getOldSchemaVersionUrl() {
 614  0
             return oldSchemaVersionUrl;
 615  
         }
 616  
 
 617  
         /**
 618  
          * Set the value of oldSchemaVersionUrl.
 619  
          *
 620  
          * @param oldSchemaVersionUrl new value of oldSchemaVersionUrl
 621  
          */
 622  
         public void setOldSchemaVersionUrl(String oldSchemaVersionUrl) {
 623  0
             this.oldSchemaVersionUrl = oldSchemaVersionUrl;
 624  0
         }
 625  
         /**
 626  
          * a timestamp - epoch time.
 627  
          */
 628  
         private long timestamp;
 629  
 
 630  
         /**
 631  
          * Get the value of timestamp - epoch time.
 632  
          *
 633  
          * @return the value of timestamp - epoch time
 634  
          */
 635  
         public long getTimestamp() {
 636  0
             return timestamp;
 637  
         }
 638  
 
 639  
         /**
 640  
          * Set the value of timestamp - epoch time.
 641  
          *
 642  
          * @param timestamp new value of timestamp - epoch time
 643  
          */
 644  
         public void setTimestamp(long timestamp) {
 645  0
             this.timestamp = timestamp;
 646  0
         }
 647  
         /**
 648  
          * indicates whether or not this item should be updated.
 649  
          */
 650  0
         private boolean needsUpdate = true;
 651  
 
 652  
         /**
 653  
          * Get the value of needsUpdate.
 654  
          *
 655  
          * @return the value of needsUpdate
 656  
          */
 657  
         public boolean getNeedsUpdate() {
 658  0
             return needsUpdate;
 659  
         }
 660  
 
 661  
         /**
 662  
          * Set the value of needsUpdate.
 663  
          *
 664  
          * @param needsUpdate new value of needsUpdate
 665  
          */
 666  
         public void setNeedsUpdate(boolean needsUpdate) {
 667  0
             this.needsUpdate = needsUpdate;
 668  0
         }
 669  
     }
 670  
     //</editor-fold>
 671  
 }