From 23b95178ff1a2d815e6c331fa1811252eacd7af7 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 10 May 2014 07:00:43 -0400 Subject: [PATCH] updated to remove archive files from the list of dependencies - additionally, if a zip file appears to be a jar it will now make a copy of the zip and scan it as a jar Former-commit-id: d927daea530abad2d578dbe0ff38b97d044b4775 --- .../analyzer/ArchiveAnalyzer.java | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java index 67415dffc..d8fb025ca 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -35,7 +36,9 @@ import java.util.logging.Logger; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; +import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.compress.compressors.CompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipUtils; @@ -99,6 +102,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { */ private static final Set EXTENSIONS = newHashSet("tar", "gz", "tgz"); + /** + * The set of file extensions to remove from the engine's collection of dependencies. + */ + private static final Set REMOVE_FROM_ANALYSIS = newHashSet("zip", "tar", "gz", "tgz"); //TODO add nupkg, apk, sar? + static { final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS); if (additionalZipExt != null) { @@ -199,9 +207,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { extractFiles(f, tmpDir, engine); //make a copy - final List dependencies = new ArrayList(engine.getDependencies()); + List dependencies = new ArrayList(engine.getDependencies()); engine.scan(tmpDir); - final List newDependencies = engine.getDependencies(); + List newDependencies = engine.getDependencies(); if (dependencies.size() != newDependencies.size()) { //get the new dependencies final Set dependencySet = new HashSet(); @@ -229,6 +237,40 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { } } } + if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) { + if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) { + final File tdir = getNextTempDirectory(); + final String fileName = dependency.getFileName(); + + LOGGER.info(String.format("The zip file '%s' appears to be a JAR file, making a deep copy and analyziing it as a JAR.", fileName)); + + final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar"); + try { + org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc); + dependencies = new ArrayList(engine.getDependencies()); + engine.scan(tmpLoc); + newDependencies = engine.getDependencies(); + if (dependencies.size() != newDependencies.size()) { + //get the new dependencies + final Set dependencySet = new HashSet(); + dependencySet.addAll(newDependencies); + dependencySet.removeAll(dependencies); + if (dependencySet.size() != 1) { + LOGGER.info("Deep copy of ZIP to JAR file resulted in more then one dependency?"); + } + for (Dependency d : dependencySet) { + //fix the dependency's display name and path + d.setFilePath(dependency.getFilePath()); + d.setDisplayFileName(dependency.getFileName()); + } + } + } catch (IOException ex) { + final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath()); + LOGGER.log(Level.FINE, msg, ex); + } + } + engine.getDependencies().remove(dependency); + } Collections.sort(engine.getDependencies()); } @@ -411,4 +453,38 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { } } } + + /** + * Attempts to determine if a zip file is actually a JAR file. + * + * @param dependency the dependency to check + * @return true if the dependency appears to be a JAR file; otherwise false + */ + private boolean isZipFileActuallyJarFile(Dependency dependency) { + boolean isJar = false; + ZipFile zip = null; + try { + zip = new ZipFile(dependency.getActualFilePath()); + if (zip.getEntry("META-INF/MANIFEST.MF") != null + || zip.getEntry("META-INF/maven") != null) { + Enumeration entries = zip.getEntries(); + while (entries.hasMoreElements()) { + ZipArchiveEntry entry = entries.nextElement(); + if (!entry.isDirectory()) { + String name = entry.getName().toLowerCase(); + if (name.endsWith(".class")) { + isJar = true; + break; + } + } + } + } + } catch (IOException ex) { + Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.SEVERE, null, ex); + } finally { + ZipFile.closeQuietly(zip); + } + + return isJar; + } }