Browse Source

增加合约打包异常删除逻辑

tags/1.1.0
shaozhuguang 5 years ago
parent
commit
c021cf48ca
5 changed files with 3 additions and 957 deletions
  1. +0
    -213
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java
  2. +0
    -193
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployExeUtil.java
  3. +0
    -119
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java
  4. +0
    -432
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java
  5. +3
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractVerifyMojo.java

+ 0
- 213
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java View File

@@ -1,213 +0,0 @@
package com.jd.blockchain;

import org.apache.commons.io.FileUtils;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.invoker.*;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


@Mojo(name = "contractCheck")
public class ContractCheckMojo extends AbstractMojo {

Logger LOG = LoggerFactory.getLogger(ContractCheckMojo.class);

public static final String CONTRACT_VERIFY = "contractVerify";

private static final String CONTRACT_MAVEN_PLUGIN = "contract-maven-plugin";

private static final String MAVEN_ASSEMBLY_PLUGIN = "maven-assembly-plugin";

private static final String JDCHAIN_PACKAGE = "com.jd.blockchain";

private static final String APACHE_MAVEN_PLUGINS = "org.apache.maven.plugins";

private static final String GOALS_VERIFY = "package";

private static final String GOALS_PACKAGE = "package";

private static final String OUT_POM_XML = "ContractPom.xml";

@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;

/**
* jar's name;
*/
@Parameter
private String finalName;

/**
* mainClass;
*/
@Parameter
private String mainClass;
/**
* ledgerVersion;
*/
@Parameter
private String ledgerVersion;

/**
* mvnHome;
*/
@Parameter
private String mvnHome;

/**
* first compile the class, then parse it;
*/
@Override
public void execute() throws MojoFailureException {
compileFiles();
}

private void compileFiles() throws MojoFailureException {
try (FileInputStream fis = new FileInputStream(project.getFile())) {

MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(fis);

//delete this plugin(contractCheck) from destination pom.xml;then add the proper plugins;
Plugin plugin = model.getBuild().getPluginsAsMap()
.get(JDCHAIN_PACKAGE + ":" + CONTRACT_MAVEN_PLUGIN);
if(plugin == null){
plugin = model.getBuild().getPluginsAsMap()
.get(APACHE_MAVEN_PLUGINS + ":" + CONTRACT_MAVEN_PLUGIN);
}

if(plugin == null) {
return;
}

model.getBuild().removePlugin(plugin);

List<Plugin> plugins = new ArrayList<>();
plugins.add(createAssembly());
plugins.add(createContractVerify());

model.getBuild().setPlugins(plugins);

handle(model);

} catch (Exception e) {
LOG.error(e.getMessage());
throw new MojoFailureException(e.getMessage());
}
}

private void invokeCompile(File file) {
InvocationRequest request = new DefaultInvocationRequest();

Invoker invoker = new DefaultInvoker();
try {
request.setPomFile(file);

request.setGoals(Collections.singletonList(GOALS_VERIFY));
invoker.setMavenHome(new File(mvnHome));
invoker.execute(request);
} catch (MavenInvocationException e) {
LOG.error(e.getMessage());
throw new IllegalStateException(e);
}
}

private Plugin createContractVerify() {
Plugin plugin = new Plugin();
plugin.setGroupId(JDCHAIN_PACKAGE);
plugin.setArtifactId(CONTRACT_MAVEN_PLUGIN);
plugin.setVersion(ledgerVersion);

Xpp3Dom finalNameNode = new Xpp3Dom("finalName");
finalNameNode.setValue(finalName);
Xpp3Dom configuration = new Xpp3Dom("configuration");
configuration.addChild(finalNameNode);

plugin.setConfiguration(configuration);
plugin.setExecutions(pluginExecution("make-assembly", GOALS_VERIFY, CONTRACT_VERIFY));

return plugin;
}

private Plugin createAssembly() {
Plugin plugin = new Plugin();
plugin.setArtifactId(MAVEN_ASSEMBLY_PLUGIN);

Xpp3Dom configuration = new Xpp3Dom("configuration");

Xpp3Dom mainClassNode = new Xpp3Dom("mainClass");
mainClassNode.setValue(mainClass);

Xpp3Dom manifest = new Xpp3Dom("manifest");
manifest.addChild(mainClassNode);

Xpp3Dom archive = new Xpp3Dom("archive");
archive.addChild(manifest);

Xpp3Dom finalNameNode = new Xpp3Dom("finalName");
finalNameNode.setValue(finalName);

Xpp3Dom appendAssemblyId = new Xpp3Dom("appendAssemblyId");
appendAssemblyId.setValue("false");

Xpp3Dom descriptorRef = new Xpp3Dom("descriptorRef");
descriptorRef.setValue("jar-with-dependencies");
Xpp3Dom descriptorRefs = new Xpp3Dom("descriptorRefs");
descriptorRefs.addChild(descriptorRef);

configuration.addChild(finalNameNode);
configuration.addChild(appendAssemblyId);
configuration.addChild(archive);
configuration.addChild(descriptorRefs);

plugin.setConfiguration(configuration);
plugin.setExecutions(pluginExecution("make-assembly", GOALS_PACKAGE, "single"));

return plugin;
}

private List<PluginExecution> pluginExecution(String id, String phase, String goal) {
PluginExecution pluginExecution = new PluginExecution();
pluginExecution.setId(id);
pluginExecution.setPhase(phase);
List<String> goals = new ArrayList<>();
goals.add(goal);
pluginExecution.setGoals(goals);
List<PluginExecution> pluginExecutions = new ArrayList<>();
pluginExecutions.add(pluginExecution);

return pluginExecutions;
}

private void handle(Model model) throws IOException {

MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer();

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

mavenXpp3Writer.write(outputStream, model);

byte[] buffer = outputStream.toByteArray();

File outPom = new File(project.getBasedir().getPath(), OUT_POM_XML);

FileUtils.writeByteArrayToFile(outPom, buffer);

invokeCompile(outPom);
}
}

