##### Coverage Report - org.owasp.dependencycheck.dependency.VulnerableSoftware

Classes in this File | Line Coverage | Branch Coverage | Complexity
VulnerableSoftware |
76% | 70/91
81% | 60/74
| 3.2777777777777777;3.278

1 |  |
     /*
2 |  |
      * This file is part of dependency-check-core.
3 |  |
      *
4 |  |
      * Dependency-check-core is free software: you can redistribute it and/or modify it
5 |  |
      * under the terms of the GNU General Public License as published by the Free
6 |  |
      * Software Foundation, either version 3 of the License, or (at your option) any
7 |  |
      * later version.
8 |  |
      *
9 |  |
      * Dependency-check-core is distributed in the hope that it will be useful, but
10 |  |
      * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 |  |
      * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 |  |
      * details.
13 |  |
      *
14 |  |
      * You should have received a copy of the GNU General Public License along with
15 |  |
      * dependency-check-core. If not, see http://www.gnu.org/licenses/.
16 |  |
      *
17 |  |
      * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
18 |  |
      */
19 |  |
     package org.owasp.dependencycheck.dependency;
20 |  |
21 |  |
     import java.io.Serializable;
22 |  |
     import java.io.UnsupportedEncodingException;
23 |  |
     import java.net.URLDecoder;
24 |  |
     import java.util.logging.Level;
25 |  |
     import java.util.logging.Logger;
26 |  |
     import org.owasp.dependencycheck.data.cpe.IndexEntry;
27 |  |
28 |  |
     /**
29 |  |
      * A record containing information about vulnerable software. This is referenced
30 |  |
      * from a vulnerability.
31 |  |
      *
32 |  |
      * @author Jeremy Long (jeremy.long@owasp.org)
33 |  |
      */
