1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  package org.owasp.dependencycheck.analyzer;
19  
20  import com.github.packageurl.MalformedPackageURLException;
21  import com.github.packageurl.PackageURL;
22  import com.github.packageurl.PackageURLBuilder;
23  import org.owasp.dependencycheck.Engine;
24  import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
25  import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem;
26  import org.owasp.dependencycheck.dependency.Confidence;
27  import org.owasp.dependencycheck.dependency.Dependency;
28  import org.owasp.dependencycheck.dependency.EvidenceType;
29  import org.owasp.dependencycheck.dependency.naming.GenericIdentifier;
30  import org.owasp.dependencycheck.dependency.naming.PurlIdentifier;
31  import org.owasp.dependencycheck.utils.Checksum;
32  import org.owasp.dependencycheck.utils.FileFilterBuilder;
33  import org.owasp.dependencycheck.utils.Settings;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  import javax.annotation.concurrent.ThreadSafe;
38  import java.io.File;
39  import java.io.FileFilter;
40  import java.io.IOException;
41  import java.nio.charset.StandardCharsets;
42  import java.nio.file.Files;
43  import java.util.regex.Matcher;
44  import java.util.regex.Pattern;
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  @Experimental
56  @ThreadSafe
57  public class CarthageAnalyzer extends AbstractFileTypeAnalyzer {
58  
59      
60  
61  
62  
63      public static final String DEPENDENCY_ECOSYSTEM = Ecosystem.IOS;
64  
65      
66  
67  
68      private static final Logger LOGGER = LoggerFactory.getLogger(CarthageAnalyzer.class);
69      
70  
71  
72      private static final String ANALYZER_NAME = "Carthage Package Analyzer";
73  
74      
75  
76  
77      private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
78  
79      
80  
81  
82      public static final String CARTFILE_RESOLVED = "Cartfile.resolved";
83      
84  
85  
86      private static final FileFilter CARTHAGE_FILTER = FileFilterBuilder.newInstance().addFilenames(CARTFILE_RESOLVED).build();
87  
88      
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100 
101 
102 
103     private static final Pattern CARTFILE_RESOLVED_DEPENDENCY_PATTERN = Pattern.compile("(github|git|binary) \"([^\"]+)\" \"([^\"]+)\"");
104 
105     
106 
107 
108     private static final Pattern CARTFILE_VERSION_PATTERN = Pattern.compile("^v?(\\d+(\\.\\d+){0,4})$");
109 
110     
111 
112 
113 
114 
115 
116 
117 
118 
119     private static final Pattern CARTFILE_RESOLVED_GITHUB_DEPENDENCY = Pattern.compile("[a-zA-Z0-9-_]+/([a-zA-Z0-9\\-_\\.]+)");
120 
121     
122 
123 
124     private static final Pattern CARTFILE_RESOLVED_GIT_DEPENDENCY = Pattern.compile(".*?/([a-zA-Z0-9\\-_\\.]+).git");
125 
126     
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137     private static final Pattern CARTFILE_RESOLVED_BINARY_DEPENDENCY = Pattern.compile("([a-zA-Z0-9\\-_\\.]+).json");
138 
139     
140 
141 
142 
143 
144     @Override
145     protected FileFilter getFileFilter() {
146         return CARTHAGE_FILTER;
147     }
148 
149     @Override
150     protected void prepareFileTypeAnalyzer(Engine engine) {
151         
152     }
153 
154     
155 
156 
157 
158 
159     @Override
160     public String getName() {
161         return ANALYZER_NAME;
162     }
163 
164     
165 
166 
167 
168 
169     @Override
170     public AnalysisPhase getAnalysisPhase() {
171         return ANALYSIS_PHASE;
172     }
173 
174     
175 
176 
177 
178 
179 
180     @Override
181     protected String getAnalyzerEnabledSettingKey() {
182         return Settings.KEYS.ANALYZER_CARTHAGE_ENABLED;
183     }
184 
185     @Override
186     protected void analyzeDependency(Dependency dependency, Engine engine)
187             throws AnalysisException {
188         if (CARTFILE_RESOLVED.equals(dependency.getFileName())) {
189             analyzeCartfileResolvedDependency(dependency, engine);
190         }
191     }
192 
193     
194 
195 
196 
197 
198 
199 
200 
201     private void analyzeCartfileResolvedDependency(Dependency cartfileResolved, Engine engine)
202             throws AnalysisException {
203         engine.removeDependency(cartfileResolved);
204 
205         final String contents;
206         try {
207             contents = new String(Files.readAllBytes(cartfileResolved.getActualFile().toPath()), StandardCharsets.UTF_8);
208         } catch (IOException e) {
209             throw new AnalysisException(
210                     "Problem occurred while reading dependency file.", e);
211         }
212 
213         final Matcher matcher = CARTFILE_RESOLVED_DEPENDENCY_PATTERN.matcher(contents);
214         while (matcher.find()) {
215             final String type = matcher.group(1);
216             String name = matcher.group(2);
217             String version = matcher.group(3);
218 
219             final Matcher versionMatcher = CARTFILE_VERSION_PATTERN.matcher(version);
220             if (versionMatcher.find()) {
221                 version = versionMatcher.group(1);
222             } else {
223                 
224                 
225                 
226                 version = "0.0.0";
227             }
228 
229             if (type.contentEquals("git")) {
230                 final Matcher nameMatcher = CARTFILE_RESOLVED_GIT_DEPENDENCY.matcher(name);
231                 if (!nameMatcher.find()) {
232                     continue;
233                 }
234                 name = nameMatcher.group(1);
235             } else if (type.contentEquals("github")) {
236                 final Matcher nameMatcher = CARTFILE_RESOLVED_GITHUB_DEPENDENCY.matcher(name);
237                 if (!nameMatcher.find()) {
238                     continue;
239                 }
240                 name = nameMatcher.group(1);
241             } else if (type.contentEquals("binary")) {
242                 final Matcher nameMatcher = CARTFILE_RESOLVED_BINARY_DEPENDENCY.matcher(name);
243                 if (!nameMatcher.find()) {
244                     continue;
245                 }
246                 name = nameMatcher.group(1);
247             }
248 
249             final Dependency dependency = new Dependency(cartfileResolved.getActualFile(), true);
250             dependency.setEcosystem(DEPENDENCY_ECOSYSTEM);
251             dependency.setName(name);
252             dependency.setVersion(version);
253 
254             try {
255                 final PackageURLBuilder builder = PackageURLBuilder.aPackageURL().withType("carthage").withName(dependency.getName());
256                 if (dependency.getVersion() != null) {
257                     builder.withVersion(dependency.getVersion());
258                 }
259                 final PackageURL purl = builder.build();
260                 dependency.addSoftwareIdentifier(new PurlIdentifier(purl, Confidence.HIGHEST));
261             } catch (MalformedPackageURLException ex) {
262                 LOGGER.debug("Unable to build package url for carthage", ex);
263                 final GenericIdentifier id;
264                 if (dependency.getVersion() != null) {
265                     id = new GenericIdentifier("carthage:" + dependency.getName() + "@" + dependency.getVersion(), Confidence.HIGHEST);
266                 } else {
267                     id = new GenericIdentifier("carthage:" + dependency.getName(), Confidence.HIGHEST);
268                 }
269                 dependency.addSoftwareIdentifier(id);
270             }
271 
272             final String packagePath = String.format("%s:%s", name, version);
273             dependency.setPackagePath(packagePath);
274             dependency.setDisplayFileName(packagePath);
275             dependency.setSha1sum(Checksum.getSHA1Checksum(packagePath));
276             dependency.setSha256sum(Checksum.getSHA256Checksum(packagePath));
277             dependency.setMd5sum(Checksum.getMD5Checksum(packagePath));
278             dependency.addEvidence(EvidenceType.VENDOR, CARTFILE_RESOLVED, "name", name, Confidence.HIGHEST);
279             dependency.addEvidence(EvidenceType.PRODUCT, CARTFILE_RESOLVED, "name", name, Confidence.HIGHEST);
280             dependency.addEvidence(EvidenceType.VERSION, CARTFILE_RESOLVED, "version", version, Confidence.HIGHEST);
281             engine.addDependency(dependency);
282         }
283     }
284 
285     
286 
287 
288 
289 
290     private void setPackagePath(Dependency dep) {
291         final File file = new File(dep.getFilePath());
292         final String parent = file.getParent();
293         if (parent != null) {
294             dep.setPackagePath(parent);
295         }
296     }
297 }