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.File;
21 import java.io.IOException;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import javax.annotation.concurrent.ThreadSafe;
25
26 import org.owasp.dependencycheck.Engine;
27 import org.owasp.dependencycheck.data.update.exception.UpdateException;
28 import org.owasp.dependencycheck.exception.WriteLockException;
29 import org.owasp.dependencycheck.utils.Downloader;
30 import org.owasp.dependencycheck.utils.ResourceNotFoundException;
31 import org.owasp.dependencycheck.utils.Settings;
32 import org.owasp.dependencycheck.utils.TooManyRequestsException;
33 import org.owasp.dependencycheck.utils.WriteLock;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37
38
39
40
41
42 @ThreadSafe
43 public class RetireJSDataSource extends LocalDataSource {
44
45
46
47
48 private static final Logger LOGGER = LoggerFactory.getLogger(RetireJSDataSource.class);
49
50
51
52 public static final String RETIREJS_UPDATED_ON = "RetireJSUpdatedOn";
53
54
55
56 private Settings settings;
57
58
59
60 public static final String DEFAULT_JS_URL = "https://raw.githubusercontent.com/Retirejs/retire.js/master/repository/jsrepository.json";
61
62
63
64
65 public RetireJSDataSource() {
66 }
67
68
69
70
71
72
73
74
75 @Override
76 public boolean update(Engine engine) throws UpdateException {
77 this.settings = engine.getSettings();
78 final String configuredUrl = settings.getString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, DEFAULT_JS_URL);
79 final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
80 final boolean forceupdate = settings.getBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, false);
81 final boolean enabled = settings.getBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
82 try {
83 final URL url = new URL(configuredUrl);
84 final File filepath = new File(url.getPath());
85 final File repoFile = new File(settings.getDataDirectory(), filepath.getName());
86 final boolean proceed = enabled && (forceupdate || (autoupdate && shouldUpdate(repoFile)));
87 if (proceed) {
88 LOGGER.debug("Begin RetireJS Update");
89 initializeRetireJsRepo(settings, url, repoFile);
90 saveLastUpdated(repoFile, System.currentTimeMillis() / 1000);
91 }
92 } catch (MalformedURLException ex) {
93 throw new UpdateException(String.format("Invalid URL for RetireJS repository (%s)", configuredUrl), ex);
94 } catch (IOException ex) {
95 throw new UpdateException("Unable to get the data directory", ex);
96 }
97 return false;
98 }
99
100
101
102
103
104
105
106
107
108
109 protected boolean shouldUpdate(File repo) throws NumberFormatException {
110 boolean proceed = true;
111 if (repo != null && repo.isFile()) {
112 final int validForHours = settings.getInt(Settings.KEYS.ANALYZER_RETIREJS_REPO_VALID_FOR_HOURS, 0);
113 final long lastUpdatedOn = getLastUpdated(repo);
114 final long now = System.currentTimeMillis();
115 LOGGER.debug("Last updated: {}", lastUpdatedOn);
116 LOGGER.debug("Now: {}", now);
117 final long msValid = validForHours * 60L * 60L * 1000L;
118 proceed = (now - lastUpdatedOn) > msValid;
119 if (!proceed) {
120 LOGGER.info("Skipping RetireJS update since last update was within {} hours.", validForHours);
121 }
122 }
123 return proceed;
124 }
125
126
127
128
129
130
131
132
133
134
135
136 @SuppressWarnings("try")
137 private void initializeRetireJsRepo(Settings settings, URL repoUrl, File repoFile) throws UpdateException {
138 try (WriteLock lock = new WriteLock(settings, true, repoFile.getName() + ".lock")) {
139 LOGGER.debug("RetireJS Repo URL: {}", repoUrl.toExternalForm());
140 Downloader.getInstance().fetchFile(repoUrl, repoFile);
141 } catch (IOException | TooManyRequestsException | ResourceNotFoundException | WriteLockException ex) {
142 throw new UpdateException("Failed to initialize the RetireJS repo", ex);
143 }
144 }
145
146 @Override
147 @SuppressWarnings("try")
148 public boolean purge(Engine engine) {
149 this.settings = engine.getSettings();
150 boolean result = true;
151 try {
152 final File dataDir = engine.getSettings().getDataDirectory();
153 final URL repoUrl = new URL(engine.getSettings().getString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, DEFAULT_JS_URL));
154 final String filename = repoUrl.getFile().substring(repoUrl.getFile().lastIndexOf("/") + 1);
155 final File repo = new File(dataDir, filename);
156 if (repo.exists()) {
157 try (WriteLock lock = new WriteLock(settings, true, filename + ".lock")) {
158 if (repo.delete()) {
159 LOGGER.info("RetireJS repo removed successfully");
160 } else {
161 LOGGER.error("Unable to delete '{}'; please delete the file manually", repo.getAbsolutePath());
162 result = false;
163 }
164 }
165 }
166 } catch (WriteLockException | IOException ex) {
167 LOGGER.error("Unable to delete the RetireJS repo - invalid configuration");
168 result = false;
169 }
170 return result;
171 }
172 }