Converted to XPath instead of SAX

Former-commit-id: e6062e1b9497a7134b6923f7f85e1fe3f18cefcc
This commit is contained in:
Will Stranathan
2014-01-26 22:11:11 -05:00
parent 17e3e51607
commit 78f7152f6c
8 changed files with 489 additions and 274 deletions

View File

@@ -17,14 +17,15 @@
*/
package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.io.FileInputStream;
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.data.nuget.NugetPackage;
import org.owasp.dependencycheck.data.nuget.NuspecParser;
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
@@ -55,11 +56,6 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
*/
private static final Set<String> 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.
*
@@ -67,9 +63,6 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
*/
@Override
public void initialize() throws Exception {
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
parser = factory.newSAXParser();
}
/**
@@ -124,30 +117,26 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
LOGGER.log(Level.INFO, "Checking Nuspec file {0}", dependency.toString());
try {
final 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);
final NuspecParser parser = new XPathNuspecParser();
NugetPackage np = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(dependency.getActualFilePath());
np = parser.parse(fis);
} finally {
if (fis != null) {
try { fis.close(); } catch (Exception e) { }
}
}
if (nh.getId() != null && !"".equals(nh.getId())) {
dependency.getProductEvidence().addEvidence("nuspec", "id", nh.getId(),
Confidence.HIGHEST);
if (np.getOwners() != null) {
dependency.getVendorEvidence().addEvidence("nuspec", "owners", np.getOwners(), 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());
dependency.getVendorEvidence().addEvidence("nuspec", "authors", np.getAuthors(), Confidence.HIGH);
dependency.getVersionEvidence().addEvidence("nuspec", "version", np.getVersion(), Confidence.HIGHEST);
dependency.getProductEvidence().addEvidence("nuspec", "id", np.getId(), Confidence.HIGHEST);
if (np.getTitle() != null) {
dependency.getProductEvidence().addEvidence("nuspec", "title", np.getTitle(), Confidence.MEDIUM);
}
} catch (Exception e) {
throw new AnalysisException(e);

View File

@@ -0,0 +1,186 @@
/*
* 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;
/**
* Represents the contents of a Nuspec manifest.
*
* @author colezlaw
*/
public class NugetPackage {
/**
* The id.
*/
private String id;
/**
* The version.
*/
private String version;
/**
* The title.
*/
private String title;
/**
* The authors.
*/
private String authors;
/**
* The owners.
*/
private String owners;
/**
* The licenseUrl.
*/
private String licenseUrl;
/**
* Creates an empty NugetPackage.
*/
public NugetPackage() {
}
/**
* Sets the id.
* @param id the id
*/
public void setId(String id) {
this.id = id;
}
/**
* Gets the id.
* @return the id
*/
public String getId() {
return id;
}
/**
* Sets the version.
* @param version the version
*/
public void setVersion(String version) {
this.version = version;
}
/**
* Gets the version.
* @return the version
*/
public String getVersion() {
return version;
}
/**
* Sets the title.
* @param title the title
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Gets the title.
* @return the title
*/
public String getTitle() {
return title;
}
/**
* Sets the authors.
* @param authors the authors
*/
public void setAuthors(String authors) {
this.authors = authors;
}
/**
* Gets the authors.
* @return the authors
*/
public String getAuthors() {
return authors;
}
/**
* Sets the owners.
* @param owners the owners
*/
public void setOwners(String owners) {
this.owners = owners;
}
/**
* Gets the owners.
* @return the owners
*/
public String getOwners() {
return owners;
}
/**
* Sets the licenseUrl.
* @param licenseUrl the licenseUrl
*/
public void setLicenseUrl(String licenseUrl) {
this.licenseUrl = licenseUrl;
}
/**
* Gets the licenseUrl.
* @return the licenseUrl
*/
public String getLicenseUrl() {
return licenseUrl;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || other.getClass() != this.getClass()) {
return false;
}
final NugetPackage o = (NugetPackage) other;
return o.getId().equals(id)
&& o.getVersion().equals(version)
&& o.getTitle().equals(title)
&& o.getAuthors().equals(authors)
&& o.getOwners().equals(owners)
&& o.getLicenseUrl().equals(licenseUrl);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + (null == id ? 0 : id.hashCode());
hash = 31 * hash + (null == version ? 0 : version.hashCode());
hash = 31 * hash + (null == title ? 0 : title.hashCode());
hash = 31 * hash + (null == authors ? 0 : authors.hashCode());
hash = 31 * hash + (null == owners ? 0 : owners.hashCode());
hash = 31 * hash + (null == licenseUrl ? 0 : licenseUrl.hashCode());
return hash;
}
}

View File

