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) 2018 Paul Irwin. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.data.nuget;
19  
20  import org.owasp.dependencycheck.utils.XmlUtils;
21  import org.w3c.dom.Document;
22  import org.w3c.dom.NamedNodeMap;
23  import org.w3c.dom.Node;
24  import org.w3c.dom.NodeList;
25  import org.xml.sax.SAXException;
26  
27  import javax.xml.parsers.DocumentBuilder;
28  import javax.xml.parsers.ParserConfigurationException;
29  import javax.xml.xpath.XPath;
30  import javax.xml.xpath.XPathConstants;
31  import javax.xml.xpath.XPathExpressionException;
32  import javax.xml.xpath.XPathFactory;
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.util.ArrayList;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Properties;
39  import org.owasp.dependencycheck.utils.InterpolationUtil;
40  import org.owasp.dependencycheck.utils.InterpolationUtil.SyntaxStyle;
41  
42  /**
43   * Parses a MSBuild project file for NuGet references using XPath.
44   *
45   * @author paulirwin
46   */
47  public class XPathMSBuildProjectParser {
48  
49      /**
50       * Parses the given stream for MSBuild PackageReference elements.
51       *
52       * @param stream the input stream to parse
53       * @param props the Directory.Build.props properties
54       * @param centrallyManaged a map of centrally managed package references
55       * @return a collection of discovered NuGet package references
56       * @throws MSBuildProjectParseException if an exception occurs
57       */
58      public List<NugetPackageReference> parse(InputStream stream, Properties props,
59              Map<String, String> centrallyManaged) throws MSBuildProjectParseException {
60          try {
61              final DocumentBuilder db = XmlUtils.buildSecureDocumentBuilder();
62              final Document d = db.parse(stream);
63  
64              final XPath xpath = XPathFactory.newInstance().newXPath();
65              final List<NugetPackageReference> packages = new ArrayList<>();
66  
67              final NodeList nodeList = (NodeList) xpath.evaluate("//PackageReference", d, XPathConstants.NODESET);
68  
69              if (nodeList == null) {
70                  throw new MSBuildProjectParseException("Unable to parse MSBuild project file");
71              }
72  
73              for (int i = 0; i < nodeList.getLength(); i++) {
74                  final Node node = nodeList.item(i);
75                  final NamedNodeMap attrs = node.getAttributes();
76  
77                  final Node includeAttr = attrs.getNamedItem("Include");
78                  if (includeAttr == null) {
79                      // Issue 5144 work-around for NPE on packageReferences other than includes
80                      continue;
81                  }
82                  final String include = includeAttr.getNodeValue();
83                  String version = null;
84  
85                  if (centrallyManaged.containsKey(include)) {
86                      if (attrs.getNamedItem("VersionOverride") != null) {
87                          version = attrs.getNamedItem("VersionOverride").getNodeValue();
88                      } else {
89                          version = centrallyManaged.get(include);
90                      }
91                  } else if (attrs.getNamedItem("Version") != null) {
92                      version = attrs.getNamedItem("Version").getNodeValue();
93                  } else if (xpath.evaluate("Version", node, XPathConstants.NODE) instanceof Node) {
94                      version = ((Node) xpath.evaluate("Version", node, XPathConstants.NODE)).getTextContent();
95                  }
96  
97                  if (include != null && version != null) {
98  
99                      final NugetPackageReference npr = new NugetPackageReference();
100 
101                     npr.setId(include);
102                     npr.setVersion(InterpolationUtil.interpolate(version, props, SyntaxStyle.MSBUILD));
103 
104                     packages.add(npr);
105                 }
106             }
107 
108             return packages;
109         } catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException | MSBuildProjectParseException e) {
110             throw new MSBuildProjectParseException("Unable to parse MSBuild project file", e);
111         }
112     }
113 
114 }