new analyzer for Package.swift

This commit is contained in:
bjiang
2016-05-05 19:21:21 -04:00
parent 043f8e0523
commit d25f6e813c
7 changed files with 402 additions and 87 deletions

View File

@@ -146,9 +146,9 @@ public class CocoaPodsAnalyzer extends AbstractFileTypeAnalyzer {
final String name = addStringEvidence(product, contents, blockVariable, "name", "name", Confidence.HIGHEST);
if (!name.isEmpty()) {
vendor.addEvidence(PODSPEC, "name_project", name, Confidence.LOW);
vendor.addEvidence(PODSPEC, "name_project", name, Confidence.HIGHEST);
}
addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.LOW);
addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.HIGHEST);
addStringEvidence(vendor, contents, blockVariable, "author", "authors?", Confidence.HIGHEST);
addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST);

View File

@@ -0,0 +1,224 @@
/*
* 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) 2015 Bianca Jiang. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.json.JsonObject;
import javax.json.JsonString;
import javax.json.JsonValue;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.EvidenceCollection;
import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Bianca Xue Jiang
*
*/
public class SwiftPackageManagerAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(SwiftPackageManagerAnalyzer.class);
/**
* The name of the analyzer.
*/
private static final String ANALYZER_NAME = "SWIFT Package Manager Analyzer";
/**
* The phase that this analyzer is intended to run in.
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/**
* The file name to scan.
*/
public static final String SPM_FILE_NAME = "Package.swift";
/**
* Filter that detects files named "package.json".
*/
private static final FileFilter SPM_FILE_FILTER = FileFilterBuilder.newInstance().addFilenames(SPM_FILE_NAME).build();
/**
* The capture group #1 is the block variable.
* e.g.
* "import PackageDescription
* let package = Package(
* name: "Gloss"
* )"
*/
private static final Pattern SPM_BLOCK_PATTERN
= Pattern.compile("let[^=]+=\\s*Package\\s*\\(\\s*([^)]*)\\s*\\)", Pattern.DOTALL);
/**
* Returns the FileFilter
*
* @return the FileFilter
*/
@Override
protected FileFilter getFileFilter() {
return SPM_FILE_FILTER;
}
@Override
protected void initializeFileTypeAnalyzer() throws Exception {
// NO-OP
}
/**
* Returns the name of the analyzer.
*
* @return the name of the analyzer.
*/
@Override
public String getName() {
return ANALYZER_NAME;
}
/**
* Returns the phase that the analyzer is intended to run in.
*
* @return the phase that the analyzer is intended to run in.
*/
@Override
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
*
* @return the analyzer's enabled property setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED;
}
@Override
protected void analyzeFileType(Dependency dependency, Engine engine)
throws AnalysisException {
String contents;
try {
contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset());
} catch (IOException e) {
throw new AnalysisException(
"Problem occurred while reading dependency file.", e);
}
final Matcher matcher = SPM_BLOCK_PATTERN.matcher(contents);
if (matcher.find()) {
contents = contents.substring(matcher.end());
final String packageDescription = matcher.group(1);
if(packageDescription.isEmpty())
return;
final EvidenceCollection vendor = dependency.getVendorEvidence();
final EvidenceCollection product = dependency.getProductEvidence();
// final EvidenceCollection version = dependency.getVersionEvidence();
final String name = addStringEvidence(product, packageDescription, "name", "name", Confidence.HIGHEST);
if (!name.isEmpty()) {
vendor.addEvidence(SPM_FILE_NAME, "name_project", name, Confidence.HIGHEST);
}
// addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.LOW);
// addStringEvidence(vendor, contents, blockVariable, "author", "authors?", Confidence.HIGHEST);
// addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST);
// addStringEvidence(vendor, contents, blockVariable, "license", "licen[cs]es?", Confidence.HIGHEST);
// addStringEvidence(version, contents, blockVariable, "version", "version", Confidence.HIGHEST);
setPackagePath(dependency);
}
}
private String addStringEvidence(EvidenceCollection evidences,
String packageDescription, String field, String fieldPattern, Confidence confidence) {
String value = "";
//capture array value between [ ]
final Matcher matcher = Pattern.compile(
String.format("%s *:\\s*\"([^\"]*)", fieldPattern), Pattern.DOTALL).matcher(packageDescription);
if(matcher.find()) {
value = matcher.group(1);
}
if(value != null) {
value = value.trim();
if(value.length() > 0)
evidences.addEvidence (SPM_FILE_NAME, field, value, confidence);
}
return value;
}
private void setPackagePath(Dependency dep) {
File file = new File(dep.getFilePath());
String parent = file.getParent();
if(parent != null)
dep.setPackagePath(parent);
}
/**
* Adds information to an evidence collection from the node json configuration.
*
* @param json information from node.js
* @param collection a set of evidence about a dependency
* @param key the key to obtain the data from the json information
*/
private void addToEvidence(JsonObject json, EvidenceCollection collection, String key) {
if (json.containsKey(key)) {
final JsonValue value = json.get(key);
if (value instanceof JsonString) {
collection.addEvidence(SPM_FILE_NAME, key, ((JsonString) value).getString(), Confidence.HIGHEST);
} else if (value instanceof JsonObject) {
final JsonObject jsonObject = (JsonObject) value;
for (final Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
final String property = entry.getKey();
final JsonValue subValue = entry.getValue();
if (subValue instanceof JsonString) {
collection.addEvidence(SPM_FILE_NAME,
String.format("%s.%s", key, property),
((JsonString) subValue).getString(),
Confidence.HIGHEST);
} else {
LOGGER.warn("JSON sub-value not string as expected: {}", subValue);
}
}
} else {
LOGGER.warn("JSON value not string or JSON object as expected: {}", value);
}
}
}
}