+ 0
- 193
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployExeUtil.java View File

@@ -1,193 +0,0 @@
package com.jd.blockchain;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BlockchainIdentityData;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.DataAccountRegisterOperation;
import com.jd.blockchain.ledger.EndpointRequest;
import com.jd.blockchain.ledger.NodeRequest;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionContentBody;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.UserRegisterOperation;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.net.NetworkAddress;

/**
* @Author zhaogw
* @Date 2018/11/2 10:18
*/
public enum ContractDeployExeUtil {
instance;
private BlockchainService bcsrv;
private Bytes contractAddress;

public BlockchainKeypair getKeyPair(String pubPath, String prvPath, String rawPassword){
PubKey pub = null;
PrivKey prv = null;
try {
prv = KeyGenCommand.readPrivKey(prvPath, KeyGenCommand.encodePassword(rawPassword));
pub = KeyGenCommand.readPubKey(pubPath);

} catch (Exception e) {
e.printStackTrace();
}

return new BlockchainKeypair(pub, prv);
}

public PubKey getPubKey(String pubPath){
PubKey pub = null;
try {
if(pubPath == null){
BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate();
pub = contractKeyPair.getPubKey();
}else {
pub = KeyGenCommand.readPubKey(pubPath);
}

} catch (Exception e) {
e.printStackTrace();
}

return pub;
}
public byte[] getChainCode(String path){
byte[] chainCode = null;
File file = null;
InputStream input = null;
try {
file = new File(path);
input = new FileInputStream(file);
chainCode = new byte[input.available()];
input.read(chainCode);

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(input!=null){
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return chainCode;
}

private void register(){
DataContractRegistry.register(TransactionContent.class);
DataContractRegistry.register(TransactionContentBody.class);
DataContractRegistry.register(TransactionRequest.class);
DataContractRegistry.register(NodeRequest.class);
DataContractRegistry.register(EndpointRequest.class);
DataContractRegistry.register(TransactionResponse.class);
DataContractRegistry.register(DataAccountKVSetOperation.class);
DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class);
DataContractRegistry.register(Operation.class);
DataContractRegistry.register(ContractCodeDeployOperation.class);
DataContractRegistry.register(ContractEventSendOperation.class);
DataContractRegistry.register(DataAccountRegisterOperation.class);
DataContractRegistry.register(UserRegisterOperation.class);
}

public BlockchainService initBcsrv(String host, int port) {
if(bcsrv!=null){
return bcsrv;
}
NetworkAddress addr = new NetworkAddress(host, port);
GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(addr);
bcsrv = gwsrvFact.getBlockchainService();
return bcsrv;
}

public boolean deploy(HashDigest ledgerHash, BlockchainIdentity contractIdentity, BlockchainKeypair ownerKey, byte[] chainCode){
register();

TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash);
txTpl.contracts().deploy(contractIdentity, chainCode);
PreparedTransaction ptx = txTpl.prepare();
ptx.sign(ownerKey);
// 提交并等待共识返回;
TransactionResponse txResp = ptx.commit();

// 验证结果;
contractAddress = contractIdentity.getAddress();
this.setContractAddress(contractAddress);
System.out.println("contract's address="+contractAddress);
return txResp.isSuccess();
}
public boolean deploy(String host, int port, HashDigest ledgerHash, BlockchainKeypair ownerKey, byte[] chainCode){
register();

BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity();
initBcsrv(host,port);
return deploy(ledgerHash, contractIdentity, ownerKey, chainCode);
}

// 根据用户指定的公钥生成合约地址
public boolean deploy(String host, int port, String ledger,String ownerPubPath, String ownerPrvPath,
String ownerPassword, String chainCodePath,String pubPath){
PubKey pubKey = getPubKey(pubPath);
BlockchainIdentity contractIdentity = new BlockchainIdentityData(pubKey);
byte[] chainCode = getChainCode(chainCodePath);

BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword);
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger));
initBcsrv(host,port);
return deploy(ledgerHash, contractIdentity, ownerKey, chainCode);
}

