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) 2023 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.data.nuget;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.Map;
25  import java.util.Set;
26  import javax.xml.parsers.DocumentBuilder;
27  import javax.xml.parsers.ParserConfigurationException;
28  import javax.xml.xpath.XPath;
29  import javax.xml.xpath.XPathConstants;
30  import javax.xml.xpath.XPathExpressionException;
31  import javax.xml.xpath.XPathFactory;
32  import org.owasp.dependencycheck.utils.XmlUtils;
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Node;
35  import org.w3c.dom.Element;
36  import org.w3c.dom.NodeList;
37  import org.xml.sax.SAXException;
38  
39  /**
40   * Parses `Directory.Build.props`.
41   *
42   * @see
43   * <a href="https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019">Directory.Build.props</a>
44   * @author Jeremy Long
45   */
46  public class DirectoryBuildPropsParser {
47  
48      /**
49       * The collection of imports identified during parsing.
50       */
51      private Set<String> imports = new HashSet<>();
52  
53      /**
54       * Returns the imports identified during parsing.
55       *
56       * @return the imports identified during parsing.
57       */
58      public Set<String> getImports() {
59          return imports;
60      }
61  
62      /**
63       * Parse the properties from the `Directory.Build.props` file InputStream.If
64       * any import nodes are found while parsing, the values will be available
65       * via `getImports()` after parsing is complete.
66       *
67       * @param stream the input stream containing the props file to parse.
68       * @return the properties.
69       * @throws MSBuildProjectParseException thrown if there is a parsing error.
70       */
71      public Map<String, String> parse(InputStream stream) throws MSBuildProjectParseException {
72          try {
73              final HashMap<String, String> props = new HashMap<>();
74  
75              final DocumentBuilder db = XmlUtils.buildSecureDocumentBuilder();
76              final Document d = db.parse(stream);
77  
78              final XPath xpath = XPathFactory.newInstance().newXPath();
79  
80              //<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
81              final NodeList importList = (NodeList) xpath.evaluate("//Import", d, XPathConstants.NODESET);
82              if (importList != null) {
83                  for (int i = 0; i < importList.getLength(); i++) {
84                      final Node importNode = importList.item(i);
85                      final Node project = importNode.getAttributes().getNamedItem("Project");
86                      imports.add(project.getNodeValue());
87                  }
88              }
89              final NodeList propertyGroups = (NodeList) xpath.evaluate("//PropertyGroup", d, XPathConstants.NODESET);
90              if (propertyGroups != null) {
91                  for (int i = 0; i < propertyGroups.getLength(); i++) {
92                      final Node group = propertyGroups.item(i);
93                      final NodeList propertyNodes = group.getChildNodes();
94                      for (int x = 0; x < propertyNodes.getLength(); x++) {
95                          final Node node = propertyNodes.item(x);
96                          if (node instanceof Element) {
97                              final Element property = (Element) node;
98                              final String name = property.getNodeName();
99                              final Node value = property.getChildNodes().item(0);
100                             if (value != null) {
101                                 props.put(name, value.getNodeValue().trim());
102                             }
103                         }
104                     }
105                 }
106             }
107             return props;
108         } catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException ex) {
109             throw new MSBuildProjectParseException("Error parsing Directory.Build.props", ex);
110         }
111     }
112 }