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