@@ -1,12 +1,12 @@ | |||
package com.jd.blockchain.contract.maven; | |||
import com.jd.blockchain.contract.ContractJarUtils; | |||
import com.jd.blockchain.contract.maven.rule.BlackList; | |||
import com.jd.blockchain.contract.maven.rule.WhiteList; | |||
import com.jd.blockchain.contract.maven.rule.DependencyExclude; | |||
import com.jd.blockchain.contract.maven.verify.ResolveEngine; | |||
import com.jd.blockchain.contract.maven.verify.VerifyEngine; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.maven.artifact.Artifact; | |||
import org.apache.maven.plugin.MojoExecutionException; | |||
import org.apache.maven.plugin.MojoFailureException; | |||
@@ -16,8 +16,14 @@ import org.apache.maven.project.MavenProject; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Set; | |||
import static com.jd.blockchain.contract.ContractJarUtils.BLACK_CONF; | |||
import static com.jd.blockchain.contract.ContractJarUtils.WHITE_CONF; | |||
@Mojo(name = "compile") | |||
public class ContractCompileMojo extends SingleAssemblyMojo { | |||
@@ -42,46 +48,122 @@ public class ContractCompileMojo extends SingleAssemblyMojo { | |||
// 首先对MainClass进行校验,要求必须有MainClass | |||
String mainClass = mainClassVerify(); | |||
// 将JDChain本身代码之外的代码移除(不打包进整个Jar) | |||
// 排除所有依赖,只打包当前代码 | |||
// excludeAllArtifactExclude(super.getProject().getDependencyArtifacts()); | |||
// handleArtifactCompile(super.getProject().getDependencyArtifacts()); | |||
handleArtifactExclude(super.getProject().getDependencyArtifacts()); | |||
// 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包 | |||
super.setDescriptorRefs(new String[]{JAR_DEPENDENCE}); | |||
// 执行打包命令 | |||
// 该命令生成的是只含有当前项目的实际代码的Jar包,该Jar包仅用于校验MainClass | |||
super.execute(); | |||
// 将本次打包好的文件重新命名,以便于后续重新打包需要 | |||
// 把文件改名,然后重新再生成一个文件 | |||
File dstFile; | |||
// 生成解析引擎 | |||
ResolveEngine resolveEngine = new ResolveEngine(getLog(), mainClass); | |||
// 获取本次生成的Jar文件 | |||
File defaultJarFile; | |||
try { | |||
dstFile = rename(getProject(), getFinalName()); | |||
} catch (IOException e) { | |||
defaultJarFile = rename(getProject(), getFinalName()); | |||
// 校验当前MainClass是否满足需求 | |||
resolveEngine.verifyCurrentProjectMainClass(defaultJarFile); | |||
// 校验完成后将该Jar删除 | |||
// FileUtils.forceDelete(mainClassFile); | |||
} catch (Exception e) { | |||
getLog().error(e); | |||
throw new MojoFailureException(e.getMessage()); | |||
} | |||
// 首先校验该类的Jar包中是否包含不符合规范的命名,以及该类的代码中的部分解析 | |||
File finalJarFile = verify(dstFile, mainClass); | |||
// 将所有的依赖的jar包全部打包进一个包中,以便于进行ASM检查 | |||
handleArtifactCompile(super.getProject().getDependencyArtifacts()); | |||
// 然后再打包一次,本次打包完成后,其中的代码包含所有的class(JDK自身的除外) | |||
super.execute(); | |||
// 对代码中的一些规则进行校验,主要是校验其是否包含一些不允许使用的类、包、方法等 | |||
verify(mainClass); | |||
// 删除中间的一些文件 | |||
// // 将JDChain本身之外的代码打包进Jar包,然后编译 | |||
// handleArtifactExclude(super.getProject().getDependencyArtifacts()); | |||
// | |||
// // 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包 | |||
// super.setDescriptorRefs(new String[]{JAR_DEPENDENCE}); | |||
// | |||
// // 生成Jar包(该Jar包中不包含JDChain内部的代码) | |||
// super.execute(); | |||
// | |||
// File defaultJarFile; | |||
// try { | |||
// defaultJarFile = rename(getProject(), getFinalName()); | |||
// } catch (Exception e) { | |||
// getLog().error(e); | |||
// throw new MojoFailureException(e.getMessage()); | |||
// } | |||
// 校验该Jar包 | |||
verify(defaultJarFile, mainClass); | |||
File deployJarFile = resolveEngine.verify(defaultJarFile); | |||
// 删除中间产生的临时文件 | |||
try { | |||
FileUtils.forceDelete(dstFile); | |||
} catch (IOException e) { | |||
throw new MojoFailureException(e.getMessage()); | |||
FileUtils.forceDelete(defaultJarFile); | |||
} catch (Exception e) { | |||
getLog().error(e); | |||
} | |||
getLog().info(String.format("JDChain's Contract compile success, path = %s !", deployJarFile.getPath())); | |||
// // 将JDChain本身代码之外的代码移除(不打包进整个Jar) | |||
// handleArtifactExclude(super.getProject().getDependencyArtifacts()); | |||
// | |||
// // 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包 | |||
// super.setDescriptorRefs(new String[]{JAR_DEPENDENCE}); | |||
// | |||
// // 执行打包命令 | |||
// super.execute(); | |||
// // 将本次打包好的文件重新命名,以便于后续重新打包需要 | |||
// // 把文件改名,然后重新再生成一个文件 | |||
// File dstFile; | |||
// try { | |||
// dstFile = rename(getProject(), getFinalName()); | |||
// } catch (IOException e) { | |||
// getLog().error(e); | |||
// throw new MojoFailureException(e.getMessage()); | |||
// } | |||
// | |||
// // dstFile理论上应该含有 | |||
// | |||
// // 首先校验该类的Jar包中是否包含不符合规范的命名,以及该类的代码中的部分解析 | |||
// | |||
// ResolveEngine resolveEngine = new ResolveEngine(getLog(), mainClass); | |||
// | |||
// // 校验mainClass | |||
// resolveEngine.verifyCurrentProjectMainClass(dstFile); | |||
// | |||
// | |||
// | |||
// File finalJarFile = resolveEngine.verify(); | |||
// | |||
// // 将所有的依赖的jar包全部打包进一个包中,以便于进行ASM检查 | |||
// handleArtifactCompile(super.getProject().getDependencyArtifacts()); | |||
// | |||
// // 然后再打包一次,本次打包完成后,其中的代码包含所有的class(JDK自身的除外) | |||
// super.execute(); | |||
// | |||
// File jarFile = new File(jarPath(getProject(), getFinalName())); | |||
// | |||
// // 校验mainClass | |||
// resolveEngine.verifyCurrentProjectMainClass(jarFile); | |||
// | |||
// // 对代码中的一些规则进行校验,主要是校验其是否包含一些不允许使用的类、包、方法等 | |||
// verify(jarFile, mainClass); | |||
// | |||
// // 删除中间的一些文件 | |||
//// try { | |||
//// FileUtils.forceDelete(dstFile); | |||
//// } catch (IOException e) { | |||
//// throw new MojoFailureException(e.getMessage()); | |||
//// } | |||
// | |||
// 若执行到此处没有异常则表明打包成功,打印打包成功消息 | |||
getLog().info(String.format("JDChain's Contract compile success, path = %s !", finalJarFile.getPath())); | |||
// getLog().info(String.format("JDChain's Contract compile success, path = %s !", finalJarFile.getPath())); | |||
} | |||
private String mainClassVerify() throws MojoFailureException { | |||
@@ -107,10 +189,20 @@ public class ContractCompileMojo extends SingleAssemblyMojo { | |||
getLog().info(String.format("GroupId[%s] ArtifactId[%s] belongs to DependencyExclude !!!", groupId, artifactId)); | |||
// 属于排除的名单之中 | |||
artifact.setScope(SCOPE_PROVIDED); | |||
} else { | |||
getLog().info(String.format("GroupId[%s] ArtifactId[%s] not belongs to DependencyExclude !!!", groupId, artifactId)); | |||
// 属于排除的名单之中 | |||
artifact.setScope(SCOPE_COMPILE); | |||
} | |||
} | |||
} | |||
private void excludeAllArtifactExclude(Set<Artifact> artifacts) { | |||
for (Artifact artifact : artifacts) { | |||
artifact.setScope(SCOPE_PROVIDED); | |||
} | |||
} | |||
private void handleArtifactCompile(Set<Artifact> artifacts) { | |||
for (Artifact artifact : artifacts) { | |||
if (artifact.getScope().equals(SCOPE_PROVIDED)) { | |||
@@ -135,17 +227,14 @@ public class ContractCompileMojo extends SingleAssemblyMojo { | |||
File.separator + finalName + "-" + JAR_DEPENDENCE + ".jar"; | |||
} | |||
private void verify(String mainClass) throws MojoFailureException { | |||
private void verify(File jarFile, String mainClass) throws MojoFailureException { | |||
try { | |||
File jarFile = new File(jarPath(getProject(), getFinalName())); | |||
VerifyEngine verifyEngine = new VerifyEngine(getLog(), jarFile, mainClass, black, white); | |||
verifyEngine.verify(); | |||
// 校验完成后将该jar包删除 | |||
FileUtils.forceDelete(jarFile); | |||
// FileUtils.forceDelete(jarFile); | |||
} catch (Exception e) { | |||
getLog().error(e); | |||
@@ -153,20 +242,47 @@ public class ContractCompileMojo extends SingleAssemblyMojo { | |||
} | |||
} | |||
private File verify(File jarFile, String mainClass) throws MojoFailureException { | |||
ResolveEngine resolveEngine = new ResolveEngine(getLog(), jarFile, mainClass); | |||
return resolveEngine.verify(); | |||
private static void init() { | |||
try { | |||
black = AbstractContract.initBlack(loadBlackConf()); | |||
white = AbstractContract.initWhite(loadWhiteConf()); | |||
} catch (Exception e) { | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
private static List<String> loadWhiteConf() { | |||
return resolveConfig(WHITE_CONF); | |||
} | |||
private static void init() { | |||
private static List<String> loadBlackConf() { | |||
return resolveConfig(BLACK_CONF); | |||
} | |||
private static List<String> resolveConfig(String fileName) { | |||
List<String> configs = new ArrayList<>(); | |||
try { | |||
black = AbstractContract.initBlack(ContractJarUtils.loadBlackConf()); | |||
white = AbstractContract.initWhite(ContractJarUtils.loadWhiteConf()); | |||
List<String> readLines = loadConfig(fileName); | |||
if (!readLines.isEmpty()) { | |||
for (String readLine : readLines) { | |||
String[] lines = readLine.split(","); | |||
configs.addAll(Arrays.asList(lines)); | |||
} | |||
} | |||
} catch (Exception e) { | |||
throw new IllegalStateException(e); | |||
} | |||
return configs; | |||
} | |||
public static List<String> loadConfig(String fileName) throws Exception { | |||
return IOUtils.readLines( | |||
ContractCompileMojo.class.getResourceAsStream("/" + fileName)); | |||
} | |||
} |
@@ -52,6 +52,7 @@ public class BlackList { | |||
} | |||
public boolean isBlack(Class<?> clazz, String methodName) { | |||
// 判断该Class是否属于黑名单 | |||
if (isCurrentClassBlack(clazz, methodName)) { | |||
return true; | |||
@@ -75,7 +76,7 @@ public class BlackList { | |||
String packageName = clazz.getPackage().getName(); | |||
for (String bp : blackPackages) { | |||
if (packageName.equals(bp) || packageName.startsWith(bp)) { | |||
if ((packageName + ".").equals(bp) || packageName.startsWith(bp)) { | |||
return true; | |||
} | |||
} | |||
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.contract.maven.rule; | |||
import com.jd.blockchain.contract.ContractJarUtils; | |||
import com.jd.blockchain.contract.maven.ContractCompileMojo; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
@@ -11,7 +11,7 @@ public class DependencyExclude { | |||
private static final String COMMON_ARTIFACTID = "*"; | |||
private static final String CONFIG = "provided.conf"; | |||
private static final String CONFIG = "providers.conf"; | |||
private static final Map<String, List<Dependency>> DEPENDENCYS = new ConcurrentHashMap<>(); | |||
@@ -24,7 +24,7 @@ public class DependencyExclude { | |||
} | |||
private static void init() throws Exception { | |||
List<String> readLines = ContractJarUtils.loadConfig(CONFIG); | |||
List<String> readLines = ContractCompileMojo.loadConfig(CONFIG); | |||
if (!readLines.isEmpty()) { | |||
for (String line : readLines) { | |||
// groupId/artifactId | |||
@@ -1,7 +1,10 @@ | |||
package com.jd.blockchain.contract.maven.verify; | |||
import com.alibaba.fastjson.JSON; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractJarUtils; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.maven.plugin.MojoFailureException; | |||
import org.apache.maven.plugin.logging.Log; | |||
@@ -21,23 +24,49 @@ public class ResolveEngine { | |||
private Log LOGGER; | |||
private File jarFile; | |||
// private File jarFile; | |||
private String mainClass; | |||
public ResolveEngine(Log LOGGER, File jarFile, String mainClass) { | |||
// public ResolveEngine(Log LOGGER, File jarFile, String mainClass) { | |||
public ResolveEngine(Log LOGGER, String mainClass) { | |||
this.LOGGER = LOGGER; | |||
this.jarFile = jarFile; | |||
// this.jarFile = jarFile; | |||
this.mainClass = mainClass; | |||
} | |||
public File verify() throws MojoFailureException { | |||
/** | |||
* 校验当前项目中MainClass其是否满足JDChain合约写法 | |||
* | |||
* @param mainClassJarFile | |||
* @throws MojoFailureException | |||
*/ | |||
public void verifyCurrentProjectMainClass(File mainClassJarFile) throws MojoFailureException { | |||
// 校验MainClass | |||
try { | |||
// 首先校验MainClass | |||
ClassLoader classLoader = verifyMainClass(jarFile); | |||
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass start...", mainClassJarFile.getName())); | |||
// 自定义ClassLoader,必须使用Thread.currentThread().getContextClassLoader() | |||
// 保证其项目内部加载的Jar包无须再加载一次 | |||
URLClassLoader classLoader = new URLClassLoader(new URL[]{mainClassJarFile.toURI().toURL()}, | |||
Thread.currentThread().getContextClassLoader()); | |||
// 从MainClass作为入口进行MainClass代码校验 | |||
Class<?> mClass = classLoader.loadClass(mainClass); | |||
ContractType.resolve(mClass); | |||
// 校验完成后需要释放,否则无法删除该Jar文件 | |||
classLoader.close(); | |||
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass end...", mainClassJarFile.getName())); | |||
} catch (Exception e) { | |||
throw new MojoFailureException(e.getMessage()); | |||
} | |||
} | |||
public File verify(File defaultJarFile) throws MojoFailureException { | |||
try { | |||
// 检查jar包中所有的class的命名,要求其包名不能为com.jd.blockchain.* | |||
LinkedList<String> totalClasses = loadAllClass(jarFile); | |||
LinkedList<String> totalClasses = loadAllClass(defaultJarFile); | |||
if (!totalClasses.isEmpty()) { | |||
@@ -47,9 +76,8 @@ public class ResolveEngine { | |||
LOGGER.debug(String.format("Verify Dependency Class[%s] start......", dotClassName)); | |||
// 获取其包名 | |||
Class<?> currentClass = classLoader.loadClass(dotClassName); | |||
String packageName = currentClass.getPackage().getName(); | |||
// 将class转换为包名 | |||
String packageName = class2Package(dotClassName); | |||
if (ContractJarUtils.isJDChainPackage(packageName)) { | |||
throw new IllegalStateException(String.format("Class[%s]'s package[%s] cannot start with %s !", | |||
@@ -61,18 +89,23 @@ public class ResolveEngine { | |||
} | |||
// 处理完成之后,生成finalName-JDChain-Contract.jar | |||
return compileCustomJar(); | |||
return compileCustomJar(defaultJarFile); | |||
} catch (Exception e) { | |||
LOGGER.error(e.getMessage()); | |||
throw new MojoFailureException(e.getMessage()); | |||
} | |||
} | |||
private File compileCustomJar() throws IOException { | |||
private String class2Package(String dotClassName) { | |||
return dotClassName.substring(0, dotClassName.lastIndexOf(".")); | |||
} | |||
private File compileCustomJar(File defaultJarFile) throws IOException { | |||
String fileParentPath = jarFile.getParentFile().getPath(); | |||
String fileParentPath = defaultJarFile.getParentFile().getPath(); | |||
String jarFileName = jarFile.getName(); | |||
String jarFileName = defaultJarFile.getName(); | |||
String fileName = jarFileName.substring(0, jarFileName.lastIndexOf(".")); | |||
@@ -80,13 +113,13 @@ public class ResolveEngine { | |||
String dstJarPath = fileParentPath + File.separator + | |||
fileName + "-temp-" + System.currentTimeMillis() + ".jar"; | |||
File srcJar = jarFile, dstJar = new File(dstJarPath); | |||
File srcJar = defaultJarFile, dstJar = new File(dstJarPath); | |||
LOGGER.debug(String.format("Jar from [%s] to [%s] Copying", jarFile.getPath(), dstJarPath)); | |||
LOGGER.debug(String.format("Jar from [%s] to [%s] Copying", defaultJarFile.getPath(), dstJarPath)); | |||
// 首先进行Copy处理 | |||
copy(srcJar, dstJar); | |||
LOGGER.debug(String.format("Jar from [%s] to [%s] Copied", jarFile.getPath(), dstJarPath)); | |||
LOGGER.debug(String.format("Jar from [%s] to [%s] Copied", defaultJarFile.getPath(), dstJarPath)); | |||
byte[] txtBytes = contractMF(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8); | |||
@@ -128,6 +161,9 @@ public class ResolveEngine { | |||
} | |||
} | |||
} | |||
// Jar文件使用完成后需要关闭,否则可能会产生无法删除的问题 | |||
jarFile.close(); | |||
return allClass; | |||
} | |||
} |
@@ -52,7 +52,8 @@ public class VerifyEngine { | |||
// 加载所有的jar,然后ASM获取MAP | |||
URL jarURL = jarFile.toURI().toURL(); | |||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{jarURL}); | |||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{jarURL}, | |||
Thread.currentThread().getContextClassLoader()); | |||
// 解析Jar包中所有的Class | |||
Map<String, ContractClass> allContractClasses = resolveClasses(jarClasses()); | |||
@@ -60,6 +61,8 @@ public class VerifyEngine { | |||
// 开始处理MainClass | |||
verify(urlClassLoader, allContractClasses); | |||
// 校验完成后需要释放ClassLoader,否则无法删除该Jar包 | |||
urlClassLoader.close(); | |||
} | |||
public void verify(URLClassLoader urlClassLoader, Map<String, ContractClass> allContractClasses) throws Exception { | |||
@@ -91,6 +94,8 @@ public class VerifyEngine { | |||
// 将该方法设置为已处理 | |||
haveManagedMethods.add(managedKey); | |||
String dotClassName = method.getDotClassName(); | |||
Class<?> dotClass = urlClassLoader.loadClass(dotClassName); | |||
if (dotClass == null) { | |||
@@ -137,8 +142,13 @@ public class VerifyEngine { | |||
} | |||
} else { | |||
// 非URLClassLoader加载的类,只需要做判断即可 | |||
// 对于系统加载的类,其白名单优先级高于黑名单 | |||
// 1、不再需要获取其方法; | |||
// 2、只需要判断黑名单不需要判断白名单 | |||
// 首先判断是否为白名单 | |||
if (white.isWhite(dotClass)) { | |||
return; | |||
} | |||
// 然后判断其是否为黑名单 | |||
if (black.isBlack(dotClass, method.getMethodName())) { | |||
throw new IllegalStateException(String.format("Class [%s] Method [%s] is Black !!!", dotClassName, method.getMethodName())); | |||
} | |||
@@ -187,8 +197,6 @@ public class VerifyEngine { | |||
continue; | |||
} | |||
LOGGER.info(String.format("Resolve Class [%s] ...", className)); | |||
ContractClass contractClass = new ContractClass(className); | |||
ClassReader cr = new ClassReader(classContent); | |||
cr.accept(new ASMClassVisitor(contractClass), ClassReader.SKIP_DEBUG); | |||
@@ -1,5 +1,13 @@ | |||
java.io.* | |||
java.nio.* | |||
java.io.File | |||
java.io.InputStream | |||
java.io.OutputStream | |||
java.io.DataInput | |||
java.io.DataOutput | |||
java.io.Reader | |||
java.io.Writer | |||
java.io.Flushable | |||
java.nio.channels.* | |||
java.nio.file.* | |||
java.net.* | |||
java.sql.* | |||
java.lang.reflect.* | |||
@@ -1 +1,3 @@ | |||
com.jd.blockchain.* | |||
com.jd.blockchain.* | |||
java.nio.charset.Charset | |||
com.alibaba.fastjson.* |
@@ -13,9 +13,13 @@ import com.jd.blockchain.service.TransactionBatchResultHandle; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.transaction.TxBuilder; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import org.apache.commons.io.IOUtils; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.InputStream; | |||
import java.util.Random; | |||
import static org.junit.Assert.*; | |||
@@ -44,6 +48,9 @@ public class ContractInvokingTest { | |||
// 采用基于内存的 Storage; | |||
private MemoryKVStorage storage = new MemoryKVStorage(); | |||
// 用于测试的发布合约文件 | |||
private static final String CONTRACT_JAR = "contract-JDChain-Contract.jar"; | |||
@Test | |||
public void test() { | |||
// 初始化账本到指定的存储库; | |||
@@ -82,7 +89,6 @@ public class ContractInvokingTest { | |||
// 构建基于接口调用合约的交易请求,用于测试合约调用; | |||
TxBuilder txBuilder = new TxBuilder(ledgerHash); | |||
TestContract contractProxy = txBuilder.contract(contractAddress, TestContract.class); | |||
TestContract contractProxy1 = txBuilder.contract(contractAddress, TestContract.class); | |||
String asset = "AK"; | |||
long issueAmount = new Random().nextLong(); | |||
@@ -190,8 +196,7 @@ public class ContractInvokingTest { | |||
} | |||
private byte[] chainCode() { | |||
byte[] chainCode = new byte[1024]; | |||
new Random().nextBytes(chainCode); | |||
return chainCode; | |||
return BytesUtils.copyToBytes(this.getClass().getResourceAsStream("/" + CONTRACT_JAR)); | |||
} | |||
} |
@@ -1,69 +0,0 @@ | |||
package test.com.jd.blockchain.ledger.data; | |||
import org.apache.commons.io.FileUtils; | |||
import org.junit.Test; | |||
import org.springframework.core.io.ClassPathResource; | |||
import java.io.File; | |||
import java.nio.charset.StandardCharsets; | |||
import static com.jd.blockchain.contract.ContractJarUtils.*; | |||
import static org.junit.Assert.fail; | |||
public class ContractJarUtilsTest { | |||
private String jarName = "complex"; | |||
@Test | |||
public void test() { | |||
byte[] chainCode = null; | |||
try { | |||
ClassPathResource classPathResource = new ClassPathResource(jarName + ".jar"); | |||
String classPath = classPathResource.getFile().getParentFile().getPath(); | |||
// 首先将Jar包转换为指定的格式 | |||
String srcJarPath = classPath + | |||
File.separator + jarName + ".jar"; | |||
String dstJarPath = classPath + | |||
File.separator + jarName + "-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 = classPath + | |||
File.separator + jarName + "-jdchain.jar"; | |||
File finalJar = new File(finalJarPath); | |||
copy(dstJar, finalJar, contractMFJarEntry(), txtBytes, null); | |||
// 删除临时文件 | |||
FileUtils.forceDelete(dstJar); | |||
// 读取finalJar中的内容 | |||
chainCode = FileUtils.readFileToByteArray(finalJar); | |||
FileUtils.forceDelete(finalJar); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
try { | |||
verify(chainCode); | |||
System.out.println("Verify Success !!!"); | |||
} catch (Exception e) { | |||
fail("Verify Fail !!"); | |||
} | |||
} | |||
@Test | |||
public void testSign() { | |||
byte[] test = "zhangsan".getBytes(StandardCharsets.UTF_8); | |||
System.out.println(contractMF(test)); | |||
} | |||
} |