All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xml.guard.model.DeclarationMapping.kt Maven / Gradle / Ivy

There is a newer version: 3.0.5
Show newest version
package com.xml.guard.model

import com.github.javaparser.JavaParser
import com.github.javaparser.ast.body.EnumDeclaration
import com.github.javaparser.ast.body.FieldDeclaration
import com.github.javaparser.ast.body.MethodDeclaration
import com.github.javaparser.ast.body.VariableDeclarator
import com.xml.guard.entensions.GuardExtension
import com.xml.guard.utils.getClassPackage
import com.xml.guard.utils.getDirPath
import com.xml.guard.utils.getRandomString
import com.xml.guard.utils.inDeclarationBlackList
import com.xml.guard.utils.inPackageNameBlackList
import com.xml.guard.utils.isJava
import com.xml.guard.utils.isKt
import com.xml.guard.utils.javaDirs
import com.xml.guard.utils.lowercaseFirstChar
import com.xml.guard.utils.replaceLast
import org.gradle.api.Project
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.util.regex.Pattern

class DeclarationMapping(private val guardExtension: GuardExtension) {
    private val constValPattern by lazy { "\\s*const\\s*val\\s*(\\w*)\\s*=" }

    // 白名单
    private val declarationWhiteList by lazy { guardExtension.declarationWhiteList }

    // 静态字段
    internal val staticFieldMapping by lazy { mutableMapOf() }

    // 非静态字段
    internal val nonStaticFieldMapping by lazy { mutableMapOf() }

    // 函数名称
    internal val methodNameMapping by lazy { mutableMapOf() }

    // 函数参数
    internal val methodParameterMapping by lazy { mutableMapOf() }

    // 枚举常量
    internal val enumConstantMapping by lazy { mutableMapOf() }

    internal val allMappingMap by lazy { mutableMapOf() }

    // 寻找出所有静态字段、枚举常量名称
    fun findAllDeclaration(
        androidProjects: List,
        variantName: String
    ): Map {
        androidProjects.forEach { project ->
            project.files(project.javaDirs(variantName)).asFileTree.files.forEach asFileTree@{ file ->
                if (inClassWhiteList(project, file)) {
                    return@asFileTree
                }
                when {
                    file.isJava -> findAllDeclarationFromJava(file)
                    file.isKt -> findAllDeclarationFromKotlin(file)
                }
            }
        }
        return allMappingMap
    }

