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) 2012 Jeremy Long. All Rights Reserved.
17 */
18 package org.owasp.dependencycheck.dependency;
19
20 import java.io.Serializable;
21 import java.util.Collections;
22 import java.util.Set;
23 import java.util.TreeSet;
24 import javax.annotation.concurrent.ThreadSafe;
25 import org.apache.commons.lang3.builder.EqualsBuilder;
26 import org.apache.commons.lang3.builder.HashCodeBuilder;
27 import org.owasp.dependencycheck.utils.Filter;
28
29 /**
30 * Used to maintain a collection of Evidence.
31 *
32 * @author Jeremy Long
33 */
34 @ThreadSafe
35 class EvidenceCollection implements Serializable {
36
37 /**
38 * The serial version UID for serialization.
39 */
40 private static final long serialVersionUID = 867580958972090027L;
41 /**
42 * A collection of vendor evidence.
43 */
44 private final Set<Evidence> vendors = new TreeSet<>();
45 /**
46 * A collection of strings used to adjust Lucene's vendor term weighting.
47 */
48 private final Set<String> vendorWeightings = new TreeSet<>();
49 /**
50 * A collection of product evidence.
51 */
52 private final Set<Evidence> products = new TreeSet<>();
53 /**
54 * A collection of strings used to adjust Lucene's product term weighting.
55 */
56 private final Set<String> productWeightings = new TreeSet<>();
57 /**
58 * A collection of version evidence.
59 */
60 private final Set<Evidence> versions = new TreeSet<>();
61
62 /**
63 * Used to iterate over highest confidence evidence contained in the
64 * collection.
65 */
66 private static final Filter<Evidence> HIGHEST_CONFIDENCE = new Filter<Evidence>() {
67 @Override
68 public boolean passes(Evidence evidence) {
69 return evidence.getConfidence() == Confidence.HIGHEST;
70 }
71 };
72 /**
73 * Used to iterate over high confidence evidence contained in the
74 * collection.
75 */
76 private static final Filter<Evidence> HIGH_CONFIDENCE = new Filter<Evidence>() {
77 @Override
78 public boolean passes(Evidence evidence) {
79 return evidence.getConfidence() == Confidence.HIGH;
80 }
81 };
82 /**
83 * Used to iterate over medium confidence evidence contained in the
84 * collection.
85 */
86 private static final Filter<Evidence> MEDIUM_CONFIDENCE = new Filter<Evidence>() {
87 @Override
88 public boolean passes(Evidence evidence) {
89 return evidence.getConfidence() == Confidence.MEDIUM;
90 }
91 };
92 /**
93 * Used to iterate over low confidence evidence contained in the collection.
94 */
95 private static final Filter<Evidence> LOW_CONFIDENCE = new Filter<Evidence>() {
96 @Override
97 public boolean passes(Evidence evidence) {
98 return evidence.getConfidence() == Confidence.LOW;
99 }
100 };
101
102 /**
103 * Used to iterate over evidence of the specified type and confidence.
104 *
105 * @param type the evidence type to iterate over
106 * @param confidence the confidence level for the evidence to be iterated
107 * over.
108 * @return Iterable<Evidence> an iterable collection of evidence
109 */
110 public synchronized Iterable<Evidence> getIterator(EvidenceType type, Confidence confidence) {
111 if (null != confidence && null != type) {
112 final Set<Evidence> list;
113
114 switch (type) {
115 case VENDOR:
116 list = Collections.unmodifiableSet(new TreeSet<>(vendors));
117 break;
118 case PRODUCT:
119 list = Collections.unmodifiableSet(new TreeSet<>(products));
120 break;
121 case VERSION:
122 list = Collections.unmodifiableSet(new TreeSet<>(versions));
123 break;
124 default:
125 return null;
126 }
127
128 switch (confidence) {
129 case HIGHEST:
130 return EvidenceCollection.HIGHEST_CONFIDENCE.filter(list);
131 case HIGH:
132 return EvidenceCollection.HIGH_CONFIDENCE.filter(list);
133 case MEDIUM:
134 return EvidenceCollection.MEDIUM_CONFIDENCE.filter(list);
135 default:
136 return EvidenceCollection.LOW_CONFIDENCE.filter(list);
137 }
138 }
139 return null;
140 }
141
142 /**
143 * Adds evidence to the collection.
144 *
145 * @param type the type of evidence (vendor, product, version)
146 * @param e Evidence
147 */
148 public synchronized void addEvidence(EvidenceType type, Evidence e) {
149 if (null != type) {
150 switch (type) {
151 case VENDOR:
152 vendors.add(e);
153 break;
154 case PRODUCT:
155 products.add(e);
156 break;
157 case VERSION:
158 versions.add(e);
159 break;
160 default:
161 break;
162 }
163 }
164 }
165
166 /**
167 * Removes evidence from the collection.
168 *
169 * @param type the type of evidence (vendor, product, version)
170 * @param e Evidence.
171 */
172 public synchronized void removeEvidence(EvidenceType type, Evidence e) {
173 if (null != type) {
174 switch (type) {
175 case VENDOR:
176 vendors.remove(e);
177 break;
178 case PRODUCT:
179 products.remove(e);
180 break;
181 case VERSION:
182 versions.remove(e);
183 break;
184 default:
185 break;
186 }
187 }
188 }
189
190 /**
191 * Creates an Evidence object from the parameters and adds the resulting
192 * object to the evidence collection.
193 *
194 * @param type the type of evidence (vendor, product, version)
195 * @param source the source of the Evidence.
196 * @param name the name of the Evidence.
197 * @param value the value of the Evidence.
198 * @param confidence the confidence of the Evidence.
199 */
200 public void addEvidence(EvidenceType type, String source, String name, String value, Confidence confidence) {
201 final Evidence e = new Evidence(source, name, value, confidence);
202 addEvidence(type, e);
203 }
204
205 /**
206 * Adds term to the vendor weighting collection. The terms added here are
207 * used later to boost the score of other terms. This is a way of combining
208 * evidence from multiple sources to boost the confidence of the given
209 * evidence.
210 *
211 * Example: The term 'Apache' is found in the manifest of a JAR and is added
212 * to the Collection. When we parse the package names within the JAR file we
213 * may add these package names to the "weighted" strings collection to boost
214 * the score in the Lucene query. That way when we construct the Lucene
215 * query we find the term Apache in the collection AND in the weighted
216 * strings; as such, we will boost the confidence of the term Apache.
217 *
218 * @param str to add to the weighting collection.
219 */
220 public synchronized void addVendorWeighting(String str) {
221 vendorWeightings.add(str.toLowerCase());
222 }
223
224 /**
225 * Adds term to the product weighting collection. The terms added here are
226 * used later to boost the score of other terms. This is a way of combining
227 * evidence from multiple sources to boost the confidence of the given
228 * evidence.
229 *
230 * Example: The term 'Apache' is found in the manifest of a JAR and is added
231 * to the Collection. When we parse the package names within the JAR file we
232 * may add these package names to the "weighted" strings collection to boost
233 * the score in the Lucene query. That way when we construct the Lucene
234 * query we find the term Apache in the collection AND in the weighted
235 * strings; as such, we will boost the confidence of the term Apache.
236 *
237 * @param str to add to the weighting collection.
238 */
239 public synchronized void addProductWeighting(String str) {
240 productWeightings.add(str.toLowerCase());
241 }
242
243 /**
244 * Returns an unmodifiable set of vendor Weightings - a list of terms that
245 * are believed to be of higher confidence when also found in another
246 * location.
247 *
248 * @return an unmodifiable set of vendor weighting strings
249 */
250 public synchronized Set<String> getVendorWeightings() {
251 return Collections.unmodifiableSet(new TreeSet<>(vendorWeightings));
252 }
253
254 /**
255 * Returns an unmodifiable set of product Weightings - a list of terms that
256 * are believed to be of higher confidence when also found in another
257 * location.
258 *
259 * @return an unmodifiable set of vendor weighting strings
260 */
261 public synchronized Set<String> getProductWeightings() {
262 return Collections.unmodifiableSet(new TreeSet<>(productWeightings));
263 }
264
265 /**
266 * Returns the unmodifiable set of evidence of the given type.
267 *
268 * @param type the type of evidence (vendor, product, version)
269 * @return the unmodifiable set of evidence
270 */
271 public synchronized Set<Evidence> getEvidence(EvidenceType type) {
272 if (null != type) {
273 switch (type) {
274 case VENDOR:
275 return Collections.unmodifiableSet(new TreeSet<>(vendors));
276 case PRODUCT:
277 return Collections.unmodifiableSet(new TreeSet<>(products));
278 case VERSION:
279 return Collections.unmodifiableSet(new TreeSet<>(versions));
280 default:
281 break;
282 }
283 }
284 return null;
285 }
286
287 /**
288 * Returns the unmodifiable set of evidence.
289 *
290 * @return the unmodifiable set of evidence
291 */
292 public synchronized Set<Evidence> getEvidence() {
293 final Set<Evidence> e = new TreeSet<>(vendors);
294 e.addAll(products);
295 e.addAll(versions);
296 return Collections.unmodifiableSet(e);
297 }
298
299 /**
300 * Tests if the evidence collection contains the given evidence.
301 *
302 * @param type the type of evidence (vendor, product, version)
303 * @param e the evidence to search
304 * @return true if the evidence is found; otherwise false
305 */
306 public synchronized boolean contains(EvidenceType type, Evidence e) {
307 if (null != type) {
308 switch (type) {
309 case VENDOR:
310 return vendors.contains(e);
311 case PRODUCT:
312 return products.contains(e);
313 case VERSION:
314 return versions.contains(e);
315 default:
316 break;
317 }
318 }
319 return false;
320 }
321
322 /**
323 * Returns whether or not the collection contains evidence of a specified
324 * type and confidence.
325 *
326 * @param type the type of evidence (vendor, product, version)
327 * @param confidence A Confidence value.
328 * @return boolean.
329 */
330 public synchronized boolean contains(EvidenceType type, Confidence confidence) {
331 if (null == type) {
332 return false;
333 }
334 final Set<Evidence> col;
335 switch (type) {
336 case VENDOR:
337 col = vendors;
338 break;
339 case PRODUCT:
340 col = products;
341 break;
342 case VERSION:
343 col = versions;
344 break;
345 default:
346 return false;
347 }
348 for (Evidence e : col) {
349 if (e.getConfidence().equals(confidence)) {
350 return true;
351 }
352 }
353 return false;
354 }
355
356 /**
357 * Returns a string of evidence 'values'.
358 *
359 * @return a string containing the evidence.
360 */
361 @Override
362 public synchronized String toString() {
363 final StringBuilder sb = new StringBuilder();
364 sb.append("{vendors: [");
365 for (Evidence e : this.vendors) {
366 sb.append("'").append(e.getValue()).append("', ");
367 }
368 sb.append("],/nproducts: [");
369 for (Evidence e : this.products) {
370 sb.append("'").append(e.getValue()).append("', ");
371 }
372 sb.append("],/nversions: [");
373 for (Evidence e : this.versions) {
374 sb.append("'").append(e.getValue()).append("', ");
375 }
376 sb.append("]");
377 return sb.toString();
378 }
379
380 /**
381 * Returns the number of elements in the EvidenceCollection.
382 *
383 * @return the number of elements in the collection.
384 */
385 public synchronized int size() {
386 return vendors.size() + products.size() + versions.size();
387 }
388
389 @Override
390 public int hashCode() {
391 return new HashCodeBuilder(13, 43)
392 .append(vendors)
393 .append(vendorWeightings)
394 .append(products)
395 .append(productWeightings)
396 .append(versions)
397 .toHashCode();
398 }
399
400 @Override
401 public boolean equals(Object obj) {
402 if (obj == null || !(obj instanceof EvidenceCollection)) {
403 return false;
404 }
405 if (this == obj) {
406 return true;
407 }
408 final EvidenceCollection other = (EvidenceCollection) obj;
409 return new EqualsBuilder()
410 .append(this.vendors, other.vendors)
411 .append(this.vendorWeightings, other.vendorWeightings)
412 .append(this.products, other.products)
413 .append(this.productWeightings, other.productWeightings)
414 .append(this.versions, other.versions)
415 .isEquals();
416 }
417 }