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 org.owasp.dependencycheck.Engine;
21 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
22 import org.owasp.dependencycheck.data.composer.ComposerDependency;
23 import org.owasp.dependencycheck.data.composer.ComposerException;
24 import org.owasp.dependencycheck.data.composer.ComposerLockParser;
25 import org.owasp.dependencycheck.dependency.Confidence;
26 import org.owasp.dependencycheck.dependency.Dependency;
27 import org.owasp.dependencycheck.utils.Checksum;
28 import org.owasp.dependencycheck.utils.FileFilterBuilder;
29 import org.owasp.dependencycheck.utils.Settings;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import java.io.FileFilter;
34 import java.io.FileInputStream;
35 import java.io.FileNotFoundException;
36 import java.nio.charset.Charset;
37 import java.security.MessageDigest;
38 import java.security.NoSuchAlgorithmException;
39 import org.owasp.dependencycheck.exception.InitializationException;
40
41
42
43
44
45
46 @Experimental
47 public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
48
49
50
51
52 private static final Logger LOGGER = LoggerFactory.getLogger(ComposerLockAnalyzer.class);
53
54
55
56
57 private static final String ANALYZER_NAME = "Composer.lock analyzer";
58
59
60
61
62 private static final String COMPOSER_LOCK = "composer.lock";
63
64
65
66
67 private static final FileFilter FILE_FILTER = FileFilterBuilder.newInstance().addFilenames(COMPOSER_LOCK).build();
68
69
70
71
72
73
74 @Override
75 protected FileFilter getFileFilter() {
76 return FILE_FILTER;
77 }
78
79
80
81
82
83
84
85 @Override
86 protected void initializeFileTypeAnalyzer() throws InitializationException {
87 try {
88 sha1 = MessageDigest.getInstance("SHA1");
89 } catch (NoSuchAlgorithmException ex) {
90 setEnabled(false);
91 throw new InitializationException("Unable to create SHA1 MmessageDigest", ex);
92 }
93 }
94
95
96
97
98
99 private MessageDigest sha1 = null;
100
101
102
103
104
105
106
107
108 @Override
109 protected void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
110 FileInputStream fis = null;
111 try {
112 fis = new FileInputStream(dependency.getActualFile());
113 final ComposerLockParser clp = new ComposerLockParser(fis);
114 LOGGER.info("Checking composer.lock file {}", dependency.getActualFilePath());
115 clp.process();
116 for (ComposerDependency dep : clp.getDependencies()) {
117 final Dependency d = new Dependency(dependency.getActualFile());
118 d.setDisplayFileName(String.format("%s:%s/%s", dependency.getDisplayFileName(), dep.getGroup(), dep.getProject()));
119 final String filePath = String.format("%s:%s/%s", dependency.getFilePath(), dep.getGroup(), dep.getProject());
120 d.setFilePath(filePath);
121 d.setSha1sum(Checksum.getHex(sha1.digest(filePath.getBytes(Charset.defaultCharset()))));
122 d.getVendorEvidence().addEvidence(COMPOSER_LOCK, "vendor", dep.getGroup(), Confidence.HIGHEST);
123 d.getProductEvidence().addEvidence(COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGHEST);
124 d.getVersionEvidence().addEvidence(COMPOSER_LOCK, "version", dep.getVersion(), Confidence.HIGHEST);
125 LOGGER.info("Adding dependency {}", d);
126 engine.getDependencies().add(d);
127 }
128 } catch (FileNotFoundException fnfe) {
129 LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());
130 } catch (ComposerException ce) {
131 LOGGER.warn("Error parsing composer.json {}", dependency.getActualFilePath(), ce);
132 } finally {
133 if (fis != null) {
134 try {
135 fis.close();
136 } catch (Exception e) {
137 LOGGER.debug("Unable to close file", e);
138 }
139 }
140 }
141 }
142
143
144
145
146
147
148 @Override
149 protected String getAnalyzerEnabledSettingKey() {
150 return Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED;
151 }
152
153
154
155
156
157
158 @Override
159 public String getName() {
160 return ANALYZER_NAME;
161 }
162
163
164
165
166
167
168 @Override
169 public AnalysisPhase getAnalysisPhase() {
170 return AnalysisPhase.INFORMATION_COLLECTION;
171 }
172 }