// 暂不支持从插件执行合约;此外,由于合约参数调用的格式发生变化,故此方法被废弃;by: huanghaiquan at 2019-04-30;
// public boolean exeContract(String ledger,String ownerPubPath, String ownerPrvPath,
// String ownerPassword,String event,String contractArgs){
// BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword);
// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger));
//
// // 定义交易,传输最简单的数字、字符串、提取合约中的地址;
// TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash);
// txTpl.contractEvents().send(getContractAddress(),event,contractArgs.getBytes());
//
// // 签名;
// PreparedTransaction ptx = txTpl.prepare();
// ptx.sign(ownerKey);
//
// // 提交并等待共识返回;
// TransactionResponse txResp = ptx.commit();
//
// // 验证结果;
// return txResp.isSuccess();
// }

public Bytes getContractAddress() {
return contractAddress;
}

public void setContractAddress(Bytes contractAddress) {
this.contractAddress = contractAddress;
}
}

+ 0
- 119
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java View File

@@ -1,119 +0,0 @@
package com.jd.blockchain;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.StringUtils;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.io.FileUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
* for contract remote deploy;
* @goal contractDeploy
* @phase process-sources
* @Author zhaogw
* @Date 2018/10/18 10:12
*/

@Mojo(name = "deploy")
public class ContractDeployMojo extends AbstractMojo {
Logger logger = LoggerFactory.getLogger(ContractDeployMojo.class);

@Parameter
private File config;

@Override
public void execute()throws MojoFailureException {
Properties prop = new Properties();
InputStream input = null;

try {
input = new FileInputStream(config);
prop.load(input);

} catch (IOException ex) {
logger.error(ex.getMessage());
throw new MojoFailureException("io error");
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
}
}
int port;
try {
port = Integer.parseInt(prop.getProperty("port"));
}catch (NumberFormatException e){
logger.error(e.getMessage());
throw new MojoFailureException("invalid port");
}
String host = prop.getProperty("host");
String ledger = prop.getProperty("ledger");
String pubKey = prop.getProperty("pubKey");
String prvKey = prop.getProperty("prvKey");
String password = prop.getProperty("password");
String contractPath = prop.getProperty("contractPath");


if(StringUtils.isEmpty(host)){
logger.info("host不能为空");
return;
}

if(StringUtils.isEmpty(ledger)){
logger.info("ledger不能为空.");
return;
}
if(StringUtils.isEmpty(pubKey)){
logger.info("pubKey不能为空.");
return;
}
if(StringUtils.isEmpty(prvKey)){
logger.info("prvKey不能为空.");
return;
}
if(StringUtils.isEmpty(contractPath)){
logger.info("contractPath不能为空.");
return;
}

File contract = new File(contractPath);
if (!contract.isFile()){
logger.info("文件"+contractPath+"不存在");
return;
}
byte[] contractBytes = FileUtils.readBytes(contractPath);


PrivKey prv = KeyGenCommand.decodePrivKeyWithRawPassword(prvKey, password);
PubKey pub = KeyGenCommand.decodePubKey(pubKey);
BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(pub, prv);
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger));

