From b7d77042bf9f4c3334c17705a86472e048934efe Mon Sep 17 00:00:00 2001 From: Will Stranathan Date: Fri, 24 Jan 2014 07:10:53 -0500 Subject: [PATCH] Initial checkin of an analyzer which gets info from .nuspec files Former-commit-id: efc3b60b2ebf372c6bf1697b87cbfd0b9422b07f --- .../analyzer/NuspecAnalyzer.java | 158 +++++++++++++++ .../data/nuget/NuspecHandler.java | 187 ++++++++++++++++++ .../data/nuget/package-info.java | 15 ++ .../analyzer/NuspecAnalyzerTest.java | 55 ++++++ 4 files changed, 415 insertions(+) create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/NuspecHandler.java create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/package-info.java create mode 100644 dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java new file mode 100644 index 000000000..9c17b8239 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java @@ -0,0 +1,158 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2014 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import java.io.File; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.data.nuget.NuspecHandler; +import org.owasp.dependencycheck.dependency.Confidence; +import org.owasp.dependencycheck.dependency.Dependency; + +/** + * Analyzer which will parse a Nuspec file to gather module information. + * + * @author colezlaw + */ +public class NuspecAnalyzer extends AbstractAnalyzer { + + /** + * The logger + */ + private static final Logger LOGGER = Logger.getLogger(NuspecAnalyzer.class.getName()); + + /** + * The name of the analyzer + */ + private static final String ANALYZER_NAME = "Nuspec Analyzer"; + + /** + * The phase in which the analyzer runs + */ + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; + + /** + * The types of files on which this will work. + */ + private static final Set SUPPORTED_EXTENSIONS = newHashSet("nuspec"); + + /** + * The SAXParser we'll use to parse nuspec files. + */ + private SAXParser parser; + + /** + * Initializes the analyzer once before any analysis is performed. + * + * @throws Exception if there's an error during initialization + */ + @Override + public void initialize() throws Exception { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + parser = factory.newSAXParser(); + } + + /** + * Returns the analyzer's name. + * + * @return the name of the analyzer + */ + @Override + public String getName() { + return ANALYZER_NAME; + } + + /** + * Returns the analysis phase under which the analyzer runs. + * + * @return the phase under which this analyzer runs + */ + @Override + public AnalysisPhase getAnalysisPhase() { + return ANALYSIS_PHASE; + } + + /** + * Returns the extensions for which this Analyzer runs. + * + * @return the extensions for which this Analyzer runs + */ + @Override + public Set getSupportedExtensions() { + return SUPPORTED_EXTENSIONS; + } + + /** + * Determines whether the incoming extension is supported. + * + * @param extension the extension to check for support + * @return whether the extension is supported + */ + @Override + public boolean supportsExtension(String extension) { + return SUPPORTED_EXTENSIONS.contains(extension); + } + + /** + * Performs the analysis. + * + * @param dependency the dependency to analyze + * @param engine the engine + * @throws AnalysisException when there's an exception during analysis + */ + @Override + public void analyze(Dependency dependency, Engine engine) throws AnalysisException { + LOGGER.log(Level.INFO, "Checking Nuspec file {0}", dependency.toString()); + try { + NuspecHandler nh = new NuspecHandler(); + parser.parse(new File(dependency.getActualFilePath()), nh); + if (nh.getVersion() != null && !"".equals(nh.getVersion())) { + dependency.getVersionEvidence().addEvidence("nuspec", "version", nh.getVersion(), + Confidence.HIGHEST); + } + if (nh.getId() != null && !"".equals(nh.getId())) { + dependency.getProductEvidence().addEvidence("nuspec", "id", nh.getId(), + Confidence.HIGHEST); + } + if (nh.getOwners() != null && !"".equals(nh.getOwners())) { + dependency.getVendorEvidence().addEvidence("nuspec", "owners", nh.getOwners(), + Confidence.HIGHEST); + } + if (nh.getAuthors() != null && !"".equals(nh.getAuthors())) { + dependency.getVendorEvidence().addEvidence("nuspec", "authors", nh.getAuthors(), + Confidence.MEDIUM); + } + if (nh.getTitle() != null && !"".equals(nh.getTitle())) { + dependency.getProductEvidence().addEvidence("nuspec", "title", nh.getTitle(), + Confidence.MEDIUM); + } + if (nh.getLicenseUrl() != null && !"".equals(nh.getLicenseUrl())) { + dependency.setLicense(nh.getLicenseUrl()); + } + } catch (Exception e) { + throw new AnalysisException(e); + } + } +} + +// vim: cc=120:sw=4:ts=4:sts=4 diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/NuspecHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/NuspecHandler.java new file mode 100644 index 000000000..e0572becd --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/NuspecHandler.java @@ -0,0 +1,187 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2014 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.nuget; + +import java.util.logging.Level; +import java.util.logging.Logger; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A DefaultHandler for parsing a Nuspec + * file. + */ +public class NuspecHandler extends DefaultHandler { + private String id; + private String version; + private String title; + private String authors; + private String owners; + private String licenseUrl; + + private boolean inId; + private boolean inVersion; + private boolean inTitle; + private boolean inAuthors; + private boolean inOwners; + private boolean inLicenseUrl; + + private static final String NS_NUSPEC = + "http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"; + + private static final Logger LOGGER = Logger.getLogger(NuspecHandler.class.getName()); + + /** + * Creates a NugetHandler + */ + public NuspecHandler() { + inId = inVersion = inTitle = inAuthors = inOwners = inLicenseUrl = false; + } + + /** + * Gets the id. + * @return the id + */ + public String getId() { + return id; + } + + /** + * Gets the version. + */ + public String getVersion() { + return version; + } + + /** + * Gets the title. + */ + public String getTitle() { + return title; + } + + /** + * Gets the authors. + */ + public String getAuthors() { + return authors; + } + + /** + * Gets the owners. + */ + public String getOwners() { + return owners; + } + + /** + * Gets the licenseUrl; + */ + public String getLicenseUrl() { + return licenseUrl; + } + + /** + * Receive notification of the start of an element. + * @param uri The Namespace URL, or the empty string if the element has no + * Namespace URI or if Namespace processing is not being + * performed. + * @param localName The loca name (without prefix), or the empty string if + * Namespace processing is not being performed. + * @param qName The qualified name (with prefix), or the empty string if + * qualified names are not available. + * @param attributes The attributes attached to the element. If there are + * no attributes, it shall be an empty Attributes object. + * @throws SAXException Any SAX exception, possibly wrapping another + * exception. + */ + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException { + if (NS_NUSPEC.equals(uri) && "id".equals(localName)) { + id = ""; + inId = true; + } else if (NS_NUSPEC.equals(uri) && "version".equals(localName)) { + version = ""; + inVersion = true; + } else if (NS_NUSPEC.equals(uri) && "title".equals(localName)) { + title = ""; + inTitle = true; + } else if (NS_NUSPEC.equals(uri) && "authors".equals(localName)) { + authors = ""; + inAuthors = true; + } else if (NS_NUSPEC.equals(uri) && "owners".equals(localName)) { + owners = ""; + inOwners = true; + } else if (NS_NUSPEC.equals(uri) && "licenseUrl".equals(localName)) { + licenseUrl = ""; + inLicenseUrl = true; + } + } + + /** + * Receive notification of the end of an element. + * By default, do nothing. Application writers may override this method in + * a subclass to take specific actions at the end of each element (such as + * finalising a tree node or writing output to a file). + * @param uri The Namespace URI, or the empty string if the element has no + * Namespace URI or if Namespace processing is not being + * performed. + * @param localName The local name (without prefix), or the empty string if + * Namespace processing is not being performed. + * @param qName The qualified name (with prefix), or the empty string if + * qualified names are not available. + * @throws SAXException Any SAX exception, possibly wrapping another + * exception. + */ + public void endElement(String uri, String localName, String qName) + throws SAXException { + inId = inVersion = inTitle = inAuthors = inOwners = inLicenseUrl = false; + } + + /** + * Receive notification of character data inside an element. + * By default, do nothing. Application writers may override this method to + * take specific actions for each chunk of character data (such as adding + * the data to a node or buffer, or printing it to a file). + * @param ch The characters. + * @param start The start position in the character array. + * @param length The number of characters to use from the character array. + * @throws SAXException Any SAX exception, possibly wrapping another + * exception. + */ + public void characters(char[] ch, int start, int length) + throws SAXException { + String toAppend = new String(ch, start, length); + if (inId) { + id += toAppend; + } else if (inVersion) { + version += toAppend; + } else if (inTitle) { + title += toAppend; + } else if (inAuthors) { + authors += toAppend; + } else if (inOwners) { + owners += toAppend; + } else if (inLicenseUrl) { + licenseUrl += toAppend; + } + } +} + +// vim: cc=120:sw=4:ts=4:sts=4 diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/package-info.java new file mode 100644 index 000000000..95d7c721f --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nuget/package-info.java @@ -0,0 +1,15 @@ +/** + * + * + * org.owasp.dependencycheck.data.nuget + * + * + *

+ * Contains classes related to parsing Nuget related files

+ *

+ * These are used to abstract away Nuget-related handling from Dependency Check + * so they can be used elsewhere.

+ * + * + */ +package org.owasp.dependencycheck.data.nuget; diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java new file mode 100644 index 000000000..9e4551063 --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java @@ -0,0 +1,55 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2013 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +public class NuspecAnalyzerTest { + private NuspecAnalyzer instance; + + @Before + public void setUp() { + instance = new NuspecAnalyzer(); + } + + @Test + public void testGetAnalyzerName() { + assertEquals("Nuspec Analyzer", instance.getName()); + } + + @Test + public void testGetSupportedExtensions() { + assertTrue(instance.getSupportedExtensions().contains("nuspec")); + assertFalse(instance.getSupportedExtensions().contains("nupkg")); + } + + @Test + public void testSupportsExtension() { + assertTrue(instance.supportsExtension("nuspec")); + assertFalse(instance.supportsExtension("nupkg")); + } + + @Test + public void testGetAnalysisPhaze() { + assertEquals(AnalysisPhase.INFORMATION_COLLECTION, instance.getAnalysisPhase()); + } +} + +// vim: cc=120:sw=4:ts=4:sts=4