mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-18 07:14:09 +01:00
auto-format changed indentations
Former-commit-id: 1ef56dd84a5167644c2767cefdee54d555175c55
This commit is contained in:
@@ -47,298 +47,291 @@ import org.owasp.dependencycheck.utils.Settings;
|
|||||||
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to analyze a Wheel or egg distriution files, or their contents in
|
* Used to analyze a Wheel or egg distriution files, or their contents in unzipped form, and collect information that can be used
|
||||||
* unzipped form, and collect information that can be used to determine the
|
* to determine the associated CPE.
|
||||||
* associated CPE.
|
|
||||||
*
|
*
|
||||||
* @author Dale Visser <dvisser@ida.org>
|
* @author Dale Visser <dvisser@ida.org>
|
||||||
*/
|
*/
|
||||||
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of egg metatdata files to analyze.
|
* Name of egg metatdata files to analyze.
|
||||||
*/
|
*/
|
||||||
private static final String PKG_INFO = "PKG-INFO";
|
private static final String PKG_INFO = "PKG-INFO";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of wheel metadata files to analyze.
|
* Name of wheel metadata files to analyze.
|
||||||
*/
|
*/
|
||||||
private static final String METADATA = "METADATA";
|
private static final String METADATA = "METADATA";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(PythonDistributionAnalyzer.class.getName());
|
.getLogger(PythonDistributionAnalyzer.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The count of directories created during analysis. This is used for
|
* The count of directories created during analysis. This is used for creating temporary directories.
|
||||||
* creating temporary directories.
|
*/
|
||||||
*/
|
private static int dirCount = 0;
|
||||||
private static int dirCount = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
*/
|
*/
|
||||||
private static final String ANALYZER_NAME = "Python Distribution Analyzer";
|
private static final String ANALYZER_NAME = "Python Distribution Analyzer";
|
||||||
/**
|
/**
|
||||||
* The phase that this analyzer is intended to run in.
|
* The phase that this analyzer is intended to run in.
|
||||||
*/
|
*/
|
||||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of file extensions supported by this analyzer.
|
* The set of file extensions supported by this analyzer.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> EXTENSIONS = newHashSet("whl", "egg",
|
private static final Set<String> EXTENSIONS = newHashSet("whl", "egg",
|
||||||
"zip", METADATA, PKG_INFO);
|
"zip", METADATA, PKG_INFO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to match on egg archive candidate extenssions.
|
* Used to match on egg archive candidate extenssions.
|
||||||
*/
|
*/
|
||||||
private static final Pattern EGG_OR_ZIP = Pattern.compile("egg|zip");
|
private static final Pattern EGG_OR_ZIP = Pattern.compile("egg|zip");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parent directory for the individual directories per archive.
|
* The parent directory for the individual directories per archive.
|
||||||
*/
|
*/
|
||||||
private File tempFileLocation;
|
private File tempFileLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter that detects *.dist-info files (but doesn't verify they are
|
* Filter that detects *.dist-info files (but doesn't verify they are directories.
|
||||||
* directories.
|
*/
|
||||||
*/
|
private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter(
|
||||||
private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter(
|
".dist-info");
|
||||||
".dist-info");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter that detects files named "METADATA".
|
* Filter that detects files named "METADATA".
|
||||||
*/
|
*/
|
||||||
private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter(
|
private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter(
|
||||||
"EGG-INFO");
|
"EGG-INFO");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter that detects files named "METADATA".
|
* Filter that detects files named "METADATA".
|
||||||
*/
|
*/
|
||||||
private static final FilenameFilter METADATA_FILTER = new NameFileFilter(
|
private static final FilenameFilter METADATA_FILTER = new NameFileFilter(
|
||||||
METADATA);
|
METADATA);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter that detects files named "PKG-INFO".
|
* Filter that detects files named "PKG-INFO".
|
||||||
*/
|
*/
|
||||||
private static final FilenameFilter PKG_INFO_FILTER = new NameFileFilter(
|
private static final FilenameFilter PKG_INFO_FILTER = new NameFileFilter(
|
||||||
PKG_INFO);
|
PKG_INFO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||||
*
|
*
|
||||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
public Set<String> getSupportedExtensions() {
|
||||||
return EXTENSIONS;
|
return EXTENSIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the analyzer.
|
* Returns the name of the analyzer.
|
||||||
*
|
*
|
||||||
* @return the name of the analyzer.
|
* @return the name of the analyzer.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return ANALYZER_NAME;
|
return ANALYZER_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the phase that the analyzer is intended to run in.
|
* Returns the phase that the analyzer is intended to run in.
|
||||||
*
|
*
|
||||||
* @return the phase that the analyzer is intended to run in.
|
* @return the phase that the analyzer is intended to run in.
|
||||||
*/
|
*/
|
||||||
public AnalysisPhase getAnalysisPhase() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the key used in the properties file to reference the analyzer's
|
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||||
* enabled property.
|
*
|
||||||
*
|
* @return the analyzer's enabled property setting key
|
||||||
* @return the analyzer's enabled property setting key
|
*/
|
||||||
*/
|
@Override
|
||||||
@Override
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
protected String getAnalyzerEnabledSettingKey() {
|
return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
|
||||||
return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
throws AnalysisException {
|
throws AnalysisException {
|
||||||
if ("whl".equals(dependency.getFileExtension())) {
|
if ("whl".equals(dependency.getFileExtension())) {
|
||||||
collectMetadataFromArchiveFormat(dependency, DIST_INFO_FILTER,
|
collectMetadataFromArchiveFormat(dependency, DIST_INFO_FILTER,
|
||||||
METADATA_FILTER);
|
METADATA_FILTER);
|
||||||
} else if (EGG_OR_ZIP.matcher(
|
} else if (EGG_OR_ZIP.matcher(
|
||||||
StringUtils.stripToEmpty(dependency.getFileExtension()))
|
StringUtils.stripToEmpty(dependency.getFileExtension()))
|
||||||
.matches()) {
|
.matches()) {
|
||||||
collectMetadataFromArchiveFormat(dependency, EGG_INFO_FILTER,
|
collectMetadataFromArchiveFormat(dependency, EGG_INFO_FILTER,
|
||||||
PKG_INFO_FILTER);
|
PKG_INFO_FILTER);
|
||||||
} else {
|
} else {
|
||||||
final File actualFile = dependency.getActualFile();
|
final File actualFile = dependency.getActualFile();
|
||||||
final String name = actualFile.getName();
|
final String name = actualFile.getName();
|
||||||
final boolean metadata = METADATA.equals(name);
|
final boolean metadata = METADATA.equals(name);
|
||||||
if (metadata || PKG_INFO.equals(name)) {
|
if (metadata || PKG_INFO.equals(name)) {
|
||||||
final File parent = actualFile.getParentFile();
|
final File parent = actualFile.getParentFile();
|
||||||
final String parentName = parent.getName();
|
final String parentName = parent.getName();
|
||||||
dependency.setDisplayFileName(parentName + "/" + name);
|
dependency.setDisplayFileName(parentName + "/" + name);
|
||||||
if (parent.isDirectory()
|
if (parent.isDirectory()
|
||||||
&& (metadata && parentName.endsWith(".dist-info")
|
&& (metadata && parentName.endsWith(".dist-info")
|
||||||
|| parentName.endsWith(".egg-info") || "EGG-INFO"
|
|| parentName.endsWith(".egg-info") || "EGG-INFO"
|
||||||
.equals(parentName))) {
|
.equals(parentName))) {
|
||||||
collectWheelMetadata(dependency, actualFile);
|
collectWheelMetadata(dependency, actualFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectMetadataFromArchiveFormat(Dependency dependency,
|
private void collectMetadataFromArchiveFormat(Dependency dependency,
|
||||||
FilenameFilter folderFilter, FilenameFilter metadataFilter)
|
FilenameFilter folderFilter, FilenameFilter metadataFilter)
|
||||||
throws AnalysisException {
|
throws AnalysisException {
|
||||||
final File temp = getNextTempDirectory();
|
final File temp = getNextTempDirectory();
|
||||||
LOGGER.fine(String.format("%s exists? %b", temp, temp.exists()));
|
LOGGER.fine(String.format("%s exists? %b", temp, temp.exists()));
|
||||||
try {
|
try {
|
||||||
ExtractionUtil.extractFilesUsingFilter(
|
ExtractionUtil.extractFilesUsingFilter(
|
||||||
new File(dependency.getActualFilePath()), temp,
|
new File(dependency.getActualFilePath()), temp,
|
||||||
metadataFilter);
|
metadataFilter);
|
||||||
} catch (ExtractionException ex) {
|
} catch (ExtractionException ex) {
|
||||||
throw new AnalysisException(ex);
|
throw new AnalysisException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
collectWheelMetadata(
|
collectWheelMetadata(
|
||||||
dependency,
|
dependency,
|
||||||
getMatchingFile(getMatchingFile(temp, folderFilter),
|
getMatchingFile(getMatchingFile(temp, folderFilter),
|
||||||
metadataFilter));
|
metadataFilter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure a usable temporary directory is available.
|
* Makes sure a usable temporary directory is available.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||||
final File baseDir = Settings.getTempDirectory();
|
final File baseDir = Settings.getTempDirectory();
|
||||||
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
|
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
|
||||||
if (!tempFileLocation.delete()) {
|
if (!tempFileLocation.delete()) {
|
||||||
final String msg = String.format(
|
final String msg = String.format(
|
||||||
"Unable to delete temporary file '%s'.",
|
"Unable to delete temporary file '%s'.",
|
||||||
tempFileLocation.getAbsolutePath());
|
tempFileLocation.getAbsolutePath());
|
||||||
throw new AnalysisException(msg);
|
throw new AnalysisException(msg);
|
||||||
}
|
}
|
||||||
if (!tempFileLocation.mkdirs()) {
|
if (!tempFileLocation.mkdirs()) {
|
||||||
final String msg = String.format(
|
final String msg = String.format(
|
||||||
"Unable to create directory '%s'.",
|
"Unable to create directory '%s'.",
|
||||||
tempFileLocation.getAbsolutePath());
|
tempFileLocation.getAbsolutePath());
|
||||||
throw new AnalysisException(msg);
|
throw new AnalysisException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes any files extracted from the Wheel during analysis.
|
* Deletes any files extracted from the Wheel during analysis.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
||||||
final boolean success = FileUtils.delete(tempFileLocation);
|
final boolean success = FileUtils.delete(tempFileLocation);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.log(Level.WARNING,
|
||||||
"Failed to delete some temporary files, see the log for more details");
|
"Failed to delete some temporary files, see the log for more details");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gathers evidence from the METADATA file.
|
* Gathers evidence from the METADATA file.
|
||||||
*
|
*
|
||||||
* @param dependency
|
* @param dependency the dependency being analyzed
|
||||||
* the dependency being analyzed
|
* @throws MalformedURLException
|
||||||
* @throws MalformedURLException
|
*/
|
||||||
*/
|
private static void collectWheelMetadata(Dependency dependency, File file)
|
||||||
private static void collectWheelMetadata(Dependency dependency, File file)
|
throws AnalysisException {
|
||||||
throws AnalysisException {
|
final InternetHeaders headers = getManifestProperties(file);
|
||||||
final InternetHeaders headers = getManifestProperties(file);
|
addPropertyToEvidence(headers, dependency.getVersionEvidence(),
|
||||||
addPropertyToEvidence(headers, dependency.getVersionEvidence(),
|
"Version", Confidence.HIGHEST);
|
||||||
"Version", Confidence.HIGHEST);
|
addPropertyToEvidence(headers, dependency.getProductEvidence(), "Name",
|
||||||
addPropertyToEvidence(headers, dependency.getProductEvidence(), "Name",
|
Confidence.HIGHEST);
|
||||||
Confidence.HIGHEST);
|
final String url = headers.getHeader("Home-page", null);
|
||||||
final String url = headers.getHeader("Home-page", null);
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
final EvidenceCollection vendorEvidence = dependency
|
.getVendorEvidence();
|
||||||
.getVendorEvidence();
|
if (StringUtils.isNotBlank(url)) {
|
||||||
if (StringUtils.isNotBlank(url)) {
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
if (UrlStringUtils.isUrl(url)) {
|
vendorEvidence.addEvidence(METADATA, "vendor", url,
|
||||||
vendorEvidence.addEvidence(METADATA, "vendor", url,
|
Confidence.MEDIUM);
|
||||||
Confidence.MEDIUM);
|
}
|
||||||
}
|
}
|
||||||
}
|
addPropertyToEvidence(headers, vendorEvidence, "Author", Confidence.LOW);
|
||||||
addPropertyToEvidence(headers, vendorEvidence, "Author", Confidence.LOW);
|
final String summary = headers.getHeader("Summary", null);
|
||||||
final String summary = headers.getHeader("Summary", null);
|
if (StringUtils.isNotBlank(summary)) {
|
||||||
if (StringUtils.isNotBlank(summary)) {
|
JarAnalyzer
|
||||||
JarAnalyzer
|
.addDescription(dependency, summary, METADATA, "summary");
|
||||||
.addDescription(dependency, summary, METADATA, "summary");
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static void addPropertyToEvidence(InternetHeaders headers,
|
private static void addPropertyToEvidence(InternetHeaders headers,
|
||||||
EvidenceCollection evidence, String property, Confidence confidence) {
|
EvidenceCollection evidence, String property, Confidence confidence) {
|
||||||
final String value = headers.getHeader(property, null);
|
final String value = headers.getHeader(property, null);
|
||||||
LOGGER.fine(String.format("Property: %s, Value: %s\n", property, value));
|
LOGGER.fine(String.format("Property: %s, Value: %s\n", property, value));
|
||||||
if (StringUtils.isNotBlank(value)) {
|
if (StringUtils.isNotBlank(value)) {
|
||||||
evidence.addEvidence(METADATA, property, value, confidence);
|
evidence.addEvidence(METADATA, property, value, confidence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final File getMatchingFile(File folder, FilenameFilter filter) {
|
private static final File getMatchingFile(File folder, FilenameFilter filter) {
|
||||||
File result = null;
|
File result = null;
|
||||||
final File[] matches = folder.listFiles(filter);
|
final File[] matches = folder.listFiles(filter);
|
||||||
if (null != matches && 1 == matches.length) {
|
if (null != matches && 1 == matches.length) {
|
||||||
result = matches[0];
|
result = matches[0];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InternetHeaders getManifestProperties(File manifest) {
|
private static InternetHeaders getManifestProperties(File manifest) {
|
||||||
final InternetHeaders result = new InternetHeaders();
|
final InternetHeaders result = new InternetHeaders();
|
||||||
if (null == manifest) {
|
if (null == manifest) {
|
||||||
LOGGER.fine("Manifest file not found.");
|
LOGGER.fine("Manifest file not found.");
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
result.load(new AutoCloseInputStream(new BufferedInputStream(
|
result.load(new AutoCloseInputStream(new BufferedInputStream(
|
||||||
new FileInputStream(manifest))));
|
new FileInputStream(manifest))));
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the next temporary destingation directory for extracting an
|
* Retrieves the next temporary destingation directory for extracting an archive.
|
||||||
* archive.
|
*
|
||||||
*
|
* @return a directory
|
||||||
* @return a directory
|
* @throws AnalysisException thrown if unable to create temporary directory
|
||||||
* @throws AnalysisException
|
*/
|
||||||
* thrown if unable to create temporary directory
|
private File getNextTempDirectory() throws AnalysisException {
|
||||||
*/
|
File directory;
|
||||||
private File getNextTempDirectory() throws AnalysisException {
|
|
||||||
File directory;
|
|
||||||
|
|
||||||
// getting an exception for some directories not being able to be
|
// getting an exception for some directories not being able to be
|
||||||
// created; might be because the directory already exists?
|
// created; might be because the directory already exists?
|
||||||
do {
|
do {
|
||||||
dirCount += 1;
|
dirCount += 1;
|
||||||
directory = new File(tempFileLocation, String.valueOf(dirCount));
|
directory = new File(tempFileLocation, String.valueOf(dirCount));
|
||||||
} while (directory.exists());
|
} while (directory.exists());
|
||||||
if (!directory.mkdirs()) {
|
if (!directory.mkdirs()) {
|
||||||
throw new AnalysisException(String.format(
|
throw new AnalysisException(String.format(
|
||||||
"Unable to create temp directory '%s'.",
|
"Unable to create temp directory '%s'.",
|
||||||
directory.getAbsolutePath()));
|
directory.getAbsolutePath()));
|
||||||
}
|
}
|
||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user