Coverage Report - org.owasp.dependencycheck.dependency.VulnerableSoftware
 
Classes in this File Line Coverage Branch Coverage Complexity
VulnerableSoftware
76%
70/91
81%
60/74
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  59027
 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  6904
             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  6904
         }
 55  6904
     }
 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  8917
         this.name = cpeName;
 72  8917
         if (cpeName != null && cpeName.length() > 7) {
 73  8917
             final String[] data = cpeName.substring(7).split(":");
 74  8917
             if (data.length >= 1) {
 75  8917
                 this.setVendor(URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8")); //.replaceAll("[_-]", " ")
 76  8917
                 if (data.length >= 2) {
 77  8917
                     this.setProduct(URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8")); //.replaceAll("[_-]", " ")
 78  8917
                     if (data.length >= 3) {
 79  8901
                         version = URLDecoder.decode(data[2].replace("+", "%2B"), "UTF-8");
 80  8901
                         if (data.length >= 4) {
 81  2356
                             revision = URLDecoder.decode(data[3].replace("+", "%2B"), "UTF-8");
 82  2356
                             if (data.length >= 5) {
 83  1
                                 edition = URLDecoder.decode(data[4].replace("+", "%2B"), "UTF-8");
 84  
                             }
 85  
                         }
 86  
                     }
 87  
                 }
 88  
             }
 89  
         }
 90  8917
     }
 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  1924
         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  38
         this.previousVersion = previousVersion;
 121  38
     }
 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  3662
         int hash = 7;
 153  3662
         hash = 83 * hash + (this.getName() != null ? this.getName().hashCode() : 0);
 154  3662
         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  50111
         int result = 0;
 177  50111
         final String[] left = this.getName().split(":");
 178  50111
         final String[] right = vs.getName().split(":");
 179  50111
         final int max = (left.length <= right.length) ? left.length : right.length;
 180  50111
         if (max > 0) {
 181  302866
             for (int i = 0; result == 0 && i < max; i++) {
 182  252755
                 final String[] subLeft = left[i].split("\\.");
 183  252755
                 final String[] subRight = right[i].split("\\.");
 184  252755
                 final int subMax = (subLeft.length <= subRight.length) ? subLeft.length : subRight.length;
 185  252755
                 if (subMax > 0) {
 186  567549
                     for (int x = 0; result == 0 && x < subMax; x++) {
 187  314794
                         if (isPositiveInteger(subLeft[x]) && isPositiveInteger(subRight[x])) {
 188  109094
                             final int iLeft = Integer.parseInt(subLeft[x]);
 189  109094
                             final int iRight = Integer.parseInt(subRight[x]);
 190  109094
                             if (iLeft != iRight) {
 191  42544
                                 if (iLeft > iRight) {
 192  39084
                                     result = 2;
 193  
                                 } else {
 194  3460
                                     result = -2;
 195  
                                 }
 196  
                             }
 197  109094
                         } else {
 198  205700
                             result = subLeft[x].compareToIgnoreCase(subRight[x]);
 199  
                         }
 200  
                     }
 201  252755
                     if (result == 0) {
 202  204705
                         if (subLeft.length > subRight.length) {
 203  1440
                             result = 2;
 204  
                         }
 205  204705
                         if (subRight.length > subLeft.length) {
 206  7
                             result = -2;
 207  
                         }
 208  
                     }
 209  
                 } else {
 210  0
                     result = left[i].compareToIgnoreCase(right[i]);
 211  
                 }
 212  
             }
 213  50111
             if (result == 0) {
 214  614
                 if (left.length > right.length) {
 215  604
                     result = 2;
 216  
                 }
 217  614
                 if (right.length > left.length) {
 218  10
                     result = -2;
 219  
                 }
 220  
             }
 221  
         } else {
 222  0
             result = this.getName().compareToIgnoreCase(vs.getName());
 223  
         }
 224  50111
         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  424020
         if (str == null || str.isEmpty()) {
 235  12
             return false;
 236  
         }
 237  659456
         for (int i = 0; i < str.length(); i++) {
 238  441136
             final char c = str.charAt(i);
 239  441136
             if (c < '0' || c > '9') {
 240  205688
                 return false;
 241  
             }
 242  
         }
 243  218320
         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  109747
         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  14153
         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  16805
         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  
 }