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) 2020 Jeremy Long. All Rights Reserved.
17 */
18 package org.owasp.dependencycheck.analyzer;
19
20 import java.io.IOException;
21 import java.util.concurrent.TimeUnit;
22 import javax.annotation.concurrent.ThreadSafe;
23 import org.apache.lucene.index.CorruptIndexException;
24 import org.apache.lucene.queryparser.classic.ParseException;
25 import org.owasp.dependencycheck.Engine;
26 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
27 import org.owasp.dependencycheck.data.cpe.IndexException;
28 import org.owasp.dependencycheck.data.cpe.NpmCpeMemoryIndex;
29 import org.owasp.dependencycheck.data.nvdcve.CveDB;
30 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
31 import org.owasp.dependencycheck.dependency.Dependency;
32 import org.owasp.dependencycheck.utils.Settings;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37 * NpmCPEAnalyzer takes a project dependency and attempts to discern if there is
38 * an associated CPE. Unlike the CPEAnalyzer, the NpmCPEAnalyzer only includes
39 * product and vendor associates known to be related to node from the NVD data
40 * set. It uses the evidence contained within the dependency to search the
41 * Lucene index.
42 *
43 * @author Jeremy Long
44 */
45 @ThreadSafe
46 @Experimental
47 public class NpmCPEAnalyzer extends CPEAnalyzer {
48
49 /**
50 * The Logger.
51 */
52 private static final Logger LOGGER = LoggerFactory.getLogger(NpmCPEAnalyzer.class);
53
54 /**
55 * Returns the analysis phase that this analyzer should run in.
56 *
57 * @return the analysis phase that this analyzer should run in.
58 */
59 @Override
60 public AnalysisPhase getAnalysisPhase() {
61 //TODO this is a hack because we use the same singleton CPE Index as the CPE Analyzer
62 // thus to filter to just node products we can't run in the same phase.
63 // possibly extenend the CPE Index to include an ecosystem and use that
64 // as a filter for node..
65 return AnalysisPhase.PRE_IDENTIFIER_ANALYSIS;
66 }
67
68 /**
69 * Returns the name of this analyzer.
70 *
71 * @return the name of this analyzer.
72 */
73 @Override
74 public String getName() {
75 return "NPM CPE Analyzer";
76 }
77
78 /**
79 * <p>
80 * Returns the setting key to determine if the analyzer is enabled.</p>
81 *
82 * @return the key for the analyzer's enabled property
83 */
84 @Override
85 protected String getAnalyzerEnabledSettingKey() {
86 return Settings.KEYS.ANALYZER_NPM_CPE_ENABLED;
87 }
88
89 /**
90 * Opens the data source.
91 *
92 * @param cve a reference to the NVD CVE database
93 * @throws IOException when the Lucene directory to be queried does not
94 * exist or is corrupt.
95 * @throws DatabaseException when the database throws an exception. This
96 * usually occurs when the database is in use by another process.
97 */
98 @Override
99 public void open(CveDB cve) throws IOException, DatabaseException {
100 setCveDB(cve);
101 setMemoryIndex(NpmCpeMemoryIndex.getInstance());
102 try {
103 final long creationStart = System.currentTimeMillis();
104 getMemoryIndex().open(cve.getVendorProductListForNode(), this.getSettings());
105 final long creationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - creationStart);
106 LOGGER.info("Created CPE Index ({} seconds)", creationSeconds);
107 } catch (IndexException ex) {
108 LOGGER.debug("IndexException", ex);
109 throw new DatabaseException(ex);
110 }
111 }
112
113 /**
114 * Analyzes a dependency and attempts to determine if there are any CPE
115 * identifiers for this dependency.
116 *
117 * @param dependency The Dependency to analyze.
118 * @param engine The analysis engine
119 * @throws AnalysisException is thrown if there is an issue analyzing the
120 * dependency.
121 */
122 @Override
123 protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
124 if (!"npm".equals(dependency.getEcosystem())) {
125 return;
126 }
127 try {
128 determineCPE(dependency);
129 } catch (CorruptIndexException ex) {
130 throw new AnalysisException("CPE Index is corrupt.", ex);
131 } catch (IOException ex) {
132 throw new AnalysisException("Failure opening the CPE Index.", ex);
133 } catch (ParseException ex) {
134 throw new AnalysisException("Unable to parse the generated Lucene query for this dependency.", ex);
135 }
136 }
137 }