1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.data.update;
19
20 import java.io.IOException;
21 import java.net.MalformedURLException;
22 import java.net.URL;
23 import java.nio.charset.StandardCharsets;
24 import java.util.Arrays;
25 import javax.annotation.concurrent.ThreadSafe;
26
27 import org.owasp.dependencycheck.Engine;
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.Downloader;
35 import org.owasp.dependencycheck.utils.ResourceNotFoundException;
36 import org.owasp.dependencycheck.utils.Settings;
37 import org.owasp.dependencycheck.utils.TooManyRequestsException;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
42
43
44
45
46
47
48
49 @ThreadSafe
50 public class EngineVersionCheck implements CachedWebDataSource {
51
52
53
54
55 private static final Logger LOGGER = LoggerFactory.getLogger(EngineVersionCheck.class);
56
57
58
59 public static final String ENGINE_VERSION_CHECKED_ON = "VersionCheckOn";
60
61
62
63 public static final String CURRENT_ENGINE_RELEASE = "CurrentEngineRelease";
64
65
66
67
68 private String updateToVersion;
69
70
71
72 private Settings settings;
73
74
75
76
77
78
79 protected EngineVersionCheck(Settings settings) {
80 this.settings = settings;
81 }
82
83
84
85
86 public EngineVersionCheck() {
87 }
88
89
90
91
92
93
94
95 protected String getUpdateToVersion() {
96 return updateToVersion;
97 }
98
99
100
101
102
103
104
105 protected void setUpdateToVersion(String version) {
106 updateToVersion = version;
107 }
108
109
110
111
112
113
114
115
116
117
118
119 @Override
120 public boolean update(Engine engine) throws UpdateException {
121 this.settings = engine.getSettings();
122 try {
123 final CveDB db = engine.getDatabase();
124 final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
125 final boolean enabled = settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true);
126 final String datafeed = settings.getString(Settings.KEYS.NVD_API_DATAFEED_URL);
127
128
129
130
131
132
133 if (enabled && autoupdate && datafeed != null) {
134 LOGGER.debug("Begin Engine Version Check");
135
136 final DatabaseProperties properties = db.getDatabaseProperties();
137
138 final long lastChecked = DateUtil.getEpochValueInSeconds(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
139 final long now = System.currentTimeMillis() / 1000;
140 updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
141 final String currentVersion = settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
142 LOGGER.debug("Last checked: {}", lastChecked);
143 LOGGER.debug("Now: {}", now);
144 LOGGER.debug("Current version: {}", currentVersion);
145 final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
146 if (updateNeeded) {
147 LOGGER.warn("A new version of dependency-check is available. Consider updating to version {}.",
148 updateToVersion);
149 }
150 }
151 } catch (DatabaseException ex) {
152 LOGGER.debug("Database Exception opening databases to retrieve properties", ex);
153 throw new UpdateException("Error occurred updating database properties.");
154 }
155 return false;
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties,
172 String currentVersion) throws UpdateException {
173
174 final int checkRange = 30;
175 if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) {
176 LOGGER.debug("Checking web for new version.");
177 final String publishedData = getCurrentReleaseVersion();
178 if (publishedData != null) {
179 final String[] parts = publishedData.split("\n");
180 if (parts.length > 1) {
181 final String message = String.join("\n", Arrays.copyOfRange(parts, 1, parts.length)).trim();
182 LOGGER.warn("\n\n*********************************************************\n"
183 + message
184 + "\n*********************************************************\n");
185 }
186 final String currentRelease = parts[0].trim();
187 final DependencyVersion v = new DependencyVersion(currentRelease);
188 if (v.getVersionParts() != null && v.getVersionParts().size() >= 3) {
189 updateToVersion = v.toString();
190 if (!currentRelease.equals(updateToVersion)) {
191 properties.save(CURRENT_ENGINE_RELEASE, updateToVersion);
192 }
193 properties.save(ENGINE_VERSION_CHECKED_ON, Long.toString(now));
194 }
195 }
196 LOGGER.debug("Current Release: {}", updateToVersion);
197 }
198 if (updateToVersion == null) {
199 LOGGER.debug("Unable to obtain current release");
200 return false;
201 }
202 final DependencyVersion running = new DependencyVersion(currentVersion);
203 final DependencyVersion released = new DependencyVersion(updateToVersion);
204 if (running.compareTo(released) < 0) {
205 LOGGER.debug("Upgrade recommended");
206 return true;
207 }
208 LOGGER.debug("Upgrade not needed");
209 return false;
210 }
211
212
213
214
215
216
217
218 protected String getCurrentReleaseVersion() {
219 try {
220 final String str = settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "https://dependency-check.github.io/DependencyCheck/current.txt");
221 final URL url = new URL(str);
222 String releaseVersion = null;
223 releaseVersion = Downloader.getInstance().fetchContent(url, StandardCharsets.UTF_8);
224 return releaseVersion.trim();
225 } catch (TooManyRequestsException ex) {
226 LOGGER.debug("Unable to retrieve current release version of dependency-check - downloader failed on HTTP 429 Too many requests");
227 } catch (ResourceNotFoundException ex) {
228 LOGGER.debug("Unable to retrieve current release version of dependency-check - downloader failed on HTTP 404 ResourceNotFound");
229 } catch (MalformedURLException ex) {
230 LOGGER.debug("Unable to retrieve current release version of dependency-check - malformed url?");
231 } catch (IOException ex) {
232 LOGGER.debug("Unable to retrieve current release version of dependency-check - i/o exception");
233 }
234 return null;
235 }
236
237 @Override
238 public boolean purge(Engine engine) {
239 return true;
240 }
241 }