Coverage Report - org.owasp.dependencycheck.data.update.EngineVersionCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
EngineVersionCheck
41%
35/85
35%
12/34
5.143
 
 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 org.apache.commons.io.IOUtils;
 25  
 import org.owasp.dependencycheck.data.nvdcve.CveDB;
 26  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
 27  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
 28  
 import org.owasp.dependencycheck.data.update.exception.UpdateException;
 29  
 import org.owasp.dependencycheck.utils.DateUtil;
 30  
 import org.owasp.dependencycheck.utils.DependencyVersion;
 31  
 import org.owasp.dependencycheck.utils.InvalidSettingException;
 32  
 import org.owasp.dependencycheck.utils.Settings;
 33  
 import org.owasp.dependencycheck.utils.URLConnectionFactory;
 34  
 import org.owasp.dependencycheck.utils.URLConnectionFailureException;
 35  
 import org.slf4j.Logger;
 36  
 import org.slf4j.LoggerFactory;
 37  
 
 38  
 /**
 39  
  * Checks the gh-pages dependency-check site to determine the current released
 40  
  * version number. If the released version number is greater then the running
 41  
  * version number a warning is printed recommending that an upgrade be
 42  
  * performed.
 43  
  *
 44  
  * @author Jeremy Long
 45  
  */
 46  2
 public class EngineVersionCheck implements CachedWebDataSource {
 47  
 
 48  
     /**
 49  
      * Static logger.
 50  
      */
 51  1
     private static final Logger LOGGER = LoggerFactory.getLogger(EngineVersionCheck.class);
 52  
     /**
 53  
      * The property key indicating when the last version check occurred.
 54  
      */
 55  
     public static final String ENGINE_VERSION_CHECKED_ON = "VersionCheckOn";
 56  
     /**
 57  
      * The property key indicating when the last version check occurred.
 58  
      */
 59  
     public static final String CURRENT_ENGINE_RELEASE = "CurrentEngineRelease";
 60  
     /**
 61  
      * Reference to the Cve Database.
 62  
      */
 63  2
     private CveDB cveDB = null;
 64  
 
 65  
     /**
 66  
      * The version retrieved from the database properties or web to check
 67  
      * against.
 68  
      */
 69  
     private String updateToVersion;
 70  
 
 71  
     /**
 72  
      * Getter for updateToVersion - only used for testing. Represents the
 73  
      * version retrieved from the database.
 74  
      *
 75  
      * @return the version to test
 76  
      */
 77  
     protected String getUpdateToVersion() {
 78  0
         return updateToVersion;
 79  
     }
 80  
 
 81  
     /**
 82  
      * Setter for updateToVersion - only used for testing. Represents the
 83  
      * version retrieved from the database.
 84  
      *
 85  
      * @param version the version to test
 86  
      */
 87  
     protected void setUpdateToVersion(String version) {
 88  7
         updateToVersion = version;
 89  7
     }
 90  
 
 91  
     /**
 92  
      * Downloads the current released version number and compares it to the
 93  
      * running engine's version number. If the released version number is newer
 94  
      * a warning is printed recommending an upgrade.
 95  
      *
 96  
      * @throws UpdateException thrown if the local database properties could not
 97  
      * be updated
 98  
      */
 99  
     @Override
 100  
     public void update() throws UpdateException {
 101  
         try {
 102  0
             final boolean autoupdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
 103  0
             final boolean enabled = Settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true);
 104  0
             final String original = Settings.getString(Settings.KEYS.CVE_ORIGINAL_MODIFIED_20_URL);
 105  0
             final String current = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
 106  
             /**
 107  
              * Only update if auto-update is enabled, the engine check is
 108  
              * enabled, and the NVD CVE URLs have not been modified (i.e. the
 109  
              * user has not configured them to point to an internal source).
 110  
              */
 111  0
             if (enabled && autoupdate && original != null && original.equals(current)) {
 112  0
                 openDatabase();
 113  0
                 LOGGER.debug("Begin Engine Version Check");
 114  0
                 final DatabaseProperties properties = cveDB.getDatabaseProperties();
 115  0
                 final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
 116  0
                 final long now = System.currentTimeMillis();
 117  0
                 updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
 118  0
                 final String currentVersion = Settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
 119  0
                 LOGGER.debug("Last checked: {}", lastChecked);
 120  0
                 LOGGER.debug("Now: {}", now);
 121  0
                 LOGGER.debug("Current version: {}", currentVersion);
 122  0
                 final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
 123  0
                 if (updateNeeded) {
 124  0
                     LOGGER.warn("A new version of dependency-check is available. Consider updating to version {}.",
 125  
                             updateToVersion);
 126  
                 }
 127  
             }
 128  0
         } catch (DatabaseException ex) {
 129  0
             LOGGER.debug("Database Exception opening databases to retrieve properties", ex);
 130  0
             throw new UpdateException("Error occurred updating database properties.");
 131  0
         } catch (InvalidSettingException ex) {
 132  0
             LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
 133  
         } finally {
 134  0
             closeDatabase();
 135  0
         }
 136  0
     }
 137  
 
 138  
     /**
 139  
      * Determines if a new version of the dependency-check engine has been
 140  
      * released.
 141  
      *
 142  
      * @param lastChecked the epoch time of the last version check
 143  
      * @param now the current epoch time
 144  
      * @param properties the database properties object
 145  
      * @param currentVersion the current version of dependency-check
 146  
      * @return <code>true</code> if a newer version of the database has been
 147  
      * released; otherwise <code>false</code>
 148  
      * @throws UpdateException thrown if there is an error connecting to the
 149  
      * github documentation site or accessing the local database.
 150  
      */
 151  
     protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties,
 152  
             String currentVersion) throws UpdateException {
 153  
         //check every 30 days if we know there is an update, otherwise check every 7 days
 154  7
         final int checkRange = 30;
 155  7
         if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) {
 156  2
             LOGGER.debug("Checking web for new version.");
 157  2
             final String currentRelease = getCurrentReleaseVersion();
 158  2
             if (currentRelease != null) {
 159  2
                 final DependencyVersion v = new DependencyVersion(currentRelease);
 160  2
                 if (v.getVersionParts() != null && v.getVersionParts().size() >= 3) {
 161  2
                     updateToVersion = v.toString();
 162  2
                     if (!currentRelease.equals(updateToVersion)) {
 163  0
                         properties.save(CURRENT_ENGINE_RELEASE, updateToVersion);
 164  
                     }
 165  2
                     properties.save(ENGINE_VERSION_CHECKED_ON, Long.toString(now));
 166  
                 }
 167  
             }
 168  2
             LOGGER.debug("Current Release: {}", updateToVersion);
 169  
         }
 170  7
         if (updateToVersion == null) {
 171  0
             LOGGER.debug("Unable to obtain current release");
 172  0
             return false;
 173  
         }
 174  7
         final DependencyVersion running = new DependencyVersion(currentVersion);
 175  7
         final DependencyVersion released = new DependencyVersion(updateToVersion);
 176  7
         if (running.compareTo(released) < 0) {
 177  3
             LOGGER.debug("Upgrade recommended");
 178  3
             return true;
 179  
         }
 180  4
         LOGGER.debug("Upgrade not needed");
 181  4
         return false;
 182  
     }
 183  
 
 184  
     /**
 185  
      * Opens the CVE and CPE data stores.
 186  
      *
 187  
      * @throws DatabaseException thrown if a data store cannot be opened
 188  
      */
 189  
     protected final void openDatabase() throws DatabaseException {
 190  0
         if (cveDB != null) {
 191  0
             return;
 192  
         }
 193  0
         cveDB = new CveDB();
 194  0
         cveDB.open();
 195  0
     }
 196  
 
 197  
     /**
 198  
      * Closes the CVE and CPE data stores.
 199  
      */
 200  
     protected void closeDatabase() {
 201  0
         if (cveDB != null) {
 202  
             try {
 203  0
                 cveDB.close();
 204  0
                 cveDB = null;
 205  0
             } catch (Throwable ignore) {
 206  0
                 LOGGER.trace("Error closing the cveDB", ignore);
 207  0
             }
 208  
         }
 209  0
     }
 210  
 
 211  
     /**
 212  
      * Retrieves the current released version number from the github
 213  
      * documentation site.
 214  
      *
 215  
      * @return the current released version number
 216  
      */
 217  
     protected String getCurrentReleaseVersion() {
 218  3
         HttpURLConnection conn = null;
 219  
         try {
 220  3
             final String str = Settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt");
 221  3
             final URL url = new URL(str);
 222  3
             conn = URLConnectionFactory.createHttpURLConnection(url);
 223  3
             conn.connect();
 224  3
             if (conn.getResponseCode() != 200) {
 225  0
                 return null;
 226  
             }
 227  3
             final String releaseVersion = IOUtils.toString(conn.getInputStream(), "UTF-8");
 228  3
             if (releaseVersion != null) {
 229  6
                 return releaseVersion.trim();
 230  
             }
 231  0
         } catch (MalformedURLException ex) {
 232  0
             LOGGER.debug("Unable to retrieve current release version of dependency-check - malformed url?");
 233  0
         } catch (URLConnectionFailureException ex) {
 234  0
             LOGGER.debug("Unable to retrieve current release version of dependency-check - connection failed");
 235  0
         } catch (IOException ex) {
 236  0
             LOGGER.debug("Unable to retrieve current release version of dependency-check - i/o exception");
 237  
         } finally {
 238  3
             if (conn != null) {
 239  3
                 conn.disconnect();
 240  
             }
 241  
         }
 242  0
         return null;
 243  
     }
 244  
 }