diff --git a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java index 162ff130..869e0762 100644 --- a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java +++ b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java @@ -123,11 +123,11 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer return; } - protected void initConfig(int id, String systemConfig, String hostsConfig) { - - this.tomConfig = new TOMConfiguration(id, systemConfig, hostsConfig); - - } +// protected void initConfig(int id, String systemConfig, String hostsConfig) { +// +// this.tomConfig = new TOMConfiguration(id, systemConfig, hostsConfig); +// +// } protected void initConfig(int id, Properties systemsConfig, HostsConfig hostConfig) { this.tomConfig = new TOMConfiguration(id, systemsConfig, hostConfig); @@ -309,6 +309,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer try { LOGGER.debug("Start replica...[ID=" + getId() + "]"); + // 调整绑定Host this.replica = new ServiceReplica(tomConfig, this, this); this.topology = new BftsmartTopology(replica.getReplicaContext().getCurrentView()); status = Status.RUNNING; diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java index 01e3be99..8ed9b38e 100644 --- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java +++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java @@ -1,128 +1,128 @@ -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.NodeList; -import com.github.javaparser.ast.PackageDeclaration; -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import com.jd.blockchain.contract.ContractType; -import com.jd.blockchain.utils.IllegalDataException; -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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Properties; -import java.util.jar.Attributes; -import java.util.jar.JarFile; -import java.util.stream.Collectors; - -/** - * 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 = "checkImports") -public class CheckImportsMojo extends AbstractMojo { - - Logger logger = LoggerFactory.getLogger(CheckImportsMojo.class); - - @Parameter(defaultValue = "${project}", required = true, readonly = true) - private MavenProject project; - - /** - * jar's name; - */ - @Parameter - private String finalName; - - @Override - public void execute() throws MojoFailureException { - List sources; - try { - InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties"); - Properties properties = new Properties(); - properties.load(inputStream); - String[] packageBlackList = properties.getProperty("blacklist").split(","); - Path baseDirPath = project.getBasedir().toPath(); - sources = Files.find(baseDirPath, Integer.MAX_VALUE, (file, attrs) -> (file.toString().endsWith(".java"))).collect(Collectors.toList()); - for (Path path : sources) { - CompilationUnit compilationUnit = JavaParser.parse(path); - - compilationUnit.accept(new MethodVisitor(), null); - - NodeList imports = compilationUnit.getImports(); - for (ImportDeclaration imp : imports) { - String importName = imp.getName().asString(); - for (String item : packageBlackList) { - if (importName.startsWith(item)) { - throw new MojoFailureException("在源码中不允许包含此引入包:" + importName); - } - } - } - - //now we parse the jar; - String jarPath = project.getBuild().getDirectory()+ File.separator+finalName+".jar"; - File jarFile = new File(jarPath); - 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); - try { - Class mainClass = classLoader.loadClass(contractMainClass); - ContractType.resolve(mainClass); - } catch (ClassNotFoundException e) { - throw new IllegalDataException(e.getMessage()); - } - } - } catch (IOException exception) { - logger.error(exception.getMessage()); - throw new MojoFailureException("IO ERROR"); - } catch (NullPointerException e) { - logger.error(e.getMessage()); - } - } - - private class MethodVisitor extends VoidVisitorAdapter { - @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 */ - logger.info("method:"+n.getName()); - super.visit(n, arg); - } - - @Override - public void visit(ClassOrInterfaceDeclaration n, Void arg) { - logger.info("class:"+n.getName()+" extends:"+n.getExtendedTypes()+" implements:"+n.getImplementedTypes()); - - super.visit(n, arg); - } - - @Override - public void visit(PackageDeclaration n, Void arg) { - logger.info("package:"+n.getName()); - super.visit(n, arg); - } - - } -} +//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.NodeList; +//import com.github.javaparser.ast.PackageDeclaration; +//import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +//import com.github.javaparser.ast.body.MethodDeclaration; +//import com.github.javaparser.ast.visitor.VoidVisitorAdapter; +//import com.jd.blockchain.contract.ContractType; +//import com.jd.blockchain.utils.IllegalDataException; +//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.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.io.File; +//import java.io.IOException; +//import java.io.InputStream; +//import java.net.URL; +//import java.net.URLClassLoader; +//import java.nio.file.Files; +//import java.nio.file.Path; +//import java.util.List; +//import java.util.Properties; +//import java.util.jar.Attributes; +//import java.util.jar.JarFile; +//import java.util.stream.Collectors; +// +///** +// * 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 = "checkImports") +//public class CheckImportsMojo extends AbstractMojo { +// +// Logger logger = LoggerFactory.getLogger(CheckImportsMojo.class); +// +// @Parameter(defaultValue = "${project}", required = true, readonly = true) +// private MavenProject project; +// +// /** +// * jar's name; +// */ +// @Parameter +// private String finalName; +// +// @Override +// public void execute() throws MojoFailureException { +// List sources; +// try { +// InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties"); +// Properties properties = new Properties(); +// properties.load(inputStream); +// String[] packageBlackList = properties.getProperty("blacklist").split(","); +// Path baseDirPath = project.getBasedir().toPath(); +// sources = Files.find(baseDirPath, Integer.MAX_VALUE, (file, attrs) -> (file.toString().endsWith(".java"))).collect(Collectors.toList()); +// for (Path path : sources) { +// CompilationUnit compilationUnit = JavaParser.parse(path); +// +// compilationUnit.accept(new MethodVisitor(), null); +// +// NodeList imports = compilationUnit.getImports(); +// for (ImportDeclaration imp : imports) { +// String importName = imp.getName().asString(); +// for (String item : packageBlackList) { +// if (importName.startsWith(item)) { +// throw new MojoFailureException("在源码中不允许包含此引入包:" + importName); +// } +// } +// } +// +// //now we parse the jar; +// String jarPath = project.getBuild().getDirectory()+ File.separator+finalName+".jar"; +// File jarFile = new File(jarPath); +// 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); +// try { +// Class mainClass = classLoader.loadClass(contractMainClass); +// ContractType.resolve(mainClass); +// } catch (ClassNotFoundException e) { +// throw new IllegalDataException(e.getMessage()); +// } +// } +// } catch (IOException exception) { +// logger.error(exception.getMessage()); +// throw new MojoFailureException("IO ERROR"); +// } catch (NullPointerException e) { +// logger.error(e.getMessage()); +// } +// } +// +// private class MethodVisitor extends VoidVisitorAdapter { +// @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 */ +// logger.info("method:"+n.getName()); +// super.visit(n, arg); +// } +// +// @Override +// public void visit(ClassOrInterfaceDeclaration n, Void arg) { +// logger.info("class:"+n.getName()+" extends:"+n.getExtendedTypes()+" implements:"+n.getImplementedTypes()); +// +// super.visit(n, arg); +// } +// +// @Override +// public void visit(PackageDeclaration n, Void arg) { +// logger.info("package:"+n.getName()); +// super.visit(n, arg); +// } +// +// } +//} diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java index 7d823d95..1403e079 100644 --- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java +++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java @@ -1,6 +1,7 @@ package com.jd.blockchain; -import com.jd.blockchain.utils.ConsoleUtils; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import org.apache.commons.io.FileUtils; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; @@ -12,7 +13,6 @@ 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.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,9 +22,25 @@ import java.util.Collections; import java.util.List; -@Mojo(name = "contractCheck") +@Mojo(name = "Contract.Check") public class ContractCheckMojo extends AbstractMojo { - Logger logger = LoggerFactory.getLogger(ContractCheckMojo.class); + Logger LOG = LoggerFactory.getLogger(ContractCheckMojo.class); + + public static final String CONTRACT_VERIFY = "Contract.Verify"; + + 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 = "verify"; + + private static final String GOALS_PACKAGE = "package"; + + private static final String OUT_POM_XML = "OutPom.xml"; @Parameter(defaultValue = "${project}", required = true, readonly = true) private MavenProject project; @@ -58,27 +74,21 @@ public class ContractCheckMojo extends AbstractMojo { */ @Override public void execute() { - this.compileFiles(); - + compileFiles(); } private void compileFiles(){ - // 获取当前项目pom.xml文件所在路径 -// URL targetClasses = this.getClass().getClassLoader().getResource(""); -// File file = new File(targetClasses.getPath()); -// String pomXmlPath = file.getParentFile().getParent() + File.separator + "pom.xml"; + try (FileInputStream fis = new FileInputStream(project.getFile())) { - FileInputStream fis = null; - try { -// fis = new FileInputStream(new File(pomXmlPath)); - 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("com.jd.blockchain:contract-maven-plugin"); + Plugin plugin = model.getBuild().getPluginsAsMap() + .get(JDCHAIN_PACKAGE + ":" + CONTRACT_MAVEN_PLUGIN); if(plugin == null){ - plugin = model.getBuild().getPluginsAsMap().get("org.apache.maven.plugins:contract-maven-plugin"); + plugin = model.getBuild().getPluginsAsMap() + .get(APACHE_MAVEN_PLUGINS + ":" + CONTRACT_MAVEN_PLUGIN); } if(plugin == null) { @@ -86,26 +96,18 @@ public class ContractCheckMojo extends AbstractMojo { } model.getBuild().removePlugin(plugin); -// model.getBuild().setPlugins(null); - -// ConsoleUtils.info("----- 不携带Plugin -----"); -// print(model); List plugins = new ArrayList<>(); plugins.add(createAssembly()); - plugins.add(createCheckImports()); + plugins.add(createContractVerify()); model.getBuild().setPlugins(plugins); - ConsoleUtils.info("----- add Plugin -----"); handle(model); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (XmlPullParserException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + } catch (Exception e) { + LOG.error(e.getMessage()); + throw new IllegalStateException(e); } } @@ -116,43 +118,35 @@ public class ContractCheckMojo extends AbstractMojo { try { request.setPomFile(file); - request.setGoals( Collections.singletonList( "verify" ) ); -// request.setMavenOpts("-DmainClass="+mainClass); + request.setGoals(Collections.singletonList(GOALS_VERIFY)); invoker.setMavenHome(new File(mvnHome)); invoker.execute(request); } catch (MavenInvocationException e) { - e.printStackTrace(); + LOG.error(e.getMessage()); + throw new IllegalStateException(e); } } - private Plugin createCheckImports() { + private Plugin createContractVerify() { Plugin plugin = new Plugin(); - plugin.setGroupId("com.jd.blockchain"); - plugin.setArtifactId("contract-maven-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); - PluginExecution pluginExecution = new PluginExecution(); - pluginExecution.setId("make-assembly"); - pluginExecution.setPhase("verify"); - List goals = new ArrayList<>(); - goals.add("JDChain.Verify"); - pluginExecution.setGoals(goals); - List pluginExecutions = new ArrayList<>(); - pluginExecutions.add(pluginExecution); - plugin.setExecutions(pluginExecutions); + 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"); + plugin.setArtifactId(MAVEN_ASSEMBLY_PLUGIN); Xpp3Dom configuration = new Xpp3Dom("configuration"); @@ -180,21 +174,28 @@ public class ContractCheckMojo extends AbstractMojo { 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(String id, String phase, String goal) { PluginExecution pluginExecution = new PluginExecution(); - pluginExecution.setId("make-assembly"); - pluginExecution.setPhase("package"); + pluginExecution.setId(id); + pluginExecution.setPhase(phase); List goals = new ArrayList<>(); - goals.add("single"); + goals.add(goal); pluginExecution.setGoals(goals); List pluginExecutions = new ArrayList<>(); pluginExecutions.add(pluginExecution); - plugin.setExecutions(pluginExecutions); - return plugin; + + return pluginExecutions; } private void handle(Model model) throws IOException { + MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -203,20 +204,10 @@ public class ContractCheckMojo extends AbstractMojo { byte[] buffer = outputStream.toByteArray(); - //输出文件 -// File fileOutput = new File("fileOut.xml"); -// File fileOutput = File.createTempFile("fileOut",".xml"); - File fileOutput = new File(project.getBasedir().getPath(),"fileOut.xml"); - fileOutput.createNewFile(); - - ConsoleUtils.info("fileOutput's path="+fileOutput.getPath()); - //创建文件输出流对象 - FileOutputStream fos = new FileOutputStream(fileOutput); - //将字节数组fileInput中的内容输出到文件fileOut.xml中; - ConsoleUtils.info(new String(buffer)); - fos.write(buffer); - fos.flush(); - fos.close(); - invokeCompile(fileOutput); + File outPom = new File(project.getBasedir().getPath(), OUT_POM_XML); + + FileUtils.writeByteArrayToFile(outPom, buffer); + + invokeCompile(outPom); } } diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java index adb898b2..28d5a1fb 100644 --- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java +++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java @@ -20,6 +20,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.ResourceUtils; import java.io.*; import java.net.URL; @@ -27,15 +28,15 @@ import java.net.URLClassLoader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Enumeration; -import java.util.List; -import java.util.Properties; +import java.util.*; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import java.util.stream.Collectors; +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.*; /** @@ -47,10 +48,10 @@ import static com.jd.blockchain.utils.jar.ContractJarUtils.*; * by zhaogw * date 2019-06-05 16:17 */ -@Mojo(name = "JDChain.Verify") +@Mojo(name = CONTRACT_VERIFY) public class ContractVerifyMojo extends AbstractMojo { - Logger logger = LoggerFactory.getLogger(ContractVerifyMojo.class); + Logger LOG = LoggerFactory.getLogger(ContractVerifyMojo.class); @Parameter(defaultValue = "${project}", required = true, readonly = true) private MavenProject project; @@ -61,53 +62,249 @@ public class ContractVerifyMojo extends AbstractMojo { @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 MojoFailureException { - List sources; try { File jarFile = copyAndManage(); - InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties"); - Properties properties = new Properties(); - properties.load(inputStream); - String[] packageBlackList = properties.getProperty("blacklist").split(","); - Path baseDirPath = project.getBasedir().toPath(); - sources = Files.find(baseDirPath, Integer.MAX_VALUE, (file, attrs) -> (file.toString().endsWith(".java"))).collect(Collectors.toList()); - for (Path path : sources) { - CompilationUnit compilationUnit = JavaParser.parse(path); - - compilationUnit.accept(new MethodVisitor(), null); - - NodeList imports = compilationUnit.getImports(); - for (ImportDeclaration imp : imports) { - String importName = imp.getName().asString(); - for (String item : packageBlackList) { - if (importName.startsWith(item)) { - throw new MojoFailureException("在源码中不允许包含此引入包:" + importName); + Properties config = loadConfig(); + + List blackNameList = blackNameList(config); + + List blackPackageList = blackPackageList(config); + + Set blackClassSet = blackClassSet(config); + + LinkedList 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 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 !!!"); } - //now we parse the jar; + // 加载main-class,开始校验类型 URL jarURL = jarFile.toURI().toURL(); - ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL},this.getClass().getClassLoader()); + 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); - try { - Class mainClass = classLoader.loadClass(contractMainClass); - ContractType.resolve(mainClass); - } catch (ClassNotFoundException e) { - throw new IllegalDataException(e.getMessage()); - } + Class mainClass = classLoader.loadClass(contractMainClass); + ContractType.resolve(mainClass); + } else { + throw new IllegalStateException("There is none class !!!"); + } + } catch (Exception e) { + LOG.error(e.getMessage()); + throw new MojoFailureException(e.getMessage()); + } + } + + private List blackNameList(Properties config) { + return blackList(config, BLACK_NAME_LIST); + } + + private Set blackClassSet(Properties config) { + Set 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 blackPackageList(Properties config) { + return blackList(config, BLACK_PACKAGE_LIST); + } + + private List blackList(Properties config, String attrName) { + List 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; } - } catch (IOException exception) { - logger.error(exception.getMessage()); - throw new MojoFailureException("IO ERROR"); - } catch (NullPointerException e) { - logger.error(e.getMessage()); } + 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 { @@ -138,30 +335,104 @@ public class ContractVerifyMojo extends AbstractMojo { return finalJar; } + private Properties loadConfig() throws Exception { + + Properties properties = new Properties(); + properties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG)); + + return properties; + } + + private LinkedList loadAllClass(File file) throws Exception { + JarFile jarFile = new JarFile(file); + LinkedList allClass = new LinkedList<>(); + Enumeration 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 { + + private List 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); +// } - private class MethodVisitor extends VoidVisitorAdapter { @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 */ - logger.info("method:"+n.getName()); + public void visit(ImportDeclaration n, Void arg) { + importClasses.add(parseClass(n.toString())); super.visit(n, arg); } - @Override - public void visit(ClassOrInterfaceDeclaration n, Void arg) { - logger.info("class:"+n.getName()+" extends:"+n.getExtendedTypes()+" implements:"+n.getImplementedTypes()); + 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; + } + } - super.visit(n, arg); + private static class ContractPackage { + + private String packageName; + + private boolean isTotal = false; + + public ContractPackage() { } - @Override - public void visit(PackageDeclaration n, Void arg) { - logger.info("package:"+n.getName()); - super.visit(n, arg); + public ContractPackage(String totalPackage) { + if (totalPackage.endsWith("*")) { + this.packageName = totalPackage.substring(0, totalPackage.length() - 2).trim(); + this.isTotal = true; + } + this.packageName = totalPackage; } + public String getPackageName() { + return packageName; + } + + public boolean isTotal() { + return isTotal; + } } } diff --git a/source/contract/contract-maven-plugin/src/main/resources/config.properties b/source/contract/contract-maven-plugin/src/main/resources/config.properties index fdfca23e..4a176409 100644 --- a/source/contract/contract-maven-plugin/src/main/resources/config.properties +++ b/source/contract/contract-maven-plugin/src/main/resources/config.properties @@ -1 +1,8 @@ -blacklist=java.io,java.net,java.util.Random \ No newline at end of file +#black.name.list:打包为合约Jar后,每个Class文件不允许使用的名称,默认不允许使用com.jd.blockchain.* +black.name.list=com.jd.blockchain.* + +#black.package.list:打包为合约中的每个Class都不允许使用的包列表,某个包下面的所有包通过.*表示 +black.package.list=java.io.*, java.net.*, org.apache.commons.io.* + +#black.class.list:打包为合约中的每个Class都不允许使用的类列表 +black.class.list=java.util.Random, com.jd.blockchain.ledger.BlockchainKeyGenerator \ No newline at end of file diff --git a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java deleted file mode 100644 index 66b194c0..00000000 --- a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.CheckImportsMojo; -import org.apache.maven.plugin.testing.AbstractMojoTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; - -/** - * @Author zhaogw - * @Date 2019/3/1 21:27 - */ -public class CheckImportsMojoTest extends AbstractMojoTestCase { - Logger logger = LoggerFactory.getLogger(CheckImportsMojoTest.class); - - @Test - public void test1() throws Exception { - File pom = getTestFile( "src/test/resources/project-to-test/pom.xml" ); - assertNotNull( pom ); - assertTrue( pom.exists() ); - - CheckImportsMojo myMojo = (CheckImportsMojo) lookupMojo( "checkImports", pom ); - assertNotNull( myMojo ); - myMojo.execute(); - } -} diff --git a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractTestBase.java b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractTestBase.java new file mode 100644 index 00000000..09a5010f --- /dev/null +++ b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractTestBase.java @@ -0,0 +1,50 @@ +package com.jd.blockchain.ledger; + +import org.apache.maven.model.Build; +import org.apache.maven.project.MavenProject; +import org.junit.Test; +import org.springframework.core.io.ClassPathResource; + +import java.io.File; + +public class ContractTestBase { + + public static MavenProject mavenProjectInit() { + MavenProject mavenProject = new MavenProject(); + mavenProject.setBuild(buildInit()); + mavenProject.setFile(file()); + return mavenProject; + } + + public static File file() { + String resDir = resourceDir(); + File file = new File(resDir); + String path = file.getParentFile().getParentFile().getPath(); + return new File(path + File.separator + "src"); + } + + public static Build buildInit() { + Build build = new Build(); + build.setDirectory(resourceDir()); + return build; + } + + public static String resourceDir() { + try { + ClassPathResource classPathResource = new ClassPathResource("complex.jar"); + return classPathResource.getFile().getParentFile().getPath(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Test + public void testResourceDir() { + System.out.println(resourceDir()); + } + + @Test + public void testFile() { + System.out.println(file().getPath()); + } +} diff --git a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java index 4cfc66b5..ac9813cd 100644 --- a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java +++ b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java @@ -1,6 +1,5 @@ package com.jd.blockchain.ledger; -import com.jd.blockchain.CheckImportsMojo; import com.jd.blockchain.ContractVerifyMojo; import org.apache.maven.plugin.testing.AbstractMojoTestCase; import org.junit.Test; @@ -22,7 +21,7 @@ public class ContractVerifyMojoTest extends AbstractMojoTestCase { assertNotNull( pom ); assertTrue( pom.exists() ); - ContractVerifyMojo myMojo = (ContractVerifyMojo) lookupMojo( "JDChain.Verify", pom ); + ContractVerifyMojo myMojo = (ContractVerifyMojo) lookupMojo( "Contract.Verify", pom ); assertNotNull( myMojo ); myMojo.execute(); } diff --git a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyTest.java b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyTest.java new file mode 100644 index 00000000..dc5d2541 --- /dev/null +++ b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyTest.java @@ -0,0 +1,47 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.ContractVerifyMojo; +import org.apache.maven.project.MavenProject; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Field; + +import static com.jd.blockchain.ledger.ContractTestBase.mavenProjectInit; + +public class ContractVerifyTest { + + private MavenProject project; + + private String finalName; + + @Before + public void testInit() { + project = mavenProjectInit(); + finalName = "complex.jar"; + } + + @Test + public void test() throws Exception { + ContractVerifyMojo contractVerifyMojo = contractVerifyMojoConf(); + contractVerifyMojo.execute(); + } + + private ContractVerifyMojo contractVerifyMojoConf() throws Exception { + ContractVerifyMojo contractVerifyMojo = new ContractVerifyMojo(); + // 为不影响其内部结构,通过反射进行私有变量赋值 + Class clazz = contractVerifyMojo.getClass(); + Field projectField = clazz.getDeclaredField("project"); + Field finalNameField = clazz.getDeclaredField("finalName"); + + // 更新权限 + projectField.setAccessible(true); + finalNameField.setAccessible(true); + + // 设置具体值 + projectField.set(contractVerifyMojo, project); + finalNameField.set(contractVerifyMojo, finalName); + + return contractVerifyMojo; + } +} diff --git a/source/contract/contract-maven-plugin/src/test/resources/complex.jar b/source/contract/contract-maven-plugin/src/test/resources/complex.jar new file mode 100644 index 00000000..3c595b4d Binary files /dev/null and b/source/contract/contract-maven-plugin/src/test/resources/complex.jar differ diff --git a/source/gateway/pom.xml b/source/gateway/pom.xml index 71c8bc07..91e4ba83 100644 --- a/source/gateway/pom.xml +++ b/source/gateway/pom.xml @@ -78,22 +78,7 @@ ${commons-io.version} - - org.bitbucket.mstrobel - procyon-core - - - org.bitbucket.mstrobel - procyon-expressions - - - org.bitbucket.mstrobel - procyon-reflection - - - org.bitbucket.mstrobel - procyon-compilertools - + org.springframework.boot diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java index 4421dde1..4ff94632 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java @@ -3,11 +3,8 @@ package com.jd.blockchain.gateway.service; import com.jd.blockchain.consensus.ConsensusProvider; import com.jd.blockchain.consensus.ConsensusProviders; import com.jd.blockchain.consensus.ConsensusSettings; -import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; -import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.gateway.PeerService; -import com.jd.blockchain.gateway.decompiler.utils.DecompilerUtils; import com.jd.blockchain.ledger.ContractInfo; import com.jd.blockchain.ledger.LedgerMetadata; import com.jd.blockchain.ledger.ParticipantNode; @@ -15,6 +12,7 @@ import com.jd.blockchain.sdk.ContractSettings; import com.jd.blockchain.sdk.LedgerInitSettings; import com.jd.blockchain.utils.QueryUtil; import com.jd.blockchain.utils.codec.HexUtils; +import com.jd.blockchain.utils.decompiler.utils.DecompilerUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Arrays; diff --git a/source/utils/utils-common/pom.xml b/source/utils/utils-common/pom.xml index d0aea4d7..c897ad4d 100644 --- a/source/utils/utils-common/pom.xml +++ b/source/utils/utils-common/pom.xml @@ -43,6 +43,23 @@ spring-beans + + org.bitbucket.mstrobel + procyon-core + + + org.bitbucket.mstrobel + procyon-expressions + + + org.bitbucket.mstrobel + procyon-reflection + + + org.bitbucket.mstrobel + procyon-compilertools + + diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/decompiler/loads/BytesTypeLoader.java similarity index 99% rename from source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java rename to source/utils/utils-common/src/main/java/com/jd/blockchain/utils/decompiler/loads/BytesTypeLoader.java index 8caf66f0..379aab08 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/decompiler/loads/BytesTypeLoader.java @@ -1,4 +1,4 @@ -package com.jd.blockchain.gateway.decompiler.loads; +package com.jd.blockchain.utils.decompiler.loads; import com.strobel.assembler.ir.ConstantPool; import com.strobel.assembler.metadata.Buffer; diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/decompiler/utils/DecompilerUtils.java similarity index 98% rename from source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java rename to source/utils/utils-common/src/main/java/com/jd/blockchain/utils/decompiler/utils/DecompilerUtils.java index 0a66da9f..6d7729b4 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/decompiler/utils/DecompilerUtils.java @@ -1,6 +1,6 @@ -package com.jd.blockchain.gateway.decompiler.utils; +package com.jd.blockchain.utils.decompiler.utils; -import com.jd.blockchain.gateway.decompiler.loads.BytesTypeLoader; +import com.jd.blockchain.utils.decompiler.loads.BytesTypeLoader; import com.strobel.assembler.metadata.JarTypeLoader; import com.strobel.decompiler.Decompiler; import com.strobel.decompiler.DecompilerSettings; diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/jar/ContractJarUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/jar/ContractJarUtils.java index 08ccdbff..a59512db 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/jar/ContractJarUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/jar/ContractJarUtils.java @@ -15,7 +15,7 @@ import java.util.jar.JarOutputStream; public class ContractJarUtils { - private static final String JDCHAIN_META = "META-INF/JDCHAIN.TXT"; + private static final String JDCHAIN_META = "META-INF/CONTRACT.MF"; private static final int JDCHAIN_HASH_LENGTH = 69;