Coverage Report - org.owasp.dependencycheck.data.update.EngineVersionCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
EngineVersionCheck
47%
37/78
50%
13/26
4.286
 
 1  
 /*
 2  
  * This file is part of dependency-check-core.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  *
 16  
  * Copyright (c) 2014 Jeremy Long. All Rights Reserved.
 17  
  */
 18  
 package org.owasp.dependencycheck.data.update;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.net.HttpURLConnection;
 22  
 import java.net.MalformedURLException;
 23  
 import java.net.URL;
 24  
 import java.util.Date;
 25  
 import java.util.logging.Level;
 26  
 import java.util.logging.Logger;
 27  
 import org.apache.commons.io.IOUtils;
 28  
 import org.owasp.dependencycheck.data.nvdcve.CveDB;
 29  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
 30  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
 31  
 import org.owasp.dependencycheck.data.update.exception.UpdateException;
 32  
 import org.owasp.dependencycheck.utils.DateUtil;
 33  
 import org.owasp.dependencycheck.utils.DependencyVersion;
 34  
 import org.owasp.dependencycheck.utils.Settings;
 35  
 import org.owasp.dependencycheck.utils.URLConnectionFactory;
 36  
 import org.owasp.dependencycheck.utils.URLConnectionFailureException;
 37  
 
 38  
 /**
 39  
  *
 40  
  * @author Jeremy Long
 41  
  */
 42  2
 public class EngineVersionCheck implements CachedWebDataSource {
 43  
 
 44  
     /**
 45  
      * Static logger.
 46  
      */
 47  1
     private static final Logger LOGGER = Logger.getLogger(EngineVersionCheck.class.getName());
 48  
     /**
 49  
      * The property key indicating when the last version check occurred.
 50  
      */
 51  
     public static final String ENGINE_VERSION_CHECKED_ON = "VersionCheckOn";
 52  
     /**
 53  
      * The property key indicating when the last version check occurred.
 54  
      */
 55  
     public static final String CURRENT_ENGINE_RELEASE = "CurrentEngineRelease";
 56  
     /**
 57  
      * Reference to the Cve Database.
 58  
      */
 59  2
     private CveDB cveDB = null;
 60  
 
 61  
     /**
 62  
      * The version retrieved from the database properties or web to check against.
 63  
      */
 64  
     private String updateToVersion;
 65  
 
 66  
     /**
 67  
      * Getter for updateToVersion - only used for testing. Represents the version retrieved from the database.
 68  
      *
 69  
      * @return the version to test
 70  
      */
 71  
     protected String getUpdateToVersion() {
 72  0
         return updateToVersion;
 73  
     }
 74  
 
 75  
     /**
 76  
      * Setter for updateToVersion - only used for testing. Represents the version retrieved from the database.
 77  
      *
 78  
      * @param version the version to test
 79  
      */
 80  
     protected void setUpdateToVersion(String version) {
 81  7
         updateToVersion = version;
 82  7
     }
 83  
 
 84  
     @Override
 85  
     public void update() throws UpdateException {
 86  
         try {
 87  0
             openDatabase();
 88  0
             LOGGER.fine("Begin Engine Version Check");
 89  0
             final DatabaseProperties properties = cveDB.getDatabaseProperties();
 90  0
             final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
 91  0
             final long now = (new Date()).getTime();
 92  0
             updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
 93  0
             final String currentVersion = Settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
 94  0
             LOGGER.fine("Last checked: " + lastChecked);
 95  0
             LOGGER.fine("Now: " + now);
 96  0
             LOGGER.fine("Current version: " + currentVersion);
 97  0
             final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
 98  0
             if (updateNeeded) {
 99  0
                 final String msg = String.format("A new version of dependency-check is available. Consider updating to version %s.",
 100  
                         updateToVersion);
 101  0
                 LOGGER.warning(msg);
 102  
             }
 103  0
         } catch (DatabaseException ex) {
 104  0
             LOGGER.log(Level.FINE, "Database Exception opening databases to retrieve properties", ex);
 105  0
             throw new UpdateException("Error occured updating database properties.");
 106  
         } finally {
 107  0
             closeDatabase();
 108  0
         }
 109  0
     }
 110  
 
 111  
     /**
 112  
      * Determines if a new version of the dependency-check engine has been released.
 113  
      *
 114  
      * @param lastChecked the epoch time of the last version check
 115  
      * @param now the current epoch time
 116  
      * @param properties the database properties object
 117  
      * @param currentVersion the current version of dependency-check
 118  
      * @return <code>true</code> if a newer version of the database has been released; otherwise <code>false</code>
 119  
      * @throws UpdateException thrown if there is an error connecting to the github documentation site or accessing the
 120  
      * local database.
 121  
      */
 122  
     protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties,
 123  
             String currentVersion) throws UpdateException {
 124  
         //check every 30 days if we know there is an update, otherwise check every 7 days
 125  7
         int checkRange = 30;
 126  7
         if (updateToVersion.isEmpty()) {
 127  2
             checkRange = 7;
 128  
         }
 129  7
         if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) {
 130  2
             LOGGER.fine("Checking web for new version.");
 131  2
             final String currentRelease = getCurrentReleaseVersion();
 132  2
             if (currentRelease != null) {
 133  2
                 final DependencyVersion v = new DependencyVersion(currentRelease);
 134  2
                 if (v.getVersionParts() != null && v.getVersionParts().size() >= 3) {
 135  2
                     updateToVersion = v.toString();
 136  2
                     if (!currentRelease.equals(updateToVersion)) {
 137  0
                         properties.save(CURRENT_ENGINE_RELEASE, updateToVersion);
 138  
                     } else {
 139  2
                         properties.save(CURRENT_ENGINE_RELEASE, "");
 140  
                     }
 141  2
                     properties.save(ENGINE_VERSION_CHECKED_ON, Long.toString(now));
 142  
                 }
 143  
             }
 144  2
             LOGGER.log(Level.FINE, "Current Release: {0}", updateToVersion);
 145  
         }
 146  7
         final DependencyVersion running = new DependencyVersion(currentVersion);
 147  7
         final DependencyVersion released = new DependencyVersion(updateToVersion);
 148  7
         if (running.compareTo(released) < 0) {
 149  3
             LOGGER.fine("Upgrade recommended");
 150  3
             return true;
 151  
         }
 152  4
         LOGGER.fine("Upgrade not needed");
 153  4
         return false;
 154  
     }
 155  
 
 156  
     /**
 157  
      * Opens the CVE and CPE data stores.
 158  
      *
 159  
      * @throws DatabaseException thrown if a data store cannot be opened
 160  
      */
 161  
     protected final void openDatabase() throws DatabaseException {
 162  0
         if (cveDB != null) {
 163  0
             return;
 164  
         }
 165  0
         cveDB = new CveDB();
 166  0
         cveDB.open();
 167  0
     }
 168  
 
 169  
     /**
 170  
      * Closes the CVE and CPE data stores.
 171  
      */
 172  
     protected void closeDatabase() {
 173  0
         if (cveDB != null) {
 174  
             try {
 175  0
                 cveDB.close();
 176  0
             } catch (Throwable ignore) {
 177  0
                 LOGGER.log(Level.FINEST, "Error closing the cveDB", ignore);
 178  0
             }
 179  
         }
 180  0
     }
 181  
 
 182  
     /**
 183  
      * Retrieves the current released version number from the github documentation site.
 184  
      *
 185  
      * @return the current released version number
 186  
      */
 187  
     protected String getCurrentReleaseVersion() {
 188  3
         HttpURLConnection conn = null;
 189  
         try {
 190  3
             final String str = Settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt");
 191  3
             final URL url = new URL(str);
 192  3
             conn = URLConnectionFactory.createHttpURLConnection(url);
 193  3
             conn.connect();
 194  3
             if (conn.getResponseCode() != 200) {
 195  0
                 return null;
 196  
             }
 197  3
             final String releaseVersion = IOUtils.toString(conn.getInputStream(), "UTF-8");
 198  3
             if (releaseVersion != null) {
 199  3
                 return releaseVersion.trim();
 200  
             }
 201  0
         } catch (MalformedURLException ex) {
 202  0
             LOGGER.log(Level.FINE, "unable to retrieve current release version of dependency-check", ex);
 203  0
         } catch (URLConnectionFailureException ex) {
 204  0
             LOGGER.log(Level.FINE, "unable to retrieve current release version of dependency-check", ex);
 205  0
         } catch (IOException ex) {
 206  0
             LOGGER.log(Level.FINE, "unable to retrieve current release version of dependency-check", ex);
 207  
         } finally {
 208  3
             if (conn != null) {
 209  3
                 conn.disconnect();
 210  
             }
 211  
         }
 212  0
         return null;
 213  
     }
 214  
 }