StringBuffer sb = new StringBuffer();
sb.append("host:"+ host).append(",port:"+port).append(",ledgerHash:"+ledgerHash.toBase58()).
append(",pubKey:"+pubKey).append(",prvKey:"+prv).append(",contractPath:"+contractPath);
logger.info(sb.toString());
ContractDeployExeUtil.instance.deploy(host,port,ledgerHash, blockchainKeyPair, contractBytes);
}

}



+ 0
- 432
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java View File

@@ -1,432 +0,0 @@
package com.jd.blockchain;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.jd.blockchain.contract.ContractType;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static com.jd.blockchain.ContractCheckMojo.CONTRACT_VERIFY;
import static com.jd.blockchain.utils.decompiler.utils.DecompilerUtils.decompileJarFile;
import static com.jd.blockchain.utils.jar.ContractJarUtils.*;

/**
* first step, we want to parse the source code by javaParse. But it's repeated and difficult to parse the source.
* This is a try of "from Initail to Abandoned".
* Since we are good at the class, why not?
* Now we change a way of thinking, first we pre-compile the source code, then parse the *.jar.
*
* by zhaogw
* date 2019-06-05 16:17
*/
@Mojo(name = CONTRACT_VERIFY)
public class ContractVerifyMojo extends AbstractMojo {

Logger LOG = LoggerFactory.getLogger(ContractVerifyMojo.class);

@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;

/**
* jar's name;
*/
@Parameter
private String finalName;

private static final String JAVA_SUFFIX = ".java";

private static final String PATH_DIRECT =
"src" + File.separator +
"main" + File.separator +
"java" + File.separator;

private static final String CONFIG = "config.properties";

private static final String BLACK_PACKAGE_LIST = "black.package.list";

private static final String BLACK_CLASS_LIST = "black.class.list";

private static final String BLACK_NAME_LIST = "black.name.list";

@Override
public void execute() throws MojoExecutionException {

try {

File jarFile = copyAndManage();

// 首先校验MainClass
verifyMainClass(jarFile);

Properties config = loadConfig();

List<ContractPackage> blackNameList = blackNameList(config);

List<ContractPackage> blackPackageList = blackPackageList(config);

Set<String> blackClassSet = blackClassSet(config);

LinkedList<String> totalClassList = loadAllClass(jarFile);
// 该项目路径
String projectDir = project.getBasedir().getPath();
// 代码路径
String codeBaseDir = projectDir + File.separator + PATH_DIRECT;

if (!totalClassList.isEmpty()) {

boolean isOK = true;

for (String clazz : totalClassList) {
// 获取其包名
String packageName = packageName(clazz);

// 包的名字黑名单,不能打包该类进入Jar包中,或者合约不能命名这样的名字
boolean isNameBlack = false;
for (ContractPackage blackName : blackNameList) {
isNameBlack = verifyPackage(packageName, blackName);
if (isNameBlack) {
break;
}
}

// 假设是黑名单则打印日志
if (isNameBlack) {
// 打印信息供检查
LOG.error(String.format("Class[%s]'s Package-Name belong to BlackNameList !!!", clazz));
isOK = false;
continue;
}

// 获取该Class对应的Java文件
File javaFile = new File(codeBaseDir + clazz + JAVA_SUFFIX);

boolean isNeedDelete = false;
if (!javaFile.exists()) {
// 表明不是项目中的内容,需要通过反编译获取该文件
String source = null;
try {
source = decompileJarFile(jarFile.getPath(), clazz, true, StandardCharsets.UTF_8.name());
if (source == null || source.length() == 0) {
throw new IllegalStateException();
}
} catch (Exception e) {
LOG.warn(String.format("Decompile Jar[%s]->Class[%s] Fail !!!", jarFile.getPath(), clazz));
}
// 将source写入Java文件
File sourceTempJavaFile = new File(tempPath(codeBaseDir, clazz));
FileUtils.writeStringToFile(sourceTempJavaFile, source == null ? "" : source);
javaFile = sourceTempJavaFile;
isNeedDelete = true;
}

// 解析文件中的内容
CompilationUnit compilationUnit = JavaParser.parse(javaFile);

MethodVisitor methodVisitor = new MethodVisitor();

compilationUnit.accept(methodVisitor, null);

List<String> imports = methodVisitor.importClasses;

if (!imports.isEmpty()) {
for (String importClass : imports) {
if (importClass.endsWith("*")) {
// 导入的是包
for (ContractPackage blackPackage : blackPackageList) {
String importPackageName = importClass.substring(0, importClass.length() - 2);
if (verifyPackage(importPackageName, blackPackage)) {
// 打印信息供检查
LOG.error(String.format("Class[%s]'s import class [%s] belong to BlackPackageList !!!", clazz, importClass));
isOK = false;
break;
}
}
} else {
// 导入的是具体的类,则判断类黑名单 + 包黑名单
if (blackClassSet.contains(importClass)) {
// 包含导入类,该方式无法通过验证
LOG.error(String.format("Class[%s]'s import class [%s] belong to BlackClassList !!!", clazz, importClass));
isOK = false;
} else {
// 判断导入的该类与黑名单导入包的对应关系
for (ContractPackage blackPackage : blackPackageList) {
if (verifyClass(importClass, blackPackage)) {
LOG.error(String.format("Class[%s]'s import class [%s] belong to BlackPackageList !!!", clazz, importClass));
isOK = false;
break;
}
}
}
}
}
}
if (isNeedDelete) {
javaFile.delete();
}
}
if (!isOK) {
throw new IllegalStateException("There are many Illegal information, please check !!!");
}
} else {
throw new IllegalStateException("There is none class !!!");
}
} catch (Exception e) {
LOG.error(e.getMessage());
throw new MojoExecutionException(e.getMessage());
}
}

private void verifyMainClass(File jarFile) throws Exception {
// 加载main-class,开始校验类型
URL jarURL = jarFile.toURI().toURL();
ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL}, this.getClass().getClassLoader());
Attributes m = new JarFile(jarFile).getManifest().getMainAttributes();
String contractMainClass = m.getValue(Attributes.Name.MAIN_CLASS);
Class mainClass = classLoader.loadClass(contractMainClass);
ContractType.resolve(mainClass);
}

