Coverage Report - org.owasp.dependencycheck.maven.ReportingUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
ReportingUtil
0%
0/253
0%
0/80
4.462
 
 1  
 /*
 2  
  * This file is part of dependency-check-maven.
 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) 2014 Jeremy Long. All Rights Reserved.
 17  
  */
 18  
 package org.owasp.dependencycheck.maven;
 19  
 
 20  
 import java.io.File;
 21  
 import java.io.IOException;
 22  
 import java.io.UnsupportedEncodingException;
 23  
 import java.net.URLEncoder;
 24  
 import java.text.DateFormat;
 25  
 import java.util.Date;
 26  
 import java.util.List;
 27  
 import java.util.Set;
 28  
 import java.util.logging.Level;
 29  
 import java.util.logging.Logger;
 30  
 import org.apache.maven.doxia.sink.Sink;
 31  
 import org.owasp.dependencycheck.data.nvdcve.CveDB;
 32  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
 33  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
 34  
 import org.owasp.dependencycheck.dependency.Dependency;
 35  
 import org.owasp.dependencycheck.dependency.Evidence;
 36  
 import org.owasp.dependencycheck.dependency.Identifier;
 37  
 import org.owasp.dependencycheck.dependency.Reference;
 38  
 import org.owasp.dependencycheck.dependency.Vulnerability;
 39  
 import org.owasp.dependencycheck.dependency.VulnerableSoftware;
 40  
 import org.owasp.dependencycheck.reporting.ReportGenerator;
 41  
 
 42  
 /**
 43  
  * A utility class that encapsulates the report generation for dependency-check-maven.
 44  
  *
 45  
  * @author Jeremy Long <jeremy.long@owasp.org>
 46  
  */
 47  
 final class ReportingUtil {
 48  
 
 49  
     /**
 50  
      * Logger field reference.
 51  
      */
 52  0
     private static final Logger LOGGER = Logger.getLogger(ReportingUtil.class.getName());
 53  
 
 54  
     /**
 55  
      * Empty private constructor for this utility class.
 56  
      */
 57  0
     private ReportingUtil() {
 58  0
     }
 59  
 
 60  
     /**
 61  
      * Generates the reports for a given dependency-check engine.
 62  
      *
 63  
      * @param engine a dependency-check engine
 64  
      * @param outDirectory the directory to write the reports to
 65  
      * @param projectName the name of the project that a report is being generated for
 66  
      * @param format the format of the report to generate
 67  
      */
 68  
     static void generateExternalReports(Engine engine, File outDirectory, String projectName, String format) {
 69  0
         DatabaseProperties prop = null;
 70  0
         CveDB cve = null;
 71  
         try {
 72  0
             cve = new CveDB();
 73  0
             cve.open();
 74  0
             prop = cve.getDatabaseProperties();
 75  0
         } catch (DatabaseException ex) {
 76  0
             LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
 77  
         } finally {
 78  0
             if (cve != null) {
 79  0
                 cve.close();
 80  
             }
 81  
         }
 82  0
         final ReportGenerator r = new ReportGenerator(projectName, engine.getDependencies(), engine.getAnalyzers(), prop);
 83  
         try {
 84  0
             r.generateReports(outDirectory.getCanonicalPath(), format);
 85  0
         } catch (IOException ex) {
 86  0
             LOGGER.log(Level.SEVERE,
 87  
                     "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
 88  0
             LOGGER.log(Level.FINE, null, ex);
 89  0
         } catch (Throwable ex) {
 90  0
             LOGGER.log(Level.SEVERE,
 91  
                     "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
 92  0
             LOGGER.log(Level.FINE, null, ex);
 93  0
         }
 94  0
     }
 95  
 
 96  
     /**
 97  
      * Generates a dependency-check report using the Maven Site format.
 98  
      *
 99  
      * @param engine the engine used to scan the dependencies
 100  
      * @param sink the sink to write the data to
 101  
      * @param projectName the name of the project
 102  
      */
 103  
     static void generateMavenSiteReport(final Engine engine, Sink sink, String projectName) {
 104  0
         final List<Dependency> dependencies = engine.getDependencies();
 105  
 
 106  0
         writeSiteReportHeader(sink, projectName);
 107  0
         writeSiteReportTOC(sink, dependencies);
 108  
 
 109  0
         int cnt = 0;
 110  0
         for (Dependency d : dependencies) {
 111  0
             writeSiteReportDependencyHeader(sink, d);
 112  0
             cnt = writeSiteReportDependencyEvidenceUsed(d, cnt, sink);
 113  0
             cnt = writeSiteReportDependencyRelatedDependencies(d, cnt, sink);
 114  0
             writeSiteReportDependencyIdentifiers(d, sink);
 115  0
             writeSiteReportDependencyVulnerabilities(d, sink, cnt);
 116  0
         }
 117  0
         sink.body_();
 118  0
     }
 119  
 
 120  
     // <editor-fold defaultstate="collapsed" desc="various writeXXXXX methods to generate the Site Report">
 121  
     /**
 122  
      * Writes the vulnerabilities to the site report.
 123  
      *
 124  
      * @param d the dependency
 125  
      * @param sink the sink to write the data to
 126  
      * @param collapsibleHeaderCount the collapsible header count
 127  
      */
 128  
     private static void writeSiteReportDependencyVulnerabilities(Dependency d, Sink sink, int collapsibleHeaderCount) {
 129  0
         int cnt = collapsibleHeaderCount;
 130  0
         if (d.getVulnerabilities() != null && !d.getVulnerabilities().isEmpty()) {
 131  0
             for (Vulnerability v : d.getVulnerabilities()) {
 132  
 
 133  0
                 sink.paragraph();
 134  0
                 sink.bold();
 135  
                 try {
 136  0
                     sink.link("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + URLEncoder.encode(v.getName(), "US-ASCII"));
 137  0
                     sink.text(v.getName());
 138  0
                     sink.link_();
 139  0
                     sink.bold_();
 140  0
                 } catch (UnsupportedEncodingException ex) {
 141  0
                     sink.text(v.getName());
 142  0
                     sink.bold_();
 143  0
                     sink.lineBreak();
 144  0
                     sink.text("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + v.getName());
 145  0
                 }
 146  0
                 sink.paragraph_();
 147  0
                 sink.paragraph();
 148  0
                 sink.text("Severity: ");
 149  0
                 if (v.getCvssScore() < 4.0) {
 150  0
                     sink.text("Low");
 151  
                 } else {
 152  0
                     if (v.getCvssScore() >= 7.0) {
 153  0
                         sink.text("High");
 154  
                     } else {
 155  0
                         sink.text("Medium");
 156  
                     }
 157  
                 }
 158  0
                 sink.lineBreak();
 159  0
                 sink.text("CVSS Score: " + v.getCvssScore());
 160  0
                 if (v.getCwe() != null && !v.getCwe().isEmpty()) {
 161  0
                     sink.lineBreak();
 162  0
                     sink.text("CWE: ");
 163  0
                     sink.text(v.getCwe());
 164  
                 }
 165  0
                 sink.paragraph_();
 166  0
                 sink.paragraph();
 167  0
                 sink.text(v.getDescription());
 168  0
                 if (v.getReferences() != null && !v.getReferences().isEmpty()) {
 169  0
                     sink.list();
 170  0
                     for (Reference ref : v.getReferences()) {
 171  0
                         sink.listItem();
 172  0
                         sink.text(ref.getSource());
 173  0
                         sink.text(" - ");
 174  0
                         sink.link(ref.getUrl());
 175  0
                         sink.text(ref.getName());
 176  0
                         sink.link_();
 177  0
                         sink.listItem_();
 178  0
                     }
 179  0
                     sink.list_();
 180  
                 }
 181  0
                 sink.paragraph_();
 182  0
                 if (v.getVulnerableSoftware() != null && !v.getVulnerableSoftware().isEmpty()) {
 183  0
                     sink.paragraph();
 184  
 
 185  0
                     cnt += 1;
 186  0
                     sink.rawText("Vulnerable Software <a href=\"javascript:toggleElement(this, 'vulnSoft" + cnt + "')\">[-]</a>");
 187  0
                     sink.rawText("<div id=\"vulnSoft" + cnt + "\" style=\"display:block\">");
 188  0
                     sink.list();
 189  0
                     for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
 190  0
                         sink.listItem();
 191  
                         try {
 192  0
                             sink.link("http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + URLEncoder.encode(vs.getName(), "US-ASCII"));
 193  0
                             sink.text(vs.getName());
 194  0
                             sink.link_();
 195  0
                             if (vs.hasPreviousVersion()) {
 196  0
                                 sink.text(" and all previous versions.");
 197  
                             }
 198  0
                         } catch (UnsupportedEncodingException ex) {
 199  0
                             sink.text(vs.getName());
 200  0
                             if (vs.hasPreviousVersion()) {
 201  0
                                 sink.text(" and all previous versions.");
 202  
                             }
 203  0
                             sink.text(" (http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + vs.getName() + ")");
 204  0
                         }
 205  
 
 206  0
                         sink.listItem_();
 207  0
                     }
 208  0
                     sink.list_();
 209  0
                     sink.rawText("</div>");
 210  0
                     sink.paragraph_();
 211  
                 }
 212  0
             }
 213  
         }
 214  0
     }
 215  
 
 216  
     /**
 217  
      * Writes the identifiers to the site report.
 218  
      *
 219  
      * @param d the dependency
 220  
      * @param sink the sink to write the data to
 221  
      */
 222  
     private static void writeSiteReportDependencyIdentifiers(Dependency d, Sink sink) {
 223  0
         if (d.getIdentifiers() != null && !d.getIdentifiers().isEmpty()) {
 224  0
             sink.sectionTitle4();
 225  0
             sink.text("Identifiers");
 226  0
             sink.sectionTitle4_();
 227  0
             sink.list();
 228  0
             for (Identifier i : d.getIdentifiers()) {
 229  0
                 sink.listItem();
 230  0
                 sink.text(i.getType());
 231  0
                 sink.text(": ");
 232  0
                 if (i.getUrl() != null && i.getUrl().length() > 0) {
 233  0
                     sink.link(i.getUrl());
 234  0
                     sink.text(i.getValue());
 235  0
                     sink.link_();
 236  
                 } else {
 237  0
                     sink.text(i.getValue());
 238  
                 }
 239  0
                 if (i.getDescription() != null && i.getDescription().length() > 0) {
 240  0
                     sink.lineBreak();
 241  0
                     sink.text(i.getDescription());
 242  
                 }
 243  0
                 sink.listItem_();
 244  0
             }
 245  0
             sink.list_();
 246  
         }
 247  0
     }
 248  
 
 249  
     /**
 250  
      * Writes the related dependencies to the site report.
 251  
      *
 252  
      * @param d the dependency
 253  
      * @param sink the sink to write the data to
 254  
      * @param collapsibleHeaderCount the collapsible header count
 255  
      * @return the collapsible header count
 256  
      */
 257  
     private static int writeSiteReportDependencyRelatedDependencies(Dependency d, int collapsibleHeaderCount, Sink sink) {
 258  0
         int cnt = collapsibleHeaderCount;
 259  0
         if (d.getRelatedDependencies() != null && !d.getRelatedDependencies().isEmpty()) {
 260  0
             cnt += 1;
 261  0
             sink.sectionTitle4();
 262  0
             sink.rawText("Related Dependencies <a href=\"javascript:toggleElement(this, 'related" + cnt + "')\">[+]</a>");
 263  0
             sink.sectionTitle4_();
 264  0
             sink.rawText("<div id=\"related" + cnt + "\" style=\"display:none\">");
 265  0
             sink.list();
 266  0
             for (Dependency r : d.getRelatedDependencies()) {
 267  0
                 sink.listItem();
 268  0
                 sink.text(r.getFileName());
 269  0
                 sink.list();
 270  0
                 writeListItem(sink, "File Path: " + r.getFilePath());
 271  0
                 writeListItem(sink, "SHA1: " + r.getSha1sum());
 272  0
                 writeListItem(sink, "MD5: " + r.getMd5sum());
 273  0
                 sink.list_();
 274  0
                 sink.listItem_();
 275  0
             }
 276  0
             sink.list_();
 277  0
             sink.rawText("</div>");
 278  
         }
 279  0
         return cnt;
 280  
     }
 281  
 
 282  
     /**
 283  
      * Writes the evidence used to the site report.
 284  
      *
 285  
      * @param d the dependency
 286  
      * @param sink the sink to write the data to
 287  
      * @param collapsibleHeaderCount the collapsible header count
 288  
      * @return the collapsible header count
 289  
      */
 290  
     private static int writeSiteReportDependencyEvidenceUsed(Dependency d, int collapsibleHeaderCount, Sink sink) {
 291  0
         int cnt = collapsibleHeaderCount;
 292  0
         final Set<Evidence> evidence = d.getEvidenceForDisplay();
 293  0
         if (evidence != null && evidence.size() > 0) {
 294  0
             cnt += 1;
 295  0
             sink.sectionTitle4();
 296  0
             sink.rawText("Evidence Collected <a href=\"javascript:toggleElement(this, 'evidence" + cnt + "')\">[+]</a>");
 297  0
             sink.sectionTitle4_();
 298  0
             sink.rawText("<div id=\"evidence" + cnt + "\" style=\"display:none\">");
 299  0
             sink.table();
 300  0
             sink.tableRow();
 301  0
             writeTableHeaderCell(sink, "Source");
 302  0
             writeTableHeaderCell(sink, "Name");
 303  0
             writeTableHeaderCell(sink, "Value");
 304  0
             sink.tableRow_();
 305  0
             for (Evidence e : evidence) {
 306  0
                 sink.tableRow();
 307  0
                 writeTableCell(sink, e.getSource());
 308  0
                 writeTableCell(sink, e.getName());
 309  0
                 writeTableCell(sink, e.getValue());
 310  0
                 sink.tableRow_();
 311  0
             }
 312  0
             sink.table_();
 313  0
             sink.rawText("</div>");
 314  
         }
 315  0
         return cnt;
 316  
     }
 317  
 
 318  
     /**
 319  
      * Writes the dependency header to the site report.
 320  
      *
 321  
      * @param d the dependency
 322  
      * @param sink the sink to write the data to
 323  
      */
 324  
     private static void writeSiteReportDependencyHeader(Sink sink, Dependency d) {
 325  0
         sink.sectionTitle2();
 326  0
         sink.anchor("sha1" + d.getSha1sum());
 327  0
         sink.text(d.getFileName());
 328  0
         sink.anchor_();
 329  0
         sink.sectionTitle2_();
 330  0
         if (d.getDescription() != null && d.getDescription().length() > 0) {
 331  0
             sink.paragraph();
 332  0
             sink.bold();
 333  0
             sink.text("Description: ");
 334  0
             sink.bold_();
 335  0
             sink.text(d.getDescription());
 336  0
             sink.paragraph_();
 337  
         }
 338  0
         if (d.getLicense() != null && d.getLicense().length() > 0) {
 339  0
             sink.paragraph();
 340  0
             sink.bold();
 341  0
             sink.text("License: ");
 342  0
             sink.bold_();
 343  0
             if (d.getLicense().startsWith("http://") && !d.getLicense().contains(" ")) {
 344  0
                 sink.link(d.getLicense());
 345  0
                 sink.text(d.getLicense());
 346  0
                 sink.link_();
 347  
             } else {
 348  0
                 sink.text(d.getLicense());
 349  
             }
 350  0
             sink.paragraph_();
 351  
         }
 352  0
     }
 353  
 
 354  
     /**
 355  
      * Adds a list item to the site report.
 356  
      *
 357  
      * @param sink the sink to write the data to
 358  
      * @param text the text to write
 359  
      */
 360  
     private static void writeListItem(Sink sink, String text) {
 361  0
         sink.listItem();
 362  0
         sink.text(text);
 363  0
         sink.listItem_();
 364  0
     }
 365  
 
 366  
     /**
 367  
      * Adds a table cell to the site report.
 368  
      *
 369  
      * @param sink the sink to write the data to
 370  
      * @param text the text to write
 371  
      */
 372  
     private static void writeTableCell(Sink sink, String text) {
 373  0
         sink.tableCell();
 374  0
         sink.text(text);
 375  0
         sink.tableCell_();
 376  0
     }
 377  
 
 378  
     /**
 379  
      * Adds a table header cell to the site report.
 380  
      *
 381  
      * @param sink the sink to write the data to
 382  
      * @param text the text to write
 383  
      */
 384  
     private static void writeTableHeaderCell(Sink sink, String text) {
 385  0
         sink.tableHeaderCell();
 386  0
         sink.text(text);
 387  0
         sink.tableHeaderCell_();
 388  0
     }
 389  
 
 390  
     /**
 391  
      * Writes the TOC for the site report.
 392  
      *
 393  
      * @param sink the sink to write the data to
 394  
      * @param dependencies the dependencies that are being reported on
 395  
      */
 396  
     private static void writeSiteReportTOC(Sink sink, final List<Dependency> dependencies) {
 397  0
         sink.list();
 398  0
         for (Dependency d : dependencies) {
 399  0
             sink.listItem();
 400  0
             sink.link("#sha1" + d.getSha1sum());
 401  0
             sink.text(d.getFileName());
 402  0
             sink.link_();
 403  0
             if (!d.getVulnerabilities().isEmpty()) {
 404  0
                 sink.rawText(" <font style=\"color:red\">•</font>");
 405  
             }
 406  0
             if (!d.getRelatedDependencies().isEmpty()) {
 407  0
                 sink.list();
 408  0
                 for (Dependency r : d.getRelatedDependencies()) {
 409  0
                     writeListItem(sink, r.getFileName());
 410  0
                 }
 411  0
                 sink.list_();
 412  
             }
 413  0
             sink.listItem_();
 414  0
         }
 415  0
         sink.list_();
 416  0
     }
 417  
 
 418  
     /**
 419  
      * Writes the site report header.
 420  
      *
 421  
      * @param sink the sink to write the data to
 422  
      * @param projectName the name of the project
 423  
      */
 424  
     private static void writeSiteReportHeader(Sink sink, String projectName) {
 425  0
         sink.head();
 426  0
         sink.title();
 427  0
         sink.text("Dependency-Check Report: " + projectName);
 428  0
         sink.title_();
 429  0
         sink.head_();
 430  0
         sink.body();
 431  0
         sink.rawText("<script type=\"text/javascript\">");
 432  0
         sink.rawText("function toggleElement(el, targetId) {");
 433  0
         sink.rawText("if (el.innerText == '[+]') {");
 434  0
         sink.rawText("    el.innerText = '[-]';");
 435  0
         sink.rawText("    document.getElementById(targetId).style.display='block';");
 436  0
         sink.rawText("} else {");
 437  0
         sink.rawText("    el.innerText = '[+]';");
 438  0
         sink.rawText("    document.getElementById(targetId).style.display='none';");
 439  0
         sink.rawText("}");
 440  
 
 441  0
         sink.rawText("}");
 442  0
         sink.rawText("</script>");
 443  0
         sink.section1();
 444  0
         sink.sectionTitle1();
 445  0
         sink.text("Project: " + projectName);
 446  0
         sink.sectionTitle1_();
 447  0
         sink.date();
 448  0
         final Date now = new Date();
 449  0
         sink.text(DateFormat.getDateTimeInstance().format(now));
 450  0
         sink.date_();
 451  0
         sink.section1_();
 452  0
     }
 453  
     // </editor-fold>
 454  
 
 455  
 }