View File

@@ -23,3 +23,4 @@ org.owasp.dependencycheck.analyzer.RubyBundleInstallDeploymentAnalyzer
org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer
org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer
org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer
org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer

View File

@@ -1,85 +0,0 @@
package org.owasp.dependencycheck.analyzer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.io.File;
/**
* Unit tests for CocoaPodsAnalyzer.
*
* @author Bianca Jiang
*/
public class CocoaPodsAnalyzerTest extends BaseTest {
/**
* The analyzer to test.
*/
CocoaPodsAnalyzer analyzer;
/**
* Correctly setup the analyzer for testing.
*
* @throws Exception thrown if there is a problem
*/
@Before
public void setUp() throws Exception {
analyzer = new CocoaPodsAnalyzer();
analyzer.setFilesMatched(true);
analyzer.initialize();
}
/**
* Cleanup the analyzer's temp files, etc.
*
* @throws Exception thrown if there is a problem
*/
@After
public void tearDown() throws Exception {
analyzer.close();
analyzer = null;
}
/**
* Test of getName method, of class PythonDistributionAnalyzer.
*/
@Test
public void testGetName() {
assertThat(analyzer.getName(), is("CocoaPods Package Analyzer"));
}
/**
* Test of supportsExtension method, of class PythonDistributionAnalyzer.
*/
@Test
public void testSupportsFiles() {
assertThat(analyzer.accept(new File("test.podspec")), is(true));
}
/**
* Test of inspect method, of class PythonDistributionAnalyzer.
*
* @throws AnalysisException is thrown when an exception occurs.
*/
@Test
public void testAnalyzePackageJson() throws AnalysisException {
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this,
"swift/cocoapods/EasyPeasy.podspec"));
analyzer.analyze(result, null);
final String vendorString = result.getVendorEvidence().toString();
assertThat(vendorString, containsString("Carlos Vidal"));
assertThat(vendorString, containsString("https://github.com/nakiostudio/EasyPeasy"));
assertThat(vendorString, containsString("MIT"));
assertThat(result.getProductEvidence().toString(), containsString("EasyPeasy"));
assertThat(result.getVersionEvidence().toString(), containsString("0.2.3"));
}
}

View File