private List<ContractPackage> blackNameList(Properties config) {
return blackList(config, BLACK_NAME_LIST);
}

private Set<String> blackClassSet(Properties config) {
Set<String> blackClassSet = new HashSet<>();
String attrProp = config.getProperty(BLACK_CLASS_LIST);
if (attrProp != null && attrProp.length() > 0) {
String[] attrPropArray = attrProp.split(",");
for (String attr : attrPropArray) {
blackClassSet.add(attr.trim());
}
}
return blackClassSet;
}

private List<ContractPackage> blackPackageList(Properties config) {
return blackList(config, BLACK_PACKAGE_LIST);
}

private List<ContractPackage> blackList(Properties config, String attrName) {
List<ContractPackage> list = new ArrayList<>();
String attrProp = config.getProperty(attrName);
if (attrProp != null || attrProp.length() > 0) {
String[] attrPropArray = attrProp.split(",");
for (String attr : attrPropArray) {
list.add(new ContractPackage(attr));
}
}
return list;
}

private boolean verifyPackage(String packageName, ContractPackage contractPackage) {
boolean verify = false;
if (packageName.equals(contractPackage.packageName)) {
// 完全相同
verify = true;
} else if (packageName.startsWith(contractPackage.packageName) &&
contractPackage.isTotal) {
// 以某个包开头
verify = true;
}
return verify;
}

private boolean verifyClass(String className, ContractPackage contractPackage) {
boolean verify = false;

if (contractPackage.isTotal) {
// 表示该包下面的其他所有包都会受限制,此处需要判断起始
if (className.startsWith(contractPackage.packageName)) {
verify = true;
}
} else {
// 表示该包必须完整匹配ClassName所在包
// 获取ClassName所在包
String packageName = packageNameByDot(className);
if (packageName.equals(contractPackage.packageName)) {
verify = true;
}
}
return verify;
}

