Skip to content

Commit 9550089

Browse files
authored
Merge pull request #30 from LeeGodSRC/addition/gradle-plugin
Initial implementation for skidfuscator gradle plugin
2 parents 291445b + 4cdced7 commit 9550089

10 files changed

Lines changed: 378 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ mappings/*
4444
*.jar
4545
**/dependency-reduced-pom.xml
4646

47-
gradle
47+
/gradle/
4848
**/build/
4949
!src/**/build/
5050

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
plugins {
2+
id 'java-gradle-plugin'
3+
id 'com.gradle.plugin-publish' version '0.14.0'
4+
}
5+
6+
group = 'dev.skidfuscator'
7+
version = '0.1'
8+
9+
gradlePlugin {
10+
plugins {
11+
skidfuscator {
12+
id = 'dev.skidfuscator'
13+
implementationClass = 'dev.skidfuscator.gradle.SkidfuscatorGradlePlugin'
14+
}
15+
}
16+
}
17+
18+
pluginBundle {
19+
tags = ['obfuscator']
20+
21+
plugins {
22+
skidfuscator {
23+
displayName = 'Skidfuscator Gradle Plugin'
24+
description = 'The skidfuscator gradle plugin that will automatically obfuscates your jar on compile.'
25+
website = 'https://github.com/terminalsin/skidfuscator-java-obfuscator'
26+
vcsUrl = 'https://github.com/terminalsin/skidfuscator-java-obfuscator'
27+
}
28+
}
29+
}
30+
31+
repositories {
32+
mavenCentral()
33+
maven { url 'https://jitpack.io' }
34+
}
35+
36+
dependencies {
37+
compileOnly gradleApi()
38+
compileOnly 'org.codehaus.groovy:groovy-all:3.0.9'
39+
40+
implementation 'commons-io:commons-io:2.11.0'
41+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package dev.skidfuscator.gradle;
2+
3+
import org.gradle.api.Action;
4+
import org.gradle.api.Task;
5+
import org.gradle.api.file.FileCollection;
6+
7+
import javax.inject.Inject;
8+
import java.io.File;
9+
import java.io.IOException;
10+
import java.lang.reflect.Constructor;
11+
import java.lang.reflect.InvocationTargetException;
12+
import java.lang.reflect.Method;
13+
import java.net.URL;
14+
import java.net.URLClassLoader;
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
18+
public class SkidfuscatorCompileAction implements Action<Task> {
19+
20+
private final SkidfuscatorSpec spec;
21+
private final SkidfuscatorRuntime runtime;
22+
23+
@Inject
24+
public SkidfuscatorCompileAction(SkidfuscatorSpec spec, SkidfuscatorRuntime runtime) {
25+
this.spec = spec;
26+
this.runtime = runtime;
27+
}
28+
29+
@Override
30+
public void execute(Task task) {
31+
try {
32+
this.executeObfuscator();
33+
} catch (Throwable throwable) {
34+
throw new IllegalStateException("Failed to compile with skidfuscator", throwable);
35+
}
36+
}
37+
38+
private void executeObfuscator() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
39+
FileCollection fileCollection = runtime.fetchClasspath();
40+
List<URL> urls = new ArrayList<>();
41+
for (File file : fileCollection)
42+
urls.add(file.toURI().toURL());
43+
44+
try (URLClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[0]))) {
45+
Class<?> sessionClass = classLoader.loadClass("dev.skidfuscator.obfuscator.SkidfuscatorSession");
46+
Class<?> obfuscatorClass = classLoader.loadClass("dev.skidfuscator.obfuscator.Skidfuscator");
47+
Object session = this.buildSkidfuscatorSession(sessionClass);
48+
Object obfuscator = obfuscatorClass.getDeclaredConstructor(sessionClass).newInstance(session);
49+
50+
this.addToExemptAnalysis(obfuscator);
51+
52+
// run obfuscator!
53+
Method run = obfuscator.getClass().getMethod("run");
54+
run.invoke(obfuscator);
55+
}
56+
}
57+
58+
private void addToExemptAnalysis(Object obfuscator) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
59+
Class<?> obfuscatorClass = obfuscator.getClass();
60+
Method getExemptAnalysis = obfuscatorClass.getMethod("getExemptAnalysis");
61+
Object exemptAnalysis = getExemptAnalysis.invoke(obfuscator);
62+
63+
Method method = exemptAnalysis.getClass().getMethod("add", String.class);
64+
for (String exclude : this.spec.getExcludes())
65+
method.invoke(exemptAnalysis, exclude);
66+
}
67+
68+
private Object buildSkidfuscatorSession(Class<?> aClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
69+
Constructor<?> constructor = aClass.getDeclaredConstructor(
70+
File.class, // input
71+
File.class, // output
72+
File[].class, // libs
73+
File.class, // mappings
74+
File.class, // exempt
75+
File.class, // runtime
76+
boolean.class, // phantom
77+
boolean.class, // jmod
78+
boolean.class, // fuckit
79+
boolean.class // analytics
80+
);
81+
return constructor.newInstance(
82+
spec.getInput(), spec.getOutput(), spec.getLibs(), spec.getMappings(), spec.getExempt(), spec.getRuntime(),
83+
spec.isPhantom(), spec.isJmod(), spec.isFuckit(), spec.isAnalytics());
84+
}
85+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package dev.skidfuscator.gradle;
2+
3+
import lombok.Getter;
4+
import org.gradle.api.file.RegularFileProperty;
5+
import org.gradle.api.model.ObjectFactory;
6+
import org.gradle.api.provider.ListProperty;
7+
import org.gradle.api.provider.Property;
8+
9+
import javax.inject.Inject;
10+
11+
@Getter
12+
public class SkidfuscatorExtension {
13+
14+
private final Property<String> version;
15+
private final Property<Boolean> phantom;
16+
private final Property<Boolean> notrack;
17+
private final Property<Boolean> fuckit;
18+
private final Property<String> classifier;
19+
private final ListProperty<String> excludes;
20+
private final RegularFileProperty runtime;
21+
private final RegularFileProperty exemptionFile;
22+
23+
@Inject
24+
public SkidfuscatorExtension(ObjectFactory objectFactory) {
25+
this.version = objectFactory.property(String.class).convention("2.0.0-SNAPSHOT"); // automatically fetching?
26+
this.phantom = objectFactory.property(Boolean.class).convention(false);
27+
this.notrack = objectFactory.property(Boolean.class).convention(false);
28+
this.fuckit = objectFactory.property(Boolean.class).convention(false);
29+
this.runtime = objectFactory.fileProperty();
30+
this.classifier = objectFactory.property(String.class).convention("-obfuscated");
31+
this.excludes = objectFactory.listProperty(String.class).empty();
32+
this.exemptionFile = objectFactory.fileProperty();
33+
}
34+
35+
public void exclude(String... exludes) {
36+
this.excludes.addAll(exludes);
37+
}
38+
39+
public void phantom() {
40+
this.phantom.set(true);
41+
}
42+
43+
public void notrack() {
44+
this.notrack.set(true);
45+
}
46+
47+
public void fuckit() {
48+
this.fuckit.set(true);
49+
}
50+
51+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package dev.skidfuscator.gradle;
2+
3+
import dev.skidfuscator.gradle.util.MiscUtil;
4+
import org.apache.commons.io.FilenameUtils;
5+
import org.gradle.api.Plugin;
6+
import org.gradle.api.Project;
7+
import org.gradle.api.plugins.GroovyPlugin;
8+
import org.gradle.api.plugins.JavaPlugin;
9+
import org.gradle.api.plugins.JavaPluginExtension;
10+
import org.gradle.api.plugins.scala.ScalaPlugin;
11+
import org.gradle.api.tasks.SourceSetContainer;
12+
import org.gradle.api.tasks.compile.AbstractCompile;
13+
import org.gradle.jvm.tasks.Jar;
14+
15+
import java.io.File;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
19+
public class SkidfuscatorGradlePlugin implements Plugin<Project> {
20+
21+
private List<File> classpath;
22+
private SourceSetContainer sourceSets;
23+
private int jvm;
24+
25+
@Override
26+
public void apply(Project project) {
27+
SkidfuscatorExtension extension = project.getExtensions().create("skidfuscator", SkidfuscatorExtension.class);
28+
29+
this.sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets();
30+
this.classpath = new ArrayList<>();
31+
this.jvm = 8;
32+
project.afterEvaluate(p -> this.handle(p, extension));
33+
}
34+
35+
private void handle(Project project, SkidfuscatorExtension extension) {
36+
// read jvm and classpath information directly from language's compile task
37+
project.getPlugins().withType(JavaPlugin.class, plugin -> this.handlePlugin(project, "java"));
38+
project.getPlugins().withType(GroovyPlugin.class, plugin -> this.handlePlugin(project, "groovy"));
39+
project.getPlugins().withType(ScalaPlugin.class, plugin -> this.handlePlugin(project, "scala"));
40+
project.getPlugins().withId("org.jetbrains.kotlin.jvm", plugin -> this.handlePlugin(project, "kotlin"));
41+
// compute session and obfuscate right after jar task
42+
project.getTasks().withType(Jar.class, jar -> {
43+
final String home = System.getProperty("java.home");
44+
final File javaRuntime;
45+
final File exemption;
46+
47+
if (extension.getRuntime().isPresent()) {
48+
javaRuntime = extension.getRuntime().get().getAsFile();
49+
} else {
50+
javaRuntime = new File(
51+
home,
52+
MiscUtil.getJavaVersion() > 8
53+
? "jmods"
54+
: "lib/rt.jar"
55+
);
56+
}
57+
58+
if (extension.getExemptionFile().isPresent()) {
59+
exemption = extension.getExemptionFile().get().getAsFile();
60+
} else {
61+
exemption = null;
62+
}
63+
64+
File input = jar.getArchiveFile().get().getAsFile();
65+
File directory = input.getParentFile();
66+
67+
File output = new File(directory, FilenameUtils.getName(input.getName()) + extension.getClassifier().get() + FilenameUtils.getExtension(input.getName()));
68+
SkidfuscatorSpec spec = SkidfuscatorSpec.builder()
69+
.input(input)
70+
.output(output)
71+
.fuckit(extension.getFuckit().get())
72+
.phantom(extension.getPhantom().get())
73+
.analytics(!extension.getNotrack().get())
74+
.runtime(javaRuntime)
75+
.exempt(exemption)
76+
.jmod(this.jvm > 8)
77+
.libs(this.classpath.toArray(new File[0]))
78+
.excludes(extension.getExcludes().getOrNull())
79+
.build();
80+
SkidfuscatorRuntime runtime = new SkidfuscatorRuntime(project, extension.getVersion().get());
81+
SkidfuscatorCompileAction action = project.getObjects().newInstance(
82+
SkidfuscatorCompileAction.class,
83+
spec,
84+
runtime
85+
);
86+
87+
jar.doLast("skidfuscator", action);
88+
});
89+
}
90+
91+
private void handlePlugin(Project project, String language) {
92+
sourceSets.all(sourceSet -> {
93+
project.getTasks().named(sourceSet.getCompileTaskName(language), AbstractCompile.class, compile -> {
94+
this.jvm = MiscUtil.decodeJvmVersion(compile.getTargetCompatibility());
95+
this.classpath.addAll(compile.getClasspath().getFiles());
96+
});
97+
});
98+
}
99+
100+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package dev.skidfuscator.gradle;
2+
3+
import org.gradle.api.Project;
4+
import org.gradle.api.artifacts.Configuration;
5+
import org.gradle.api.artifacts.Dependency;
6+
import org.gradle.api.file.FileCollection;
7+
import org.gradle.api.internal.file.collections.LazilyInitializedFileCollection;
8+
import org.gradle.api.internal.project.ProjectInternal;
9+
import org.gradle.api.plugins.jvm.internal.JvmEcosystemUtilities;
10+
11+
public class SkidfuscatorRuntime {
12+
13+
private static final String NOTATION = "dev.skidfuscator.community:obfuscator:%s";
14+
15+
private final ProjectInternal project;
16+
private final String version;
17+
18+
public SkidfuscatorRuntime(Project project, String version) {
19+
this.project = (ProjectInternal) project;
20+
this.version = version;
21+
}
22+
23+
public FileCollection fetchClasspath() {
24+
return new LazilyInitializedFileCollection() {
25+
@Override
26+
public String getDisplayName() {
27+
return "Skidobfuscator runtime classpath";
28+
}
29+
30+
@Override
31+
public FileCollection createDelegate() {
32+
Dependency dependency = project.getDependencies().create(String.format(NOTATION, version));
33+
34+
return detachedRuntimeClasspath(dependency);
35+
}
36+
37+
private Configuration detachedRuntimeClasspath(Dependency... dependencies) {
38+
Configuration classpath = project.getConfigurations().detachedConfiguration(dependencies);
39+
jvmEcosystemUtilities().configureAsRuntimeClasspath(classpath);
40+
return classpath;
41+
}
42+
};
43+
}
44+
45+
private JvmEcosystemUtilities jvmEcosystemUtilities() {
46+
return project.getServices().get(JvmEcosystemUtilities.class);
47+
}
48+
49+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dev.skidfuscator.gradle;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
6+
import java.io.File;
7+
import java.util.List;
8+
9+
@Builder
10+
@Getter
11+
public class SkidfuscatorSpec {
12+
private File input;
13+
private File output;
14+
private File[] libs;
15+
private File mappings;
16+
private File exempt;
17+
private File runtime;
18+
private List<String> excludes;
19+
private boolean phantom;
20+
private boolean jmod;
21+
private boolean fuckit;
22+
private boolean analytics;
23+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package dev.skidfuscator.gradle.util;
2+
3+
import lombok.experimental.UtilityClass;
4+
5+
@UtilityClass
6+
public class MiscUtil {
7+
8+
public int getJavaVersion() {
9+
String version = System.getProperty("java.version");
10+
return decodeJvmVersion(version);
11+
}
12+
13+
public int decodeJvmVersion(String version) {
14+
if(version.startsWith("1.")) {
15+
version = version.substring(2, 3);
16+
} else {
17+
int dot = version.indexOf(".");
18+
if(dot != -1) { version = version.substring(0, dot); }
19+
} return Integer.parseInt(version);
20+
}
21+
22+
}

dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/MiscUtil.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public String replaceColor(final String string, final String replace, final Stri
3838

3939
public int getJavaVersion() {
4040
String version = System.getProperty("java.version");
41+
return decodeJvmVersion(version);
42+
}
43+
44+
public int decodeJvmVersion(String version) {
4145
if(version.startsWith("1.")) {
4246
version = version.substring(2, 3);
4347
} else {

0 commit comments

Comments
 (0)