1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck;
19
20 import org.owasp.dependencycheck.analyzer.AnalysisPhase;
21 import org.owasp.dependencycheck.analyzer.Analyzer;
22 import org.owasp.dependencycheck.analyzer.AnalyzerService;
23 import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
24 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
25 import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
26 import org.owasp.dependencycheck.data.nvdcve.CveDB;
27 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
28 import org.owasp.dependencycheck.data.update.CachedWebDataSource;
29 import org.owasp.dependencycheck.data.update.UpdateService;
30 import org.owasp.dependencycheck.data.update.exception.UpdateException;
31 import org.owasp.dependencycheck.dependency.Dependency;
32 import org.owasp.dependencycheck.exception.NoDataException;
33 import org.owasp.dependencycheck.utils.InvalidSettingException;
34 import org.owasp.dependencycheck.utils.Settings;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import java.io.File;
39 import java.io.FileFilter;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.EnumMap;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48
49
50
51
52
53
54
55 public class Engine implements FileFilter {
56
57
58
59
60 private List<Dependency> dependencies = new ArrayList<Dependency>();
61
62
63
64 private Map<AnalysisPhase, List<Analyzer>> analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
65
66
67
68
69 private Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
70
71
72
73
74 private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
75
76
77
78 private static final Logger LOGGER = LoggerFactory.getLogger(Engine.class);
79
80
81
82
83
84
85 public Engine() throws DatabaseException {
86 initializeEngine();
87 }
88
89
90
91
92
93
94
95 public Engine(ClassLoader serviceClassLoader) throws DatabaseException {
96 this.serviceClassLoader = serviceClassLoader;
97 initializeEngine();
98 }
99
100
101
102
103
104
105 protected final void initializeEngine() throws DatabaseException {
106 ConnectionFactory.initialize();
107 loadAnalyzers();
108 }
109
110
111
112
113 public void cleanup() {
114 ConnectionFactory.cleanup();
115 }
116
117
118
119
120 private void loadAnalyzers() {
121 if (!analyzers.isEmpty()) {
122 return;
123 }
124 for (AnalysisPhase phase : AnalysisPhase.values()) {
125 analyzers.put(phase, new ArrayList<Analyzer>());
126 }
127
128 final AnalyzerService service = new AnalyzerService(serviceClassLoader);
129 final Iterator<Analyzer> iterator = service.getAnalyzers();
130 while (iterator.hasNext()) {
131 final Analyzer a = iterator.next();
132 analyzers.get(a.getAnalysisPhase()).add(a);
133 if (a instanceof FileTypeAnalyzer) {
134 this.fileTypeAnalyzers.add((FileTypeAnalyzer) a);
135 }
136 }
137 }
138
139
140
141
142
143
144
145 public List<Analyzer> getAnalyzers(AnalysisPhase phase) {
146 return analyzers.get(phase);
147 }
148
149
150
151
152
153
154 public List<Dependency> getDependencies() {
155 return dependencies;
156 }
157
158
159
160
161
162
163 public void setDependencies(List<Dependency> dependencies) {
164 this.dependencies = dependencies;
165 }
166
167
168
169
170
171
172
173
174
175 public List<Dependency> scan(String[] paths) {
176 final List<Dependency> deps = new ArrayList<Dependency>();
177 for (String path : paths) {
178 final List<Dependency> d = scan(path);
179 if (d != null) {
180 deps.addAll(d);
181 }
182 }
183 return deps;
184 }
185
186
187
188
189
190
191
192
193 public List<Dependency> scan(String path) {
194 final File file = new File(path);
195 return scan(file);
196 }
197
198
199
200
201
202
203
204
205
206 public List<Dependency> scan(File[] files) {
207 final List<Dependency> deps = new ArrayList<Dependency>();
208 for (File file : files) {
209 final List<Dependency> d = scan(file);
210 if (d != null) {
211 deps.addAll(d);
212 }
213 }
214 return deps;
215 }
216
217
218
219
220
221
222
223
224
225 public List<Dependency> scan(Collection<File> files) {
226 final List<Dependency> deps = new ArrayList<Dependency>();
227 for (File file : files) {
228 final List<Dependency> d = scan(file);
229 if (d != null) {
230 deps.addAll(d);
231 }
232 }
233 return deps;
234 }
235
236
237
238
239
240
241
242
243
244 public List<Dependency> scan(File file) {
245 if (file.exists()) {
246 if (file.isDirectory()) {
247 return scanDirectory(file);
248 } else {
249 final Dependency d = scanFile(file);
250 if (d != null) {
251 final List<Dependency> deps = new ArrayList<Dependency>();
252 deps.add(d);
253 return deps;
254 }
255 }
256 }
257 return null;
258 }
259
260
261
262
263
264
265
266 protected List<Dependency> scanDirectory(File dir) {
267 final File[] files = dir.listFiles();
268 final List<Dependency> deps = new ArrayList<Dependency>();
269 if (files != null) {
270 for (File f : files) {
271 if (f.isDirectory()) {
272 final List<Dependency> d = scanDirectory(f);
273 if (d != null) {
274 deps.addAll(d);
275 }
276 } else {
277 final Dependency d = scanFile(f);
278 deps.add(d);
279 }
280 }
281 }
282 return deps;
283 }
284
285
286
287
288
289
290
291 protected Dependency scanFile(File file) {
292 Dependency dependency = null;
293 if (file.isFile()) {
294 if (accept(file)) {
295 dependency = new Dependency(file);
296 dependencies.add(dependency);
297 }
298 } else {
299 LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
300 }
301 return dependency;
302 }
303
304
305
306
307
308
309
310 public void analyzeDependencies() {
311 boolean autoUpdate = true;
312 try {
313 autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
314 } catch (InvalidSettingException ex) {
315 LOGGER.debug("Invalid setting for auto-update; using true.");
316 }
317 if (autoUpdate) {
318 doUpdates();
319 }
320
321
322 try {
323 ensureDataExists();
324 } catch (NoDataException ex) {
325 LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
326 LOGGER.debug("", ex);
327 return;
328 } catch (DatabaseException ex) {
329 LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
330 LOGGER.debug("", ex);
331 return;
332
333 }
334
335 LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
336 LOGGER.info("Analysis Starting");
337 final long analysisStart = System.currentTimeMillis();
338
339
340 for (AnalysisPhase phase : AnalysisPhase.values()) {
341 final List<Analyzer> analyzerList = analyzers.get(phase);
342
343 for (Analyzer a : analyzerList) {
344 a = initializeAnalyzer(a);
345
346
347
348
349
350 LOGGER.debug("Begin Analyzer '{}'", a.getName());
351 final Set<Dependency> dependencySet = new HashSet<Dependency>(dependencies);
352 for (Dependency d : dependencySet) {
353 boolean shouldAnalyze = true;
354 if (a instanceof FileTypeAnalyzer) {
355 final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
356 shouldAnalyze = fAnalyzer.accept(d.getActualFile());
357 }
358 if (shouldAnalyze) {
359 LOGGER.debug("Begin Analysis of '{}'", d.getActualFilePath());
360 try {
361 a.analyze(d, this);
362 } catch (AnalysisException ex) {
363 LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath());
364 LOGGER.debug("", ex);
365 } catch (Throwable ex) {
366
367 LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath());
368 LOGGER.debug("", ex);
369 }
370 }
371 }
372 }
373 }
374 for (AnalysisPhase phase : AnalysisPhase.values()) {
375 final List<Analyzer> analyzerList = analyzers.get(phase);
376
377 for (Analyzer a : analyzerList) {
378 closeAnalyzer(a);
379 }
380 }
381
382 LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
383 LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart);
384 }
385
386
387
388
389
390
391
392 protected Analyzer initializeAnalyzer(Analyzer analyzer) {
393 try {
394 LOGGER.debug("Initializing {}", analyzer.getName());
395 analyzer.initialize();
396 } catch (Throwable ex) {
397 LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
398 LOGGER.debug("", ex);
399 try {
400 analyzer.close();
401 } catch (Throwable ex1) {
402 LOGGER.trace("", ex1);
403 }
404 }
405 return analyzer;
406 }
407
408
409
410
411
412
413 protected void closeAnalyzer(Analyzer analyzer) {
414 LOGGER.debug("Closing Analyzer '{}'", analyzer.getName());
415 try {
416 analyzer.close();
417 } catch (Throwable ex) {
418 LOGGER.trace("", ex);
419 }
420 }
421
422
423
424
425 public void doUpdates() {
426 LOGGER.info("Checking for updates");
427 final long updateStart = System.currentTimeMillis();
428 final UpdateService service = new UpdateService(serviceClassLoader);
429 final Iterator<CachedWebDataSource> iterator = service.getDataSources();
430 while (iterator.hasNext()) {
431 final CachedWebDataSource source = iterator.next();
432 try {
433 source.update();
434 } catch (UpdateException ex) {
435 LOGGER.warn(
436 "Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
437 LOGGER.debug("Unable to update details for {}", source.getClass().getName(), ex);
438 }
439 }
440 LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart);
441 }
442
443
444
445
446
447
448 public List<Analyzer> getAnalyzers() {
449 final List<Analyzer> ret = new ArrayList<Analyzer>();
450 for (AnalysisPhase phase : AnalysisPhase.values()) {
451 final List<Analyzer> analyzerList = analyzers.get(phase);
452 ret.addAll(analyzerList);
453 }
454 return ret;
455 }
456
457
458
459
460
461
462
463 @Override
464 public boolean accept(File file) {
465 if (file == null) {
466 return false;
467 }
468 boolean scan = false;
469 for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
470
471
472 scan |= a.accept(file);
473 }
474 return scan;
475 }
476
477
478
479
480
481
482 public Set<FileTypeAnalyzer> getFileTypeAnalyzers() {
483 return this.fileTypeAnalyzers;
484 }
485
486
487
488
489
490
491
492 private void ensureDataExists() throws NoDataException, DatabaseException {
493 final CveDB cve = new CveDB();
494 try {
495 cve.open();
496 if (!cve.dataExists()) {
497 throw new NoDataException("No documents exist");
498 }
499 } catch (DatabaseException ex) {
500 throw new NoDataException(ex.getMessage(), ex);
501 } finally {
502 cve.close();
503 }
504 }
505 }