View Javadoc
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) 2015 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.data.update;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.net.MalformedURLException;
23  import java.net.URL;
24  import java.util.List;
25  import javax.xml.parsers.ParserConfigurationException;
26  import javax.xml.parsers.SAXParser;
27  import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.LAST_CPE_UPDATE;
28  import org.owasp.dependencycheck.data.update.cpe.CPEHandler;
29  import org.owasp.dependencycheck.data.update.cpe.Cpe;
30  import org.owasp.dependencycheck.data.update.exception.UpdateException;
31  import org.owasp.dependencycheck.utils.DateUtil;
32  import org.owasp.dependencycheck.utils.DownloadFailedException;
33  import org.owasp.dependencycheck.utils.Downloader;
34  import org.owasp.dependencycheck.utils.ExtractionUtil;
35  import org.owasp.dependencycheck.utils.Settings;
36  import org.owasp.dependencycheck.utils.XmlUtils;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  import org.xml.sax.SAXException;
40  
41  /**
42   *
43   * This class is currently unused and if enabled will likely not work on MySQL
44   * as the MERGE statement is used.
45   *
46   * The CpeUpdater is designed to download the CPE data file from NIST and import
47   * the data into the database. However, as this currently adds no beneficial
48   * data, compared to what is in the CPE data contained in the CVE data files,
49   * this class is not currently used. The code is being kept as a future update
50   * may utilize more data from the CPE XML files.
51   *
52   * @deprecated the CPE updater is not currently used.
53   * @author Jeremy Long
54   */
55  @Deprecated
56  public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
57  
58      /**
59       * Static logger.
60       */
61      private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
62  
63      @Override
64      public void update() throws UpdateException {
65          /*
66          //the following could be used if this were ever used.
67          try {
68              if (!Settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) {
69                  return;
70              }
71          } catch (InvalidSettingException ex) {
72              LOGGER.trace("inavlid setting UPDATE_NVDCVE_ENABLED", ex);
73          }
74           */
75  
76          try {
77              openDataStores();
78              if (updateNeeded()) {
79                  LOGGER.info("Updating the Common Platform Enumeration (CPE)");
80                  final File xml = downloadCpe();
81                  final List<Cpe> cpes = processXML(xml);
82                  getCveDB().deleteUnusedCpe();
83                  for (Cpe cpe : cpes) {
84                      getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
85                  }
86                  final long now = System.currentTimeMillis();
87                  getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
88                  LOGGER.info("CPE update complete");
89              }
90          } finally {
91              closeDataStores();
92          }
93      }
94  
95      /**
96       * Downloads the CPE XML file.
97       *
98       * @return the file reference to the CPE.xml file
99       * @throws UpdateException thrown if there is an issue downloading the XML
100      * file
101      */
102     private File downloadCpe() throws UpdateException {
103         File xml;
104         final URL url;
105         try {
106             url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
107             xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
108             Downloader.fetchFile(url, xml);
109             if (url.toExternalForm().endsWith(".xml.gz")) {
110                 ExtractionUtil.extractGzip(xml);
111             }
112 
113         } catch (MalformedURLException ex) {
114             throw new UpdateException("Invalid CPE URL", ex);
115         } catch (DownloadFailedException ex) {
116             throw new UpdateException("Unable to download CPE XML file", ex);
117         } catch (IOException ex) {
118             throw new UpdateException("Unable to create temporary file to download CPE", ex);
119         }
120         return xml;
121     }
122 
123     /**
124      * Parses the CPE XML file to return a list of CPE entries.
125      *
126      * @param xml the CPE data file
127      * @return the list of CPE entries
128      * @throws UpdateException thrown if there is an issue with parsing the XML
129      * file
130      */
131     private List<Cpe> processXML(final File xml) throws UpdateException {
132         try {
133             final SAXParser saxParser = XmlUtils.buildSecureSaxParser();
134             final CPEHandler handler = new CPEHandler();
135             saxParser.parse(xml, handler);
136             return handler.getData();
137         } catch (ParserConfigurationException ex) {
138             throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
139         } catch (SAXException ex) {
140             throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
141         } catch (IOException ex) {
142             throw new UpdateException("Unable to parse CPE XML file due to IO Failure", ex);
143         }
144     }
145 
146     /**
147      * Checks to find the last time the CPE data was refreshed and if it needs
148      * to be updated.
149      *
150      * @return true if the CPE data should be refreshed
151      */
152     private boolean updateNeeded() {
153         final long now = System.currentTimeMillis();
154         final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
155         long timestamp = 0;
156         final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
157         if (ts != null && ts.matches("^[0-9]+$")) {
158             timestamp = Long.parseLong(ts);
159         }
160         return !DateUtil.withinDateRange(timestamp, now, days);
161     }
162 }