    /**
     * 将映射写入文件
     */
    fun writeMappingToFile(mappingFile: File) {
        val writer = BufferedWriter(FileWriter(mappingFile, false))

        writer.write("${MappingParser.STATIC_FIELD_MAPPING}\n")
        for ((key, value) in staticFieldMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.NON_STATIC_FIELD_MAPPING}\n")
        for ((key, value) in nonStaticFieldMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.METHOD_NAME_MAPPING}\n")
        for ((key, value) in methodNameMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.METHOD_PARAMETER_MAPPING}\n")
        for ((key, value) in methodParameterMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.ENUM_CONSTANT_MAPPING}\n")
        for ((key, value) in enumConstantMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.close()
    }

    // 白名单
    fun inClassWhiteList(project: Project, file: File): Boolean {
        val rawPackage = getClassPackage(project, file)
        val rawClassPath = "${rawPackage}.${file.nameWithoutExtension}"
        return declarationWhiteList.any {
            (it == rawClassPath
                    || it == rawClassPath.getDirPath()
                    || (it.endsWith("*") && rawClassPath.startsWith(it.replaceLast("*", ""))))
        }
    }

    // 白名单
    fun inWhiteList(rawName: String): Boolean {
        if (rawName.inPackageNameBlackList()) {
            return true
        }
        if (rawName.inDeclarationBlackList()) {
            return true
        }
        return declarationWhiteList.any { it == rawName }
    }

    // 已混淆
    fun isObfuscated(rawName: String): Boolean {
        return allMappingMap.containsKey(rawName) || allMappingMap.containsValue(rawName)
    }

    private fun findAllDeclarationFromJava(file: File) {
        val cu = JavaParser().parse(file).result.get()
        cu.findAll(FieldDeclaration::class.java).forEach findAll@{ declaration ->
            declaration.variables.forEach variables@{ variable ->
                val rawName = variable.nameAsString.trim()

                // 白名单、已混淆
                if (inWhiteList(rawName) || isObfuscated(rawName)) {
                    return@variables
                }
                if (declaration.isStatic) {
                    val newName = obfuscateName(staticFieldMapping, rawName, declaration.isFinal)
                    staticFieldMapping[rawName] = newName
                } else {
                    val newName = obfuscateName(nonStaticFieldMapping, rawName)
                    nonStaticFieldMapping[rawName] = newName
                }
            }
        }

        cu.findAll(MethodDeclaration::class.java).forEach findAll@{ declaration ->
            // 函数名称混淆
            declaration.nameAsString.trim().also { rawName ->
                // 白名单、已混淆
                if (inWhiteList(rawName) || isObfuscated(rawName)) {
                    return@also
                }
                val obfuscateName = obfuscateName(methodNameMapping, rawName)
                methodNameMapping[rawName] = obfuscateName
            }

            // 函数字段名称混淆
            declaration.parameters.forEach parameters@{ parameter ->
                val rawName = parameter.nameAsString.trim()

                // 白名单、已混淆
                if (inWhiteList(rawName) || isObfuscated(rawName)) {
                    return@parameters
                }
                val obfuscateName = obfuscateName(methodParameterMapping, rawName)
                methodParameterMapping[rawName] = obfuscateName
            }

            // 函数变量名称混淆
            declaration.findAll(VariableDeclarator::class.java).forEach variable@{ variable ->
                val rawName = variable.nameAsString.trim()

                // 白名单、已混淆
                if (inWhiteList(rawName) || isObfuscated(rawName)) {
                    return@variable
                }
                val obfuscateName = obfuscateName(methodParameterMapping, rawName)
                methodParameterMapping[rawName] = obfuscateName
            }
        }

        cu.findAll(EnumDeclaration::class.java).forEach findAll@{ declaration ->
            declaration.entries.forEach entries@{ enumConstant ->
                val rawName = enumConstant.nameAsString.trim()

                // 白名单、已混淆
                if (inWhiteList(rawName) || isObfuscated(rawName)) {
                    return@entries
                }
                val obfuscateName = obfuscateName(enumConstantMapping, rawName, isFinal = true)
                enumConstantMapping[rawName] = obfuscateName
            }
        }
    }

    private fun findAllDeclarationFromKotlin(file: File) {
        file.forEachLine { line ->
            // 正则表达式匹配字符串
            val pattern = Pattern.compile(constValPattern)
            val matcher = pattern.matcher(line)

            // 输出匹配到的字段名称
            while (matcher.find()) {
                val rawName = matcher.group(1)?.trim()

                // 白名单、已混淆
                if (rawName.isNullOrBlank()
                    || inWhiteList(rawName)
                    || isObfuscated(rawName)
                ) {
                    continue
                }
                val newName = obfuscateName(staticFieldMapping, rawName, isFinal = true)
                staticFieldMapping[rawName] = newName
            }
        }
    }

    private fun obfuscateName(
        mappingMap: MutableMap,
        rawName: String,
        isFinal: Boolean = false
    ): String {
        var obfuscateName = allMappingMap[rawName]
        if (obfuscateName == null) {
            val value = MappingParser.checkObfuscate(rawName)
            obfuscateName = value.ifBlank {
                getRandomString { text ->
                    val result = if (isFinal) text.uppercase() else text.lowercaseFirstChar()
                    MappingParser.verifyObfuscateName(result)
                }
            }
            mappingMap[rawName] = obfuscateName
            allMappingMap[rawName] = obfuscateName
        }
        return obfuscateName
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy