Coverage Report - org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer
 
Classes in this File Line Coverage Branch Coverage Complexity
CocoaPodsAnalyzer
95%
47/49
75%
9/12
2
 
 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) 2016 IBM Corporation. All Rights Reserved.
 17  
  */
 18  
 package org.owasp.dependencycheck.analyzer;
 19  
 
 20  
 import java.io.File;
 21  
 import java.io.FileFilter;
 22  
 import java.io.IOException;
 23  
 import java.nio.charset.Charset;
 24  
 import java.util.regex.Matcher;
 25  
 import java.util.regex.Pattern;
 26  
 
 27  
 import org.apache.commons.io.FileUtils;
 28  
 import org.owasp.dependencycheck.Engine;
 29  
 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
 30  
 import org.owasp.dependencycheck.dependency.Confidence;
 31  
 import org.owasp.dependencycheck.dependency.Dependency;
 32  
 import org.owasp.dependencycheck.dependency.EvidenceCollection;
 33  
 import org.owasp.dependencycheck.utils.FileFilterBuilder;
 34  
 import org.owasp.dependencycheck.utils.Settings;
 35  
 
 36  
 /**
 37  
  * This analyzer is used to analyze SWIFT and Objective-C packages by collecting
 38  
  * information from .podspec files. CocoaPods dependency manager see
 39  
  * https://cocoapods.org/.
 40  
  *
 41  
  * @author Bianca Jiang (https://twitter.com/biancajiang)
 42  
  */
 43  
 @Experimental
 44  14
 public class CocoaPodsAnalyzer extends AbstractFileTypeAnalyzer {
 45  
 
 46  
     /**
 47  
      * The logger.
 48  
      */
 49  
 //    private static final Logger LOGGER = LoggerFactory.getLogger(CocoaPodsAnalyzer.class);
 50  
     /**
 51  
      * The name of the analyzer.
 52  
      */
 53  
     private static final String ANALYZER_NAME = "CocoaPods Package Analyzer";
 54  
 
 55  
     /**
 56  
      * The phase that this analyzer is intended to run in.
 57  
      */
 58  1
     private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
 59  
 
 60  
     /**
 61  
      * The file name to scan.
 62  
      */
 63  
     public static final String PODSPEC = "podspec";
 64  
     /**
 65  
      * Filter that detects files named "*.podspec".
 66  
      */
 67  1
     private static final FileFilter PODSPEC_FILTER = FileFilterBuilder.newInstance().addExtensions(PODSPEC).build();
 68  
 
 69  
     /**
 70  
      * The capture group #1 is the block variable. e.g. "Pod::Spec.new do
 71  
      * |spec|"
 72  
      */
 73  1
     private static final Pattern PODSPEC_BLOCK_PATTERN = Pattern.compile("Pod::Spec\\.new\\s+?do\\s+?\\|(.+?)\\|");
 74  
 
 75  
     /**
 76  
      * Returns the FileFilter
 77  
      *
 78  
      * @return the FileFilter
 79  
      */
 80  
     @Override
 81  
     protected FileFilter getFileFilter() {
 82  859
         return PODSPEC_FILTER;
 83  
     }
 84  
 
 85  
     @Override
 86  
     protected void initializeFileTypeAnalyzer() {
 87  
         // NO-OP
 88  6
     }
 89  
 
 90  
     /**
 91  
      * Returns the name of the analyzer.
 92  
      *
 93  
      * @return the name of the analyzer.
 94  
      */
 95  
     @Override
 96  
     public String getName() {
 97  17
         return ANALYZER_NAME;
 98  
     }
 99  
 
 100  
     /**
 101  
      * Returns the phase that the analyzer is intended to run in.
 102  
      *
 103  
      * @return the phase that the analyzer is intended to run in.
 104  
      */
 105  
     @Override
 106  
     public AnalysisPhase getAnalysisPhase() {
 107  6
         return ANALYSIS_PHASE;
 108  
     }
 109  
 
 110  
     /**
 111  
      * Returns the key used in the properties file to reference the analyzer's
 112  
      * enabled property.
 113  
      *
 114  
      * @return the analyzer's enabled property setting key
 115  
      */
 116  
     @Override
 117  
     protected String getAnalyzerEnabledSettingKey() {
 118  8
         return Settings.KEYS.ANALYZER_COCOAPODS_ENABLED;
 119  
     }
 120  
 
 121  
     @Override
 122  
     protected void analyzeDependency(Dependency dependency, Engine engine)
 123  
             throws AnalysisException {
 124  
 
 125  
         String contents;
 126  
         try {
 127  1
             contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset());
 128  0
         } catch (IOException e) {
 129  0
             throw new AnalysisException(
 130  
                     "Problem occurred while reading dependency file.", e);
 131  1
         }
 132  1
         final Matcher matcher = PODSPEC_BLOCK_PATTERN.matcher(contents);
 133  1
         if (matcher.find()) {
 134  1
             contents = contents.substring(matcher.end());
 135  1
             final String blockVariable = matcher.group(1);
 136  
 
 137  1
             final EvidenceCollection vendor = dependency.getVendorEvidence();
 138  1
             final EvidenceCollection product = dependency.getProductEvidence();
 139  1
             final EvidenceCollection version = dependency.getVersionEvidence();
 140  
 
 141  1
             final String name = addStringEvidence(product, contents, blockVariable, "name", "name", Confidence.HIGHEST);
 142  1
             if (!name.isEmpty()) {
 143  1
                 vendor.addEvidence(PODSPEC, "name_project", name, Confidence.HIGHEST);
 144  
             }
 145  1
             addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.HIGHEST);
 146  
 
 147  1
             addStringEvidence(vendor, contents, blockVariable, "author", "authors?", Confidence.HIGHEST);
 148  1
             addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST);
 149  1
             addStringEvidence(vendor, contents, blockVariable, "license", "licen[cs]es?", Confidence.HIGHEST);
 150  
 
 151  1
             addStringEvidence(version, contents, blockVariable, "version", "version", Confidence.HIGHEST);
 152  
         }
 153  
 
 154  1
         setPackagePath(dependency);
 155  1
     }
 156  
 
 157  
     /**
 158  
      * Extracts evidence from the contents and adds it to the given evidence
 159  
      * collection.
 160  
      *
 161  
      * @param evidences the evidence collection to update
 162  
      * @param contents the text to extract evidence from
 163  
      * @param blockVariable the block variable within the content to search for
 164  
      * @param field the name of the field being searched for
 165  
      * @param fieldPattern the field pattern within the contents to search for
 166  
      * @param confidence the confidence level of the evidence if found
 167  
      * @return the string that was added as evidence
 168  
      */
 169  
     private String addStringEvidence(EvidenceCollection evidences, String contents,
 170  
             String blockVariable, String field, String fieldPattern, Confidence confidence) {
 171  6
         String value = "";
 172  
 
 173  
         //capture array value between [ ]
 174  12
         final Matcher arrayMatcher = Pattern.compile(
 175  6
                 String.format("\\s*?%s\\.%s\\s*?=\\s*?\\{\\s*?(.*?)\\s*?\\}", blockVariable, fieldPattern),
 176  6
                 Pattern.CASE_INSENSITIVE).matcher(contents);
 177  6
         if (arrayMatcher.find()) {
 178  1
             value = arrayMatcher.group(1);
 179  
         } else { //capture single value between quotes
 180  10
             final Matcher matcher = Pattern.compile(
 181  5
                     String.format("\\s*?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, fieldPattern),
 182  5
                     Pattern.CASE_INSENSITIVE).matcher(contents);
 183  5
             if (matcher.find()) {
 184  4
                 value = matcher.group(2);
 185  
             }
 186  
         }
 187  6
         if (value.length() > 0) {
 188  5
             evidences.addEvidence(PODSPEC, field, value, confidence);
 189  
         }
 190  6
         return value;
 191  
     }
 192  
 
 193  
     /**
 194  
      * Sets the package path on the given dependency.
 195  
      *
 196  
      * @param dep the dependency to update
 197  
      */
 198  
     private void setPackagePath(Dependency dep) {
 199  1
         final File file = new File(dep.getFilePath());
 200  1
         final String parent = file.getParent();
 201  1
         if (parent != null) {
 202  1
             dep.setPackagePath(parent);
 203  
         }
 204  1
     }
 205  
 }