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) 2016 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.xml.hints;
19  
20  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.InputStreamReader;
26  import java.io.Reader;
27  import java.nio.charset.StandardCharsets;
28  import java.util.List;
29  import javax.annotation.concurrent.NotThreadSafe;
30  import javax.xml.parsers.ParserConfigurationException;
31  
32  import org.apache.commons.io.ByteOrderMark;
33  import org.apache.commons.io.input.BOMInputStream;
34  
35  import org.owasp.dependencycheck.utils.AutoCloseableInputSource;
36  import org.owasp.dependencycheck.utils.XmlUtils;
37  
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  import org.xml.sax.InputSource;
41  import org.xml.sax.SAXException;
42  import org.xml.sax.XMLReader;
43  
44  import static org.owasp.dependencycheck.utils.AutoCloseableInputSource.fromResource;
45  
46  /**
47   * A simple validating parser for XML Hint Rules.
48   *
49   * @author Jeremy Long
50   */
51  @NotThreadSafe
52  public class HintParser {
53  
54      /**
55       * The logger.
56       */
57      private static final Logger LOGGER = LoggerFactory.getLogger(HintParser.class);
58  
59      /**
60       * The schema for the hint XML files.
61       */
62      private static final String HINT_SCHEMA_1_2 = "schema/dependency-hint.1.2.xsd";
63  
64      /**
65       * The schema for the hint XML files.
66       */
67      private static final String HINT_SCHEMA_1_1 = "schema/dependency-hint.1.1.xsd";
68  
69      /**
70       * The schema for the hint XML files.
71       */
72      private static final String HINT_SCHEMA_1_3 = "schema/dependency-hint.1.3.xsd";
73  
74      /**
75       * The schema for the hint XML files.
76       */
77      private static final String HINT_SCHEMA_1_4 = "schema/dependency-hint.1.4.xsd";
78  
79      /**
80       * The hint rules.
81       */
82      private List<HintRule> hintRules;
83      /**
84       * The vendor duplicating hint rules.
85       */
86      private List<VendorDuplicatingHintRule> vendorDuplicatingHintRules;
87  
88      /**
89       * Returns the hint rules.
90       *
91       * @return the hint rules
92       */
93      @SuppressWarnings({"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
94      public List<HintRule> getHintRules() {
95          return hintRules;
96      }
97  
98      /**
99       * Returns the vendor duplicating hint rules.
100      *
101      * @return the vendor duplicating hint rules
102      */
103     public List<VendorDuplicatingHintRule> getVendorDuplicatingHintRules() {
104         return vendorDuplicatingHintRules;
105     }
106 
107     /**
108      * Parses the given XML file and returns a list of the hints contained.
109      *
110      * @param file an XML file containing hints
111      * @throws HintParseException thrown if the XML file cannot be parsed
112      */
113     @SuppressFBWarnings(justification = "try with resources will clean up the input stream", value = {"OBL_UNSATISFIED_OBLIGATION"})
114     public void parseHints(File file) throws HintParseException {
115         try (InputStream fis = new FileInputStream(file)) {
116             parseHints(fis);
117         } catch (SAXException | IOException ex) {
118             LOGGER.debug("", ex);
119             throw new HintParseException(ex);
120         }
121     }
122 
123     /**
124      * Parses the given XML stream and returns a list of the hint rules
125      * contained.
126      *
127      * @param inputStream an InputStream containing hint rules
128      * @throws HintParseException thrown if the XML cannot be parsed
129      * @throws SAXException thrown if the XML cannot be parsed
130      */
131     public void parseHints(InputStream inputStream) throws HintParseException, SAXException {
132         try (AutoCloseableInputSource schemaStream14 = fromResource(HINT_SCHEMA_1_4);
133              AutoCloseableInputSource schemaStream13 = fromResource(HINT_SCHEMA_1_3);
134              AutoCloseableInputSource schemaStream12 = fromResource(HINT_SCHEMA_1_2);
135              AutoCloseableInputSource schemaStream11 = fromResource(HINT_SCHEMA_1_1)) {
136 
137             final BOMInputStream bomStream = BOMInputStream.builder().setInputStream(inputStream).get();
138             final ByteOrderMark bom = bomStream.getBOM();
139             final String defaultEncoding = StandardCharsets.UTF_8.name();
140             final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName();
141 
142             final HintHandler handler = new HintHandler();
143             final XMLReader xmlReader = XmlUtils.buildSecureValidatingXmlReader(schemaStream14, schemaStream13, schemaStream12, schemaStream11);
144             xmlReader.setErrorHandler(new HintErrorHandler());
145             xmlReader.setContentHandler(handler);
146             try (Reader reader = new InputStreamReader(bomStream, charsetName)) {
147                 final InputSource in = new InputSource(reader);
148                 xmlReader.parse(in);
149                 this.hintRules = handler.getHintRules();
150                 this.vendorDuplicatingHintRules = handler.getVendorDuplicatingHintRules();
151             }
152         } catch (ParserConfigurationException | IOException ex) {
153             LOGGER.debug("", ex);
154             throw new HintParseException(ex);
155         } catch (SAXException ex) {
156             if (ex.getMessage().contains("Cannot find the declaration of element 'hints'.")) {
157                 throw ex;
158             } else {
159                 LOGGER.debug("", ex);
160                 throw new HintParseException(ex);
161             }
162         }
163     }
164 }