private String packageNameByDot(String className) {
String[] array = className.split(".");
if (Character.isLowerCase(array[array.length - 2].charAt(0))) {
// 如果是小写,表示非内部类
// 获取完整包名
return className.substring(0, className.lastIndexOf("."));
}
// 表示为内部类,该包拼装组成
StringBuilder buffer = new StringBuilder();
for (String s : array) {
if (buffer.length() > 0) {
buffer.append(".");
}
if (Character.isUpperCase(s.charAt(0))) {
// 表明已经到具体类
break;
}
buffer.append(s);
}

if (buffer.length() == 0) {
throw new IllegalStateException(String.format("Import Class [%s] Illegal !!!", className));
}

return buffer.toString();
}

private String packageName(String clazz) {
int index = clazz.lastIndexOf("/");
String packageName = clazz.substring(0, index);
return packageName.replaceAll("/", ".");
}

private File copyAndManage() throws IOException {
// 首先将Jar包转换为指定的格式
String srcJarPath = project.getBuild().getDirectory() +
File.separator + finalName + ".jar";

String dstJarPath = project.getBuild().getDirectory() +
File.separator + finalName + "-temp-" + System.currentTimeMillis() + ".jar";

File srcJar = new File(srcJarPath), dstJar = new File(dstJarPath);

// 首先进行Copy处理
copy(srcJar, dstJar);

byte[] txtBytes = contractMF(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8);

String finalJarPath = project.getBuild().getDirectory() +
File.separator + finalName + "-jdchain.jar";

File finalJar = new File(finalJarPath);

copy(dstJar, finalJar, contractMFJarEntry(), txtBytes, null);

// 删除临时文件
FileUtils.forceDelete(dstJar);

return finalJar;
}

private Properties loadConfig() throws Exception {

Properties properties = new Properties();

properties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG));

return properties;
}

private LinkedList<String> loadAllClass(File file) throws Exception {
JarFile jarFile = new JarFile(file);
LinkedList<String> allClass = new LinkedList<>();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String entryName = jarEntry.getName();
if (entryName.endsWith(".class")) {
// 内部类,不需要处理
if (!entryName.contains("$")) {
allClass.addLast(entryName.substring(0, entryName.length() - 6));
}
}
}
return allClass;
}

private String tempPath(String codeBaseDir, String clazz) {
// 获取最后的名称
String[] classArray = clazz.split("/");
String tempPath = codeBaseDir + classArray[classArray.length - 1] + "_" +
System.currentTimeMillis() + "_" + System.nanoTime() + JAVA_SUFFIX;
return tempPath;
}

private static class MethodVisitor extends VoidVisitorAdapter<Void> {

private List<String> importClasses = new ArrayList<>();

// @Override
// public void visit(MethodDeclaration n, Void arg) {
// /* here you can access the attributes of the method.
// this method will be called for all methods in this
// CompilationUnit, including inner class methods */
// super.visit(n, arg);
// }
//
// @Override
// public void visit(ClassOrInterfaceDeclaration n, Void arg) {
// super.visit(n, arg);
// }
//
// @Override
// public void visit(PackageDeclaration n, Void arg) {
// super.visit(n, arg);
// }

@Override
public void visit(ImportDeclaration n, Void arg) {
importClasses.add(parseClass(n.toString()));
super.visit(n, arg);
}

private String parseClass(String importInfo) {
String className = importInfo.substring(7, importInfo.length() - 2);
if (importInfo.startsWith("import static ")) {
// 获取静态方法的类信息
className = importInfo.substring(14, importInfo.lastIndexOf("."));
}
if (!className.contains(".")) {
throw new IllegalStateException(String.format("Import Class [%s] is Illegal !!", className));
}
return className;
}
}

private static class ContractPackage {

private String packageName;

private boolean isTotal = false;

public ContractPackage() {
}

public ContractPackage(String totalPackage) {
if (totalPackage.endsWith("*")) {
this.packageName = totalPackage.substring(0, totalPackage.length() - 2).trim();
this.isTotal = true;
} else {
this.packageName = totalPackage;
}
}

public String getPackageName() {
return packageName;
}

public boolean isTotal() {
return isTotal;
}
}
}

+ 3
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractVerifyMojo.java View File

@@ -183,9 +183,12 @@ public class ContractVerifyMojo extends AbstractMojo {
}
}
if (!isOK) {
// 需要将该Jar删除
jarFile.delete();
throw new IllegalStateException("There are many Illegal information, please check !!!");
}
} else {
jarFile.delete();
throw new IllegalStateException("There is none class !!!");
}
} catch (Exception e) {


Loading…
Cancel
Save