diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/DependencyMergingAnalyzer.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/DependencyMergingAnalyzer.html new file mode 100644 index 000000000..ce077f524 --- /dev/null +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/DependencyMergingAnalyzer.html @@ -0,0 +1,429 @@ + + + +
+ + +public class DependencyMergingAnalyzer +extends AbstractAnalyzer+
+ This analyzer will merge dependencies, created from different source, into a + single dependency.
| Constructor and Description | +
|---|
DependencyMergingAnalyzer() |
+
| Modifier and Type | +Method and Description | +
|---|---|
protected void |
+analyzeDependency(Dependency ignore,
+ Engine engine)
+Analyzes a set of dependencies.
+ |
+
AnalysisPhase |
+getAnalysisPhase()
+Returns the phase that the analyzer is intended to run in.
+ |
+
protected boolean |
+getAnalyzed()
+Returns a flag indicating if this analyzer has run.
+ |
+
protected String |
+getAnalyzerEnabledSettingKey()
+
+ Returns the setting key to determine if the analyzer is enabled.
+ |
+
String |
+getName()
+Returns the name of the analyzer.
+ |
+
boolean |
+supportsParallelProcessing()
+Does not support parallel processing as it only runs once and then
+ operates on all dependencies.
+ |
+
analyze, close, closeAnalyzer, initialize, initializeAnalyzer, isEnabled, setEnabledpublic DependencyMergingAnalyzer()+
protected boolean getAnalyzed()+
public String getName()+
public AnalysisPhase getAnalysisPhase()+
public boolean supportsParallelProcessing()+
supportsParallelProcessing in interface AnalyzersupportsParallelProcessing in class AbstractAnalyzerAbstractAnalyzer.analyze(Dependency, Engine)protected String getAnalyzerEnabledSettingKey()+
+ Returns the setting key to determine if the analyzer is enabled.
getAnalyzerEnabledSettingKey in class AbstractAnalyzerprotected void analyzeDependency(Dependency ignore, + Engine engine) + throws AnalysisException+
analyzeDependency in class AbstractAnalyzerignore - this analyzer ignores the dependency being analyzedengine - the engine that is scanning the dependenciesAnalysisException - is thrown if there is an error reading the JAR
+ file.Copyright? 2012-15 Jeremy Long. All Rights Reserved.
+ + diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.html new file mode 100644 index 000000000..bc53adf3b --- /dev/null +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.html @@ -0,0 +1,377 @@ + + + + + + +public class VersionFilterAnalyzer +extends AbstractAnalyzer+
| Constructor and Description | +
|---|
VersionFilterAnalyzer() |
+
| Modifier and Type | +Method and Description | +
|---|---|
protected void |
+analyzeDependency(Dependency dependency,
+ Engine engine)
+The HintAnalyzer uses knowledge about a dependency to add additional
+ information to help in identification of identifiers or vulnerabilities.
+ |
+
AnalysisPhase |
+getAnalysisPhase()
+Returns the phase that the analyzer is intended to run in.
+ |
+
protected String |
+getAnalyzerEnabledSettingKey()
+Returns the setting key to determine if the analyzer is enabled.
+ |
+
String |
+getName()
+Returns the name of the analyzer.
+ |
+
analyze, close, closeAnalyzer, initialize, initializeAnalyzer, isEnabled, setEnabled, supportsParallelProcessingpublic String getName()+
public AnalysisPhase getAnalysisPhase()+
protected String getAnalyzerEnabledSettingKey()+
getAnalyzerEnabledSettingKey in class AbstractAnalyzerprotected void analyzeDependency(Dependency dependency, + Engine engine) + throws AnalysisException+
analyzeDependency in class AbstractAnalyzerdependency - The dependency being analyzedengine - The scanning engineAnalysisException - is thrown if there is an exception analyzing
+ the dependency.Copyright? 2012-15 Jeremy Long. All Rights Reserved.
+ + diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/class-use/DependencyMergingAnalyzer.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/class-use/DependencyMergingAnalyzer.html new file mode 100644 index 000000000..795bf4d8a --- /dev/null +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/class-use/DependencyMergingAnalyzer.html @@ -0,0 +1,126 @@ + + + + + + +Copyright? 2012-15 Jeremy Long. All Rights Reserved.
+ + diff --git a/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/class-use/VersionFilterAnalyzer.html b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/class-use/VersionFilterAnalyzer.html new file mode 100644 index 000000000..fb3d350d5 --- /dev/null +++ b/dependency-check-core/apidocs/org/owasp/dependencycheck/analyzer/class-use/VersionFilterAnalyzer.html @@ -0,0 +1,126 @@ + + + + + + +Copyright? 2012-15 Jeremy Long. All Rights Reserved.
+ + diff --git a/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.DependencyMergingAnalyzer.html b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.DependencyMergingAnalyzer.html new file mode 100644 index 000000000..544dea02f --- /dev/null +++ b/dependency-check-core/cobertura/org.owasp.dependencycheck.analyzer.DependencyMergingAnalyzer.html @@ -0,0 +1,515 @@ + + + + +| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| DependencyMergingAnalyzer |
|
| 4.2727272727272725;4.273 |
| 1 | + | /* |
| 2 | + | * This file is part of dependency-check-core. |
| 3 | + | * |
| 4 | + | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + | * you may not use this file except in compliance with the License. |
| 6 | + | * You may obtain a copy of the License at |
| 7 | + | * |
| 8 | + | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + | * |
| 10 | + | * Unless required by applicable law or agreed to in writing, software |
| 11 | + | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + | * See the License for the specific language governing permissions and |
| 14 | + | * limitations under the License. |
| 15 | + | * |
| 16 | + | * Copyright (c) 2012 Jeremy Long. All Rights Reserved. |
| 17 | + | */ |
| 18 | + | package org.owasp.dependencycheck.analyzer; |
| 19 | + | |
| 20 | + | import java.io.File; |
| 21 | + | import java.util.HashSet; |
| 22 | + | import java.util.Iterator; |
| 23 | + | import java.util.ListIterator; |
| 24 | + | import java.util.Set; |
| 25 | + | import org.owasp.dependencycheck.Engine; |
| 26 | + | import org.owasp.dependencycheck.analyzer.exception.AnalysisException; |
| 27 | + | import org.owasp.dependencycheck.dependency.Dependency; |
| 28 | + | import org.owasp.dependencycheck.utils.Settings; |
| 29 | + | import org.slf4j.Logger; |
| 30 | + | import org.slf4j.LoggerFactory; |
| 31 | + | |
| 32 | + | /** |
| 33 | + | * <p> |
| 34 | + | * This analyzer will merge dependencies, created from different source, into a |
| 35 | + | * single dependency.</p> |
| 36 | + | * |
| 37 | + | * @author Jeremy Long |
| 38 | + | */ |
| 39 | 8 | public class DependencyMergingAnalyzer extends AbstractAnalyzer { |
| 40 | + | |
| 41 | + | //<editor-fold defaultstate="collapsed" desc="Constants and Member Variables"> |
| 42 | + | /** |
| 43 | + | * The Logger. |
| 44 | + | */ |
| 45 | 1 | private static final Logger LOGGER = LoggerFactory.getLogger(DependencyMergingAnalyzer.class); |
| 46 | + | /** |
| 47 | + | * a flag indicating if this analyzer has run. This analyzer only runs once. |
| 48 | + | */ |
| 49 | 8 | private boolean analyzed = false; |
| 50 | + | |
| 51 | + | /** |
| 52 | + | * Returns a flag indicating if this analyzer has run. This analyzer only |
| 53 | + | * runs once. Note this is currently only used in the unit tests. |
| 54 | + | * |
| 55 | + | * @return a flag indicating if this analyzer has run. This analyzer only |
| 56 | + | * runs once |
| 57 | + | */ |
| 58 | + | protected boolean getAnalyzed() { |
| 59 | 0 | return analyzed; |
| 60 | + | } |
| 61 | + | |
| 62 | + | //</editor-fold> |
| 63 | + | //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer"> |
| 64 | + | /** |
| 65 | + | * The name of the analyzer. |
| 66 | + | */ |
| 67 | + | private static final String ANALYZER_NAME = "Dependency Merging Analyzer"; |
| 68 | + | /** |
| 69 | + | * The phase that this analyzer is intended to run in. |
| 70 | + | */ |
| 71 | 1 | private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION; |
| 72 | + | |
| 73 | + | /** |
| 74 | + | * Returns the name of the analyzer. |
| 75 | + | * |
| 76 | + | * @return the name of the analyzer. |
| 77 | + | */ |
| 78 | + | @Override |
| 79 | + | public String getName() { |
| 80 | 26 | return ANALYZER_NAME; |
| 81 | + | } |
| 82 | + | |
| 83 | + | /** |
| 84 | + | * Returns the phase that the analyzer is intended to run in. |
| 85 | + | * |
| 86 | + | * @return the phase that the analyzer is intended to run in. |
| 87 | + | */ |
| 88 | + | @Override |
| 89 | + | public AnalysisPhase getAnalysisPhase() { |
| 90 | 6 | return ANALYSIS_PHASE; |
| 91 | + | } |
| 92 | + | |
| 93 | + | /** |
| 94 | + | * Does not support parallel processing as it only runs once and then |
| 95 | + | * operates on <em>all</em> dependencies. |
| 96 | + | * |
| 97 | + | * @return whether or not parallel processing is enabled |
| 98 | + | * @see #analyze(Dependency, Engine) |
| 99 | + | */ |
| 100 | + | @Override |
| 101 | + | public boolean supportsParallelProcessing() { |
| 102 | 2 | return false; |
| 103 | + | } |
| 104 | + | |
| 105 | + | /** |
| 106 | + | * <p> |
| 107 | + | * Returns the setting key to determine if the analyzer is enabled.</p> |
| 108 | + | * |
| 109 | + | * @return the key for the analyzer's enabled property |
| 110 | + | */ |
| 111 | + | @Override |
| 112 | + | protected String getAnalyzerEnabledSettingKey() { |
| 113 | 2 | return Settings.KEYS.ANALYZER_DEPENDENCY_MERGING_ENABLED; |
| 114 | + | } |
| 115 | + | //</editor-fold> |
| 116 | + | |
| 117 | + | /** |
| 118 | + | * Analyzes a set of dependencies. If they have been found to be the same |
| 119 | + | * dependency created by more multiple FileTypeAnalyzers (i.e. a gemspec |
| 120 | + | * dependency and a dependency from the Bundle Audit Analyzer. The |
| 121 | + | * dependencies are then merged into a single reportable item. |
| 122 | + | * |
| 123 | + | * @param ignore this analyzer ignores the dependency being analyzed |
| 124 | + | * @param engine the engine that is scanning the dependencies |
| 125 | + | * @throws AnalysisException is thrown if there is an error reading the JAR |
| 126 | + | * file. |
| 127 | + | */ |
| 128 | + | @Override |
| 129 | + | protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException { |
| 130 | 4 | if (!analyzed) { |
| 131 | 2 | analyzed = true; |
| 132 | 2 | final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>(); |
| 133 | 2 | final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator(); |
| 134 | + | //for (Dependency nextDependency : engine.getDependencies()) { |
| 135 | 6 | while (mainIterator.hasNext()) { |
| 136 | 4 | final Dependency dependency = mainIterator.next(); |
| 137 | 4 | if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) { |
| 138 | 2 | final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex()); |
| 139 | 4 | while (subIterator.hasNext()) { |
| 140 | 2 | final Dependency nextDependency = subIterator.next(); |
| 141 | 2 | Dependency main = null; |
| 142 | 2 | if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) { |
| 143 | 0 | if (main == dependency) { |
| 144 | 0 | mergeDependencies(dependency, nextDependency, dependenciesToRemove); |
| 145 | + | } else { |
| 146 | 0 | mergeDependencies(nextDependency, dependency, dependenciesToRemove); |
| 147 | 0 | break; //since we merged into the next dependency - skip forward to the next in mainIterator |
| 148 | + | } |
| 149 | 2 | } else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) { |
| 150 | 0 | if (main == dependency) { |
| 151 | 0 | mergeDependencies(dependency, nextDependency, dependenciesToRemove); |
| 152 | + | } else { |
| 153 | 0 | mergeDependencies(nextDependency, dependency, dependenciesToRemove); |
| 154 | 0 | break; //since we merged into the next dependency - skip forward to the next in mainIterator |
| 155 | + | } |
| 156 | + | } |
| 157 | 2 | } |
| 158 | + | } |
| 159 | 4 | } |
| 160 | + | //removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions |
| 161 | + | // was difficult because of the inner iterator. |
| 162 | 2 | engine.getDependencies().removeAll(dependenciesToRemove); |
| 163 | + | } |
| 164 | 4 | } |
| 165 | + | |
| 166 | + | /** |
| 167 | + | * Adds the relatedDependency to the dependency's related dependencies. |
| 168 | + | * |
| 169 | + | * @param dependency the main dependency |
| 170 | + | * @param relatedDependency a collection of dependencies to be removed from |
| 171 | + | * the main analysis loop, this is the source of dependencies to remove |
| 172 | + | * @param dependenciesToRemove a collection of dependencies that will be |
| 173 | + | * removed from the main analysis loop, this function adds to this |
| 174 | + | * collection |
| 175 | + | */ |
| 176 | + | private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) { |
| 177 | 0 | LOGGER.debug("Merging '{}' into '{}'", relatedDependency.getFilePath(), dependency.getFilePath()); |
| 178 | 0 | dependency.addRelatedDependency(relatedDependency); |
| 179 | 0 | dependency.getVendorEvidence().getEvidence().addAll(relatedDependency.getVendorEvidence().getEvidence()); |
| 180 | 0 | dependency.getProductEvidence().getEvidence().addAll(relatedDependency.getProductEvidence().getEvidence()); |
| 181 | 0 | dependency.getVersionEvidence().getEvidence().addAll(relatedDependency.getVersionEvidence().getEvidence()); |
| 182 | + | |
| 183 | 0 | final Iterator<Dependency> i = relatedDependency.getRelatedDependencies().iterator(); |
| 184 | 0 | while (i.hasNext()) { |
| 185 | 0 | dependency.addRelatedDependency(i.next()); |
| 186 | 0 | i.remove(); |
| 187 | + | } |
| 188 | 0 | if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) { |
| 189 | 0 | dependency.addAllProjectReferences(relatedDependency.getProjectReferences()); |
| 190 | + | } |
| 191 | 0 | dependenciesToRemove.add(relatedDependency); |
| 192 | 0 | } |
| 193 | + | |
| 194 | + | /** |
| 195 | + | * Bundling Ruby gems that are identified from different .gemspec files but |
| 196 | + | * denote the same package path. This happens when Ruby bundler installs an |
| 197 | + | * application's dependencies by running "bundle install". |
| 198 | + | * |
| 199 | + | * @param dependency1 dependency to compare |
| 200 | + | * @param dependency2 dependency to compare |
| 201 | + | * @return true if the the dependencies being analyzed appear to be the |
| 202 | + | * same; otherwise false |
| 203 | + | */ |
| 204 | + | private boolean isSameRubyGem(Dependency dependency1, Dependency dependency2) { |
| 205 | 2 | if (dependency1 == null || dependency2 == null |
| 206 | 2 | || !dependency1.getFileName().endsWith(".gemspec") |
| 207 | 0 | || !dependency2.getFileName().endsWith(".gemspec") |
| 208 | 0 | || dependency1.getPackagePath() == null |
| 209 | 0 | || dependency2.getPackagePath() == null) { |
| 210 | 2 | return false; |
| 211 | + | } |
| 212 | 0 | return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath()); |
| 213 | + | } |
| 214 | + | |
| 215 | + | /** |
| 216 | + | * Ruby gems installed by "bundle install" can have zero or more *.gemspec |
| 217 | + | * files, all of which have the same packagePath and should be grouped. If |
| 218 | + | * one of these gemspec is from <parent>/specifications/*.gemspec, because |
| 219 | + | * it is a stub with fully resolved gem meta-data created by Ruby bundler, |
| 220 | + | * this dependency should be the main one. Otherwise, use dependency2 as |
| 221 | + | * main. |
| 222 | + | * |
| 223 | + | * This method returns null if any dependency is not from *.gemspec, or the |
| 224 | + | * two do not have the same packagePath. In this case, they should not be |
| 225 | + | * grouped. |
| 226 | + | * |
| 227 | + | * @param dependency1 dependency to compare |
| 228 | + | * @param dependency2 dependency to compare |
| 229 | + | * @return the main dependency; or null if a gemspec is not included in the |
| 230 | + | * analysis |
| 231 | + | */ |
| 232 | + | private Dependency getMainGemspecDependency(Dependency dependency1, Dependency dependency2) { |
| 233 | 2 | if (isSameRubyGem(dependency1, dependency2)) { |
| 234 | 0 | final File lFile = dependency1.getActualFile(); |
| 235 | 0 | final File left = lFile.getParentFile(); |
| 236 | 0 | if (left != null && left.getName().equalsIgnoreCase("specifications")) { |
| 237 | 0 | return dependency1; |
| 238 | + | } |
| 239 | 0 | return dependency2; |
| 240 | + | } |
| 241 | 2 | return null; |
| 242 | + | } |
| 243 | + | |
| 244 | + | /** |
| 245 | + | * Bundling same swift dependencies with the same packagePath but identified |
| 246 | + | * by different file type analyzers. |
| 247 | + | * |
| 248 | + | * @param dependency1 dependency to test |
| 249 | + | * @param dependency2 dependency to test |
| 250 | + | * @return <code>true</code> if the dependencies appear to be the same; |
| 251 | + | * otherwise <code>false</code> |
| 252 | + | */ |
| 253 | + | private boolean isSameSwiftPackage(Dependency dependency1, Dependency dependency2) { |
| 254 | 2 | if (dependency1 == null || dependency2 == null |
| 255 | 2 | || (!dependency1.getFileName().endsWith(".podspec") |
| 256 | 2 | && !dependency1.getFileName().equals("Package.swift")) |
| 257 | 0 | || (!dependency2.getFileName().endsWith(".podspec") |
| 258 | 0 | && !dependency2.getFileName().equals("Package.swift")) |
| 259 | 0 | || dependency1.getPackagePath() == null |
| 260 | 0 | || dependency2.getPackagePath() == null) { |
| 261 | 2 | return false; |
| 262 | + | } |
| 263 | 0 | return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath()); |
| 264 | + | } |
| 265 | + | |
| 266 | + | /** |
| 267 | + | * Determines which of the swift dependencies should be considered the |
| 268 | + | * primary. |
| 269 | + | * |
| 270 | + | * @param dependency1 the first swift dependency to compare |
| 271 | + | * @param dependency2 the second swift dependency to compare |
| 272 | + | * @return the primary swift dependency |
| 273 | + | */ |
| 274 | + | private Dependency getMainSwiftDependency(Dependency dependency1, Dependency dependency2) { |
| 275 | 2 | if (isSameSwiftPackage(dependency1, dependency2)) { |
| 276 | 0 | if (dependency1.getFileName().endsWith(".podspec")) { |
| 277 | 0 | return dependency1; |
| 278 | + | } |
| 279 | 0 | return dependency2; |
| 280 | + | } |
| 281 | 2 | return null; |
| 282 | + | } |
| 283 | + | } |
| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| VersionFilterAnalyzer |
|
| 8.75;8.75 |
| 1 | + | /* |
| 2 | + | * This file is part of dependency-check-core. |
| 3 | + | * |
| 4 | + | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + | * you may not use this file except in compliance with the License. |
| 6 | + | * You may obtain a copy of the License at |
| 7 | + | * |
| 8 | + | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + | * |
| 10 | + | * Unless required by applicable law or agreed to in writing, software |
| 11 | + | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + | * See the License for the specific language governing permissions and |
| 14 | + | * limitations under the License. |
| 15 | + | * |
| 16 | + | * Copyright (c) 2017 Jeremy Long. All Rights Reserved. |
| 17 | + | */ |
| 18 | + | package org.owasp.dependencycheck.analyzer; |
| 19 | + | |
| 20 | + | import java.util.Iterator; |
| 21 | + | import java.util.Objects; |
| 22 | + | import org.owasp.dependencycheck.Engine; |
| 23 | + | import org.owasp.dependencycheck.analyzer.exception.AnalysisException; |
| 24 | + | import org.owasp.dependencycheck.dependency.Dependency; |
| 25 | + | import org.owasp.dependencycheck.dependency.Evidence; |
| 26 | + | import org.owasp.dependencycheck.dependency.EvidenceCollection; |
| 27 | + | import org.owasp.dependencycheck.utils.DependencyVersion; |
| 28 | + | import org.owasp.dependencycheck.utils.Settings; |
| 29 | + | import org.slf4j.Logger; |
| 30 | + | import org.slf4j.LoggerFactory; |
| 31 | + | |
| 32 | + | /** |
| 33 | + | * This analyzer attempts to filter out erroneous version numbers collected. |
| 34 | + | * Initially, this will focus on JAR files that contain a POM version number |
| 35 | + | * that matches the file name - if identified all other version information will |
| 36 | + | * be removed. |
| 37 | + | * |
| 38 | + | * @author Jeremy Long |
| 39 | + | */ |
| 40 | 15 | public class VersionFilterAnalyzer extends AbstractAnalyzer { |
| 41 | + | |
| 42 | + | //<editor-fold defaultstate="collapsed" desc="Constaints"> |
| 43 | + | /** |
| 44 | + | * Evidence source. |
| 45 | + | */ |
| 46 | + | private static final String FILE = "file"; |
| 47 | + | /** |
| 48 | + | * Evidence source. |
| 49 | + | */ |
| 50 | + | private static final String POM = "pom"; |
| 51 | + | /** |
| 52 | + | * Evidence source. |
| 53 | + | */ |
| 54 | + | private static final String NEXUS = "nexus"; |
| 55 | + | /** |
| 56 | + | * Evidence source. |
| 57 | + | */ |
| 58 | + | private static final String CENTRAL = "central"; |
| 59 | + | /** |
| 60 | + | * Evidence source. |
| 61 | + | */ |
| 62 | + | private static final String MANIFEST = "Manifest"; |
| 63 | + | /** |
| 64 | + | * Evidence name. |
| 65 | + | */ |
| 66 | + | private static final String VERSION = "version"; |
| 67 | + | /** |
| 68 | + | * Evidence name. |
| 69 | + | */ |
| 70 | + | private static final String IMPLEMENTATION_VERSION = "Implementation-Version"; |
| 71 | + | |
| 72 | + | /** |
| 73 | + | * The name of the analyzer. |
| 74 | + | */ |
| 75 | + | private static final String ANALYZER_NAME = "Version Filter Analyzer"; |
| 76 | + | /** |
| 77 | + | * The phase that this analyzer is intended to run in. |
| 78 | + | */ |
| 79 | 1 | private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION; |
| 80 | + | |
| 81 | + | //</editor-fold> |
| 82 | + | //<editor-fold defaultstate="collapsed" desc="Standard implementation of Analyzer"> |
| 83 | + | /** |
| 84 | + | * Returns the name of the analyzer. |
| 85 | + | * |
| 86 | + | * @return the name of the analyzer. |
| 87 | + | */ |
| 88 | + | @Override |
| 89 | + | public String getName() { |
| 90 | 27 | return ANALYZER_NAME; |
| 91 | + | } |
| 92 | + | |
| 93 | + | /** |
| 94 | + | * Returns the phase that the analyzer is intended to run in. |
| 95 | + | * |
| 96 | + | * @return the phase that the analyzer is intended to run in. |
| 97 | + | */ |
| 98 | + | @Override |
| 99 | + | public AnalysisPhase getAnalysisPhase() { |
| 100 | 7 | return ANALYSIS_PHASE; |
| 101 | + | } |
| 102 | + | |
| 103 | + | /** |
| 104 | + | * Returns the setting key to determine if the analyzer is enabled. |
| 105 | + | * |
| 106 | + | * @return the key for the analyzer's enabled property |
| 107 | + | */ |
| 108 | + | @Override |
| 109 | + | protected String getAnalyzerEnabledSettingKey() { |
| 110 | 3 | return Settings.KEYS.ANALYZER_VERSION_FILTER_ENABLED; |
| 111 | + | } |
| 112 | + | //</editor-fold> |
| 113 | + | |
| 114 | + | /** |
| 115 | + | * The Logger for use throughout the class |
| 116 | + | */ |
| 117 | 1 | private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class); |
| 118 | + | |
| 119 | + | /** |
| 120 | + | * The HintAnalyzer uses knowledge about a dependency to add additional |
| 121 | + | * information to help in identification of identifiers or vulnerabilities. |
| 122 | + | * |
| 123 | + | * @param dependency The dependency being analyzed |
| 124 | + | * @param engine The scanning engine |
| 125 | + | * @throws AnalysisException is thrown if there is an exception analyzing |
| 126 | + | * the dependency. |
| 127 | + | */ |
| 128 | + | @Override |
| 129 | + | protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { |
| 130 | 23 | String fileVersion = null; |
| 131 | 23 | String pomVersion = null; |
| 132 | 23 | String manifestVersion = null; |
| 133 | 23 | for (Evidence e : dependency.getVersionEvidence()) { |
| 134 | 91 | if (FILE.equals(e.getSource()) && VERSION.equals(e.getName())) { |
| 135 | 11 | fileVersion = e.getValue(Boolean.FALSE); |
| 136 | 80 | } else if ((NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) |
| 137 | 71 | || POM.equals(e.getSource())) && VERSION.equals(e.getName())) { |
| 138 | 22 | pomVersion = e.getValue(Boolean.FALSE); |
| 139 | 58 | } else if (MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName())) { |
| 140 | 9 | manifestVersion = e.getValue(Boolean.FALSE); |
| 141 | + | } |
| 142 | 91 | } |
| 143 | + | //ensure we have at least two not null |
| 144 | 23 | if (((fileVersion == null ? 0 : 1) + (pomVersion == null ? 0 : 1) + (manifestVersion == null ? 0 : 1)) > 1) { |
| 145 | 12 | final DependencyVersion dvFile = new DependencyVersion(fileVersion); |
| 146 | 12 | final DependencyVersion dvPom = new DependencyVersion(pomVersion); |
| 147 | 12 | final DependencyVersion dvManifest = new DependencyVersion(manifestVersion); |
| 148 | 12 | final boolean fileMatch = Objects.equals(dvFile, dvPom) || Objects.equals(dvFile, dvManifest); |
| 149 | 12 | final boolean manifestMatch = Objects.equals(dvManifest, dvPom) || Objects.equals(dvManifest, dvFile); |
| 150 | 12 | final boolean pomMatch = Objects.equals(dvPom, dvFile) || Objects.equals(dvPom, dvManifest); |
| 151 | 12 | if (fileMatch || manifestMatch || pomMatch) { |
| 152 | 11 | LOGGER.debug("filtering evidence from {}", dependency.getFileName()); |
| 153 | 11 | final EvidenceCollection versionEvidence = dependency.getVersionEvidence(); |
| 154 | 11 | synchronized (versionEvidence) { |
| 155 | 11 | final Iterator<Evidence> itr = versionEvidence.iterator(); |
| 156 | 63 | while (itr.hasNext()) { |
| 157 | 52 | final Evidence e = itr.next(); |
| 158 | 52 | if (!(pomMatch && VERSION.equals(e.getName()) |
| 159 | 38 | && (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource()))) |
| 160 | 25 | && !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource())) |
| 161 | 17 | && !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) { |
| 162 | 18 | itr.remove(); |
| 163 | + | } |
| 164 | 52 | } |
| 165 | 11 | } |
| 166 | + | } |
| 167 | + | } |
| 168 | 23 | } |
| 169 | + | } |
+1 /*
+2 * This file is part of dependency-check-core.
+3 *
+4 * Licensed under the Apache License, Version 2.0 (the "License");
+5 * you may not use this file except in compliance with the License.
+6 * You may obtain a copy of the License at
+7 *
+8 * http://www.apache.org/licenses/LICENSE-2.0
+9 *
+10 * Unless required by applicable law or agreed to in writing, software
+11 * distributed under the License is distributed on an "AS IS" BASIS,
+12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+13 * See the License for the specific language governing permissions and
+14 * limitations under the License.
+15 *
+16 * Copyright (c) 2017 Jeremy Long. All Rights Reserved.
+17 */
+18 package org.owasp.dependencycheck.analyzer;
+19
+20 import org.junit.Test;
+21 import static org.junit.Assert.*;
+22 import org.owasp.dependencycheck.BaseTest;
+23 import org.owasp.dependencycheck.dependency.Confidence;
+24 import org.owasp.dependencycheck.dependency.Dependency;
+25 import org.owasp.dependencycheck.dependency.EvidenceCollection;
+26 import org.owasp.dependencycheck.utils.Settings;
+27
+28 /**
+29 *
+30 * @author jerem
+31 */
+32 public class VersionFilterAnalyzerTest extends BaseTest {
+33
+34 /**
+35 * Test of getName method, of class VersionFilterAnalyzer.
+36 */
+37 @Test
+38 public void testGetName() {
+39 VersionFilterAnalyzer instance = new VersionFilterAnalyzer();
+40 String expResult = "Version Filter Analyzer";
+41 String result = instance.getName();
+42 assertEquals(expResult, result);
+43 }
+44
+45 /**
+46 * Test of getAnalysisPhase method, of class VersionFilterAnalyzer.
+47 */
+48 @Test
+49 public void testGetAnalysisPhase() {
+50 VersionFilterAnalyzer instance = new VersionFilterAnalyzer();
+51 AnalysisPhase expResult = AnalysisPhase.POST_INFORMATION_COLLECTION;
+52 AnalysisPhase result = instance.getAnalysisPhase();
+53 assertEquals(expResult, result);
+54 }
+55
+56 /**
+57 * Test of getAnalyzerEnabledSettingKey method, of class
+58 * VersionFilterAnalyzer.
+59 */
+60 @Test
+61 public void testGetAnalyzerEnabledSettingKey() {
+62 VersionFilterAnalyzer instance = new VersionFilterAnalyzer();
+63 String expResult = Settings.KEYS.ANALYZER_VERSION_FILTER_ENABLED;
+64 String result = instance.getAnalyzerEnabledSettingKey();
+65 assertEquals(expResult, result);
+66 }
+67
+68 /**
+69 * Test of analyzeDependency method, of class VersionFilterAnalyzer.
+70 */
+71 @Test
+72 public void testAnalyzeDependency() throws Exception {
+73 Dependency dependency = new Dependency();
+74 EvidenceCollection versions = dependency.getVersionEvidence();
+75
+76 versions.addEvidence("util", "version", "33.3", Confidence.HIGHEST);
+77 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+78 versions.addEvidence("other", "Implementation-Version", "1.2.3", Confidence.HIGHEST);
+79
+80 VersionFilterAnalyzer instance = new VersionFilterAnalyzer();
+81
+82 instance.analyzeDependency(dependency, null);
+83 assertEquals(3, versions.size());
+84
+85 versions.addEvidence("pom", "version", "1.2.3", Confidence.HIGHEST);
+86
+87 instance.analyzeDependency(dependency, null);
+88 assertEquals(4, versions.size());
+89
+90 versions.addEvidence("file", "version", "1.2.3", Confidence.HIGHEST);
+91 instance.analyzeDependency(dependency, null);
+92 assertEquals(2, versions.size());
+93
+94 versions.addEvidence("Manifest", "Implementation-Version", "1.2.3", Confidence.HIGHEST);
+95 instance.analyzeDependency(dependency, null);
+96 assertEquals(3, versions.size());
+97
+98 versions.addEvidence("nexus", "version", "1.2.3", Confidence.HIGHEST);
+99 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+100 instance.analyzeDependency(dependency, null);
+101 assertEquals(4, versions.size());
+102
+103 versions.addEvidence("central", "version", "1.2.3", Confidence.HIGHEST);
+104 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+105 instance.analyzeDependency(dependency, null);
+106 assertEquals(5, versions.size());
+107 }
+108
+109 /**
+110 * Test of analyzeDependency method, of class VersionFilterAnalyzer.
+111 */
+112 @Test
+113 public void testAnalyzeDependencyFilePom() throws Exception {
+114 Dependency dependency = new Dependency();
+115 EvidenceCollection versions = dependency.getVersionEvidence();
+116
+117 versions.addEvidence("util", "version", "33.3", Confidence.HIGHEST);
+118 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+119 versions.addEvidence("other", "Implementation-Version", "1.2.3", Confidence.HIGHEST);
+120
+121 VersionFilterAnalyzer instance = new VersionFilterAnalyzer();
+122
+123 instance.analyzeDependency(dependency, null);
+124 assertEquals(3, versions.size());
+125
+126 versions.addEvidence("pom", "version", "1.2.3", Confidence.HIGHEST);
+127
+128 instance.analyzeDependency(dependency, null);
+129 assertEquals(4, versions.size());
+130
+131 versions.addEvidence("file", "version", "1.2.3", Confidence.HIGHEST);
+132 instance.analyzeDependency(dependency, null);
+133 assertEquals(2, versions.size());
+134
+135 versions.addEvidence("nexus", "version", "1.2.3", Confidence.HIGHEST);
+136 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+137 instance.analyzeDependency(dependency, null);
+138 assertEquals(3, versions.size());
+139
+140 versions.addEvidence("central", "version", "1.2.3", Confidence.HIGHEST);
+141 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+142 instance.analyzeDependency(dependency, null);
+143 assertEquals(4, versions.size());
+144 }
+145
+146 /**
+147 * Test of analyzeDependency method, of class VersionFilterAnalyzer.
+148 */
+149 @Test
+150 public void testAnalyzeDependencyFileManifest() throws Exception {
+151 Dependency dependency = new Dependency();
+152 EvidenceCollection versions = dependency.getVersionEvidence();
+153
+154 versions.addEvidence("util", "version", "33.3", Confidence.HIGHEST);
+155 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+156 versions.addEvidence("other", "Implementation-Version", "1.2.3", Confidence.HIGHEST);
+157
+158 VersionFilterAnalyzer instance = new VersionFilterAnalyzer();
+159
+160 instance.analyzeDependency(dependency, null);
+161 assertEquals(3, versions.size());
+162
+163 versions.addEvidence("Manifest", "Implementation-Version", "1.2.3", Confidence.HIGHEST);
+164
+165 instance.analyzeDependency(dependency, null);
+166 assertEquals(4, versions.size());
+167
+168 versions.addEvidence("file", "version", "1.2.3", Confidence.HIGHEST);
+169 instance.analyzeDependency(dependency, null);
+170 assertEquals(2, versions.size());
+171 }
+172
+173 /**
+174 * Test of analyzeDependency method, of class VersionFilterAnalyzer.
+175 */
+176 @Test
+177 public void testAnalyzeDependencyPomManifest() throws Exception {
+178 Dependency dependency = new Dependency();
+179 EvidenceCollection versions = dependency.getVersionEvidence();
+180
+181 versions.addEvidence("util", "version", "33.3", Confidence.HIGHEST);
+182 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+183 versions.addEvidence("other", "Implementation-Version", "1.2.3", Confidence.HIGHEST);
+184
+185 VersionFilterAnalyzer instance = new VersionFilterAnalyzer();
+186
+187 instance.analyzeDependency(dependency, null);
+188 assertEquals(3, versions.size());
+189
+190 versions.addEvidence("pom", "version", "1.2.3", Confidence.HIGHEST);
+191
+192 instance.analyzeDependency(dependency, null);
+193 assertEquals(4, versions.size());
+194
+195 versions.addEvidence("Manifest", "Implementation-Version", "1.2.3", Confidence.HIGHEST);
+196 instance.analyzeDependency(dependency, null);
+197 assertEquals(2, versions.size());
+198
+199 versions.addEvidence("nexus", "version", "1.2.3", Confidence.HIGHEST);
+200 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+201 instance.analyzeDependency(dependency, null);
+202 assertEquals(3, versions.size());
+203
+204 versions.addEvidence("central", "version", "1.2.3", Confidence.HIGHEST);
+205 versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST);
+206 instance.analyzeDependency(dependency, null);
+207 assertEquals(4, versions.size());
+208 }
+209
+210 }
+
+
+1 /*
+2 * This file is part of dependency-check-core.
+3 *
+4 * Licensed under the Apache License, Version 2.0 (the "License");
+5 * you may not use this file except in compliance with the License.
+6 * You may obtain a copy of the License at
+7 *
+8 * http://www.apache.org/licenses/LICENSE-2.0
+9 *
+10 * Unless required by applicable law or agreed to in writing, software
+11 * distributed under the License is distributed on an "AS IS" BASIS,
+12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+13 * See the License for the specific language governing permissions and
+14 * limitations under the License.
+15 *
+16 * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
+17 */
+18 package org.owasp.dependencycheck.analyzer;
+19
+20 import java.io.File;
+21 import java.util.HashSet;
+22 import java.util.Iterator;
+23 import java.util.ListIterator;
+24 import java.util.Set;
+25 import org.owasp.dependencycheck.Engine;
+26 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
+27 import org.owasp.dependencycheck.dependency.Dependency;
+28 import org.owasp.dependencycheck.utils.Settings;
+29 import org.slf4j.Logger;
+30 import org.slf4j.LoggerFactory;
+31
+32 /**
+33 * <p>
+34 * This analyzer will merge dependencies, created from different source, into a
+35 * single dependency.</p>
+36 *
+37 * @author Jeremy Long
+38 */
+39 public class DependencyMergingAnalyzer extends AbstractAnalyzer {
+40
+41 //<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
+42 /**
+43 * The Logger.
+44 */
+45 private static final Logger LOGGER = LoggerFactory.getLogger(DependencyMergingAnalyzer.class);
+46 /**
+47 * a flag indicating if this analyzer has run. This analyzer only runs once.
+48 */
+49 private boolean analyzed = false;
+50
+51 /**
+52 * Returns a flag indicating if this analyzer has run. This analyzer only
+53 * runs once. Note this is currently only used in the unit tests.
+54 *
+55 * @return a flag indicating if this analyzer has run. This analyzer only
+56 * runs once
+57 */
+58 protected boolean getAnalyzed() {
+59 return analyzed;
+60 }
+61
+62 //</editor-fold>
+63 //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
+64 /**
+65 * The name of the analyzer.
+66 */
+67 private static final String ANALYZER_NAME = "Dependency Merging Analyzer";
+68 /**
+69 * The phase that this analyzer is intended to run in.
+70 */
+71 private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION;
+72
+73 /**
+74 * Returns the name of the analyzer.
+75 *
+76 * @return the name of the analyzer.
+77 */
+78 @Override
+79 public String getName() {
+80 return ANALYZER_NAME;
+81 }
+82
+83 /**
+84 * Returns the phase that the analyzer is intended to run in.
+85 *
+86 * @return the phase that the analyzer is intended to run in.
+87 */
+88 @Override
+89 public AnalysisPhase getAnalysisPhase() {
+90 return ANALYSIS_PHASE;
+91 }
+92
+93 /**
+94 * Does not support parallel processing as it only runs once and then
+95 * operates on <em>all</em> dependencies.
+96 *
+97 * @return whether or not parallel processing is enabled
+98 * @see #analyze(Dependency, Engine)
+99 */
+100 @Override
+101 public boolean supportsParallelProcessing() {
+102 return false;
+103 }
+104
+105 /**
+106 * <p>
+107 * Returns the setting key to determine if the analyzer is enabled.</p>
+108 *
+109 * @return the key for the analyzer's enabled property
+110 */
+111 @Override
+112 protected String getAnalyzerEnabledSettingKey() {
+113 return Settings.KEYS.ANALYZER_DEPENDENCY_MERGING_ENABLED;
+114 }
+115 //</editor-fold>
+116
+117 /**
+118 * Analyzes a set of dependencies. If they have been found to be the same
+119 * dependency created by more multiple FileTypeAnalyzers (i.e. a gemspec
+120 * dependency and a dependency from the Bundle Audit Analyzer. The
+121 * dependencies are then merged into a single reportable item.
+122 *
+123 * @param ignore this analyzer ignores the dependency being analyzed
+124 * @param engine the engine that is scanning the dependencies
+125 * @throws AnalysisException is thrown if there is an error reading the JAR
+126 * file.
+127 */
+128 @Override
+129 protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
+130 if (!analyzed) {
+131 analyzed = true;
+132 final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
+133 final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
+134 //for (Dependency nextDependency : engine.getDependencies()) {
+135 while (mainIterator.hasNext()) {
+136 final Dependency dependency = mainIterator.next();
+137 if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
+138 final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
+139 while (subIterator.hasNext()) {
+140 final Dependency nextDependency = subIterator.next();
+141 Dependency main = null;
+142 if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
+143 if (main == dependency) {
+144 mergeDependencies(dependency, nextDependency, dependenciesToRemove);
+145 } else {
+146 mergeDependencies(nextDependency, dependency, dependenciesToRemove);
+147 break; //since we merged into the next dependency - skip forward to the next in mainIterator
+148 }
+149 } else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) {
+150 if (main == dependency) {
+151 mergeDependencies(dependency, nextDependency, dependenciesToRemove);
+152 } else {
+153 mergeDependencies(nextDependency, dependency, dependenciesToRemove);
+154 break; //since we merged into the next dependency - skip forward to the next in mainIterator
+155 }
+156 }
+157 }
+158 }
+159 }
+160 //removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
+161 // was difficult because of the inner iterator.
+162 engine.getDependencies().removeAll(dependenciesToRemove);
+163 }
+164 }
+165
+166 /**
+167 * Adds the relatedDependency to the dependency's related dependencies.
+168 *
+169 * @param dependency the main dependency
+170 * @param relatedDependency a collection of dependencies to be removed from
+171 * the main analysis loop, this is the source of dependencies to remove
+172 * @param dependenciesToRemove a collection of dependencies that will be
+173 * removed from the main analysis loop, this function adds to this
+174 * collection
+175 */
+176 private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
+177 LOGGER.debug("Merging '{}' into '{}'", relatedDependency.getFilePath(), dependency.getFilePath());
+178 dependency.addRelatedDependency(relatedDependency);
+179 dependency.getVendorEvidence().getEvidence().addAll(relatedDependency.getVendorEvidence().getEvidence());
+180 dependency.getProductEvidence().getEvidence().addAll(relatedDependency.getProductEvidence().getEvidence());
+181 dependency.getVersionEvidence().getEvidence().addAll(relatedDependency.getVersionEvidence().getEvidence());
+182
+183 final Iterator<Dependency> i = relatedDependency.getRelatedDependencies().iterator();
+184 while (i.hasNext()) {
+185 dependency.addRelatedDependency(i.next());
+186 i.remove();
+187 }
+188 if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
+189 dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
+190 }
+191 dependenciesToRemove.add(relatedDependency);
+192 }
+193
+194 /**
+195 * Bundling Ruby gems that are identified from different .gemspec files but
+196 * denote the same package path. This happens when Ruby bundler installs an
+197 * application's dependencies by running "bundle install".
+198 *
+199 * @param dependency1 dependency to compare
+200 * @param dependency2 dependency to compare
+201 * @return true if the the dependencies being analyzed appear to be the
+202 * same; otherwise false
+203 */
+204 private boolean isSameRubyGem(Dependency dependency1, Dependency dependency2) {
+205 if (dependency1 == null || dependency2 == null
+206 || !dependency1.getFileName().endsWith(".gemspec")
+207 || !dependency2.getFileName().endsWith(".gemspec")
+208 || dependency1.getPackagePath() == null
+209 || dependency2.getPackagePath() == null) {
+210 return false;
+211 }
+212 return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
+213 }
+214
+215 /**
+216 * Ruby gems installed by "bundle install" can have zero or more *.gemspec
+217 * files, all of which have the same packagePath and should be grouped. If
+218 * one of these gemspec is from <parent>/specifications/*.gemspec, because
+219 * it is a stub with fully resolved gem meta-data created by Ruby bundler,
+220 * this dependency should be the main one. Otherwise, use dependency2 as
+221 * main.
+222 *
+223 * This method returns null if any dependency is not from *.gemspec, or the
+224 * two do not have the same packagePath. In this case, they should not be
+225 * grouped.
+226 *
+227 * @param dependency1 dependency to compare
+228 * @param dependency2 dependency to compare
+229 * @return the main dependency; or null if a gemspec is not included in the
+230 * analysis
+231 */
+232 private Dependency getMainGemspecDependency(Dependency dependency1, Dependency dependency2) {
+233 if (isSameRubyGem(dependency1, dependency2)) {
+234 final File lFile = dependency1.getActualFile();
+235 final File left = lFile.getParentFile();
+236 if (left != null && left.getName().equalsIgnoreCase("specifications")) {
+237 return dependency1;
+238 }
+239 return dependency2;
+240 }
+241 return null;
+242 }
+243
+244 /**
+245 * Bundling same swift dependencies with the same packagePath but identified
+246 * by different file type analyzers.
+247 *
+248 * @param dependency1 dependency to test
+249 * @param dependency2 dependency to test
+250 * @return <code>true</code> if the dependencies appear to be the same;
+251 * otherwise <code>false</code>
+252 */
+253 private boolean isSameSwiftPackage(Dependency dependency1, Dependency dependency2) {
+254 if (dependency1 == null || dependency2 == null
+255 || (!dependency1.getFileName().endsWith(".podspec")
+256 && !dependency1.getFileName().equals("Package.swift"))
+257 || (!dependency2.getFileName().endsWith(".podspec")
+258 && !dependency2.getFileName().equals("Package.swift"))
+259 || dependency1.getPackagePath() == null
+260 || dependency2.getPackagePath() == null) {
+261 return false;
+262 }
+263 return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
+264 }
+265
+266 /**
+267 * Determines which of the swift dependencies should be considered the
+268 * primary.
+269 *
+270 * @param dependency1 the first swift dependency to compare
+271 * @param dependency2 the second swift dependency to compare
+272 * @return the primary swift dependency
+273 */
+274 private Dependency getMainSwiftDependency(Dependency dependency1, Dependency dependency2) {
+275 if (isSameSwiftPackage(dependency1, dependency2)) {
+276 if (dependency1.getFileName().endsWith(".podspec")) {
+277 return dependency1;
+278 }
+279 return dependency2;
+280 }
+281 return null;
+282 }
+283 }
+
+
+1 /*
+2 * This file is part of dependency-check-core.
+3 *
+4 * Licensed under the Apache License, Version 2.0 (the "License");
+5 * you may not use this file except in compliance with the License.
+6 * You may obtain a copy of the License at
+7 *
+8 * http://www.apache.org/licenses/LICENSE-2.0
+9 *
+10 * Unless required by applicable law or agreed to in writing, software
+11 * distributed under the License is distributed on an "AS IS" BASIS,
+12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+13 * See the License for the specific language governing permissions and
+14 * limitations under the License.
+15 *
+16 * Copyright (c) 2017 Jeremy Long. All Rights Reserved.
+17 */
+18 package org.owasp.dependencycheck.analyzer;
+19
+20 import java.util.Iterator;
+21 import java.util.Objects;
+22 import org.owasp.dependencycheck.Engine;
+23 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
+24 import org.owasp.dependencycheck.dependency.Dependency;
+25 import org.owasp.dependencycheck.dependency.Evidence;
+26 import org.owasp.dependencycheck.dependency.EvidenceCollection;
+27 import org.owasp.dependencycheck.utils.DependencyVersion;
+28 import org.owasp.dependencycheck.utils.Settings;
+29 import org.slf4j.Logger;
+30 import org.slf4j.LoggerFactory;
+31
+32 /**
+33 * This analyzer attempts to filter out erroneous version numbers collected.
+34 * Initially, this will focus on JAR files that contain a POM version number
+35 * that matches the file name - if identified all other version information will
+36 * be removed.
+37 *
+38 * @author Jeremy Long
+39 */
+40 public class VersionFilterAnalyzer extends AbstractAnalyzer {
+41
+42 //<editor-fold defaultstate="collapsed" desc="Constaints">
+43 /**
+44 * Evidence source.
+45 */
+46 private static final String FILE = "file";
+47 /**
+48 * Evidence source.
+49 */
+50 private static final String POM = "pom";
+51 /**
+52 * Evidence source.
+53 */
+54 private static final String NEXUS = "nexus";
+55 /**
+56 * Evidence source.
+57 */
+58 private static final String CENTRAL = "central";
+59 /**
+60 * Evidence source.
+61 */
+62 private static final String MANIFEST = "Manifest";
+63 /**
+64 * Evidence name.
+65 */
+66 private static final String VERSION = "version";
+67 /**
+68 * Evidence name.
+69 */
+70 private static final String IMPLEMENTATION_VERSION = "Implementation-Version";
+71
+72 /**
+73 * The name of the analyzer.
+74 */
+75 private static final String ANALYZER_NAME = "Version Filter Analyzer";
+76 /**
+77 * The phase that this analyzer is intended to run in.
+78 */
+79 private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION;
+80
+81 //</editor-fold>
+82 //<editor-fold defaultstate="collapsed" desc="Standard implementation of Analyzer">
+83 /**
+84 * Returns the name of the analyzer.
+85 *
+86 * @return the name of the analyzer.
+87 */
+88 @Override
+89 public String getName() {
+90 return ANALYZER_NAME;
+91 }
+92
+93 /**
+94 * Returns the phase that the analyzer is intended to run in.
+95 *
+96 * @return the phase that the analyzer is intended to run in.
+97 */
+98 @Override
+99 public AnalysisPhase getAnalysisPhase() {
+100 return ANALYSIS_PHASE;
+101 }
+102
+103 /**
+104 * Returns the setting key to determine if the analyzer is enabled.
+105 *
+106 * @return the key for the analyzer's enabled property
+107 */
+108 @Override
+109 protected String getAnalyzerEnabledSettingKey() {
+110 return Settings.KEYS.ANALYZER_VERSION_FILTER_ENABLED;
+111 }
+112 //</editor-fold>
+113
+114 /**
+115 * The Logger for use throughout the class
+116 */
+117 private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class);
+118
+119 /**
+120 * The HintAnalyzer uses knowledge about a dependency to add additional
+121 * information to help in identification of identifiers or vulnerabilities.
+122 *
+123 * @param dependency The dependency being analyzed
+124 * @param engine The scanning engine
+125 * @throws AnalysisException is thrown if there is an exception analyzing
+126 * the dependency.
+127 */
+128 @Override
+129 protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
+130 String fileVersion = null;
+131 String pomVersion = null;
+132 String manifestVersion = null;
+133 for (Evidence e : dependency.getVersionEvidence()) {
+134 if (FILE.equals(e.getSource()) && VERSION.equals(e.getName())) {
+135 fileVersion = e.getValue(Boolean.FALSE);
+136 } else if ((NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource())
+137 || POM.equals(e.getSource())) && VERSION.equals(e.getName())) {
+138 pomVersion = e.getValue(Boolean.FALSE);
+139 } else if (MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName())) {
+140 manifestVersion = e.getValue(Boolean.FALSE);
+141 }
+142 }
+143 //ensure we have at least two not null
+144 if (((fileVersion == null ? 0 : 1) + (pomVersion == null ? 0 : 1) + (manifestVersion == null ? 0 : 1)) > 1) {
+145 final DependencyVersion dvFile = new DependencyVersion(fileVersion);
+146 final DependencyVersion dvPom = new DependencyVersion(pomVersion);
+147 final DependencyVersion dvManifest = new DependencyVersion(manifestVersion);
+148 final boolean fileMatch = Objects.equals(dvFile, dvPom) || Objects.equals(dvFile, dvManifest);
+149 final boolean manifestMatch = Objects.equals(dvManifest, dvPom) || Objects.equals(dvManifest, dvFile);
+150 final boolean pomMatch = Objects.equals(dvPom, dvFile) || Objects.equals(dvPom, dvManifest);
+151 if (fileMatch || manifestMatch || pomMatch) {
+152 LOGGER.debug("filtering evidence from {}", dependency.getFileName());
+153 final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
+154 synchronized (versionEvidence) {
+155 final Iterator<Evidence> itr = versionEvidence.iterator();
+156 while (itr.hasNext()) {
+157 final Evidence e = itr.next();
+158 if (!(pomMatch && VERSION.equals(e.getName())
+159 && (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource())))
+160 && !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource()))
+161 && !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) {
+162 itr.remove();
+163 }
+164 }
+165 }
+166 }
+167 }
+168 }
+169 }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This report summarizes newer versions that may be available for your project's various dependencies.
+| # of dependencies using the latest version available | +18 | |
| # of dependencies where the next version available is smaller than an incremental version update | +0 | |
| # of dependencies where the next version available is an incremental version update | +4 | |
| # of dependencies where the next version available is a minor version update | +9 | |
| # of dependencies where the next version available is a major version update | +2 |
| Status | +Group Id | +Artifact Id | +Current Version | +Scope | +Classifier | +Type | +Next Version | +Next Incremental | +Next Minor | +Next Major |
|---|---|---|---|---|---|---|---|---|---|---|
| ch.qos.logback | +logback-classic | +1.1.8 | ++ | + | jar | ++ | 1.1.9 | ++ | ||
| ch.qos.logback | +logback-core | +1.1.8 | ++ | + | jar | ++ | 1.1.9 | ++ | ||
| com.google.code.findbugs | +annotations | +3.0.1u2 | ++ | + | jar | ++ | + | + | ||
| com.h2database | +h2 | +1.3.176 | ++ | + | jar | ++ | + | 1.4.177 | +||
| com.sun.mail | +mailapi | +1.5.6 | ++ | + | jar | ++ | + | + | ||
| commons-cli | +commons-cli | +1.3.1 | ++ | + | jar | ++ | + | + | ||
| commons-collections | +commons-collections | +3.2.2 | ++ | + | jar | ++ | + | + | 20030418.083655 | |
| commons-io | +commons-io | +2.5 | ++ | + | jar | ++ | + | + | ||
| joda-time | +joda-time | +1.6 | ++ | + | jar | ++ | 1.6.1 | ++ | 2.0 | |
| junit | +junit | +4.12 | +test | ++ | jar | ++ | + | + | ||
| org.apache.ant | +ant | +1.9.8 | ++ | + | jar | ++ | + | 1.10.0 | +||
| org.apache.ant | +ant-testutil | +1.9.8 | ++ | + | jar | ++ | + | 1.10.0 | +||
| org.apache.commons | +commons-compress | +1.13 | ++ | + | jar | ++ | + | + | ||
| org.apache.commons | +commons-lang3 | +3.3.2 | ++ | + | jar | ++ | + | 3.4 | +||
| org.apache.lucene | +lucene-analyzers-common | +4.7.2 | ++ | + | jar | ++ | + | 4.8.0 | +5.0.0 | |
| org.apache.lucene | +lucene-core | +4.7.2 | ++ | + | jar | ++ | + | 4.8.0 | +5.0.0 | |
| org.apache.lucene | +lucene-queryparser | +4.7.2 | ++ | + | jar | ++ | + | 4.8.0 | +5.0.0 | |
| org.apache.lucene | +lucene-test-framework | +4.7.2 | ++ | + | jar | ++ | + | 4.8.0 | +5.0.0 | |
| org.apache.maven | +maven-core | +3.3.9 | ++ | + | jar | ++ | + | + | ||
| org.apache.maven | +maven-plugin-api | +3.3.9 | ++ | + | jar | ++ | + | + | ||
| org.apache.maven | +maven-settings | +3.3.9 | ++ | + | jar | ++ | + | + | ||
| org.apache.maven.plugin-testing | +maven-plugin-testing-harness | +3.3.0 | ++ | + | jar | ++ | + | + | ||
| org.apache.maven.plugin-tools | +maven-plugin-annotations | +3.5 | ++ | + | jar | ++ | + | + | ||
| org.apache.maven.reporting | +maven-reporting-api | +3.0 | ++ | + | jar | ++ | + | + | ||
| org.apache.maven.shared | +maven-dependency-tree | +2.2 | ++ | + | jar | ++ | + | + | 3.0 | |
| org.apache.velocity | +velocity | +1.7 | ++ | + | jar | ++ | + | + | ||
| org.glassfish | +javax.json | +1.0.4 | ++ | + | jar | ++ | + | + | ||
| org.hamcrest | +hamcrest-core | +1.3 | +test | ++ | jar | ++ | + | + | ||
| org.jmockit | +jmockit | +1.25 | +test | ++ | jar | ++ | + | 1.26 | +||
| org.jsoup | +jsoup | +1.10.1 | ++ | + | jar | ++ | 1.10.2 | ++ | ||
| org.slf4j | +slf4j-api | +1.7.22 | ++ | + | jar | ++ | + | + | ||
| org.slf4j | +slf4j-simple | +1.7.22 | ++ | + | jar | ++ | + | + | ||
| org.sonatype.plexus | +plexus-sec-dispatcher | +1.4 | ++ | + | jar | ++ | + | + | ||
| Status | +Group Id | +Artifact Id | +Current Version | +Scope | +Classifier | +Type | +Next Version | +Next Incremental | +Next Minor | +Next Major |
| Status | +|
|---|---|
| Group Id | +ch.qos.logback |
| Artifact Id | +logback-classic |
| Current Version | +1.1.8 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +1.1.9 Next Incremental |
| Status | +|
|---|---|
| Group Id | +ch.qos.logback |
| Artifact Id | +logback-core |
| Current Version | +1.1.8 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +1.1.9 Next Incremental |
| Status | +|
|---|---|
| Group Id | +com.google.code.findbugs |
| Artifact Id | +annotations |
| Current Version | +3.0.1u2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +com.h2database |
| Artifact Id | +h2 |
| Current Version | +1.3.176 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +1.4.177 Next Minor 1.4.178 1.4.179 1.4.180 1.4.181 1.4.182 1.4.183 1.4.184 1.4.185 1.4.186 1.4.187 1.4.188 1.4.189 1.4.190 1.4.191 1.4.192 1.4.193 Latest Minor |
| Status | +|
|---|---|
| Group Id | +com.sun.mail |
| Artifact Id | +mailapi |
| Current Version | +1.5.6 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +commons-cli |
| Artifact Id | +commons-cli |
| Current Version | +1.3.1 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +commons-collections |
| Artifact Id | +commons-collections |
| Current Version | +3.2.2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +20030418.083655 Next Major 20031027.000000 20040102.233541 20040616 Latest Major |
| Status | +|
|---|---|
| Group Id | +commons-io |
| Artifact Id | +commons-io |
| Current Version | +2.5 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +joda-time |
| Artifact Id | +joda-time |
| Current Version | +1.6 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +1.6.1 Next Incremental 1.6.2 Latest Incremental 2.0 Next Major 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.8.2 2.9 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 Latest Major |
| Status | +|
|---|---|
| Group Id | +junit |
| Artifact Id | +junit |
| Current Version | +4.12 |
| Scope | +test |
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.ant |
| Artifact Id | +ant |
| Current Version | +1.9.8 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +1.10.0 Next Minor |
| Status | +|
|---|---|
| Group Id | +org.apache.ant |
| Artifact Id | +ant-testutil |
| Current Version | +1.9.8 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +1.10.0 Next Minor |
| Status | +|
|---|---|
| Group Id | +org.apache.commons |
| Artifact Id | +commons-compress |
| Current Version | +1.13 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.commons |
| Artifact Id | +commons-lang3 |
| Current Version | +3.3.2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +3.4 Next Minor 3.5 Latest Minor |
| Status | +|
|---|---|
| Group Id | +org.apache.lucene |
| Artifact Id | +lucene-analyzers-common |
| Current Version | +4.7.2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +4.8.0 Next Minor 4.8.1 4.9.0 4.9.1 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 Latest Minor 5.0.0 Next Major 5.1.0 5.2.0 5.2.1 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.5.3 6.0.0 6.0.1 6.1.0 6.2.0 6.2.1 6.3.0 6.4.0 Latest Major |
| Status | +|
|---|---|
| Group Id | +org.apache.lucene |
| Artifact Id | +lucene-core |
| Current Version | +4.7.2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +4.8.0 Next Minor 4.8.1 4.9.0 4.9.1 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 Latest Minor 5.0.0 Next Major 5.1.0 5.2.0 5.2.1 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.5.3 6.0.0 6.0.1 6.1.0 6.2.0 6.2.1 6.3.0 6.4.0 Latest Major |
| Status | +|
|---|---|
| Group Id | +org.apache.lucene |
| Artifact Id | +lucene-queryparser |
| Current Version | +4.7.2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +4.8.0 Next Minor 4.8.1 4.9.0 4.9.1 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 Latest Minor 5.0.0 Next Major 5.1.0 5.2.0 5.2.1 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.5.3 6.0.0 6.0.1 6.1.0 6.2.0 6.2.1 6.3.0 6.4.0 Latest Major |
| Status | +|
|---|---|
| Group Id | +org.apache.lucene |
| Artifact Id | +lucene-test-framework |
| Current Version | +4.7.2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +4.8.0 Next Minor 4.8.1 4.9.0 4.9.1 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 Latest Minor 5.0.0 Next Major 5.1.0 5.2.0 5.2.1 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.5.3 6.0.0 6.0.1 6.1.0 6.2.0 6.2.1 6.3.0 6.4.0 Latest Major |
| Status | +|
|---|---|
| Group Id | +org.apache.maven |
| Artifact Id | +maven-core |
| Current Version | +3.3.9 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.maven |
| Artifact Id | +maven-plugin-api |
| Current Version | +3.3.9 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.maven |
| Artifact Id | +maven-settings |
| Current Version | +3.3.9 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.maven.plugin-testing |
| Artifact Id | +maven-plugin-testing-harness |
| Current Version | +3.3.0 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.maven.plugin-tools |
| Artifact Id | +maven-plugin-annotations |
| Current Version | +3.5 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.maven.reporting |
| Artifact Id | +maven-reporting-api |
| Current Version | +3.0 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.apache.maven.shared |
| Artifact Id | +maven-dependency-tree |
| Current Version | +2.2 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +3.0 Next Major |
| Status | +|
|---|---|
| Group Id | +org.apache.velocity |
| Artifact Id | +velocity |
| Current Version | +1.7 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.glassfish |
| Artifact Id | +javax.json |
| Current Version | +1.0.4 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.hamcrest |
| Artifact Id | +hamcrest-core |
| Current Version | +1.3 |
| Scope | +test |
| Classifier | +|
| Type | +jar |
| Status | +|
|---|---|
| Group Id | +org.jmockit |
| Artifact Id | +jmockit |
| Current Version | +1.25 |
| Scope | +test |
| Classifier | +|
| Type | +jar |
| Newer versions | +1.26 Next Minor 1.27 1.28 1.29 1.30 Latest Minor |
| Status | +|
|---|---|
| Group Id | +org.jsoup |
| Artifact Id | +jsoup |
| Current Version | +1.10.1 |
| Scope | +|
| Classifier | +|
| Type | +jar |
| Newer versions | +1.10.2 Next Incremental |
| Status | +|
|---|---|
| Group Id | +org.slf4j |
| Artifact Id | +slf4j-api |
| Current Version | +1.7.22 |
| Scope | +|
| Classifier | +|
| Type | +jar |
+
+
+
+
+
+ OWASP dependency-check-plugin is a maven archetype for generating a maven project for a dependency-check plugin (i.e. a project containing one or more analyzers).
+mvn archetype:generate -DarchetypeGroupId=org.owasp -DarchetypeArtifactId=dependency-check-plugin -DarchetypeVersion=1.4.5 +
+
+
+
+
+
+
+
+
+
+
+
+ | t |
+
+
+
+
+
+ Typically the licenses listed for the project are that of the project itself, and not of dependencies.
+ Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. +