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.exception.InitializationException;
28 import org.owasp.dependencycheck.utils.Checksum;
29 import org.owasp.dependencycheck.utils.FileFilterBuilder;
30 import org.owasp.dependencycheck.utils.Settings;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import java.io.FileFilter;
35 import java.io.FileInputStream;
36 import java.io.FileNotFoundException;
37 import java.nio.charset.Charset;
38 import java.security.MessageDigest;
39 import java.security.NoSuchAlgorithmException;
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 getSha1MessageDigest();
89 } catch (IllegalStateException ex) {
90 setEnabled(false);
91 throw new InitializationException("Unable to create SHA1 MessageDigest", ex);
92 }
93 }
94
95
96
97
98
99
100
101
102 @Override
103 protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
104 FileInputStream fis = null;
105 try {
106 fis = new FileInputStream(dependency.getActualFile());
107 final ComposerLockParser clp = new ComposerLockParser(fis);
108 LOGGER.info("Checking composer.lock file {}", dependency.getActualFilePath());
109 clp.process();
110 for (ComposerDependency dep : clp.getDependencies()) {
111 final Dependency d = new Dependency(dependency.getActualFile());
112 d.setDisplayFileName(String.format("%s:%s/%s", dependency.getDisplayFileName(), dep.getGroup(), dep.getProject()));
113 final String filePath = String.format("%s:%s/%s", dependency.getFilePath(), dep.getGroup(), dep.getProject());
114 final MessageDigest sha1 = getSha1MessageDigest();
115 d.setFilePath(filePath);
116 d.setSha1sum(Checksum.getHex(sha1.digest(filePath.getBytes(Charset.defaultCharset()))));
117 d.getVendorEvidence().addEvidence(COMPOSER_LOCK, "vendor", dep.getGroup(), Confidence.HIGHEST);
118 d.getProductEvidence().addEvidence(COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGHEST);
119 d.getVersionEvidence().addEvidence(COMPOSER_LOCK, "version", dep.getVersion(), Confidence.HIGHEST);
120 LOGGER.info("Adding dependency {}", d);
121 engine.getDependencies().add(d);
122 }
123 } catch (FileNotFoundException fnfe) {
124 LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());
125 } catch (ComposerException ce) {
126 LOGGER.warn("Error parsing composer.json {}", dependency.getActualFilePath(), ce);
127 } finally {
128 if (fis != null) {
129 try {
130 fis.close();
131 } catch (Exception e) {
132 LOGGER.debug("Unable to close file", e);
133 }
134 }
135 }
136 }
137
138
139
140
141
142
143 @Override
144 protected String getAnalyzerEnabledSettingKey() {
145 return Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED;
146 }
147
148
149
150
151
152
153 @Override
154 public String getName() {
155 return ANALYZER_NAME;
156 }
157
158
159
160
161
162
163 @Override
164 public AnalysisPhase getAnalysisPhase() {
165 return AnalysisPhase.INFORMATION_COLLECTION;
166 }
167
168
169
170
171
172
173 private MessageDigest getSha1MessageDigest() {
174 try {
175 return MessageDigest.getInstance("SHA1");
176 } catch (NoSuchAlgorithmException e) {
177 LOGGER.error(e.getMessage());
178 throw new IllegalStateException("Failed to obtain the SHA1 message digest.", e);
179 }
180 }
181 }