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