View Javadoc

    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.File;
    22  import java.io.IOException;
    23  import java.security.NoSuchAlgorithmException;
    24  import java.util.ArrayList;
    25  import java.util.List;
    26  import java.util.Set;
    27  import java.util.SortedSet;
    28  import java.util.TreeSet;
    29  import java.util.logging.Level;
    30  import java.util.logging.Logger;
    31  import org.owasp.dependencycheck.utils.Checksum;
    32  import org.owasp.dependencycheck.utils.FileUtils;
    33
    34  /**
    35   * A program dependency. This object is one of the core components within
    36   * DependencyCheck. It is used to collect information about the dependency in
    37   * the form of evidence. The Evidence is then used to determine if there are any
    38   * known, published, vulnerabilities associated with the program dependency.
    39   *
    40   * @author Jeremy Long (jeremy.long@owasp.org)
    41   */
    42  public class Dependency implements Comparable<Dependency> {
    43
    44      /**
    45       * The actual file path of the dependency on disk.
    46       */
    47      private String actualFilePath;
    48      /**
    49       * The file path to display.
    50       */
    51      private String filePath;
    52      /**
    53       * The file name of the dependency.
    54       */
    55      private String fileName;
    56      /**
    57       * The file extension of the dependency.
    58       */
    59      private String fileExtension;
    60      /**
    61       * The md5 hash of the dependency.
    62       */
    63      private String md5sum;
    64      /**
    65       * The SHA1 hash of the dependency.
    66       */
    67      private String sha1sum;
    68      /**
    69       * A list of Identifiers.
    70       */
    71      private Set<Identifier> identifiers;
    72      /**
    73       * A collection of vendor evidence.
    74       */
    75      private final EvidenceCollection vendorEvidence;
    76      /**
    77       * A collection of product evidence.
    78       */
    79      private final EvidenceCollection productEvidence;
    80      /**
    81       * A collection of version evidence.
    82       */
    83      private final EvidenceCollection versionEvidence;
    84
    85      /**
    86       * Constructs a new Dependency object.
    87       */
    88      public Dependency() {
    89          vendorEvidence = new EvidenceCollection();
    90          productEvidence = new EvidenceCollection();
    91          versionEvidence = new EvidenceCollection();
    92          identifiers = new TreeSet<Identifier>();
    93          vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
    94      }
    95
    96      /**
    97       * Constructs a new Dependency object.
    98       *
    99       * @param file the File to create the dependency object from.
    100      */
    101     public Dependency(File file) {
    102         this();
    103         this.actualFilePath = file.getPath();
    104         this.filePath = this.actualFilePath;
    105         this.fileName = file.getName();
    106         this.fileExtension = FileUtils.getFileExtension(fileName);
    107         determineHashes(file);
    108     }
    109
    110     /**
    111      * Returns the file name of the dependency.
    112      *
    113      * @return the file name of the dependency.
    114      */
    115     public String getFileName() {
    116         return this.fileName;
    117     }
    118
    119     /**
    120      * Sets the file name of the dependency.
    121      *
    122      * @param fileName the file name of the dependency.
    123      */
    124     public void setFileName(String fileName) {
    125         this.fileName = fileName;
    126     }
    127
    128     /**
    129      * Sets the actual file path of the dependency on disk.
    130      *
    131      * @param actualFilePath the file path of the dependency.
    132      */
    133     public void setActualFilePath(String actualFilePath) {
    134         this.actualFilePath = actualFilePath;
    135     }
    136
    137     /**
    138      * Gets the file path of the dependency.
    139      *
    140      * @return the file path of the dependency.
    141      */
    142     public String getActualFilePath() {
    143         return this.actualFilePath;
    144     }
    145
    146     /**
    147      * Sets the file path of the dependency.
    148      *
    149      * @param filePath the file path of the dependency.
    150      */
    151     public void setFilePath(String filePath) {
    152         this.filePath = filePath;
    153     }
    154
    155     /**
    156      * <p>Gets the file path of the dependency.</p> <p><b>NOTE:</b> This may not
    157      * be the actual path of the file on disk. The actual path of the file on
    158      * disk can be obtained via the getActualFilePath().</p>
    159      *
    160      * @return the file path of the dependency.
    161      */
    162     public String getFilePath() {
    163         return this.filePath;
    164     }
    165
    166     /**
    167      * Sets the file name of the dependency.
    168      *
    169      * @param fileExtension the file name of the dependency.
    170      */
    171     public void setFileExtension(String fileExtension) {
    172         this.fileExtension = fileExtension;
    173     }
    174
    175     /**
    176      * Gets the file extension of the dependency.
    177      *
    178      * @return the file extension of the dependency.
    179      */
    180     public String getFileExtension() {
    181         return this.fileExtension;
    182     }
    183
    184     /**
    185      * Returns the MD5 Checksum of the dependency file.
    186      *
    187      * @return the MD5 Checksum
    188      */
    189     public String getMd5sum() {
    190         return this.md5sum;
    191     }
    192
    193     /**
    194      * Sets the MD5 Checksum of the dependency.
    195      *
    196      * @param md5sum the MD5 Checksum
    197      */
    198     public void setMd5sum(String md5sum) {
    199         this.md5sum = md5sum;
    200     }
    201
    202     /**
    203      * Returns the SHA1 Checksum of the dependency.
    204      *
    205      * @return the SHA1 Checksum
    206      */
    207     public String getSha1sum() {
    208         return this.sha1sum;
    209     }
    210
    211     /**
    212      * Sets the SHA1 Checksum of the dependency.
    213      *
    214      * @param sha1sum the SHA1 Checksum
    215      */
    216     public void setSha1sum(String sha1sum) {
    217         this.sha1sum = sha1sum;
    218     }
    219
    220     /**
    221      * Returns a List of Identifiers.
    222      *
    223      * @return an ArrayList of Identifiers.
    224      */
    225     public Set<Identifier> getIdentifiers() {
    226         return this.identifiers;
    227     }
    228
    229     /**
    230      * Sets a List of Identifiers.
    231      *
    232      * @param identifiers A list of Identifiers.
    233      */
    234     public void setIdentifiers(Set<Identifier> identifiers) {
    235         this.identifiers = identifiers;
    236     }
    237
    238     /**
    239      * Adds an entry to the list of detected Identifiers for the dependency
    240      * file.
    241      *
    242      * @param type the type of identifier (such as CPE)
    243      * @param value the value of the identifier
    244      * @param url the URL of the identifier
    245      */
    246     public void addIdentifier(String type, String value, String url) {
    247         final Identifier i = new Identifier(type, value, url);
    248         this.identifiers.add(i);
    249     }
    250
    251     /**
    252      * Adds an entry to the list of detected Identifiers for the dependency
    253      * file.
    254      *
    255      * @param identifier the identifier to add
    256      */
    257     public void addIdentifier(Identifier identifier) {
    258         this.identifiers.add(identifier);
    259     }
    260
    261     /**
    262      * Returns the evidence used to identify this dependency.
    263      *
    264      * @return an EvidenceCollection.
    265      */
    266     public EvidenceCollection getEvidence() {
    267         return EvidenceCollection.merge(this.productEvidence, this.vendorEvidence, this.versionEvidence);
    268     }
    269
    270     /**
    271      * Returns the evidence used to identify this dependency.
    272      *
    273      * @return an EvidenceCollection.
    274      */
    275     public EvidenceCollection getEvidenceUsed() {
    276         return EvidenceCollection.mergeUsed(this.productEvidence, this.vendorEvidence, this.versionEvidence);
    277     }
    278
    279     /**
    280      * Gets the Vendor Evidence.
    281      *
    282      * @return an EvidenceCollection.
    283      */
    284     public EvidenceCollection getVendorEvidence() {
    285         return this.vendorEvidence;
    286     }
    287
    288     /**
    289      * Gets the Product Evidence.
    290      *
    291      * @return an EvidenceCollection.
    292      */
    293     public EvidenceCollection getProductEvidence() {
    294         return this.productEvidence;
    295     }
    296
    297     /**
    298      * Gets the Version Evidence.
    299      *
    300      * @return an EvidenceCollection.
    301      */
    302     public EvidenceCollection getVersionEvidence() {
    303         return this.versionEvidence;
    304     }
    305     /**
    306      * A list of exceptions that occurred during analysis of this dependency.
    307      */
    308     private List<Exception> analysisExceptions = new ArrayList<Exception>();
    309
    310     /**
    311      * Get the value of analysisExceptions.
    312      *
    313      * @return the value of analysisExceptions
    314      */
    315     public List<Exception> getAnalysisExceptions() {
    316         return analysisExceptions;
    317     }
    318
    319     /**
    320      * Set the value of analysisExceptions.
    321      *
    322      * @param analysisExceptions new value of analysisExceptions
    323      */
    324     public void setAnalysisExceptions(List<Exception> analysisExceptions) {
    325         this.analysisExceptions = analysisExceptions;
    326     }
    327
    328     /**
    329      * Adds an exception to the analysis exceptions collection.
    330      *
    331      * @param ex an exception.
    332      */
    333     public void addAnalysisException(Exception ex) {
    334         this.analysisExceptions.add(ex);
    335     }
    336     /**
    337      * The description of the JAR file.
    338      */
    339     private String description;
    340
    341     /**
    342      * Get the value of description.
    343      *
    344      * @return the value of description
    345      */
    346     public String getDescription() {
    347         return description;
    348     }
    349
    350     /**
    351      * Set the value of description.
    352      *
    353      * @param description new value of description
    354      */
    355     public void setDescription(String description) {
    356         this.description = description;
    357     }
    358     /**
    359      * The license that this dependency uses.
    360      */
    361     private String license;
    362
    363     /**
    364      * Get the value of license.
    365      *
    366      * @return the value of license
    367      */
    368     public String getLicense() {
    369         return license;
    370     }
    371
    372     /**
    373      * Set the value of license.
    374      *
    375      * @param license new value of license
    376      */
    377     public void setLicense(String license) {
    378         this.license = license;
    379     }
    380     /**
    381      * A list of vulnerabilities for this dependency.
    382      */
    383     private SortedSet<Vulnerability> vulnerabilities;
    384
    385     /**
    386      * Get the list of vulnerabilities.
    387      *
    388      * @return the list of vulnerabilities
    389      */
    390     public SortedSet<Vulnerability> getVulnerabilities() {
    391         return vulnerabilities;
    392     }
    393
    394     /**
    395      * Set the value of vulnerabilities.
    396      *
    397      * @param vulnerabilities new value of vulnerabilities
    398      */
    399     public void setVulnerabilities(SortedSet<Vulnerability> vulnerabilities) {
    400         this.vulnerabilities = vulnerabilities;
    401     }
    402
    403     /**
    404      * Determines the sha1 and md5 sum for the given file.
    405      *
    406      * @param file the file to create checksums for
    407      */
    408     private void determineHashes(File file) {
    409         String md5 = null;
    410         String sha1 = null;
    411         try {
    412             md5 = Checksum.getMD5Checksum(file);
    413             sha1 = Checksum.getSHA1Checksum(file);
    414         } catch (IOException ex) {
    415             final String msg = String.format("Unable to read '%s' to determine hashes.", file.getName());
    416             Logger.getLogger(Dependency.class.getName()).log(Level.WARNING, msg);
    417             Logger.getLogger(Dependency.class.getName()).log(Level.FINE, null, ex);
    418         } catch (NoSuchAlgorithmException ex) {
    419             final String msg = "Unable to use MD5 of SHA1 checksums.";
    420             Logger.getLogger(Dependency.class.getName()).log(Level.WARNING, msg);
    421             Logger.getLogger(Dependency.class.getName()).log(Level.FINE, null, ex);
    422         }
    423         this.setMd5sum(md5);
    424         this.setSha1sum(sha1);
    425     }
    426
    427     /**
    428      * Adds a vulnerability to the dependency.
    429      *
    430      * @param vulnerability a vulnerability outlining a vulnerability.
    431      */
    432     public void addVulnerability(Vulnerability vulnerability) {
    433         this.vulnerabilities.add(vulnerability);
    434     }
    435     /**
    436      * A collection of related dependencies.
    437      */
    438     private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
    439
    440     /**
    441      * Get the value of relatedDependencies.
    442      *
    443      * @return the value of relatedDependencies
    444      */
    445     public Set<Dependency> getRelatedDependencies() {
    446         return relatedDependencies;
    447     }
    448
    449     /**
    450      * Set the value of relatedDependencies.
    451      *
    452      * @param relatedDependencies new value of relatedDependencies
    453      */
    454     public void setRelatedDependencies(Set<Dependency> relatedDependencies) {
    455         this.relatedDependencies = relatedDependencies;
    456     }
    457
    458     /**
    459      * Adds a related dependency.
    460      *
    461      * @param dependency a reference to the related dependency
    462      */
    463     public void addRelatedDependency(Dependency dependency) {
    464         relatedDependencies.add(dependency);
    465     }
    466
    467     /**
    468      * Implementation of the Comparable<Dependency> interface. The comparison is
    469      * solely based on the file name.
    470      *
    471      * @param o a dependency to compare
    472      * @return an integer representing the natural ordering
    473      */
    474     public int compareTo(Dependency o) {
    475         return this.getFileName().compareToIgnoreCase(o.getFileName());
    476     }
    477
    478     /**
    479      * Implementation of the equals method.
    480      *
    481      * @param obj the object to compare
    482      * @return true if the objects are equal, otherwise false
    483      */
    484     @Override
    485     public boolean equals(Object obj) {
    486         if (obj == null) {
    487             return false;
    488         }
    489         if (getClass() != obj.getClass()) {
    490             return false;
    491         }
    492         final Dependency other = (Dependency) obj;
    493         if ((this.actualFilePath == null) ? (other.actualFilePath != null) : !this.actualFilePath.equals(other.actualFilePath)) {
    494             return false;
    495         }
    496         if ((this.filePath == null) ? (other.filePath != null) : !this.filePath.equals(other.filePath)) {
    497             return false;
    498         }
    499         if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) {
    500             return false;
    501         }
    502         if ((this.fileExtension == null) ? (other.fileExtension != null) : !this.fileExtension.equals(other.fileExtension)) {
    503             return false;
    504         }
    505         if ((this.md5sum == null) ? (other.md5sum != null) : !this.md5sum.equals(other.md5sum)) {
    506             return false;
    507         }
    508         if ((this.sha1sum == null) ? (other.sha1sum != null) : !this.sha1sum.equals(other.sha1sum)) {
    509             return false;
    510         }
    511         if (this.identifiers != other.identifiers && (this.identifiers == null || !this.identifiers.equals(other.identifiers))) {
    512             return false;
    513         }
    514         if (this.vendorEvidence != other.vendorEvidence && (this.vendorEvidence == null || !this.vendorEvidence.equals(other.vendorEvidence))) {
    515             return false;
    516         }
    517         if (this.productEvidence != other.productEvidence && (this.productEvidence == null || !this.productEvidence.equals(other.productEvidence))) {
    518             return false;
    519         }
    520         if (this.versionEvidence != other.versionEvidence && (this.versionEvidence == null || !this.versionEvidence.equals(other.versionEvidence))) {
    521             return false;
    522         }
    523         if (this.analysisExceptions != other.analysisExceptions
    524                 && (this.analysisExceptions == null || !this.analysisExceptions.equals(other.analysisExceptions))) {
    525             return false;
    526         }
    527         if ((this.description == null) ? (other.description != null) : !this.description.equals(other.description)) {
    528             return false;
    529         }
    530         if ((this.license == null) ? (other.license != null) : !this.license.equals(other.license)) {
    531             return false;
    532         }
    533         if (this.vulnerabilities != other.vulnerabilities && (this.vulnerabilities == null || !this.vulnerabilities.equals(other.vulnerabilities))) {
    534             return false;
    535         }
    536         if (this.relatedDependencies != other.relatedDependencies
    537                 && (this.relatedDependencies == null || !this.relatedDependencies.equals(other.relatedDependencies))) {
    538             return false;
    539         }
    540         return true;
    541     }
    542
    543     /**
    544      * Generates the HashCode.
    545      *
    546      * @return the HashCode
    547      */
    548     @Override
    549     public int hashCode() {
    550         int hash = 3;
    551         hash = 47 * hash + (this.actualFilePath != null ? this.actualFilePath.hashCode() : 0);
    552         hash = 47 * hash + (this.filePath != null ? this.filePath.hashCode() : 0);
    553         hash = 47 * hash + (this.fileName != null ? this.fileName.hashCode() : 0);
    554         hash = 47 * hash + (this.fileExtension != null ? this.fileExtension.hashCode() : 0);
    555         hash = 47 * hash + (this.md5sum != null ? this.md5sum.hashCode() : 0);
    556         hash = 47 * hash + (this.sha1sum != null ? this.sha1sum.hashCode() : 0);
    557         hash = 47 * hash + (this.identifiers != null ? this.identifiers.hashCode() : 0);
    558         hash = 47 * hash + (this.vendorEvidence != null ? this.vendorEvidence.hashCode() : 0);
    559         hash = 47 * hash + (this.productEvidence != null ? this.productEvidence.hashCode() : 0);
    560         hash = 47 * hash + (this.versionEvidence != null ? this.versionEvidence.hashCode() : 0);
    561         hash = 47 * hash + (this.analysisExceptions != null ? this.analysisExceptions.hashCode() : 0);
    562         hash = 47 * hash + (this.description != null ? this.description.hashCode() : 0);
    563         hash = 47 * hash + (this.license != null ? this.license.hashCode() : 0);
    564         hash = 47 * hash + (this.vulnerabilities != null ? this.vulnerabilities.hashCode() : 0);
    565         hash = 47 * hash + (this.relatedDependencies != null ? this.relatedDependencies.hashCode() : 0);
    566         return hash;
    567     }
    568
    569     /**
    570      * Standard toString() implementation showing the filename, actualFilePath,
    571      * and filePath.
    572      *
    573      * @return the string representation of the file
    574      */
    575     @Override
    576     public String toString() {
    577         return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath + "', filePath='" + filePath + "'}";
    578     }
    579 }