View Javadoc
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&lt;Evidence&gt; 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 }