mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-23 17:41:28 +01:00
initial release
This commit is contained in:
12
README
12
README
@@ -1,14 +1,18 @@
|
|||||||
About:
|
About:
|
||||||
DependencyCheck is a simple utility that attempts to determine if there is a Common Product Enumeration (CPE) identifier for a given project dependency. If found, it will generate a report linking to the associated CVE entries.
|
DependencyCheck is a simple utility that attempts to determine if there is a
|
||||||
|
Common Product Enumeration (CPE) identifier for a given project dependency.
|
||||||
|
If found, it will generate a report linking to the associated CVE entries.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
Still under development: mvn package site
|
Still under development: mvn package site
|
||||||
|
|
||||||
|
java -jar dependencycheck-0.1.jar -h
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
Add CVE download/indexing and CPE lookup.
|
Add CVE download/indexing and CPE lookup.
|
||||||
Finish report generation.
|
Finish report generation (xml).
|
||||||
Fix/finish the CLI.
|
Consider utilizing the OSVDB in addition to CPE/CVE.
|
||||||
|
|
||||||
Author: Jeremy Long (jeremy.long@gmail.com)
|
Author: Jeremy Long (jeremy.long@gmail.com)
|
||||||
|
|
||||||
Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||||
|
|||||||
56
pom.xml
56
pom.xml
@@ -16,13 +16,14 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
|
along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>org.codesecure</groupId>
|
<groupId>org.codesecure</groupId>
|
||||||
<artifactId>DependencyCheck</artifactId>
|
<artifactId>DependencyCheck</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>0.1</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>DependencyCheck</name>
|
<name>DependencyCheck</name>
|
||||||
@@ -34,6 +35,11 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
<email>jeremy.long@gmail.com</email>
|
<email>jeremy.long@gmail.com</email>
|
||||||
</developer>
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:git@github.com:jeremylong/DependencyCheck.git</connection>
|
||||||
|
<url>scm:git:git@github.com:jeremylong/DependencyCheck.git</url>
|
||||||
|
<developerConnection>scm:git:git@github.com:jeremylong/DependencyCheck.git</developerConnection>
|
||||||
|
</scm>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>GNU General Public License version 3</name>
|
<name>GNU General Public License version 3</name>
|
||||||
@@ -44,6 +50,25 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<build>
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**/*.properties</include>
|
||||||
|
</includes>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/*.properties</exclude>
|
||||||
|
<exclude>**/*.gif</exclude>
|
||||||
|
<exclude>**/*.js</exclude>
|
||||||
|
</excludes>
|
||||||
|
<filtering>false</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
@@ -54,7 +79,9 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>2.5.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
@@ -153,15 +180,15 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
<workingDirectory>target</workingDirectory>
|
<workingDirectory>target</workingDirectory>
|
||||||
</property>
|
</property>
|
||||||
<property>
|
<property>
|
||||||
<name>index.cpe</name>
|
<name>cve</name>
|
||||||
<value>${project.build.directory}/store/cpe</value>
|
<value>${project.build.directory}/store/cve</value>
|
||||||
</property>
|
</property>
|
||||||
<property>
|
<property>
|
||||||
<name>index.osvdb</name>
|
<name>osvdb</name>
|
||||||
<value>${project.build.directory}/store/osvdb</value>
|
<value>${project.build.directory}/store/osvdb</value>
|
||||||
</property>
|
</property>
|
||||||
<property>
|
<property>
|
||||||
<name>index.cpe</name>
|
<name>cpe</name>
|
||||||
<value>${project.build.directory}/store/cpe</value>
|
<value>${project.build.directory}/store/cpe</value>
|
||||||
</property>
|
</property>
|
||||||
</systemProperties>
|
</systemProperties>
|
||||||
@@ -392,5 +419,24 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
<classifier>javadoc</classifier>
|
<classifier>javadoc</classifier>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>joda-time</groupId>
|
||||||
|
<artifactId>joda-time</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>joda-time</groupId>
|
||||||
|
<artifactId>joda-time</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<classifier>javadoc</classifier>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>joda-time</groupId>
|
||||||
|
<artifactId>joda-time</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<classifier>sources</classifier>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,14 +1,32 @@
|
|||||||
package org.codesecure.dependencycheck;
|
package org.codesecure.dependencycheck;
|
||||||
|
/*
|
||||||
|
* This file is part of DependencyCheck.
|
||||||
|
*
|
||||||
|
* DependencyCheck is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* DependencyCheck is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with DependencyCheck. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.prefs.Preferences;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
import org.codesecure.dependencycheck.data.cpe.CPEQuery;
|
import org.codesecure.dependencycheck.data.cpe.CPEQuery;
|
||||||
|
import org.codesecure.dependencycheck.data.cpe.Index;
|
||||||
import org.codesecure.dependencycheck.data.cpe.xml.Importer;
|
import org.codesecure.dependencycheck.data.cpe.xml.Importer;
|
||||||
import org.codesecure.dependencycheck.reporting.ReportGenerator;
|
import org.codesecure.dependencycheck.reporting.ReportGenerator;
|
||||||
import org.codesecure.dependencycheck.scanner.Dependency;
|
import org.codesecure.dependencycheck.scanner.Dependency;
|
||||||
@@ -34,9 +52,8 @@ import org.xml.sax.SAXException;
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* The command line interface for the DependencyCheck application.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long (jeremy.long@gmail.com)
|
* @author Jeremy Long (jeremy.long@gmail.com)
|
||||||
*/
|
*/
|
||||||
@@ -50,7 +67,12 @@ public class App {
|
|||||||
App app = new App();
|
App app = new App();
|
||||||
app.run(args);
|
app.run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main CLI entry-point into the application.
|
||||||
|
*
|
||||||
|
* @param args the command line arguments
|
||||||
|
*/
|
||||||
public void run(String[] args) {
|
public void run(String[] args) {
|
||||||
CliParser cli = new CliParser();
|
CliParser cli = new CliParser();
|
||||||
try {
|
try {
|
||||||
@@ -62,18 +84,32 @@ public class App {
|
|||||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cli.isGetVersion()) {
|
if (cli.isGetVersion()) {
|
||||||
cli.printVersionInfo();
|
cli.printVersionInfo();
|
||||||
} else if (cli.isLoadCPE()) {
|
} else if (cli.isLoadCPE()) {
|
||||||
loadCPE(cli.getCpeFile());
|
loadCPE(cli.getCpeFile());
|
||||||
} else if (cli.isRunScan()) {
|
} else if (cli.isRunScan()) {
|
||||||
|
if (cli.isAutoUpdate()) {
|
||||||
|
Index cpeI = new Index();
|
||||||
|
try {
|
||||||
|
cpeI.updateIndexFromWeb();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runScan(cli.getReportDirectory(), cli.getApplicationName(), cli.getScanFiles());
|
runScan(cli.getReportDirectory(), cli.getApplicationName(), cli.getScanFiles());
|
||||||
} else {
|
} else {
|
||||||
cli.printHelp();
|
cli.printHelp();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the specified CPE.XML file into Lucene Index.
|
||||||
|
* @param cpePath
|
||||||
|
*/
|
||||||
private void loadCPE(String cpePath) {
|
private void loadCPE(String cpePath) {
|
||||||
try {
|
try {
|
||||||
Importer.importXML(cpePath);
|
Importer.importXML(cpePath);
|
||||||
@@ -85,6 +121,13 @@ public class App {
|
|||||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the specified directories and writes the dependency reports to the reportDirectory.
|
||||||
|
* @param reportDirectory the path to the directory where the reports will be written.
|
||||||
|
* @param applicationName the application name for the report.
|
||||||
|
* @param files the files/directories to scan.
|
||||||
|
*/
|
||||||
private void runScan(String reportDirectory, String applicationName, String[] files) {
|
private void runScan(String reportDirectory, String applicationName, String[] files) {
|
||||||
try {
|
try {
|
||||||
Scanner scanner = new Scanner();
|
Scanner scanner = new Scanner();
|
||||||
@@ -106,13 +149,11 @@ public class App {
|
|||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
} catch (org.apache.lucene.queryParser.ParseException ex) {
|
} catch (org.apache.lucene.queryParser.ParseException ex) {
|
||||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class CPEQuery {
|
|||||||
* utilized within the CPE Names.
|
* utilized within the CPE Names.
|
||||||
*/
|
*/
|
||||||
static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 _-]";
|
static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 _-]";
|
||||||
/* A string representation of a regular expression used to remove all but
|
/* A string representation of a regular expression used to remove all but
|
||||||
* alpha characters.
|
* alpha characters.
|
||||||
*/
|
*/
|
||||||
static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
|
static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
|
||||||
@@ -191,15 +191,15 @@ public class CPEQuery {
|
|||||||
do {
|
do {
|
||||||
List<Entry> entries = searchCPE(vendors, titles, versions, dependency.getTitleEvidence().getWeighting(),
|
List<Entry> entries = searchCPE(vendors, titles, versions, dependency.getTitleEvidence().getWeighting(),
|
||||||
dependency.getVendorEvidence().getWeighting());
|
dependency.getVendorEvidence().getWeighting());
|
||||||
|
|
||||||
if (entries.size()>0) {
|
if (entries.size() > 0) {
|
||||||
List<String> verified = verifyEntries(entries, dependency);
|
List<String> verified = verifyEntries(entries, dependency);
|
||||||
if (verified.size() > 0) {
|
if (verified.size() > 0) {
|
||||||
found = true;
|
found = true;
|
||||||
dependency.setCPEs(verified);
|
dependency.setCPEs(verified);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
int round = cnt % 3;
|
int round = cnt % 3;
|
||||||
if (round == 0) {
|
if (round == 0) {
|
||||||
@@ -320,7 +320,7 @@ public class CPEQuery {
|
|||||||
*/
|
*/
|
||||||
protected String buildSearch(String vendor, String product, String version,
|
protected String buildSearch(String vendor, String product, String version,
|
||||||
List<String> vendorWeighting, List<String> produdctWeightings) {
|
List<String> vendorWeighting, List<String> produdctWeightings) {
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(vendor.length() + product.length()
|
StringBuilder sb = new StringBuilder(vendor.length() + product.length()
|
||||||
+ version.length() + Fields.PRODUCT.length() + Fields.VERSION.length()
|
+ version.length() + Fields.PRODUCT.length() + Fields.VERSION.length()
|
||||||
+ Fields.VENDOR.length() + STRING_BUILDER_BUFFER);
|
+ Fields.VENDOR.length() + STRING_BUILDER_BUFFER);
|
||||||
@@ -335,7 +335,7 @@ public class CPEQuery {
|
|||||||
if (!appendWeightedSearch(sb, Fields.VENDOR, vendor.toLowerCase(), vendorWeighting)) {
|
if (!appendWeightedSearch(sb, Fields.VENDOR, vendor.toLowerCase(), vendorWeighting)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append(Fields.VERSION).append(":(");
|
sb.append(Fields.VERSION).append(":(");
|
||||||
if (sb.indexOf("^") > 0) {
|
if (sb.indexOf("^") > 0) {
|
||||||
//if we have a weighting on something else, reduce the weighting on the version a lot
|
//if we have a weighting on something else, reduce the weighting on the version a lot
|
||||||
@@ -369,7 +369,7 @@ public class CPEQuery {
|
|||||||
sb.append(" ").append(field).append(":( ");
|
sb.append(" ").append(field).append(":( ");
|
||||||
|
|
||||||
String cleanText = cleanseText(searchText);
|
String cleanText = cleanseText(searchText);
|
||||||
|
|
||||||
if ("".equals(cleanText)) {
|
if ("".equals(cleanText)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -408,7 +408,7 @@ public class CPEQuery {
|
|||||||
private String cleanseText(String text) {
|
private String cleanseText(String text) {
|
||||||
return text.replaceAll(CLEANSE_CHARACTER_RX, " ");
|
return text.replaceAll(CLEANSE_CHARACTER_RX, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two strings after lower casing them and removing the non-alpha
|
* Compares two strings after lower casing them and removing the non-alpha
|
||||||
* characters.
|
* characters.
|
||||||
|
|||||||
@@ -19,10 +19,16 @@ package org.codesecure.dependencycheck.data.cpe;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
@@ -38,6 +44,8 @@ import org.apache.lucene.util.Version;
|
|||||||
import org.codesecure.dependencycheck.utils.Downloader;
|
import org.codesecure.dependencycheck.utils.Downloader;
|
||||||
import org.codesecure.dependencycheck.utils.Settings;
|
import org.codesecure.dependencycheck.utils.Settings;
|
||||||
import org.codesecure.dependencycheck.data.cpe.xml.Importer;
|
import org.codesecure.dependencycheck.data.cpe.xml.Importer;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.Days;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Index class is used to utilize and maintain the CPE Index.
|
* The Index class is used to utilize and maintain the CPE Index.
|
||||||
@@ -46,6 +54,14 @@ import org.codesecure.dependencycheck.data.cpe.xml.Importer;
|
|||||||
*/
|
*/
|
||||||
public class Index {
|
public class Index {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Te name of the properties file containing the timestamp of the last update.
|
||||||
|
*/
|
||||||
|
private static final String UPDATE_PROPERTIES_FILE = "lastupdated.prop";
|
||||||
|
/**
|
||||||
|
* The properties file key for the last updated field.
|
||||||
|
*/
|
||||||
|
private static final String LAST_UPDATED = "lastupdated";
|
||||||
/**
|
/**
|
||||||
* The Lucene directory containing the index.
|
* The Lucene directory containing the index.
|
||||||
*/
|
*/
|
||||||
@@ -124,10 +140,47 @@ public class Index {
|
|||||||
outputPath = File.createTempFile("cpe", ".xml");
|
outputPath = File.createTempFile("cpe", ".xml");
|
||||||
Downloader.fetchFile(url, outputPath);
|
Downloader.fetchFile(url, outputPath);
|
||||||
Importer.importXML(outputPath.toString());
|
Importer.importXML(outputPath.toString());
|
||||||
|
writeLastUpdatedPropertyFile();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
} finally {
|
} finally {
|
||||||
outputPath.delete();
|
boolean deleted = false;
|
||||||
|
try {
|
||||||
|
deleted = outputPath.delete();
|
||||||
|
} finally {
|
||||||
|
if (!deleted) {
|
||||||
|
outputPath.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeLastUpdatedPropertyFile() {
|
||||||
|
DateTime now = new DateTime();
|
||||||
|
String dir = Settings.getString(Settings.KEYS.CPE_INDEX);
|
||||||
|
File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
|
||||||
|
Properties prop = new Properties();
|
||||||
|
prop.put(this.LAST_UPDATED, String.valueOf(now.getMillis()));
|
||||||
|
OutputStream os = null;
|
||||||
|
try {
|
||||||
|
os = new FileOutputStream(cpeProp);
|
||||||
|
OutputStreamWriter out = new OutputStreamWriter(os);
|
||||||
|
prop.store(out, dir);
|
||||||
|
} catch (FileNotFoundException ex) {
|
||||||
|
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
os.flush();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
os.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,6 +191,43 @@ public class Index {
|
|||||||
* @return whether or not the CPE Index needs to be updated.
|
* @return whether or not the CPE Index needs to be updated.
|
||||||
*/
|
*/
|
||||||
public boolean updateNeeded() {
|
public boolean updateNeeded() {
|
||||||
return true;
|
boolean needed = false;
|
||||||
|
String lastUpdated = null;
|
||||||
|
String dir = Settings.getString(Settings.KEYS.CPE_INDEX);
|
||||||
|
File f = new File(dir);
|
||||||
|
if (!f.exists()) {
|
||||||
|
needed = true;
|
||||||
|
} else {
|
||||||
|
File cpeProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
|
||||||
|
if (!cpeProp.exists()) {
|
||||||
|
needed = true;
|
||||||
|
} else {
|
||||||
|
Properties prop = new Properties();
|
||||||
|
FileInputStream is = null;
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(cpeProp);
|
||||||
|
prop.load(is);
|
||||||
|
lastUpdated = prop.getProperty(this.LAST_UPDATED);
|
||||||
|
} catch (FileNotFoundException ex) {
|
||||||
|
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
long lastupdate = Long.parseLong(lastUpdated);
|
||||||
|
DateTime last = new DateTime(lastupdate);
|
||||||
|
DateTime now = new DateTime();
|
||||||
|
Days d = Days.daysBetween(last, now);
|
||||||
|
int days = d.getDays();
|
||||||
|
int freq = Settings.getInt(Settings.KEYS.CPE_DOWNLOAD_FREQUENCY);
|
||||||
|
if (days >= freq) {
|
||||||
|
needed = true;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
needed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return needed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,25 @@ public class Importer {
|
|||||||
private Importer() {
|
private Importer() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports the CPE XML File into the Lucene Index.
|
||||||
|
*
|
||||||
|
* @param file containing the path to the CPE XML file.
|
||||||
|
* @throws ParserConfigurationException is thrown if the parser is misconfigured.
|
||||||
|
* @throws SAXException is thrown when there is a SAXException.
|
||||||
|
* @throws IOException is thrown when there is an IOException.
|
||||||
|
*/
|
||||||
|
public static void importXML(File file) throws ParserConfigurationException, SAXException, IOException {
|
||||||
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
|
CPEHandler handler = new CPEHandler();
|
||||||
|
Indexer indexer = new Indexer();
|
||||||
|
indexer.open();
|
||||||
|
handler.registerSaveDelegate(indexer);
|
||||||
|
saxParser.parse(file, handler);
|
||||||
|
indexer.close();
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Imports the CPE XML File into the Lucene Index.
|
* Imports the CPE XML File into the Lucene Index.
|
||||||
*
|
*
|
||||||
@@ -48,14 +67,7 @@ public class Importer {
|
|||||||
* @throws IOException is thrown when there is an IOException.
|
* @throws IOException is thrown when there is an IOException.
|
||||||
*/
|
*/
|
||||||
public static void importXML(String path) throws ParserConfigurationException, SAXException, IOException {
|
public static void importXML(String path) throws ParserConfigurationException, SAXException, IOException {
|
||||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
|
||||||
SAXParser saxParser = factory.newSAXParser();
|
|
||||||
CPEHandler handler = new CPEHandler();
|
|
||||||
Indexer indexer = new Indexer();
|
|
||||||
indexer.open();
|
|
||||||
handler.registerSaveDelegate(indexer);
|
|
||||||
File f = new File(path);
|
File f = new File(path);
|
||||||
saxParser.parse(f, handler);
|
Importer.importXML(f);
|
||||||
indexer.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import java.io.InputStreamReader;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.apache.velocity.VelocityContext;
|
|
||||||
import org.apache.velocity.app.VelocityEngine;
|
import org.apache.velocity.app.VelocityEngine;
|
||||||
import org.apache.velocity.context.Context;
|
import org.apache.velocity.context.Context;
|
||||||
import org.apache.velocity.runtime.RuntimeConstants;
|
import org.apache.velocity.runtime.RuntimeConstants;
|
||||||
@@ -42,20 +41,28 @@ import org.codesecure.dependencycheck.scanner.Dependency;
|
|||||||
*/
|
*/
|
||||||
public class ReportGenerator {
|
public class ReportGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the Dependency Reports for the identified dependencies.
|
||||||
|
*
|
||||||
|
* @param outputDir the path where the reports should be written.
|
||||||
|
* @param applicationName the name of the application that was scanned.
|
||||||
|
* @param dependencies a list of dependencies to include in the report.
|
||||||
|
* @throws IOException is thrown when the template file does not exist.
|
||||||
|
* @throws Exception is thrown if there is an error writting out the reports.
|
||||||
|
*/
|
||||||
public void generateReports(String outputDir, String applicationName, List<Dependency> dependencies) throws IOException, Exception {
|
public void generateReports(String outputDir, String applicationName, List<Dependency> dependencies) throws IOException, Exception {
|
||||||
|
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
Map<String, Object> properties = new HashMap<String, Object>();
|
||||||
properties.put("dependencies",dependencies);
|
properties.put("dependencies", dependencies);
|
||||||
properties.put("applicationName", applicationName);
|
properties.put("applicationName", applicationName);
|
||||||
|
|
||||||
String reportName = applicationName.replaceAll("[^a-zA-Z0-9-_ \\.]+", "");
|
String reportName = applicationName.replaceAll("[^a-zA-Z0-9-_ \\.]+", "");
|
||||||
String filename = outputDir + File.separatorChar + reportName;
|
String filename = outputDir + File.separatorChar + reportName;
|
||||||
generateReport("HtmlReport",filename+".html",properties);
|
generateReport("HtmlReport", filename + ".html", properties);
|
||||||
//generateReport("XmlReport",filename+".xml",properties);
|
//generateReport("XmlReport",filename + ".xml",properties);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* much of this code is from http://stackoverflow.com/questions/2931516/loading-velocity-template-inside-a-jar-file
|
* much of this code is from http://stackoverflow.com/questions/2931516/loading-velocity-template-inside-a-jar-file
|
||||||
* @param templateName the name of the template to load.
|
* @param templateName the name of the template to load.
|
||||||
@@ -64,23 +71,23 @@ public class ReportGenerator {
|
|||||||
* @throws IOException is thrown when the template file does not exist.
|
* @throws IOException is thrown when the template file does not exist.
|
||||||
* @throws Exception is thrown when an exception occurs.
|
* @throws Exception is thrown when an exception occurs.
|
||||||
*/
|
*/
|
||||||
protected void generateReport(String templateName, String outFileName,
|
protected void generateReport(String templateName, String outFileName,
|
||||||
Map<String, Object> properties) throws IOException, Exception {
|
Map<String, Object> properties) throws IOException, Exception {
|
||||||
|
|
||||||
VelocityEngine ve = new VelocityEngine();
|
VelocityEngine ve = new VelocityEngine();
|
||||||
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
|
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
|
||||||
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
|
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
|
||||||
|
|
||||||
ToolManager manager = new ToolManager();
|
ToolManager manager = new ToolManager();
|
||||||
Context context = manager.createContext();
|
Context context = manager.createContext();
|
||||||
EasyFactoryConfiguration config = new EasyFactoryConfiguration();
|
EasyFactoryConfiguration config = new EasyFactoryConfiguration();
|
||||||
config.addDefaultTools();
|
config.addDefaultTools();
|
||||||
config.toolbox("application")
|
config.toolbox("application")
|
||||||
.tool("esc","org.apache.velocity.tools.generic.EscapeTool")
|
.tool("esc", "org.apache.velocity.tools.generic.EscapeTool")
|
||||||
.tool("org.apache.velocity.tools.generic.DateTool");
|
.tool("org.apache.velocity.tools.generic.DateTool");
|
||||||
|
|
||||||
manager.configure(config);
|
manager.configure(config);
|
||||||
|
|
||||||
ve.init();
|
ve.init();
|
||||||
|
|
||||||
final String templatePath = "templates/" + templateName + ".vsl";
|
final String templatePath = "templates/" + templateName + ".vsl";
|
||||||
@@ -91,19 +98,19 @@ public class ReportGenerator {
|
|||||||
|
|
||||||
InputStreamReader reader = new InputStreamReader(input);
|
InputStreamReader reader = new InputStreamReader(input);
|
||||||
BufferedWriter writer = null;
|
BufferedWriter writer = null;
|
||||||
|
|
||||||
//VelocityContext context = new VelocityContext();
|
//VelocityContext context = new VelocityContext();
|
||||||
|
|
||||||
//load the data into the context
|
//load the data into the context
|
||||||
if (properties != null) {
|
if (properties != null) {
|
||||||
for (Map.Entry<String, Object> property : properties.entrySet()) {
|
for (Map.Entry<String, Object> property : properties.entrySet()) {
|
||||||
context.put(property.getKey(), property.getValue());
|
context.put(property.getKey(), property.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writer = new BufferedWriter(new FileWriter(new File(outFileName)));
|
writer = new BufferedWriter(new FileWriter(new File(outFileName)));
|
||||||
|
|
||||||
if (!ve.evaluate(context, writer, templatePath, reader)) {
|
if (!ve.evaluate(context, writer, templatePath, reader)) {
|
||||||
throw new Exception("Failed to convert the template into html.");
|
throw new Exception("Failed to convert the template into html.");
|
||||||
}
|
}
|
||||||
@@ -112,12 +119,12 @@ public class ReportGenerator {
|
|||||||
try {
|
try {
|
||||||
writer.close();
|
writer.close();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
//ignore this error.
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
reader.close();
|
reader.close();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
//ignore this error.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* <html>
|
||||||
|
* <head>
|
||||||
|
* <title>org.codesecure.dependencycheck.reporting</title>
|
||||||
|
* </head>
|
||||||
|
* <body>
|
||||||
|
* Contains classes used to generate reports.
|
||||||
|
* </body>
|
||||||
|
* </html>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.codesecure.dependencycheck.reporting;
|
||||||
@@ -65,13 +65,16 @@ public class Dependency {
|
|||||||
*/
|
*/
|
||||||
protected EvidenceCollection versionEvidence = null;
|
protected EvidenceCollection versionEvidence = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Dependency object.
|
||||||
|
*/
|
||||||
public Dependency() {
|
public Dependency() {
|
||||||
vendorEvidence = new EvidenceCollection();
|
vendorEvidence = new EvidenceCollection();
|
||||||
titleEvidence = new EvidenceCollection();
|
titleEvidence = new EvidenceCollection();
|
||||||
versionEvidence = new EvidenceCollection();
|
versionEvidence = new EvidenceCollection();
|
||||||
cpes = new ArrayList<String>();
|
cpes = new ArrayList<String>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the file name of the JAR.
|
* Returns the file name of the JAR.
|
||||||
*
|
*
|
||||||
@@ -180,8 +183,8 @@ public class Dependency {
|
|||||||
public EvidenceCollection getEvidence() {
|
public EvidenceCollection getEvidence() {
|
||||||
return EvidenceCollection.mergeUsed(this.titleEvidence, this.vendorEvidence, this.versionEvidence);
|
return EvidenceCollection.mergeUsed(this.titleEvidence, this.vendorEvidence, this.versionEvidence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the evidence used to identify this dependency.
|
* Returns the evidence used to identify this dependency.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -234,5 +234,5 @@ public class EvidenceCollection implements Iterable<Evidence> {
|
|||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,22 +51,23 @@ public class JarAnalyzer implements Analyzer {
|
|||||||
private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core
|
private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core
|
||||||
private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation
|
private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation
|
||||||
|
|
||||||
|
|
||||||
private enum STRING_STATE {
|
private enum STRING_STATE {
|
||||||
|
|
||||||
ALPHA,
|
ALPHA,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
OTHER
|
OTHER
|
||||||
}
|
}
|
||||||
|
|
||||||
private STRING_STATE determineState(char c) {
|
private STRING_STATE determineState(char c) {
|
||||||
if (c>='0' && c<='9' || c=='.') {
|
if (c >= '0' && c <= '9' || c == '.') {
|
||||||
return STRING_STATE.NUMBER;
|
return STRING_STATE.NUMBER;
|
||||||
} else if (c>='a' && c<='z') {
|
} else if (c >= 'a' && c <= 'z') {
|
||||||
return STRING_STATE.ALPHA;
|
return STRING_STATE.ALPHA;
|
||||||
} else {
|
} else {
|
||||||
return STRING_STATE.OTHER;
|
return STRING_STATE.OTHER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a specified JAR file and collects information from the manifest and
|
* Loads a specified JAR file and collects information from the manifest and
|
||||||
* checksums to identify the correct CPE information.
|
* checksums to identify the correct CPE information.
|
||||||
@@ -82,19 +83,17 @@ public class JarAnalyzer implements Analyzer {
|
|||||||
String fileName = file.getName();
|
String fileName = file.getName();
|
||||||
dependency.setFileName(fileName);
|
dependency.setFileName(fileName);
|
||||||
dependency.setFilePath(file.getCanonicalPath());
|
dependency.setFilePath(file.getCanonicalPath());
|
||||||
String fileNameEvidence = fileName.substring(0,fileName.length()-4)
|
String fileNameEvidence = fileName.substring(0, fileName.length() - 4)
|
||||||
.toLowerCase()
|
.toLowerCase().replace('-', ' ').replace('_', ' ');
|
||||||
.replace('-', ' ')
|
|
||||||
.replace('_', ' ');
|
|
||||||
StringBuilder sb = new StringBuilder(fileNameEvidence.length());
|
StringBuilder sb = new StringBuilder(fileNameEvidence.length());
|
||||||
STRING_STATE state = determineState(fileNameEvidence.charAt(0));
|
STRING_STATE state = determineState(fileNameEvidence.charAt(0));
|
||||||
|
|
||||||
for(int i=0;i<fileNameEvidence.length();i++) {
|
for (int i = 0; i < fileNameEvidence.length(); i++) {
|
||||||
char c = fileNameEvidence.charAt(i);
|
char c = fileNameEvidence.charAt(i);
|
||||||
STRING_STATE new_state = determineState(c);
|
STRING_STATE newState = determineState(c);
|
||||||
if (new_state != state) {
|
if (newState != state) {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
state = new_state;
|
state = newState;
|
||||||
}
|
}
|
||||||
sb.append(c);
|
sb.append(c);
|
||||||
}
|
}
|
||||||
@@ -106,7 +105,7 @@ public class JarAnalyzer implements Analyzer {
|
|||||||
fileNameEvidence, Evidence.Confidence.HIGH);
|
fileNameEvidence, Evidence.Confidence.HIGH);
|
||||||
dependency.getVersionEvidence().addEvidence("jar", "file name",
|
dependency.getVersionEvidence().addEvidence("jar", "file name",
|
||||||
fileNameEvidence, Evidence.Confidence.HIGH);
|
fileNameEvidence, Evidence.Confidence.HIGH);
|
||||||
|
|
||||||
String md5 = null;
|
String md5 = null;
|
||||||
String sha1 = null;
|
String sha1 = null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class Scanner {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (implmnts) {
|
if (implmnts) {
|
||||||
this.analyzers.put(extension, (Analyzer) analyzer.newInstance());
|
this.analyzers.put(extension, (Analyzer) analyzer.newInstance());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public final class CliParser {
|
|||||||
//TODO - need a new exception type here, this isn't really a parseexception.
|
//TODO - need a new exception type here, this isn't really a parseexception.
|
||||||
throw new ParseException("Scan cannot be run without specifying a directory to write the reports to via the 'out' argument.");
|
throw new ParseException("Scan cannot be run without specifying a directory to write the reports to via the 'out' argument.");
|
||||||
} else {
|
} else {
|
||||||
String p = line.getOptionValue(ArgumentName.OUT,"");
|
String p = line.getOptionValue(ArgumentName.OUT, "");
|
||||||
File f = new File(p);
|
File f = new File(p);
|
||||||
if ("".equals(p) || !(f.exists() && f.isDirectory())) {
|
if ("".equals(p) || !(f.exists() && f.isDirectory())) {
|
||||||
//TODO - need a new exception type here, this isn't really a parseexception.
|
//TODO - need a new exception type here, this isn't really a parseexception.
|
||||||
@@ -151,22 +151,29 @@ public final class CliParser {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("static-access")
|
@SuppressWarnings("static-access")
|
||||||
private Options createCommandLineOptions() {
|
private Options createCommandLineOptions() {
|
||||||
Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false, "print this message");
|
Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
|
||||||
Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION, false, "print the version information and exit");
|
"print this message");
|
||||||
|
|
||||||
Option appname = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APPNAME).withDescription("the name of the application being scanned").create(ArgumentName.APPNAME_SHORT);
|
|
||||||
|
|
||||||
Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN).withDescription("the path to scan").create(ArgumentName.SCAN_SHORT);
|
Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
|
||||||
|
false, "print the version information and exit");
|
||||||
|
|
||||||
Option load = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.CPE).withDescription("load the CPE xml file").create(ArgumentName.CPE_SHORT);
|
Option noupdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
|
||||||
|
false, "disables the automatic updating of the CPE data.");
|
||||||
|
|
||||||
|
Option appname = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APPNAME)
|
||||||
|
.withDescription("the name of the application being scanned").create(ArgumentName.APPNAME_SHORT);
|
||||||
|
|
||||||
|
Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
|
||||||
|
.withDescription("the path to scan - this option can be specified multiple times.").create(ArgumentName.SCAN_SHORT);
|
||||||
|
|
||||||
|
Option load = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.CPE)
|
||||||
|
.withDescription("load the CPE xml file").create(ArgumentName.CPE_SHORT);
|
||||||
|
|
||||||
|
Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
|
||||||
|
.withDescription("the folder to write reports to.").create(ArgumentName.OUT_SHORT);
|
||||||
|
|
||||||
Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT).withDescription("the folder to write reports to.").create(ArgumentName.OUT_SHORT);
|
|
||||||
|
|
||||||
//TODO add the ability to load a properties file to override the defaults...
|
//TODO add the ability to load a properties file to override the defaults...
|
||||||
//TODO add the ability to load the CVE entries.
|
|
||||||
//TODO add a switch to auto-update CVE entries.
|
|
||||||
//TODO add a switch to auto-update CPE entries.
|
|
||||||
|
|
||||||
OptionGroup og = new OptionGroup();
|
OptionGroup og = new OptionGroup();
|
||||||
og.addOption(path);
|
og.addOption(path);
|
||||||
og.addOption(load);
|
og.addOption(load);
|
||||||
@@ -177,6 +184,7 @@ public final class CliParser {
|
|||||||
opts.addOption(appname);
|
opts.addOption(appname);
|
||||||
opts.addOption(version);
|
opts.addOption(version);
|
||||||
opts.addOption(help);
|
opts.addOption(help);
|
||||||
|
opts.addOption(noupdate);
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
@@ -222,10 +230,14 @@ public final class CliParser {
|
|||||||
*/
|
*/
|
||||||
public void printHelp() {
|
public void printHelp() {
|
||||||
HelpFormatter formatter = new HelpFormatter();
|
HelpFormatter formatter = new HelpFormatter();
|
||||||
formatter.printHelp("DependencyCheck", options, true);
|
formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
|
||||||
|
"\n" + Settings.getString("application.name", "DependencyCheck") +
|
||||||
|
" can be used to identify if there are any known CVE vulnerabilities in libraries utillized by an application." +
|
||||||
|
" " + Settings.getString("application.name", "DependencyCheck") + " will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.\n",
|
||||||
|
options, "", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the file command line parameter(s) specified for the 'cpe' argument.
|
* Retrieves the file command line parameter(s) specified for the 'cpe' argument.
|
||||||
*
|
*
|
||||||
@@ -234,7 +246,7 @@ public final class CliParser {
|
|||||||
public String getCpeFile() {
|
public String getCpeFile() {
|
||||||
return line.getOptionValue(ArgumentName.CPE);
|
return line.getOptionValue(ArgumentName.CPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the file command line parameter(s) specified for the 'scan' argument.
|
* Retrieves the file command line parameter(s) specified for the 'scan' argument.
|
||||||
*
|
*
|
||||||
@@ -242,12 +254,21 @@ public final class CliParser {
|
|||||||
*/
|
*/
|
||||||
public String[] getScanFiles() {
|
public String[] getScanFiles() {
|
||||||
return line.getOptionValues(ArgumentName.SCAN);
|
return line.getOptionValues(ArgumentName.SCAN);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the directory to write the reports to specified on the command line.
|
||||||
|
* @return the path to the reports directory.
|
||||||
|
*/
|
||||||
public String getReportDirectory() {
|
public String getReportDirectory() {
|
||||||
return line.getOptionValue(ArgumentName.OUT);
|
return line.getOptionValue(ArgumentName.OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the application name specified on the command line.
|
||||||
|
* @return the applicatoin name.
|
||||||
|
*/
|
||||||
public String getApplicationName() {
|
public String getApplicationName() {
|
||||||
return line.getOptionValue(ArgumentName.APPNAME);
|
return line.getOptionValue(ArgumentName.APPNAME);
|
||||||
}
|
}
|
||||||
@@ -257,49 +278,83 @@ public final class CliParser {
|
|||||||
* <li>Implementation-Version: ${pom.version}</li></ul>
|
* <li>Implementation-Version: ${pom.version}</li></ul>
|
||||||
*/
|
*/
|
||||||
public void printVersionInfo() {
|
public void printVersionInfo() {
|
||||||
String version = "DependencyCheck version unknown";
|
String version = String.format("%s version %s",
|
||||||
|
Settings.getString("application.name", "DependencyCheck"),
|
||||||
URLClassLoader cl = (URLClassLoader) this.getClass().getClassLoader();
|
Settings.getString("application.version", "Unknown"));
|
||||||
InputStream is = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
URL url = cl.findResource("META-INF/MANIFEST.MF");
|
|
||||||
is = url.openStream();
|
|
||||||
Manifest manifest = new Manifest(is);
|
|
||||||
Attributes atts = manifest.getMainAttributes();
|
|
||||||
version = atts.getValue(Attributes.Name.IMPLEMENTATION_TITLE)
|
|
||||||
+ " version "
|
|
||||||
+ atts.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
Logger.getLogger(CliParser.class.getName()).log(Level.WARNING, null, ex);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
is.close();
|
|
||||||
is = null;
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
Logger.getLogger(CliParser.class.getName()).log(Level.FINEST, null, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println(version);
|
System.out.println(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the auto update feature has been disabled. If it has been disabled
|
||||||
|
* via the command line this will return false.
|
||||||
|
*
|
||||||
|
* @return if auto-update is allowed.
|
||||||
|
*/
|
||||||
|
public boolean isAutoUpdate() {
|
||||||
|
return (line != null) ? !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE) : false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of static final strings that represent the possible command
|
* A collection of static final strings that represent the possible command
|
||||||
* line arguments.
|
* line arguments.
|
||||||
*/
|
*/
|
||||||
public static class ArgumentName {
|
public static class ArgumentName {
|
||||||
|
/**
|
||||||
|
* The long CLI argument name specifing the directory/file to scan
|
||||||
|
*/
|
||||||
public static final String SCAN = "scan";
|
public static final String SCAN = "scan";
|
||||||
public static final String CPE = "cpe";
|
/**
|
||||||
public static final String OUT = "out";
|
* The short CLI argument name specifing the directory/file to scan
|
||||||
public static final String APPNAME = "app";
|
*/
|
||||||
public static final String VERSION = "version";
|
|
||||||
public static final String HELP = "help";
|
|
||||||
public static final String SCAN_SHORT = "s";
|
public static final String SCAN_SHORT = "s";
|
||||||
|
/**
|
||||||
|
* The long CLI argument name specifing the path to the CPE.XML file to import
|
||||||
|
*/
|
||||||
|
public static final String CPE = "cpe";
|
||||||
|
/**
|
||||||
|
* The short CLI argument name specifing the path to the CPE.XML file to import
|
||||||
|
*/
|
||||||
public static final String CPE_SHORT = "c";
|
public static final String CPE_SHORT = "c";
|
||||||
|
/**
|
||||||
|
* The long CLI argument name specifing that the CPE/CVE/etc. data should not be automatically updated.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_AUTO_UPDATE = "noupdate";
|
||||||
|
/**
|
||||||
|
* The short CLI argument name specifing that the CPE/CVE/etc. data should not be automatically updated.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
|
||||||
|
/**
|
||||||
|
* The long CLI argument name specifing the directory to write the reports to.
|
||||||
|
*/
|
||||||
|
public static final String OUT = "out";
|
||||||
|
/**
|
||||||
|
* The short CLI argument name specifing the directory to write the reports to.
|
||||||
|
*/
|
||||||
public static final String OUT_SHORT = "o";
|
public static final String OUT_SHORT = "o";
|
||||||
public static final String VERSION_SHORT = "v";
|
/**
|
||||||
public static final String HELP_SHORT = "h";
|
* The long CLI argument name specifing the name of the application to be scanned.
|
||||||
|
*/
|
||||||
|
public static final String APPNAME = "app";
|
||||||
|
/**
|
||||||
|
* The short CLI argument name specifing the name of the application to be scanned.
|
||||||
|
*/
|
||||||
public static final String APPNAME_SHORT = "a";
|
public static final String APPNAME_SHORT = "a";
|
||||||
|
/**
|
||||||
|
* The long CLI argument name asking for help.
|
||||||
|
*/
|
||||||
|
public static final String HELP = "help";
|
||||||
|
/**
|
||||||
|
* The short CLI argument name asking for help.
|
||||||
|
*/
|
||||||
|
public static final String HELP_SHORT = "h";
|
||||||
|
/**
|
||||||
|
* The long CLI argument name asking for the version.
|
||||||
|
*/
|
||||||
|
public static final String VERSION_SHORT = "v";
|
||||||
|
/**
|
||||||
|
* The short CLI argument name asking for the version.
|
||||||
|
*/
|
||||||
|
public static final String VERSION = "version";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import java.util.logging.Logger;
|
|||||||
*/
|
*/
|
||||||
public class Settings {
|
public class Settings {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The collection of keys used within the properties file.
|
* The collection of keys used within the properties file.
|
||||||
*/
|
*/
|
||||||
@@ -42,19 +43,23 @@ public class Settings {
|
|||||||
/**
|
/**
|
||||||
* The properties key for the path where the CPE Lucene Index will be stored.
|
* The properties key for the path where the CPE Lucene Index will be stored.
|
||||||
*/
|
*/
|
||||||
public static final String CPE_INDEX = "index.cpe";
|
public static final String CPE_INDEX = "cpe";
|
||||||
/**
|
/**
|
||||||
* The properties key for the URL to the CPE.
|
* The properties key for the URL to the CPE.
|
||||||
*/
|
*/
|
||||||
public static final String CPE_URL = "index.cpe.url";
|
public static final String CPE_URL = "cpe.url";
|
||||||
|
/**
|
||||||
|
* The properties key for the URL to the CPE.
|
||||||
|
*/
|
||||||
|
public static final String CPE_DOWNLOAD_FREQUENCY = "cpe.downloadfrequency";
|
||||||
/**
|
/**
|
||||||
* The properties key for the path where the CCE Lucene Index will be stored.
|
* The properties key for the path where the CCE Lucene Index will be stored.
|
||||||
*/
|
*/
|
||||||
public static final String CVE_INDEX = "index.cve";
|
public static final String CVE_INDEX = "cve";
|
||||||
/**
|
/**
|
||||||
* The properties key for the path where the OSVDB Lucene Index will be stored.
|
* The properties key for the path where the OSVDB Lucene Index will be stored.
|
||||||
*/
|
*/
|
||||||
public static final String OSVDB_INDEX = "index.osvdb";
|
public static final String OSVDB_INDEX = "osvdb";
|
||||||
/**
|
/**
|
||||||
* The properties key prefix for the analyzer assocations.
|
* The properties key prefix for the analyzer assocations.
|
||||||
*/
|
*/
|
||||||
@@ -77,6 +82,24 @@ public class Settings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value from the properties file. If the value was specified as a
|
||||||
|
* system property or passed in via the -Dprop=value argument - this method
|
||||||
|
* will return the value from the system properties before the values in
|
||||||
|
* the contained configuration file.
|
||||||
|
*
|
||||||
|
* @param key the key to lookup within the properties file.
|
||||||
|
* @param defaultValue the default value for the requested property.
|
||||||
|
* @return the property from the properties file.
|
||||||
|
*/
|
||||||
|
public static String getString(String key, String defaultValue) {
|
||||||
|
String str = System.getProperty(key, instance.props.getProperty(key));
|
||||||
|
if (str==null) {
|
||||||
|
str = defaultValue;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a value from the properties file. If the value was specified as a
|
* Returns a value from the properties file. If the value was specified as a
|
||||||
* system property or passed in via the -Dprop=value argument - this method
|
* system property or passed in via the -Dprop=value argument - this method
|
||||||
@@ -127,13 +150,28 @@ public class Settings {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// public static boolean getBoolean(String key) {
|
/**
|
||||||
// return Boolean.parseBoolean(instance.props.getProperty(key));
|
* Returns a integer value from the properties file. If the value was specified as a
|
||||||
// }
|
* system property or passed in via the -Dprop=value argument - this method
|
||||||
// public static long getLong(String key) {
|
* will return the value from the system properties before the values in
|
||||||
// return Long.parseLong(instance.props.getProperty(key));
|
* the contained configuration file.
|
||||||
// }
|
*
|
||||||
// public static int getInt(String key) {
|
* @param key the key to lookup within the properties file.
|
||||||
// return Integer.parseInt(instance.props.getProperty(key));
|
* @return the property from the properties file.
|
||||||
// }
|
*/
|
||||||
|
public static int getInt(String key) {
|
||||||
|
return Integer.parseInt(Settings.getString(key));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a boolean value from the properties file. If the value was specified as a
|
||||||
|
* system property or passed in via the -Dprop=value argument - this method
|
||||||
|
* will return the value from the system properties before the values in
|
||||||
|
* the contained configuration file.
|
||||||
|
*
|
||||||
|
* @param key the key to lookup within the properties file.
|
||||||
|
* @return the property from the properties file.
|
||||||
|
*/
|
||||||
|
public static boolean getBoolean(String key) {
|
||||||
|
return Boolean.parseBoolean(Settings.getString(key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
# To change this template, choose Tools | Templates
|
application.name=${pom.name}
|
||||||
# and open the template in the editor.
|
application.version=${pom.version}
|
||||||
|
|
||||||
index.cpe=store/cpe
|
cpe=store/cpe
|
||||||
index.cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.xml
|
cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.2.xml
|
||||||
index.cve=store/cve
|
cpe.downloadfrequency=1
|
||||||
index.osvdb=store/osvdb
|
cve=store/cve
|
||||||
|
osvdb=store/osvdb
|
||||||
|
|
||||||
file.extension.analyzer.association.jar=org.codesecure.dependencycheck.scanner.JarAnalyzer
|
file.extension.analyzer.association.jar=org.codesecure.dependencycheck.scanner.JarAnalyzer
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
@version 1
|
@version 1
|
||||||
*#
|
*#
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -274,7 +273,9 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
#set($cnt=0)
|
#set($cnt=0)
|
||||||
#foreach($dependency in $dependencies)
|
#foreach($dependency in $dependencies)
|
||||||
<h3 class="subsectionheader standardsubsection"><a name="$esc.html($dependency.FilePath)"></a>$esc.html($dependency.FileName)</h3>
|
<h3 class="subsectionheader standardsubsection"><a name="$esc.html($dependency.FilePath)"></a>$esc.html($dependency.FileName)</h3>
|
||||||
<div class="subsectioncontent">File Path: $esc.html($dependency.FilePath)
|
<div class="subsectioncontent">File Path: $esc.html($dependency.FilePath)<br/>
|
||||||
|
MD5: $esc.html($dependency.Md5sum)<br/>
|
||||||
|
SHA1: $esc.html($dependency.Sha1sum)
|
||||||
#set($cnt=$cnt+1)
|
#set($cnt=$cnt+1)
|
||||||
<h4 id="header$cnt" class="subsectionheader expandablesubsection white">Evidence</h4>
|
<h4 id="header$cnt" class="subsectionheader expandablesubsection white">Evidence</h4>
|
||||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||||
@@ -293,8 +294,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
Information for specific CVE entries for the idenfied CPE can be found <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$esc.url($cpevalue)" target="blank">here</a>.
|
Information for specific CVE entries for the idenfied CPE can be found <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$esc.url($cpevalue)" target="blank">here</a>.
|
||||||
#* http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-0838
|
#* http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-0838
|
||||||
<a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=" target="blank">cve://a:/blah1.blah</a><br/>
|
<a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=" target="blank">cve://a:/blah1.blah</a><br/>
|
||||||
<a href="cve.mitre.org" target="blank">cve://a:/blah2.blah</a><br/>
|
*#
|
||||||
<a href="cve.mitre.org" target="blank">cve://a:/blah3.blah</a><br/>*#
|
|
||||||
</div>
|
</div>
|
||||||
#end
|
#end
|
||||||
#if($dependency.getCPEs().size()>1)
|
#if($dependency.getCPEs().size()>1)
|
||||||
@@ -310,7 +310,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
#end
|
#end
|
||||||
|
|
||||||
#if($dependency.getCPEs().size()==0)
|
#if($dependency.getCPEs().size()==0)
|
||||||
<h4>No CPE Identifies were found for this dependency.</h4>
|
<h4>No CPE Identifiers were found for this dependency.</h4>
|
||||||
#end
|
#end
|
||||||
</div>
|
</div>
|
||||||
#end
|
#end
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -31,7 +31,7 @@ public abstract class BaseIndexTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void ensureIndexExists() throws Exception {
|
protected void ensureIndexExists() throws Exception {
|
||||||
String indexPath = Settings.getString("index.cpe");
|
String indexPath = Settings.getString("cpe");
|
||||||
java.io.File f = new File(indexPath);
|
java.io.File f = new File(indexPath);
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
f.mkdirs();
|
f.mkdirs();
|
||||||
|
|||||||
@@ -336,9 +336,8 @@ public class CliParserTest extends TestCase {
|
|||||||
baos.flush();
|
baos.flush();
|
||||||
String text = (new String(baos.toByteArray()));
|
String text = (new String(baos.toByteArray()));
|
||||||
String[] lines = text.split(System.getProperty("line.separator"));
|
String[] lines = text.split(System.getProperty("line.separator"));
|
||||||
assertEquals("usage: DependencyCheck [-a <name>] [-c <file> | -s <path>] [-h] [-o", lines[0]);
|
assertTrue(lines[0].startsWith("usage: "));
|
||||||
assertEquals(" <folder>] [-v]", lines[1]);
|
assertTrue((lines.length>2));
|
||||||
assertEquals(8, lines.length);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
System.setOut(out);
|
System.setOut(out);
|
||||||
fail("CliParser.printVersionInfo did not write anything to system.out.");
|
fail("CliParser.printVersionInfo did not write anything to system.out.");
|
||||||
|
|||||||
@@ -36,15 +36,17 @@ public class DownloaderTest {
|
|||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test of fetchFile method, of class Downloader.
|
//This test is being removed because it is a bit too slow.
|
||||||
* @throws Exception thrown when an excpetion occurs.
|
// /**
|
||||||
*/
|
// * Test of fetchFile method, of class Downloader.
|
||||||
@Test
|
// * @throws Exception thrown when an excpetion occurs.
|
||||||
public void testFetchFile_URL_String() throws Exception {
|
// */
|
||||||
System.out.println("fetchFile");
|
// @Test
|
||||||
URL url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
|
// public void testFetchFile_URL_String() throws Exception {
|
||||||
String outputPath = "target\\downloaded_cpe.xml";
|
// System.out.println("fetchFile");
|
||||||
Downloader.fetchFile(url, outputPath);
|
// URL url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
|
||||||
}
|
// String outputPath = "target\\downloaded_cpe.xml";
|
||||||
|
// Downloader.fetchFile(url, outputPath);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user