diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CocoaPodsAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CocoaPodsAnalyzer.java new file mode 100644 index 000000000..4d05e6505 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CocoaPodsAnalyzer.java @@ -0,0 +1,189 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * © Copyright IBM Corporation 2016. + */ +package org.owasp.dependencycheck.analyzer; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.FileUtils; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.dependency.Confidence; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceCollection; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.Settings; + +/** + * This analyzer is used to analyze SWIFT and Objective-C packages by collecting + * information from .podspec files. CocoaPods dependency manager see https://cocoapods.org/. + * + * @author Bianca Jiang (https://twitter.com/biancajiang) + */ +@Experimental +public class CocoaPodsAnalyzer extends AbstractFileTypeAnalyzer { + + /** + * The logger. + */ +// private static final Logger LOGGER = LoggerFactory.getLogger(CocoaPodsAnalyzer.class); + + /** + * The name of the analyzer. + */ + private static final String ANALYZER_NAME = "CocoaPods Package Analyzer"; + + /** + * The phase that this analyzer is intended to run in. + */ + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; + + /** + * The file name to scan. + */ + public static final String PODSPEC = "podspec"; + /** + * Filter that detects files named "*.podspec". + */ + private static final FileFilter PODSPEC_FILTER = FileFilterBuilder.newInstance().addExtensions(PODSPEC).build(); + + + /** + * The capture group #1 is the block variable. + * e.g. "Pod::Spec.new do |spec|" + */ + private static final Pattern PODSPEC_BLOCK_PATTERN + = Pattern.compile("Pod::Spec\\.new\\s+?do\\s+?\\|(.+?)\\|"); + + + /** + * Returns the FileFilter + * + * @return the FileFilter + */ + @Override + protected FileFilter getFileFilter() { + return PODSPEC_FILTER; + } + + @Override + protected void initializeFileTypeAnalyzer() { + // NO-OP + } + + /** + * Returns the name of the analyzer. + * + * @return the name of the analyzer. + */ + @Override + public String getName() { + return ANALYZER_NAME; + } + + /** + * Returns the phase that the analyzer is intended to run in. + * + * @return the phase that the analyzer is intended to run in. + */ + @Override + public AnalysisPhase getAnalysisPhase() { + return ANALYSIS_PHASE; + } + + /** + * Returns the key used in the properties file to reference the analyzer's enabled property. + * + * @return the analyzer's enabled property setting key + */ + @Override + protected String getAnalyzerEnabledSettingKey() { + return Settings.KEYS.ANALYZER_COCOAPODS_ENABLED; + } + + @Override + protected void analyzeFileType(Dependency dependency, Engine engine) + throws AnalysisException { + + String contents; + try { + contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset()); + } catch (IOException e) { + throw new AnalysisException( + "Problem occurred while reading dependency file.", e); + } + final Matcher matcher = PODSPEC_BLOCK_PATTERN.matcher(contents); + if (matcher.find()) { + contents = contents.substring(matcher.end()); + final String blockVariable = matcher.group(1); + + final EvidenceCollection vendor = dependency.getVendorEvidence(); + final EvidenceCollection product = dependency.getProductEvidence(); + final EvidenceCollection version = dependency.getVersionEvidence(); + + final String name = addStringEvidence(product, contents, blockVariable, "name", "name", Confidence.HIGHEST); + if (!name.isEmpty()) { + vendor.addEvidence(PODSPEC, "name_project", name, Confidence.HIGHEST); + } + addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.HIGHEST); + + addStringEvidence(vendor, contents, blockVariable, "author", "authors?", Confidence.HIGHEST); + addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST); + addStringEvidence(vendor, contents, blockVariable, "license", "licen[cs]es?", Confidence.HIGHEST); + + addStringEvidence(version, contents, blockVariable, "version", "version", Confidence.HIGHEST); + } + + setPackagePath(dependency); + } + + private String addStringEvidence(EvidenceCollection evidences, String contents, + String blockVariable, String field, String fieldPattern, Confidence confidence) { + String value = ""; + + //capture array value between [ ] + final Matcher arrayMatcher = Pattern.compile( + String.format("\\s*?%s\\.%s\\s*?=\\s*?\\{\\s*?(.*?)\\s*?\\}", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents); + if(arrayMatcher.find()) { + value = arrayMatcher.group(1); + } + //capture single value between quotes + else { + final Matcher matcher = Pattern.compile( + String.format("\\s*?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents); + if (matcher.find()) { + value = matcher.group(2); + } + } + if(value.length() > 0) + evidences.addEvidence(PODSPEC, field, value, confidence); + + return value; + } + + private void setPackagePath(Dependency dep) { + File file = new File(dep.getFilePath()); + String parent = file.getParent(); + if(parent != null) + dep.setPackagePath(parent); + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java index 419eacb09..42b322e65 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java @@ -117,6 +117,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal final ListIterator subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex()); while (subIterator.hasNext()) { final Dependency nextDependency = subIterator.next(); + Dependency main = null; if (hashesMatch(dependency, nextDependency) && !containedInWar(dependency.getFilePath()) && !containedInWar(nextDependency.getFilePath())) { if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) { @@ -143,11 +144,17 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal mergeDependencies(nextDependency, dependency, dependenciesToRemove); break; //since we merged into the next dependency - skip forward to the next in mainIterator } - } else if (isSameRubyGem(dependency, nextDependency)) { - final Dependency main = getMainGemspecDependency(dependency, nextDependency); - if (main == dependency) { - mergeDependencies(dependency, nextDependency, dependenciesToRemove); - } else { + } else if ( (main = getMainGemspecDependency(dependency, nextDependency)) != null ) { + if (main == dependency) { + mergeDependencies(dependency, nextDependency, dependenciesToRemove); + } else { + mergeDependencies(nextDependency, dependency, dependenciesToRemove); + break; //since we merged into the next dependency - skip forward to the next in mainIterator + } + } else if ( (main = getMainSwiftDependency(dependency, nextDependency)) != null) { + if (main == dependency) { + mergeDependencies(dependency, nextDependency, dependenciesToRemove); + } else { mergeDependencies(nextDependency, dependency, dependenciesToRemove); break; //since we merged into the next dependency - skip forward to the next in mainIterator } @@ -375,6 +382,33 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal } return null; } + + /** + * Bundling same swift dependencies with the same packagePath but identified by different analyzers. + */ + private boolean isSameSwiftPackage(Dependency dependency1, Dependency dependency2) { + if (dependency1 == null || dependency2 == null || + (!dependency1.getFileName().endsWith(".podspec") && + !dependency1.getFileName().equals("Package.swift")) || + (!dependency2.getFileName().endsWith(".podspec") && + !dependency2.getFileName().equals("Package.swift")) || + dependency1.getPackagePath() == null || + dependency2.getPackagePath() == null) { + return false; + } + if (dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath())) + return true; + + return false; + } + private Dependency getMainSwiftDependency(Dependency dependency1, Dependency dependency2) { + if (isSameSwiftPackage(dependency1, dependency2)) { + if(dependency1.getFileName().endsWith(".podspec")) + return dependency1; + return dependency2; + } + return null; + } /** * This is likely a very broken attempt at determining if the 'left' diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java index fcaaeb102..5e6dee5b8 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java @@ -93,26 +93,27 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer { //add version evidence final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName); + final String packageName = DependencyVersionUtil.parsePreVersion(fileName); if (version != null) { // If the version number is just a number like 2 or 23, reduce the confidence // a shade. This should hopefully correct for cases like log4j.jar or // struts2-core.jar if (version.getVersionParts() == null || version.getVersionParts().size() < 2) { - dependency.getVersionEvidence().addEvidence("file", "name", + dependency.getVersionEvidence().addEvidence("file", "version", version.toString(), Confidence.MEDIUM); } else { dependency.getVersionEvidence().addEvidence("file", "version", version.toString(), Confidence.HIGHEST); } dependency.getVersionEvidence().addEvidence("file", "name", - fileName, Confidence.MEDIUM); + packageName, Confidence.MEDIUM); } if (!IGNORED_FILES.accept(f)) { dependency.getProductEvidence().addEvidence("file", "name", - fileName, Confidence.HIGH); + packageName, Confidence.HIGH); dependency.getVendorEvidence().addEvidence("file", "name", - fileName, Confidence.HIGH); + packageName, Confidence.HIGH); } } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java index 58c633910..aad0cb036 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java @@ -685,7 +685,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer { foundSomething = true; versionEvidence.addEvidence(source, key, value, Confidence.HIGH); } else if ("specification-version".equalsIgnoreCase(key)) { - specificationVersion = key; + specificationVersion = value; } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) { foundSomething = true; vendorEvidence.addEvidence(source, key, value, Confidence.HIGH); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java index 8c5d0efed..56001c9d7 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java @@ -23,25 +23,26 @@ import java.io.FileFilter; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.nio.charset.Charset; + import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvdcve.CveDB; +import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Reference; import org.owasp.dependencycheck.dependency.Vulnerability; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.owasp.dependencycheck.data.nvdcve.DatabaseException; -import org.owasp.dependencycheck.exception.InitializationException; /** * Used to analyze Ruby Bundler Gemspec.lock files utilizing the 3rd party diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzer.java index ebe77e7b8..b89a11d92 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright (c) 2016 Bianca Jiang. All Rights Reserved. + * © Copyright IBM Corporation 2016. */ package org.owasp.dependencycheck.analyzer; @@ -43,7 +43,7 @@ import org.owasp.dependencycheck.dependency.Dependency; * {@link RubyGemspecAnalyzer}, so it will enabled/disabled with * {@link RubyGemspecAnalyzer}. * - * @author Bianca Jiang (biancajiang@gmail.com) + * @author Bianca Jiang (https://twitter.com/biancajiang) */ @Experimental public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageManagerAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageManagerAnalyzer.java new file mode 100644 index 000000000..f28feecae --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageManagerAnalyzer.java @@ -0,0 +1,177 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * © Copyright IBM Corporation 2016. + */ +package org.owasp.dependencycheck.analyzer; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.FileUtils; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.dependency.Confidence; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceCollection; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.Settings; + +/** + * This analyzer is used to analyze the SWIFT Package Manager (https://swift.org/package-manager/). + * It collects information about a package from Package.swift files. + * + * @author Bianca Jiang (https://twitter.com/biancajiang) + */ +@Experimental +public class SwiftPackageManagerAnalyzer extends AbstractFileTypeAnalyzer { + + /** + * The name of the analyzer. + */ + private static final String ANALYZER_NAME = "SWIFT Package Manager Analyzer"; + + /** + * The phase that this analyzer is intended to run in. + */ + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; + + /** + * The file name to scan. + */ + public static final String SPM_FILE_NAME = "Package.swift"; + + /** + * Filter that detects files named "package.json". + */ + private static final FileFilter SPM_FILE_FILTER = FileFilterBuilder.newInstance().addFilenames(SPM_FILE_NAME).build(); + + /** + * The capture group #1 is the block variable. + * e.g. + * "import PackageDescription + * let package = Package( + * name: "Gloss" + * )" + */ + private static final Pattern SPM_BLOCK_PATTERN + = Pattern.compile("let[^=]+=\\s*Package\\s*\\(\\s*([^)]*)\\s*\\)", Pattern.DOTALL); + + /** + * Returns the FileFilter + * + * @return the FileFilter + */ + @Override + protected FileFilter getFileFilter() { + return SPM_FILE_FILTER; + } + + @Override + protected void initializeFileTypeAnalyzer() { + // NO-OP + } + + /** + * Returns the name of the analyzer. + * + * @return the name of the analyzer. + */ + @Override + public String getName() { + return ANALYZER_NAME; + } + + /** + * Returns the phase that the analyzer is intended to run in. + * + * @return the phase that the analyzer is intended to run in. + */ + @Override + public AnalysisPhase getAnalysisPhase() { + return ANALYSIS_PHASE; + } + + /** + * Returns the key used in the properties file to reference the analyzer's enabled property. + * + * @return the analyzer's enabled property setting key + */ + @Override + protected String getAnalyzerEnabledSettingKey() { + return Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED; + } + + @Override + protected void analyzeFileType(Dependency dependency, Engine engine) + throws AnalysisException { + + String contents; + try { + contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset()); + } catch (IOException e) { + throw new AnalysisException( + "Problem occurred while reading dependency file.", e); + } + final Matcher matcher = SPM_BLOCK_PATTERN.matcher(contents); + if (matcher.find()) { + contents = contents.substring(matcher.end()); + final String packageDescription = matcher.group(1); + if(packageDescription.isEmpty()) + return; + + final EvidenceCollection product = dependency.getProductEvidence(); + final EvidenceCollection vendor = dependency.getVendorEvidence(); + + //SPM is currently under development for SWIFT 3. Its current metadata includes package name and dependencies. + //Future interesting metadata: version, license, homepage, author, summary, etc. + final String name = addStringEvidence(product, packageDescription, "name", "name", Confidence.HIGHEST); + if (!name.isEmpty()) { + vendor.addEvidence(SPM_FILE_NAME, "name_project", name, Confidence.HIGHEST); + } + } + setPackagePath(dependency); + } + + private String addStringEvidence(EvidenceCollection evidences, + String packageDescription, String field, String fieldPattern, Confidence confidence) { + String value = ""; + + final Matcher matcher = Pattern.compile( + String.format("%s *:\\s*\"([^\"]*)", fieldPattern), Pattern.DOTALL).matcher(packageDescription); + if(matcher.find()) { + value = matcher.group(1); + } + + if(value != null) { + value = value.trim(); + if(value.length() > 0) + evidences.addEvidence (SPM_FILE_NAME, field, value, confidence); + } + + return value; + } + + private void setPackagePath(Dependency dep) { + File file = new File(dep.getFilePath()); + String parent = file.getParent(); + if(parent != null) + dep.setPackagePath(parent); + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java index 483413dcb..b91510b1e 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java @@ -39,6 +39,11 @@ public final class DependencyVersionUtil { * are missing a version number using the previous regex. */ private static final Pattern RX_SINGLE_VERSION = Pattern.compile("\\d+(\\.?([_-](release|beta|alpha)|[a-zA-Z_-]{1,3}\\d{1,8}))?"); + + /** + * Regular expression to extract the part before the version numbers if there are any based on RX_VERSION. In most cases, this part represents a more accurate name. + */ + private static final Pattern RX_PRE_VERSION = Pattern.compile("^(.+)[_-](\\d+\\.\\d{1,6})+"); /** * Private constructor for utility class. @@ -95,4 +100,27 @@ public final class DependencyVersionUtil { } return new DependencyVersion(version); } + + /** + *

+ * A utility class to extract the part before version numbers from file names (or other strings containing version numbers. + * In most cases, this part represents a more accurate name than the full file name.

+ *
+     * Example:
+     * Give the file name: library-name-1.4.1r2-release.jar
+     * This function would return: library-name
+ * + * @param text the text being analyzed + * @return the part before the version numbers if any, otherwise return the text itself. + */ + public static String parsePreVersion(String text) { + if(parseVersion(text) == null) + return text; + + Matcher matcher = RX_PRE_VERSION.matcher(text); + if (matcher.find()) { + return matcher.group(1); + } + return text; + } } diff --git a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer index 7f67a3d84..674d1d0f7 100644 --- a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer +++ b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer @@ -22,3 +22,5 @@ org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer +org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer +org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer diff --git a/dependency-check-core/src/main/resources/dependencycheck.properties b/dependency-check-core/src/main/resources/dependencycheck.properties index def5b8d86..fe567580e 100644 --- a/dependency-check-core/src/main/resources/dependencycheck.properties +++ b/dependency-check-core/src/main/resources/dependencycheck.properties @@ -96,6 +96,8 @@ analyzer.nuspec.enabled=true analyzer.openssl.enabled=true analyzer.central.enabled=true analyzer.nexus.enabled=false +analyzer.cocoapods.enabled=true +analyzer.swift.package.manager.enabled=true #whether the nexus analyzer uses the proxy analyzer.nexus.proxy=true diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java index 050259597..c1b57ab66 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java @@ -117,7 +117,6 @@ public class RubyBundleAuditAnalyzerTest extends BaseDBTestCase { final Engine engine = new Engine(); analyzer.analyze(result, engine); int size = engine.getDependencies().size(); - assertTrue(size >= 1); Dependency dependency = engine.getDependencies().get(0); diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/SwiftAnalyzersTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/SwiftAnalyzersTest.java new file mode 100644 index 000000000..94e4b020d --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/SwiftAnalyzersTest.java @@ -0,0 +1,123 @@ +package org.owasp.dependencycheck.analyzer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.owasp.dependencycheck.BaseTest; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.dependency.Dependency; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.io.File; + +/** + * Unit tests for CocoaPodsAnalyzer. + * + * @author Bianca Jiang + */ +public class SwiftAnalyzersTest extends BaseTest { + + /** + * The analyzer to test. + */ + CocoaPodsAnalyzer podsAnalyzer; + SwiftPackageManagerAnalyzer spmAnalyzer; + + /** + * Correctly setup the analyzer for testing. + * + * @throws Exception thrown if there is a problem + */ + @Before + public void setUp() throws Exception { + podsAnalyzer = new CocoaPodsAnalyzer(); + podsAnalyzer.setFilesMatched(true); + podsAnalyzer.initialize(); + + spmAnalyzer = new SwiftPackageManagerAnalyzer(); + spmAnalyzer.setFilesMatched(true); + spmAnalyzer.initialize(); + } + + /** + * Cleanup the analyzer's temp files, etc. + * + * @throws Exception thrown if there is a problem + */ + @After + public void tearDown() throws Exception { + podsAnalyzer.close(); + podsAnalyzer = null; + + spmAnalyzer.close(); + spmAnalyzer = null; + } + + /** + * Test of getName method, of class CocoaPodsAnalyzer. + */ + @Test + public void testPodsGetName() { + assertThat(podsAnalyzer.getName(), is("CocoaPods Package Analyzer")); + } + + /** + * Test of getName method, of class SwiftPackageManagerAnalyzer. + */ + @Test + public void testSPMGetName() { + assertThat(spmAnalyzer.getName(), is("SWIFT Package Manager Analyzer")); + } + + /** + * Test of supportsFiles method, of class CocoaPodsAnalyzer. + */ + @Test + public void testPodsSupportsFiles() { + assertThat(podsAnalyzer.accept(new File("test.podspec")), is(true)); + } + + /** + * Test of supportsFiles method, of class SwiftPackageManagerAnalyzer. + */ + @Test + public void testSPMSupportsFiles() { + assertThat(spmAnalyzer.accept(new File("Package.swift")), is(true)); + } + + /** + * Test of analyze method, of class CocoaPodsAnalyzer. + * + * @throws AnalysisException is thrown when an exception occurs. + */ + @Test + public void testCocoaPodsAnalyzer() throws AnalysisException { + final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, + "swift/cocoapods/EasyPeasy.podspec")); + podsAnalyzer.analyze(result, null); + final String vendorString = result.getVendorEvidence().toString(); + + assertThat(vendorString, containsString("Carlos Vidal")); + assertThat(vendorString, containsString("https://github.com/nakiostudio/EasyPeasy")); + assertThat(vendorString, containsString("MIT")); + assertThat(result.getProductEvidence().toString(), containsString("EasyPeasy")); + assertThat(result.getVersionEvidence().toString(), containsString("0.2.3")); + } + + /** + * Test of analyze method, of class SwiftPackageManagerAnalyzer. + * + * @throws AnalysisException is thrown when an exception occurs. + */ + @Test + public void testSPMAnalyzer() throws AnalysisException { + final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, + "swift/Gloss/Package.swift")); + spmAnalyzer.analyze(result, null); + + assertThat(result.getProductEvidence().toString(), containsString("Gloss")); + } +} diff --git a/dependency-check-core/src/test/resources/swift/Gloss/Gloss.podspec b/dependency-check-core/src/test/resources/swift/Gloss/Gloss.podspec new file mode 100644 index 000000000..3d05500ca --- /dev/null +++ b/dependency-check-core/src/test/resources/swift/Gloss/Gloss.podspec @@ -0,0 +1,17 @@ +Pod::Spec.new do |s| + s.name = "Gloss" + s.version = "0.7.2" + s.summary = "A shiny JSON parsing library in Swift" + s.description = "A shiny JSON parsing library in Swift. Features include mapping JSON to objects, mapping objects to JSON, handling of nested objects and custom transformations." + s.homepage = "https://github.com/hkellaway/Gloss" + s.license = { :type => "MIT", :file => "LICENSE" } + s.author = { "Harlan Kellaway" => "hello@harlankellaway.com" } + s.social_media_url = "http://twitter.com/HarlanKellaway" + s.source = { :git => "https://github.com/hkellaway/Gloss.git", :tag => s.version.to_s } + + s.platforms = { :ios => "8.0", :osx => "10.9", :tvos => "9.0", :watchos => "2.0" } + s.requires_arc = true + + s.source_files = 'Sources/*.{swift}' + +end diff --git a/dependency-check-core/src/test/resources/swift/Gloss/Package.swift b/dependency-check-core/src/test/resources/swift/Gloss/Package.swift new file mode 100644 index 000000000..ac1039468 --- /dev/null +++ b/dependency-check-core/src/test/resources/swift/Gloss/Package.swift @@ -0,0 +1,30 @@ +// +// Package.swift +// Gloss +// +// Copyright (c) 2015 Harlan Kellaway +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import PackageDescription + +let package = Package( + name: "Gloss" +) diff --git a/dependency-check-core/src/test/resources/swift/cocoapods/EasyPeasy.podspec b/dependency-check-core/src/test/resources/swift/cocoapods/EasyPeasy.podspec new file mode 100644 index 000000000..52d0ef7a8 --- /dev/null +++ b/dependency-check-core/src/test/resources/swift/cocoapods/EasyPeasy.podspec @@ -0,0 +1,25 @@ +Pod::Spec.new do |s| + s.name = "EasyPeasy" + s.version = "0.2.3" + s.summary = "EasyPeasy is a Swift framework that eases the creation of + Autolayout constraints programmatically" + s.description = <<-DESC + EasyPeasy is a Swift framework that lets you create Autolayout constraints + programmatically without headaches and never ending boilerplate code. Besides the + basics, **EasyPeasy** resolves most of the constraint conflicts for you and lets + you attach to a constraint conditional closures that are evaluated before applying + a constraint, this lets you apply (or not) a constraint depending on platform, size + classes, orientation... or the state of your controller, easy peasy! + DESC + s.homepage = "https://github.com/nakiostudio/EasyPeasy" + s.license = 'MIT' + s.author = { "Carlos Vidal" => "nakioparkour@gmail.com" } + s.source = { :git => "https://github.com/nakiostudio/EasyPeasy.git", :tag => s.version.to_s } + s.social_media_url = 'https://twitter.com/carlostify' + + s.platform = :ios, '8.0' + s.requires_arc = true + + s.source_files = 'EasyPeasy/**/*' + s.frameworks = 'UIKit' +end diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java index de6f4d7e1..359d24171 100644 --- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java +++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java @@ -288,6 +288,14 @@ public final class Settings { * The properties key for whether the OpenSSL analyzer is enabled. */ public static final String ANALYZER_OPENSSL_ENABLED = "analyzer.openssl.enabled"; + /** + * The properties key for whether the cocoapods analyzer is enabled. + */ + public static final String ANALYZER_COCOAPODS_ENABLED = "analyzer.cocoapods.enabled"; + /** + * The properties key for whether the SWIFT package manager analyzer is enabled. + */ + public static final String ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED = "analyzer.swift.package.manager.enabled"; /** * The properties key for the Central search URL. */