mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-17 23:04:07 +01:00
checkstyle corrections
Former-commit-id: 0067c70b027c153e56a7e48d7fe1066aadba9016
This commit is contained in:
@@ -41,244 +41,283 @@ import org.owasp.dependencycheck.utils.Settings;
|
|||||||
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to analyze a Python package, and collect information that can be used to
|
* Used to analyze a Python package, and collect information that can be used to determine the associated CPE.
|
||||||
* determine the associated CPE.
|
|
||||||
*
|
*
|
||||||
* @author Dale Visser <dvisser@ida.org>
|
* @author Dale Visser <dvisser@ida.org>
|
||||||
*/
|
*/
|
||||||
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when compiling file scanning regex patterns.
|
* Used when compiling file scanning regex patterns.
|
||||||
*/
|
*/
|
||||||
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
||||||
| Pattern.CASE_INSENSITIVE;
|
| Pattern.CASE_INSENSITIVE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(PythonDistributionAnalyzer.class.getName());
|
.getLogger(PythonDistributionAnalyzer.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filename extensions for files to be analyzed.
|
* Filename extensions for files to be analyzed.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> EXTENSIONS = Collections
|
private static final Set<String> EXTENSIONS = Collections
|
||||||
.unmodifiableSet(Collections.singleton("py"));
|
.unmodifiableSet(Collections.singleton("py"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pattern for matching the module docstring in a source file.
|
* Pattern for matching the module docstring in a source file.
|
||||||
*/
|
*/
|
||||||
private static final Pattern MODULE_DOCSTRING = Pattern.compile(
|
private static final Pattern MODULE_DOCSTRING = Pattern.compile(
|
||||||
"^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
|
"^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches assignments to version variables in Python source code.
|
* Matches assignments to version variables in Python source code.
|
||||||
*/
|
*/
|
||||||
private static final Pattern VERSION_PATTERN = Pattern.compile(
|
private static final Pattern VERSION_PATTERN = Pattern.compile(
|
||||||
"\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
|
"\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
|
||||||
REGEX_OPTIONS);
|
REGEX_OPTIONS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches assignments to title variables in Python source code.
|
* Matches assignments to title variables in Python source code.
|
||||||
*/
|
*/
|
||||||
private static final Pattern TITLE_PATTERN = compileAssignPattern("title");
|
private static final Pattern TITLE_PATTERN = compileAssignPattern("title");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches assignments to summary variables in Python source code.
|
* Matches assignments to summary variables in Python source code.
|
||||||
*/
|
*/
|
||||||
private static final Pattern SUMMARY_PATTERN = compileAssignPattern("summary");
|
private static final Pattern SUMMARY_PATTERN = compileAssignPattern("summary");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches assignments to URL/URL variables in Python source code.
|
* Matches assignments to URL/URL variables in Python source code.
|
||||||
*/
|
*/
|
||||||
private static final Pattern URI_PATTERN = compileAssignPattern("ur[il]");
|
private static final Pattern URI_PATTERN = compileAssignPattern("ur[il]");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches assignments to home page variables in Python source code.
|
* Matches assignments to home page variables in Python source code.
|
||||||
*/
|
*/
|
||||||
private static final Pattern HOMEPAGE_PATTERN = compileAssignPattern("home_?page");
|
private static final Pattern HOMEPAGE_PATTERN = compileAssignPattern("home_?page");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches assignments to author variables in Python source code.
|
* Matches assignments to author variables in Python source code.
|
||||||
*/
|
*/
|
||||||
private static final Pattern AUTHOR_PATTERN = compileAssignPattern("author");
|
private static final Pattern AUTHOR_PATTERN = compileAssignPattern("author");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter that detects files named "__init__.py".
|
* Filter that detects files named "__init__.py".
|
||||||
*/
|
*/
|
||||||
private static final FileFilter INIT_PY_FILTER = new NameFileFilter(
|
private static final FileFilter INIT_PY_FILTER = new NameFileFilter("__init__.py");
|
||||||
"__init__.py");
|
|
||||||
|
|
||||||
private static final FileFilter PY_FILTER = new SuffixFileFilter(".py");
|
/**
|
||||||
|
* The file filter for python files.
|
||||||
|
*/
|
||||||
|
private static final FileFilter PY_FILTER = new SuffixFileFilter(".py");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the Python Package Analyzer.
|
* Returns the name of the Python Package Analyzer.
|
||||||
*/
|
*
|
||||||
@Override
|
* @return the name of the analyzer
|
||||||
public String getName() {
|
*/
|
||||||
return "Python Package Analyzer";
|
@Override
|
||||||
}
|
public String getName() {
|
||||||
|
return "Python Package Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell that we are used for information collection.
|
* Tell that we are used for information collection.
|
||||||
*/
|
*
|
||||||
@Override
|
* @return INFORMATION_COLLECTION
|
||||||
public AnalysisPhase getAnalysisPhase() {
|
*/
|
||||||
return AnalysisPhase.INFORMATION_COLLECTION;
|
@Override
|
||||||
}
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the set of supported file extensions.
|
* Returns the set of supported file extensions.
|
||||||
*/
|
*
|
||||||
@Override
|
* @return the set of supported file extensions
|
||||||
protected Set<String> getSupportedExtensions() {
|
*/
|
||||||
return EXTENSIONS;
|
@Override
|
||||||
}
|
protected Set<String> getSupportedExtensions() {
|
||||||
|
return EXTENSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No-op initializer implementation.
|
* No-op initializer implementation.
|
||||||
*/
|
*
|
||||||
@Override
|
* @throws Exception never thrown
|
||||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
*/
|
||||||
// Nothing to do here.
|
@Override
|
||||||
}
|
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
private static Pattern compileAssignPattern(String name) {
|
/**
|
||||||
return Pattern.compile(
|
* Utility function to create a regex pattern matcher.
|
||||||
String.format("\\b(__)?%s(__)?\\b *= *(['\"]+)(.*?)\\3", name),
|
*
|
||||||
REGEX_OPTIONS);
|
* @param name the value to use when constructing the assignment pattern
|
||||||
}
|
* @return the compiled Pattern
|
||||||
|
*/
|
||||||
|
private static Pattern compileAssignPattern(String name) {
|
||||||
|
return Pattern.compile(
|
||||||
|
String.format("\\b(__)?%s(__)?\\b *= *(['\"]+)(.*?)\\3", name),
|
||||||
|
REGEX_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
* Analyzes python packages and adds evidence to the dependency.
|
||||||
throws AnalysisException {
|
*
|
||||||
final File file = dependency.getActualFile();
|
* @param dependency the dependency being analyzed
|
||||||
final File parent = file.getParentFile();
|
* @param engine the engine being used to perform the scan
|
||||||
final String parentName = parent.getName();
|
* @throws AnalysisException thrown if there is an unrecoverable error analyzing the dependency
|
||||||
boolean found = false;
|
*/
|
||||||
if (INIT_PY_FILTER.accept(file)) {
|
@Override
|
||||||
for (final File sourcefile : parent.listFiles(PY_FILTER)) {
|
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
found |= analyzeFileContents(dependency, sourcefile);
|
throws AnalysisException {
|
||||||
}
|
final File file = dependency.getActualFile();
|
||||||
}
|
final File parent = file.getParentFile();
|
||||||
if (found) {
|
final String parentName = parent.getName();
|
||||||
dependency.setDisplayFileName(parentName + "/__init__.py");
|
boolean found = false;
|
||||||
dependency.getProductEvidence().addEvidence(file.getName(),
|
if (INIT_PY_FILTER.accept(file)) {
|
||||||
"PackageName", parentName, Confidence.MEDIUM);
|
for (final File sourcefile : parent.listFiles(PY_FILTER)) {
|
||||||
} else {
|
found |= analyzeFileContents(dependency, sourcefile);
|
||||||
// copy, alter and set in case some other thread is iterating over
|
}
|
||||||
final List<Dependency> deps = new ArrayList<Dependency>(
|
}
|
||||||
engine.getDependencies());
|
if (found) {
|
||||||
deps.remove(dependency);
|
dependency.setDisplayFileName(parentName + "/__init__.py");
|
||||||
engine.setDependencies(deps);
|
dependency.getProductEvidence().addEvidence(file.getName(),
|
||||||
}
|
"PackageName", parentName, Confidence.MEDIUM);
|
||||||
}
|
} else {
|
||||||
|
// copy, alter and set in case some other thread is iterating over
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>(
|
||||||
|
engine.getDependencies());
|
||||||
|
deps.remove(dependency);
|
||||||
|
engine.setDependencies(deps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should gather information from leading docstrings, file comments,
|
* This should gather information from leading docstrings, file comments, and assignments to __version__, __title__,
|
||||||
* and assignments to __version__, __title__, __summary__, __uri__, __url__,
|
* __summary__, __uri__, __url__, __home*page__, __author__, and their all caps equivalents.
|
||||||
* __home*page__, __author__, and their all caps equivalents.
|
*
|
||||||
*
|
* @param dependency the dependency being analyzed
|
||||||
* @return whether evidence was found
|
* @param file the file name to analyze
|
||||||
*/
|
* @return whether evidence was found
|
||||||
private boolean analyzeFileContents(Dependency dependency, File file)
|
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||||
throws AnalysisException {
|
*/
|
||||||
String contents = "";
|
private boolean analyzeFileContents(Dependency dependency, File file)
|
||||||
try {
|
throws AnalysisException {
|
||||||
contents = FileUtils.readFileToString(file).trim();
|
String contents = "";
|
||||||
} catch (IOException e) {
|
try {
|
||||||
throw new AnalysisException(
|
contents = FileUtils.readFileToString(file).trim();
|
||||||
"Problem occured while reading dependency file.", e);
|
} catch (IOException e) {
|
||||||
}
|
throw new AnalysisException(
|
||||||
boolean found = false;
|
"Problem occured while reading dependency file.", e);
|
||||||
if (!contents.isEmpty()) {
|
}
|
||||||
final String source = file.getName();
|
boolean found = false;
|
||||||
found = gatherEvidence(VERSION_PATTERN, contents, source,
|
if (!contents.isEmpty()) {
|
||||||
dependency.getVersionEvidence(), "SourceVersion",
|
final String source = file.getName();
|
||||||
Confidence.MEDIUM);
|
found = gatherEvidence(VERSION_PATTERN, contents, source,
|
||||||
found |= addSummaryInfo(dependency, SUMMARY_PATTERN, 4, contents,
|
dependency.getVersionEvidence(), "SourceVersion",
|
||||||
source, "summary");
|
Confidence.MEDIUM);
|
||||||
if (INIT_PY_FILTER.accept(file)) {
|
found |= addSummaryInfo(dependency, SUMMARY_PATTERN, 4, contents,
|
||||||
found |= addSummaryInfo(dependency, MODULE_DOCSTRING, 2,
|
source, "summary");
|
||||||
contents, source, "docstring");
|
if (INIT_PY_FILTER.accept(file)) {
|
||||||
}
|
found |= addSummaryInfo(dependency, MODULE_DOCSTRING, 2,
|
||||||
found |= gatherEvidence(TITLE_PATTERN, contents, source,
|
contents, source, "docstring");
|
||||||
dependency.getProductEvidence(), "SourceTitle",
|
}
|
||||||
Confidence.LOW);
|
found |= gatherEvidence(TITLE_PATTERN, contents, source,
|
||||||
final EvidenceCollection vendorEvidence = dependency
|
dependency.getProductEvidence(), "SourceTitle",
|
||||||
.getVendorEvidence();
|
Confidence.LOW);
|
||||||
found |= gatherEvidence(AUTHOR_PATTERN, contents, source,
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
vendorEvidence, "SourceAuthor", Confidence.MEDIUM);
|
.getVendorEvidence();
|
||||||
try {
|
found |= gatherEvidence(AUTHOR_PATTERN, contents, source,
|
||||||
found |= gatherHomePageEvidence(URI_PATTERN, vendorEvidence,
|
vendorEvidence, "SourceAuthor", Confidence.MEDIUM);
|
||||||
source, "URL", contents);
|
try {
|
||||||
found |= gatherHomePageEvidence(HOMEPAGE_PATTERN,
|
found |= gatherHomePageEvidence(URI_PATTERN, vendorEvidence,
|
||||||
vendorEvidence, source, "HomePage", contents);
|
source, "URL", contents);
|
||||||
} catch (MalformedURLException e) {
|
found |= gatherHomePageEvidence(HOMEPAGE_PATTERN,
|
||||||
LOGGER.warning(e.getMessage());
|
vendorEvidence, source, "HomePage", contents);
|
||||||
}
|
} catch (MalformedURLException e) {
|
||||||
}
|
LOGGER.warning(e.getMessage());
|
||||||
return found;
|
}
|
||||||
}
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean addSummaryInfo(Dependency dependency, Pattern pattern,
|
/**
|
||||||
int group, String contents, String source, String key) {
|
* Adds summary information to the dependency
|
||||||
final Matcher matcher = pattern.matcher(contents);
|
*
|
||||||
final boolean found = matcher.find();
|
* @param dependency the dependency being analyzed
|
||||||
if (found) {
|
* @param pattern the pattern used to perform analysis
|
||||||
JarAnalyzer.addDescription(dependency, matcher.group(group),
|
* @param group the group from the pattern that indicates the data to use
|
||||||
source, key);
|
* @param contents the data being analyzed
|
||||||
}
|
* @param source the source name to use when recording the evidence
|
||||||
return found;
|
* @param key the key name to use when recording the evidence
|
||||||
}
|
* @return true if evidence was collected; otherwise false
|
||||||
|
*/
|
||||||
|
private boolean addSummaryInfo(Dependency dependency, Pattern pattern,
|
||||||
|
int group, String contents, String source, String key) {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
final boolean found = matcher.find();
|
||||||
|
if (found) {
|
||||||
|
JarAnalyzer.addDescription(dependency, matcher.group(group),
|
||||||
|
source, key);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean gatherHomePageEvidence(Pattern pattern,
|
/**
|
||||||
EvidenceCollection evidence, String source, String name,
|
* Collects evidence from the home page URL.
|
||||||
String contents) throws MalformedURLException {
|
*
|
||||||
final Matcher matcher = pattern.matcher(contents);
|
* @param pattern the pattern to match
|
||||||
boolean found = false;
|
* @param evidence the evidence collection to add the evidence to
|
||||||
if (matcher.find()) {
|
* @param source the source of the evidence
|
||||||
final String url = matcher.group(4);
|
* @param name the name of the evidence
|
||||||
if (UrlStringUtils.isUrl(url)) {
|
* @param contents the home page URL
|
||||||
found = true;
|
* @return true if evidence was collected; otherwise false
|
||||||
evidence.addEvidence(source, name, url, Confidence.MEDIUM);
|
* @throws MalformedURLException
|
||||||
}
|
*/
|
||||||
}
|
private boolean gatherHomePageEvidence(Pattern pattern,
|
||||||
return found;
|
EvidenceCollection evidence, String source, String name,
|
||||||
}
|
String contents) throws MalformedURLException {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
boolean found = false;
|
||||||
|
if (matcher.find()) {
|
||||||
|
final String url = matcher.group(4);
|
||||||
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
|
found = true;
|
||||||
|
evidence.addEvidence(source, name, url, Confidence.MEDIUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gather evidence from a Python source file usin the given string
|
* Gather evidence from a Python source file usin the given string assignment regex pattern.
|
||||||
* assignment regex pattern.
|
*
|
||||||
*
|
* @param pattern to scan contents with
|
||||||
* @param pattern
|
* @param contents of Python source file
|
||||||
* to scan contents with
|
* @param source for storing evidence
|
||||||
* @param contents
|
* @param evidence to store evidence in
|
||||||
* of Python source file
|
* @param name of evidence
|
||||||
* @param source
|
* @param confidence in evidence
|
||||||
* for storing evidence
|
* @return whether evidence was found
|
||||||
* @param evidence
|
*/
|
||||||
* to store evidence in
|
private boolean gatherEvidence(Pattern pattern, String contents,
|
||||||
* @param name
|
String source, EvidenceCollection evidence, String name,
|
||||||
* of evidence
|
Confidence confidence) {
|
||||||
* @param confidence
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
* in evidence
|
final boolean found = matcher.find();
|
||||||
* @return whether evidence was found
|
if (found) {
|
||||||
*/
|
evidence.addEvidence(source, name, matcher.group(4), confidence);
|
||||||
private boolean gatherEvidence(Pattern pattern, String contents,
|
}
|
||||||
String source, EvidenceCollection evidence, String name,
|
return found;
|
||||||
Confidence confidence) {
|
}
|
||||||
final Matcher matcher = pattern.matcher(contents);
|
|
||||||
final boolean found = matcher.find();
|
|
||||||
if (found) {
|
|
||||||
evidence.addEvidence(source, name, matcher.group(4), confidence);
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getAnalyzerEnabledSettingKey() {
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
|
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user