View Javadoc
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) 2015 The OWASP Foundation. All Rights Reserved.
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   * Used to analyze a composer.lock file for a composer PHP app.
43   *
44   * @author colezlaw
45   */
46  @Experimental
47  public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
48  
49      /**
50       * The logger.
51       */
52      private static final Logger LOGGER = LoggerFactory.getLogger(ComposerLockAnalyzer.class);
53  
54      /**
55       * The analyzer name.
56       */
57      private static final String ANALYZER_NAME = "Composer.lock analyzer";
58  
59      /**
60       * composer.json.
61       */
62      private static final String COMPOSER_LOCK = "composer.lock";
63  
64      /**
65       * The FileFilter.
66       */
67      private static final FileFilter FILE_FILTER = FileFilterBuilder.newInstance().addFilenames(COMPOSER_LOCK).build();
68  
69      /**
70       * Returns the FileFilter.
71       *
72       * @return the FileFilter
73       */
74      @Override
75      protected FileFilter getFileFilter() {
76          return FILE_FILTER;
77      }
78  
79      /**
80       * Initializes the analyzer.
81       *
82       * @throws InitializationException thrown if an exception occurs getting an
83       * instance of SHA1
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       * The MessageDigest for calculating a new digest for the new dependencies
97       * added.
98       */
99      private MessageDigest sha1 = null;
100 
101     /**
102      * Entry point for the analyzer.
103      *
104      * @param dependency the dependency to analyze
105      * @param engine the engine scanning
106      * @throws AnalysisException if there's a failure during analysis
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      * Gets the key to determine whether the analyzer is enabled.
145      *
146      * @return the key specifying whether the analyzer is enabled
147      */
148     @Override
149     protected String getAnalyzerEnabledSettingKey() {
150         return Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED;
151     }
152 
153     /**
154      * Returns the analyzer's name.
155      *
156      * @return the analyzer's name
157      */
158     @Override
159     public String getName() {
160         return ANALYZER_NAME;
161     }
162 
163     /**
164      * Returns the phase this analyzer should run under.
165      *
166      * @return the analysis phase
167      */
168     @Override
169     public AnalysisPhase getAnalysisPhase() {
170         return AnalysisPhase.INFORMATION_COLLECTION;
171     }
172 }