Procházet zdrojové kódy

fixbug https://gitee.com/JustryDeng/class-winter/issues/I7D9UW

JustryDeng před 3 roky
rodič
revize
cea1927efc

+ 12 - 12
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/Reverses.java

@@ -120,8 +120,8 @@ public class Reverses {
                     try {
                         projectPath = JarUtil.getRootPath(projectPath);
                     } catch (ClassWinterException e) {
-                        // 如果没有指定解密该projectPath,那么返回
-                        if (!ifPointToDecrypt(decryptProjectPathPrefixSet, projectPath)) {
+                        // 如果不需要试着解密该projectPath,那么返回
+                        if (notPointToDecrypt(projectPath, decryptProjectPathPrefixSet)) {
                             return classfileBuffer;
                         }
                     } catch (Exception e) {
@@ -142,13 +142,13 @@ public class Reverses {
                         }
                     }
                     if (decryptProjectPathPrefixSet.size() > 0) {
-                        if (!ifPointToDecrypt(decryptProjectPathPrefixSet, projectPath)) {
+                        if (notPointToDecrypt(projectPath, decryptProjectPathPrefixSet)) {
                             return classfileBuffer;
                         }
                     }
                     className = className.replace("/", ".").replace("\\", ".");
                     // 本项目的印章
-                    if (Cache.sealCache == null) {
+                    if (!Cache.sealCache.containsKey(projectPath)) {
                         try {
                             byte[] sealByte = IOUtil.readFileFromWorkbenchRoot(new File(projectPath), Constant.SEAL_FILE);
                             if (sealByte == null) {
@@ -160,7 +160,7 @@ public class Reverses {
                             }
                             String sealContent = new String(sealByte, StandardCharsets.UTF_8);
                             Logger.debug(Reverses.class, "seal of the project is -> " + sealContent);
-                            Cache.sealCache = sealContent;
+                            Cache.sealCache.put(projectPath, sealContent);
                         } catch (Exception e) {
                             Logger.error(Reverses.class, "Obtain project seal fail.");
                             Logger.error(Reverses.class, ExceptionUtil.getStackTraceMessage(e));
@@ -251,7 +251,7 @@ public class Reverses {
                     
                     /// ============================================ 处理class文件
                     // 判断是否应该解密
-                    if (DecryptExecutor.checklistContain(projectPath, className) && DecryptExecutor.verifySeal(classfileBuffer)) {
+                    if (DecryptExecutor.checklistContain(projectPath, className) && DecryptExecutor.verifySeal(projectPath, classfileBuffer)) {
                         //noinspection DuplicatedCode
                         try {
                             Logger.debug(Reverses.class, "Decrypt class[" + className + "] start.");
@@ -304,17 +304,17 @@ public class Reverses {
     }
     
     /**
-     * 是否指定了要试着解密projectPath指向的代码
+     * 是否不需要试着解密projectPath指向的代码
      */
-    private static boolean ifPointToDecrypt(Set<String> decryptProjectPathPrefixSet, String projectPath) {
-        boolean needTryDecrypt = false;
+    private static boolean notPointToDecrypt(String projectPath, Set<String> decryptProjectPathPrefixSet) {
+        boolean notNeedTryDecrypt = true;
         for (String decryptProjectPathPrefix : decryptProjectPathPrefixSet) {
             if (projectPath != null && projectPath.startsWith(decryptProjectPathPrefix)) {
-                needTryDecrypt = true;
+                notNeedTryDecrypt = false;
                 break;
             }
         }
-        return needTryDecrypt;
+        return notNeedTryDecrypt;
     }
     
     /**
@@ -326,7 +326,7 @@ public class Reverses {
                 Logger.error(Reverses.class, "Curr projectPath is -> " + projectPath);
             }
             TimeUnit.SECONDS.sleep(10);
-        } catch (InterruptedException interruptedException) {
+        } catch (InterruptedException ignore) {
         }
         System.exit(-1);
     }

+ 20 - 18
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/executor/DecryptExecutor.java

@@ -20,6 +20,7 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 import java.util.zip.ZipFile;
 
@@ -31,11 +32,11 @@ import java.util.zip.ZipFile;
  */
 public class DecryptExecutor {
     
-    /** 要解密的文件清单,记录已加密的class的全类名的清单文件 */
-    private static Set<String> checklist;
+    /** key- projectPath; value-要解密的文件清单,记录已加密的class的全类名的清单文件 */
+    private static Map<String, Set<String>> checklist = new ConcurrentHashMap<>(8);
     
     /**
-     * 以key-value的形式记录lib中的被混淆的类(key-被混淆的类的无后缀全类名, value-存放采集到的类所在lib的信息的文件夹)
+     * 以key-value的形式记录lib中的被混淆的类(key-被混淆的类的无后缀全类名, value-存放采集到的类所在lib的信息的文件夹)
      *
      * key   - 形如: com.abc.xyz.Qwer
      * value - 形如: META-INF/winter/abc-1.0.0_jar/
@@ -99,19 +100,18 @@ public class DecryptExecutor {
      * @return classLongName是否在(记录已加密类的)清单列表中
      */
     public static boolean checklistContain(String projectPath, String classLongName) {
-        if (checklist == null) {
+        if (!checklist.containsKey(projectPath)) {
             byte[] checklistByte = IOUtil.readFileFromWorkbenchRoot(new File(projectPath),
                     Constant.ALREADY_ENCRYPTED_CLASS_CHECKLIST_CLASSES_SAVE_FILE);
             if (checklistByte == null) {
-                checklist = new HashSet<>();
                 Logger.debug(DecryptExecutor.class, "checklistByte is null. ");
             } else {
                 String checklistContent = new String(checklistByte, StandardCharsets.UTF_8);
                 Logger.debug(DecryptExecutor.class, "checklistContent " + checklistContent);
-                checklist = new HashSet<>(Arrays.asList(checklistContent.split(Constant.COMMA)));
+                checklist.put(projectPath, new HashSet<>(Arrays.asList(checklistContent.split(Constant.COMMA))));
             }
         }
-        return checklist.contains(classLongName);
+        return checklist.get(projectPath).contains(classLongName);
     }
     
     /**
@@ -175,12 +175,16 @@ public class DecryptExecutor {
     /**
      * 判断类classBytes是否被盖章
      *
-     * @param classBytes
-     *            类的字节码
+     * @param projectPath 项目路径
+     * @param classBytes 类的字节码
      * @return classBytes中是否存在加密印章
      */
-    public static boolean verifySeal(byte[] classBytes) {
-        return new String(classBytes, StandardCharsets.UTF_8).contains(Cache.sealCache);
+    public static boolean verifySeal(String projectPath, byte[] classBytes) {
+        String seal = Cache.sealCache.get(projectPath);
+        if (StrUtil.isBlank(seal)) {
+            throw new ClassWinterException("seal should not be blank. curr projectPath -> " + projectPath + ". curr sealCache is -> " + Cache.sealCache);
+        }
+        return new String(classBytes, StandardCharsets.UTF_8).contains(seal);
     }
     
     /**
@@ -263,10 +267,8 @@ public class DecryptExecutor {
     /**
      * 恢复非class文件的混淆
      *
-     * @param zipFilePath
-     *            项目jar/war包路径
-     * @param password
-     *            项目加密密码(可能为null)
+     * @param zipFilePath 项目jar/war包路径
+     * @param password 项目加密密码(可能为null)
      * @return  被替换了的ZipEntry的相对路径及重写前后的内容信息<br/>
      *          k - ZipEntry的相对路径,如:BOOT-INF/classes/application.yml<br/>
      *          v - 左:重写前的内容,右:重写后的内容
@@ -291,7 +293,7 @@ public class DecryptExecutor {
         for (String zipEntryName : needToDecryptNonClassFileSet) {
             // 只处理有印章的
             byte[] cleanedBytes = IOUtil.readFileFromWorkbenchRoot(zipFile, zipEntryName);
-            if (DecryptExecutor.verifySeal(cleanedBytes)) {
+            if (DecryptExecutor.verifySeal(zipFilePath, cleanedBytes)) {
                 byte[] encryptedBytes = IOUtil.readFileFromWorkbenchRoot(zipFile,
                         Constant.DEFAULT_ENCRYPTED_NON_CLASSES_SAVE_DIR + zipEntryName);
                 byte[] bytes = EncryptUtil.decrypt(encryptedBytes, userIfInputPwdWhileDecrypt ? password :
@@ -329,7 +331,7 @@ public class DecryptExecutor {
             }
             // 存时,是加密存进去的; 这里读取时,解密一下
             passwordByte = EncryptUtil.decrypt(new String(passwordByte, StandardCharsets.UTF_8),
-                    Cache.sealCache.toCharArray()).getBytes(StandardCharsets.UTF_8);
+                    Cache.sealCache.get(projectPath).toCharArray()).getBytes(StandardCharsets.UTF_8);
             String password = new String(passwordByte, StandardCharsets.UTF_8);
             char[] passwordCharArr = password.toCharArray();
             // 放入缓存
@@ -348,7 +350,7 @@ public class DecryptExecutor {
             Objects.requireNonNull(passwordByte);
             // 存时,是加密存进去的; 这里读取时,解密一下
             char[] passwordCharArr = EncryptUtil.decrypt(new String(passwordByte, StandardCharsets.UTF_8),
-                    Cache.sealCache.toCharArray()).toCharArray();
+                    Cache.sealCache.get(projectPath).toCharArray()).toCharArray();
             Cache.libPasswordCache.put(classWinterInfoDir, passwordCharArr);
             return passwordCharArr;
         }

+ 4 - 4
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/Cache.java

@@ -3,8 +3,8 @@ package winter.com.ideaaedi.classwinter.util;
 import winter.com.ideaaedi.classwinter.author.JustryDeng;
 import winter.com.ideaaedi.classwinter.executor.EncryptExecutor;
 
-import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * 简单缓存
@@ -24,10 +24,10 @@ public final class Cache {
      *     <li>value-密码</li>
      * </ul>
      */
-    public static Map<String, char[]> passwordCacheForEncrypt = new HashMap<>(8);
+    public static volatile Map<String, char[]> passwordCacheForEncrypt = new ConcurrentHashMap<>(8);
     
-    /** 本项目加密时的印章 */
-    public static volatile String sealCache = null;
+    /** 本项目加密时的印章 (key-projectPath; value-印章) */
+    public static volatile Map<String, String>  sealCache =  new ConcurrentHashMap<>(8);
     
     /**
      * 以key-value的形式记录lib的印章。(key-存放采集到的类所在lib的信息的文件夹, value-印章字符串)