@@ -1,240 +0,0 @@
/*
* 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.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A <code>DefaultHandler</code> for parsing a Nuspec
* file.
* @author colezlaw
*/
public class NuspecHandler extends DefaultHandler {
/**
* Holds the id
*/
private String id;
/**
* Holds the version
*/
private String version;
/**
* Holds the title
*/
private String title;
/**
* Holds the authors
*/
private String authors;
/**
* Holds the owners
*/
private String owners;
/**
* Holds the licenseUrl
*/
private String licenseUrl;
/**
* Indicates whether we're currently processing the id.
*/
private boolean inId;
/**
* Indicates whether we're currently processing the version.
*/
private boolean inVersion;
/**
* Indicates whether we're currently processing the title.
*/
private boolean inTitle;
/**
* Indicates whether we're currently processing the authors.
*/
private boolean inAuthors;
/**
* Indicates whether we're currently processing the owners.
*/
private boolean inOwners;
/**
* Indicates whether we're currently processing the licenseUrl.
*/
private boolean inLicenseUrl;
/**
* The Namespace for Nuspec documents.
*/
private static final String NS_NUSPEC =
"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd";
/**
* Creates a NugetHandler.
*/
public NuspecHandler() {
inId = false;
inVersion = false;
inTitle = false;
inAuthors = false;
inOwners = false;
inLicenseUrl = false;
}
/**
* Gets the id.
* @return the id
*/
public String getId() {
return id;
}
/**
* Gets the version.
* @return the version
*/
public String getVersion() {
return version;
}
/**
* Gets the title.
* @return the title
*/
public String getTitle() {
return title;
}
/**
* Gets the authors.
* @return the authors
*/
public String getAuthors() {
return authors;
}
/**
* Gets the owners.
* @return the owners
*/
public String getOwners() {
return owners;
}
/**
* Gets the licenseUrl.
* @return 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 = false;
inVersion = false;
inTitle = false;
inAuthors = false;
inOwners = false;
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 {
final 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

View File

@@ -0,0 +1,68 @@
/*
* 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;
/**
* Exception during the parsing of a Nuspec file.
*
* @author colezlaw
*/
public class NuspecParseException extends Exception {
/**
* The serialVersionUID
*/
private static final long serialVersionUID = 1;
/**
* Constructs a new exception with <code>null</code> as its detail message.
*
* The cause is not initialized, and may subsequently be initialized by a call
* to {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
*/
public NuspecParseException() {
super();
}
/**
* Constructs a new exception with the specified detail message. The cause is
* not initialized, and may subsequently be initialized by a call to
* {@link java.lang.Throwable#initCause(java.lang.Throwable).
*
* @param message the detail message. The detail message is saved for later retrieval
* by the {@link java.lang.Throwable#getMessage()} method.
*/
public NuspecParseException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* Note that the detail message associated with <code>cause</code> is <em>not</em>
* automatically incorporated in this exception's detail message.
*
* @param message the detail message (whcih is saved for later retrieval by the
* {@link java.lang.Throwable#getMessage()} method.
* @param cause the cause (which is saved for later retrieval by the
* {@link java.lang.Throwable#getCause()} method). (A <code>null</code> value is permitted,
* and indicates that the cause is nonexistent or unknown).
*/
public NuspecParseException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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.io.InputStream;
/**
* Interface defining methods for parsing a Nuspec file.
*
* @author willstranathan
*
*/
public interface NuspecParser {
/**
* Parse an input stream and return the resulting {@link NugetPackage}.
*
* @param stream the input stream to parse
* @return the populated bean
* @throws NuspecParseException when an exception occurs
*/
NugetPackage parse(InputStream stream) throws NuspecParseException;
}

View File

@@ -0,0 +1,82 @@
/*
* 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.io.InputStream;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* Parse a Nuspec file using XPath.
*
* @author willstranathan
*/
public class XPathNuspecParser implements NuspecParser {
/**
* Gets the string value of a node or null if it's not present
*
* @param n the node to test
* @return the string content of the node, or null if the node itself is null
*/
private String getOrNull(Node n) {
if (n != null) {
return n.getTextContent();
} else {
return null;
}
}
/**
* Parse an input stream and return the resulting {@link NugetPackage}.
*
* @param stream the input stream to parse
* @return the populated bean
* @throws NuspecParseException when an exception occurs
*/
@Override
public NugetPackage parse(InputStream stream) throws NuspecParseException {
try {
final Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(stream);
final XPath xpath = XPathFactory.newInstance().newXPath();
final NugetPackage nuspec = new NugetPackage();
if (xpath.evaluate("/package/metadata/id", d, XPathConstants.NODE) == null
|| xpath.evaluate("/package/metadata/version", d, XPathConstants.NODE) == null
|| xpath.evaluate("/package/metadata/authors", d, XPathConstants.NODE) == null
|| xpath.evaluate("/package/metadata/description", d, XPathConstants.NODE) == null) {
throw new NuspecParseException("Invalid Nuspec format");
}
nuspec.setId(xpath.evaluate("/package/metadata/id", d));
nuspec.setVersion(xpath.evaluate("/package/metadata/version", d));
nuspec.setAuthors(xpath.evaluate("/package/metadata/authors", d));
nuspec.setOwners(getOrNull((Node) xpath.evaluate("/package/metadata/owners", d, XPathConstants.NODE)));
nuspec.setLicenseUrl(getOrNull((Node) xpath.evaluate("/package/metadata/licenseUrl", d, XPathConstants.NODE)));
nuspec.setTitle(getOrNull((Node) xpath.evaluate("/package/metadata/title", d, XPathConstants.NODE)));
return nuspec;
} catch (Exception e) {
throw new NuspecParseException("Unable to parse nuspec", e);
}
}
}