@@ -0,0 +1,128 @@
package org.owasp.dependencycheck.analyzer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.io.File;
/**
* Unit tests for CocoaPodsAnalyzer.
*
* @author Bianca Jiang
*/
public class SwiftAnalyzersTest extends BaseTest {
/**
* The analyzer to test.
*/
CocoaPodsAnalyzer podsAnalyzer;
SwiftPackageManagerAnalyzer spmAnalyzer;
/**
* Correctly setup the analyzer for testing.
*
* @throws Exception thrown if there is a problem
*/
@Before
public void setUp() throws Exception {
podsAnalyzer = new CocoaPodsAnalyzer();
podsAnalyzer.setFilesMatched(true);
podsAnalyzer.initialize();
spmAnalyzer = new SwiftPackageManagerAnalyzer();
spmAnalyzer.setFilesMatched(true);
spmAnalyzer.initialize();
}
/**
* Cleanup the analyzer's temp files, etc.
*
* @throws Exception thrown if there is a problem
*/
@After
public void tearDown() throws Exception {
podsAnalyzer.close();
podsAnalyzer = null;
spmAnalyzer.close();
spmAnalyzer = null;
}
/**
* Test of getName method, of class CocoaPodsAnalyzer.
*/
@Test
public void testPodsGetName() {
assertThat(podsAnalyzer.getName(), is("CocoaPods Package Analyzer"));
}
/**
* Test of getName method, of class SwiftPackageManagerAnalyzer.
*/
@Test
public void testSPMGetName() {
assertThat(spmAnalyzer.getName(), is("SWIFT Package Manager Analyzer"));
}
/**
* Test of supportsFiles method, of class CocoaPodsAnalyzer.
*/
@Test
public void testPodsSupportsFiles() {
assertThat(podsAnalyzer.accept(new File("test.podspec")), is(true));
}
/**
* Test of supportsFiles method, of class SwiftPackageManagerAnalyzer.
*/
@Test
public void testSPMSupportsFiles() {
assertThat(spmAnalyzer.accept(new File("Package.swift")), is(true));
}
/**
* Test of analyze method, of class CocoaPodsAnalyzer.
*
* @throws AnalysisException is thrown when an exception occurs.
*/
@Test
public void testCocoaPodsAnalyzer() throws AnalysisException {
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this,
"swift/cocoapods/EasyPeasy.podspec"));
podsAnalyzer.analyze(result, null);
final String vendorString = result.getVendorEvidence().toString();
assertThat(vendorString, containsString("Carlos Vidal"));
assertThat(vendorString, containsString("https://github.com/nakiostudio/EasyPeasy"));
assertThat(vendorString, containsString("MIT"));
assertThat(result.getProductEvidence().toString(), containsString("EasyPeasy"));
assertThat(result.getVersionEvidence().toString(), containsString("0.2.3"));
}
/**
* Test of analyze method, of class SwiftPackageManagerAnalyzer.
*
* @throws AnalysisException is thrown when an exception occurs.
*/
@Test
public void testSPMAnalyzer() throws AnalysisException {
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this,
"swift/Gloss/Package.swift"));
spmAnalyzer.analyze(result, null);
System.out.println(result.getProductEvidence().toString());
// assertThat(vendorString, containsString("Carlos Vidal"));
// assertThat(vendorString, containsString("https://github.com/nakiostudio/EasyPeasy"));
// assertThat(vendorString, containsString("MIT"));
assertThat(result.getProductEvidence().toString(), containsString("Gloss"));
// assertThat(result.getVersionEvidence().toString(), containsString("0.2.3"));
}
}

View File

@@ -0,0 +1,17 @@
Pod::Spec.new do |s|
s.name = "Gloss"
s.version = "0.7.2"
s.summary = "A shiny JSON parsing library in Swift"
s.description = "A shiny JSON parsing library in Swift. Features include mapping JSON to objects, mapping objects to JSON, handling of nested objects and custom transformations."
s.homepage = "https://github.com/hkellaway/Gloss"
s.license = { :type => "MIT", :file => "LICENSE" }
s.author = { "Harlan Kellaway" => "hello@harlankellaway.com" }
s.social_media_url = "http://twitter.com/HarlanKellaway"
s.source = { :git => "https://github.com/hkellaway/Gloss.git", :tag => s.version.to_s }
s.platforms = { :ios => "8.0", :osx => "10.9", :tvos => "9.0", :watchos => "2.0" }
s.requires_arc = true
s.source_files = 'Sources/*.{swift}'
end

View File

@@ -0,0 +1,30 @@
//
// Package.swift
// Gloss
//
// Copyright (c) 2015 Harlan Kellaway
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import PackageDescription
let package = Package(
name: "Gloss"
)