34 | 61009 |
     public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> {
35 |  |
36 |  |
         /**
37 |  |
          * The serial version UID.
38 |  |
          */
39 |  |
         private static final long serialVersionUID = 307319490326651052L;
40 |  |
41 |  |
         /**
42 |  |
          * Parse a CPE entry from the cpe string representation.
43 |  |
          *
44 |  |
          * @param cpe a cpe entry (e.g. cpe:/a:vendor:software:version)
45 |  |
          */
46 |  |
         public void setCpe(String cpe) {
47 |  |
             try {
48 | 7616 |
                 parseName(cpe);
49 | 0 |
             } catch (UnsupportedEncodingException ex) {
50 | 0 |
                 final String msg = String.format("Character encoding is unsupported for CPE '%s'.", cpe);
51 | 0 |
                 Logger.getLogger(VulnerableSoftware.class.getName()).log(Level.WARNING, msg);
52 | 0 |
                 Logger.getLogger(VulnerableSoftware.class.getName()).log(Level.FINE, null, ex);
53 | 0 |
                 setName(cpe);
54 | 7616 |
             }
55 | 7616 |
         }
56 |  |
57 |  |
         /**
58 |  |
          * <p>Parses a name attribute value, from the cpe.xml, into its
59 |  |
          * corresponding parts: vendor, product, version, revision.</p>
60 |  |
          * <p>Example:</p>
61 |  |
          * <code>&nbsp;&nbsp;&nbsp;cpe:/a:apache:struts:1.1:rc2</code>
62 |  |
          *
63 |  |
          * <p>Results in:</p> <ul> <li>Vendor: apache</li> <li>Product: struts</li>
64 |  |
          * <li>Version: 1.1</li> <li>Revision: rc2</li> </ul>
65 |  |
          *
66 |  |
          * @param cpeName the cpe name
67 |  |
          * @throws UnsupportedEncodingException should never be thrown...
68 |  |
          */
69 |  |
         @Override
70 |  |
         public void parseName(String cpeName) throws UnsupportedEncodingException {
71 | 11151 |
             this.name = cpeName;
72 | 11151 |
             if (cpeName != null && cpeName.length() > 7) {
73 | 11151 |
                 final String[] data = cpeName.substring(7).split(":");
74 | 11151 |
                 if (data.length >= 1) {
75 | 11151 |
                     this.setVendor(URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8")); //.replaceAll("[_-]", " ")
76 | 11151 |
                     if (data.length >= 2) {
77 | 11151 |
                         this.setProduct(URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8")); //.replaceAll("[_-]", " ")
78 | 11151 |
                         if (data.length >= 3) {
79 | 11123 |
                             version = URLDecoder.decode(data[2].replace("+", "%2B"), "UTF-8");
80 | 11123 |
                             if (data.length >= 4) {
81 | 2318 |
                                 revision = URLDecoder.decode(data[3].replace("+", "%2B"), "UTF-8");
82 | 2318 |
                                 if (data.length >= 5) {
83 | 1 |
                                     edition = URLDecoder.decode(data[4].replace("+", "%2B"), "UTF-8");
84 |  |
                                 }
85 |  |
                             }
86 |  |
                         }
87 |  |
                     }
88 |  |
                 }
89 |  |
             }
90 | 11151 |
         }
91 |  |
         /**
92 |  |
          * If present, indicates that previous version are vulnerable.
93 |  |
          */
94 |  |
         private String previousVersion;
95 |  |
96 |  |
         /**
97 |  |
          * Indicates if previous versions of this software are vulnerable.
98 |  |
          *
99 |  |
          * @return if previous versions of this software are vulnerable
100 |  |
          */
101 |  |
         public boolean hasPreviousVersion() {
102 | 1895 |
             return previousVersion != null;
103 |  |
         }
104 |  |
105 |  |
         /**
106 |  |
          * Get the value of previousVersion.
107 |  |
          *
108 |  |
          * @return the value of previousVersion
109 |  |
          */
110 |  |
         public String getPreviousVersion() {
111 | 0 |
             return previousVersion;
112 |  |
         }
113 |  |
114 |  |
         /**
115 |  |
          * Set the value of previousVersion.
116 |  |
          *
117 |  |
          * @param previousVersion new value of previousVersion
118 |  |
          */
119 |  |
         public void setPreviousVersion(String previousVersion) {
120 | 43 |
             this.previousVersion = previousVersion;
121 | 43 |
         }
122 |  |
123 |  |
         /**
124 |  |
          * Standard equals implementation to compare this VulnerableSoftware to
125 |  |
          * another object.
126 |  |
          *
127 |  |
          * @param obj the object to compare
128 |  |
          * @return whether or not the objects are equal
129 |  |
          */
130 |  |
         @Override
131 |  |
         public boolean equals(Object obj) {
132 | 1 |
             if (obj == null) {
133 | 0 |
                 return false;
134 |  |
             }
135 | 1 |
             if (getClass() != obj.getClass()) {
136 | 0 |
                 return false;
137 |  |
             }
138 | 1 |
             final VulnerableSoftware other = (VulnerableSoftware) obj;
139 | 1 |
             if ((this.getName() == null) ? (other.getName() != null) : !this.getName().equals(other.getName())) {
140 | 1 |
                 return false;
141 |  |
             }
142 | 0 |
             return true;
143 |  |
         }
144 |  |
145 |  |
         /**
146 |  |
          * Standard implementation of hashCode.
147 |  |
          *
148 |  |
          * @return the hashCode for the object
149 |  |
          */
150 |  |
         @Override
151 |  |
         public int hashCode() {
152 | 4383 |
             int hash = 7;
153 | 4383 |
             hash = 83 * hash + (this.getName() != null ? this.getName().hashCode() : 0);
154 | 4383 |
             return hash;
155 |  |
         }
156 |  |
157 |  |
         /**
158 |  |
          * Standard toString() implementation display the name and whether or not
159 |  |
          * previous versions are also affected.
160 |  |
          *
161 |  |
          * @return a string representation of the object
162 |  |
          */
163 |  |
         @Override
164 |  |
         public String toString() {
165 | 0 |
             return "VulnerableSoftware{ name=" + name + ", previousVersion=" + previousVersion + '}';
166 |  |
         }
167 |  |
168 |  |
         /**
169 |  |
          * Implementation of the comparable interface.
170 |  |
          *
171 |  |
          * @param vs the VulnerableSoftware to compare
172 |  |
          * @return an integer indicating the ordering of the two objects
173 |  |
          */
174 |  |
         @Override
175 |  |
         public int compareTo(VulnerableSoftware vs) {
176 | 49859 |
             int result = 0;
177 | 49859 |
             final String[] left = this.getName().split(":");
178 | 49859 |
             final String[] right = vs.getName().split(":");
179 | 49859 |
             final int max = (left.length <= right.length) ? left.length : right.length;
180 | 49859 |
             if (max > 0) {
181 | 301368 |
                 for (int i = 0; result == 0 && i < max; i++) {
182 | 251509 |
                     final String[] subLeft = left[i].split("\\.");
183 | 251509 |
                     final String[] subRight = right[i].split("\\.");
184 | 251509 |
                     final int subMax = (subLeft.length <= subRight.length) ? subLeft.length : subRight.length;
185 | 251509 |
                     if (subMax > 0) {
186 | 564931 |
                         for (int x = 0; result == 0 && x < subMax; x++) {
187 | 313422 |
                             if (isPositiveInteger(subLeft[x]) && isPositiveInteger(subRight[x])) {
188 | 108826 |
                                 final int iLeft = Integer.parseInt(subLeft[x]);
189 | 108826 |
                                 final int iRight = Integer.parseInt(subRight[x]);
190 | 108826 |
                                 if (iLeft != iRight) {
191 | 42480 |
                                     if (iLeft > iRight) {
192 | 39020 |
                                         result = 2;
193 |  |
                                     } else {
194 | 3460 |
                                         result = -2;
195 |  |
                                     }
196 |  |
                                 }
197 | 108826 |
                             } else {
198 | 204596 |
                                 result = subLeft[x].compareToIgnoreCase(subRight[x]);
199 |  |
                             }
200 |  |
                         }
201 | 251509 |
                         if (result == 0) {
202 | 203675 |
                             if (subLeft.length > subRight.length) {
203 | 1430 |
                                 result = 2;
204 |  |
                             }
205 | 203675 |
                             if (subRight.length > subLeft.length) {
206 | 7 |
                                 result = -2;
207 |  |
                             }
208 |  |
                         }
209 |  |
                     } else {
210 | 0 |
                         result = left[i].compareToIgnoreCase(right[i]);
211 |  |
                     }
212 |  |
                 }
213 | 49859 |
                 if (result == 0) {
214 | 588 |
                     if (left.length > right.length) {
215 | 578 |
                         result = 2;
216 |  |
                     }
217 | 588 |
                     if (right.length > left.length) {
218 | 10 |
                         result = -2;
219 |  |
                     }
220 |  |
                 }
221 |  |
             } else {
222 | 0 |
                 result = this.getName().compareToIgnoreCase(vs.getName());
223 |  |
             }
224 | 49859 |
             return result;
225 |  |
         }
226 |  |
227 |  |
         /**
228 |  |
          * Determines if the string passed in is a positive integer.
229 |  |
          *
230 |  |
          * @param str the string to test
231 |  |
          * @return true if the string only contains 0-9, otherwise false.
232 |  |
          */
233 |  |
         private static boolean isPositiveInteger(final String str) {
234 | 422342 |
             if (str == null || str.isEmpty()) {
235 | 12 |
                 return false;
236 |  |
             }
237 | 657204 |
             for (int i = 0; i < str.length(); i++) {
238 | 439458 |
                 final char c = str.charAt(i);
239 | 439458 |
                 if (c < '0' || c > '9') {
240 | 204584 |
                     return false;
241 |  |
                 }
242 |  |
             }
243 | 217746 |
             return true;
244 |  |
         }
245 |  |
         /**
246 |  |
          * The name of the cpe.
247 |  |
          */
248 |  |
         private String name;
249 |  |
250 |  |
         /**
251 |  |
          * Get the value of name.
252 |  |
          *
253 |  |
          * @return the value of name
254 |  |
          */
255 |  |
         public String getName() {
256 | 110720 |
             return name;
257 |  |
         }
258 |  |
259 |  |
         /**
260 |  |
          * Set the value of name.
261 |  |
          *
262 |  |
          * @param name new value of name
263 |  |
          */
264 |  |
         public void setName(String name) {
265 | 0 |
             this.name = name;
266 | 0 |
         }
267 |  |
         /**
268 |  |
          * The product version number.
269 |  |
          */
270 |  |
         private String version;
271 |  |
272 |  |
         /**
273 |  |
          * Get the value of version.
274 |  |
          *
275 |  |
          * @return the value of version
276 |  |
          */
277 |  |
         public String getVersion() {
278 | 19587 |
             return version;
279 |  |
         }
280 |  |
281 |  |
         /**
282 |  |
          * Set the value of version.
283 |  |
          *
284 |  |
          * @param version new value of version
285 |  |
          */
286 |  |
         public void setVersion(String version) {
287 | 0 |
             this.version = version;
288 | 0 |
         }
289 |  |
         /**
290 |  |
          * The product revision version.
291 |  |
          */
292 |  |
         private String revision;
293 |  |
294 |  |
         /**
295 |  |
          * Get the value of revision.
296 |  |
          *
297 |  |
          * @return the value of revision
298 |  |
          */
299 |  |
         public String getRevision() {
300 | 19171 |
             return revision;
301 |  |
         }
302 |  |
303 |  |
         /**
304 |  |
          * Set the value of revision.
305 |  |
          *
306 |  |
          * @param revision new value of revision
307 |  |
          */
308 |  |
         public void setRevision(String revision) {
309 | 0 |
             this.revision = revision;
310 | 0 |
         }
311 |  |
         /**
312 |  |
          * The product edition.
313 |  |
          */
314 |  |
         private String edition;
315 |  |
316 |  |
         /**
317 |  |
          * Get the value of edition.
318 |  |
          *
319 |  |
          * @return the value of edition
320 |  |
          */
321 |  |
         public String getEdition() {
322 | 0 |
             return edition;
323 |  |
         }
324 |  |
325 |  |
         /**
326 |  |
          * Set the value of edition.
327 |  |
          *
328 |  |
          * @param edition new value of edition
329 |  |
          */
330 |  |
         public void setEdition(String edition) {
331 | 0 |
             this.edition = edition;
332 | 0 |
         }
333 |  |
     }