mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-03-31 21:44:04 +03:00
[FEATURE] Новое API сборки лаунчера
This commit is contained in:
parent
4260199de7
commit
93436de104
6 changed files with 189 additions and 200 deletions
|
@ -18,7 +18,6 @@
|
||||||
import pro.gravit.launchserver.manangers.ReconfigurableManager;
|
import pro.gravit.launchserver.manangers.ReconfigurableManager;
|
||||||
import pro.gravit.launchserver.manangers.SessionManager;
|
import pro.gravit.launchserver.manangers.SessionManager;
|
||||||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||||
import pro.gravit.launchserver.manangers.hook.BuildHookManager;
|
|
||||||
import pro.gravit.launchserver.modules.events.LaunchServerFullInitEvent;
|
import pro.gravit.launchserver.modules.events.LaunchServerFullInitEvent;
|
||||||
import pro.gravit.launchserver.modules.events.LaunchServerInitPhase;
|
import pro.gravit.launchserver.modules.events.LaunchServerInitPhase;
|
||||||
import pro.gravit.launchserver.modules.events.LaunchServerPostInitPhase;
|
import pro.gravit.launchserver.modules.events.LaunchServerPostInitPhase;
|
||||||
|
@ -226,9 +225,6 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
|
||||||
|
|
||||||
public final CertificateManager certificateManager;
|
public final CertificateManager certificateManager;
|
||||||
|
|
||||||
|
|
||||||
public final BuildHookManager buildHookManager;
|
|
||||||
|
|
||||||
public final ProguardConf proguardConf;
|
public final ProguardConf proguardConf;
|
||||||
|
|
||||||
|
|
||||||
|
@ -310,7 +306,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
}
|
}
|
||||||
|
|
||||||
// build hooks, anti-brutforce and other
|
// build hooks, anti-brutforce and other
|
||||||
buildHookManager = new BuildHookManager();
|
|
||||||
proguardConf = new ProguardConf(this);
|
proguardConf = new ProguardConf(this);
|
||||||
sessionManager = new SessionManager();
|
sessionManager = new SessionManager();
|
||||||
mirrorManager = new MirrorManager();
|
mirrorManager = new MirrorManager();
|
||||||
|
|
|
@ -1,28 +1,91 @@
|
||||||
package pro.gravit.launchserver.binary;
|
package pro.gravit.launchserver.binary;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.Launcher;
|
||||||
|
import pro.gravit.launcher.serialize.HOutput;
|
||||||
|
import pro.gravit.launcher.serialize.stream.StreamObject;
|
||||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
import pro.gravit.utils.helper.JarHelper;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipException;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import static pro.gravit.utils.helper.IOHelper.UNICODE_CHARSET;
|
||||||
|
import static pro.gravit.utils.helper.IOHelper.newZipEntry;
|
||||||
|
|
||||||
public class BuildContext {
|
public class BuildContext {
|
||||||
public final ZipOutputStream output;
|
public final ZipOutputStream output;
|
||||||
public final LauncherConfigurator config;
|
public final LauncherConfigurator config;
|
||||||
public final MainBuildTask data;
|
public final List<JarFile> readerClassPath;
|
||||||
|
public final MainBuildTask task;
|
||||||
public final HashSet<String> fileList;
|
public final HashSet<String> fileList;
|
||||||
|
public final HashSet<String> clientModules;
|
||||||
|
|
||||||
|
private final static class RuntimeDirVisitor extends SimpleFileVisitor<Path> {
|
||||||
|
private final ZipOutputStream output;
|
||||||
|
private final Map<String, byte[]> hashs;
|
||||||
|
private final Path sourceDir;
|
||||||
|
private final String targetDir;
|
||||||
|
|
||||||
|
private RuntimeDirVisitor(ZipOutputStream output, Map<String, byte[]> hashs, Path sourceDir, String targetDir) {
|
||||||
|
this.output = output;
|
||||||
|
this.hashs = hashs;
|
||||||
|
this.sourceDir = sourceDir;
|
||||||
|
this.targetDir = targetDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||||
|
String dirName = IOHelper.toString(sourceDir.relativize(dir));
|
||||||
|
output.putNextEntry(newEntry(dirName + '/'));
|
||||||
|
return super.preVisitDirectory(dir, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
String fileName = IOHelper.toString(sourceDir.relativize(file));
|
||||||
|
if(hashs != null)
|
||||||
|
hashs.put(fileName, SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, file));
|
||||||
|
|
||||||
|
// Create zip entry and transfer contents
|
||||||
|
output.putNextEntry(newEntry(fileName));
|
||||||
|
IOHelper.transfer(file, output);
|
||||||
|
|
||||||
|
// Return result
|
||||||
|
return super.visitFile(file, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZipEntry newEntry(String fileName) {
|
||||||
|
return newZipEntry( targetDir + IOHelper.CROSS_SEPARATOR + fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public BuildContext(ZipOutputStream output, LauncherConfigurator config, MainBuildTask data) {
|
public BuildContext(ZipOutputStream output, LauncherConfigurator config, List<JarFile> readerClassPath, MainBuildTask task) {
|
||||||
this.output = output;
|
this.output = output;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.data = data;
|
this.readerClassPath = readerClassPath;
|
||||||
|
this.task = task;
|
||||||
fileList = new HashSet<>(1024);
|
fileList = new HashSet<>(1024);
|
||||||
|
clientModules = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushFile(String filename, InputStream inputStream) throws IOException {
|
public void pushFile(String filename, InputStream inputStream) throws IOException {
|
||||||
|
@ -32,6 +95,26 @@ public void pushFile(String filename, InputStream inputStream) throws IOExceptio
|
||||||
output.closeEntry();
|
output.closeEntry();
|
||||||
fileList.add(filename);
|
fileList.add(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pushFile(String filename, StreamObject object) throws IOException
|
||||||
|
{
|
||||||
|
ZipEntry zip = IOHelper.newZipEntry(filename);
|
||||||
|
output.putNextEntry(zip);
|
||||||
|
object.write(new HOutput(output));
|
||||||
|
output.closeEntry();
|
||||||
|
fileList.add(filename);
|
||||||
|
}
|
||||||
|
public void pushFile(String filename, Object object, Type type) throws IOException
|
||||||
|
{
|
||||||
|
String bytes = Launcher.gsonManager.gson.toJson(object, type);
|
||||||
|
pushBytes(filename, bytes.getBytes(UNICODE_CHARSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushDir(Path dir, String targetDir, Map<String, byte[]> hashMap, boolean hidden) throws IOException
|
||||||
|
{
|
||||||
|
IOHelper.walk(dir, new RuntimeDirVisitor(output, hashMap, dir, targetDir), hidden);
|
||||||
|
}
|
||||||
|
|
||||||
public void pushBytes(String filename, byte[] bytes) throws IOException {
|
public void pushBytes(String filename, byte[] bytes) throws IOException {
|
||||||
ZipEntry zip = IOHelper.newZipEntry(filename);
|
ZipEntry zip = IOHelper.newZipEntry(filename);
|
||||||
output.putNextEntry(zip);
|
output.putNextEntry(zip);
|
||||||
|
@ -39,7 +122,7 @@ public void pushBytes(String filename, byte[] bytes) throws IOException {
|
||||||
output.closeEntry();
|
output.closeEntry();
|
||||||
fileList.add(filename);
|
fileList.add(filename);
|
||||||
}
|
}
|
||||||
|
@Deprecated
|
||||||
public void pushJarFile(ZipInputStream input) throws IOException {
|
public void pushJarFile(ZipInputStream input) throws IOException {
|
||||||
ZipEntry e = input.getNextEntry();
|
ZipEntry e = input.getNextEntry();
|
||||||
while (e != null) {
|
while (e != null) {
|
||||||
|
@ -53,7 +136,7 @@ public void pushJarFile(ZipInputStream input) throws IOException {
|
||||||
e = input.getNextEntry();
|
e = input.getNextEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Deprecated
|
||||||
public void pushJarFile(ZipInputStream input, Set<String> blacklist) throws IOException {
|
public void pushJarFile(ZipInputStream input, Set<String> blacklist) throws IOException {
|
||||||
ZipEntry e = input.getNextEntry();
|
ZipEntry e = input.getNextEntry();
|
||||||
while (e != null) {
|
while (e != null) {
|
||||||
|
@ -67,4 +150,47 @@ public void pushJarFile(ZipInputStream input, Set<String> blacklist) throws IOEx
|
||||||
e = input.getNextEntry();
|
e = input.getNextEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void pushJarFile(Path jarfile, Predicate<ZipEntry> filter, Predicate<String> needTransform) throws IOException
|
||||||
|
{
|
||||||
|
pushJarFile(jarfile.toUri().toURL(), filter, needTransform);
|
||||||
|
}
|
||||||
|
public void pushJarFile(URL jarfile, Predicate<ZipEntry> filter, Predicate<String> needTransform) throws IOException
|
||||||
|
{
|
||||||
|
try (ZipInputStream input = new ZipInputStream(IOHelper.newInput(jarfile))) {
|
||||||
|
ZipEntry e = input.getNextEntry();
|
||||||
|
while(e != null)
|
||||||
|
{
|
||||||
|
String filename = e.getName();
|
||||||
|
if(e.isDirectory() || fileList.contains(filename) || filter.test(e))
|
||||||
|
{
|
||||||
|
e = input.getNextEntry();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
output.putNextEntry(IOHelper.newZipEntry(e));
|
||||||
|
} catch (ZipException ex) {
|
||||||
|
LogHelper.warning("Write %s failed: %s", filename, ex.getMessage() == null ? "null" : ex.getMessage());
|
||||||
|
e = input.getNextEntry();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (filename.endsWith(".class")) {
|
||||||
|
String classname = filename.replace('/', '.').substring(0,
|
||||||
|
filename.length() - ".class".length());
|
||||||
|
if(!needTransform.test(classname))
|
||||||
|
{
|
||||||
|
IOHelper.transfer(input, output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] bytes = IOHelper.read(input);
|
||||||
|
bytes = task.transformClass(bytes, classname, this);
|
||||||
|
output.write(bytes);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
IOHelper.transfer(input, output);
|
||||||
|
fileList.add(filename);
|
||||||
|
e = input.getNextEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,23 +9,20 @@
|
||||||
import pro.gravit.launcher.Launcher;
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launcher.LauncherConfig;
|
import pro.gravit.launcher.LauncherConfig;
|
||||||
import pro.gravit.launcher.SecureAutogenConfig;
|
import pro.gravit.launcher.SecureAutogenConfig;
|
||||||
import pro.gravit.launcher.serialize.HOutput;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.asm.ClassMetadataReader;
|
import pro.gravit.launchserver.asm.ClassMetadataReader;
|
||||||
import pro.gravit.launchserver.asm.ConfigGenerator;
|
import pro.gravit.launchserver.asm.ConfigGenerator;
|
||||||
import pro.gravit.launchserver.binary.BuildContext;
|
import pro.gravit.launchserver.binary.BuildContext;
|
||||||
import pro.gravit.launchserver.binary.LauncherConfigurator;
|
import pro.gravit.launchserver.binary.LauncherConfigurator;
|
||||||
|
import pro.gravit.utils.HookException;
|
||||||
|
import pro.gravit.utils.HookSet;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.JarHelper;
|
import pro.gravit.utils.helper.JarHelper;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileVisitResult;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.SimpleFileVisitor;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
@ -44,6 +41,38 @@ public class MainBuildTask implements LauncherBuildTask {
|
||||||
public interface Transformer {
|
public interface Transformer {
|
||||||
byte[] transform(byte[] input, String classname, BuildContext context);
|
byte[] transform(byte[] input, String classname, BuildContext context);
|
||||||
}
|
}
|
||||||
|
public static class IOHookSet<R> {
|
||||||
|
public final Set<IOHook<R>> list = new HashSet<>();
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IOHook<R> {
|
||||||
|
/**
|
||||||
|
* @param context custom param
|
||||||
|
* False to continue processing hook
|
||||||
|
* @throws HookException The hook may return the error text throwing this exception
|
||||||
|
*/
|
||||||
|
void hook(R context) throws HookException, IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerHook(IOHook<R> hook) {
|
||||||
|
list.add(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean unregisterHook(IOHook<R> hook) {
|
||||||
|
return list.remove(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context custom param
|
||||||
|
* False to continue
|
||||||
|
* @throws HookException The hook may return the error text throwing this exception
|
||||||
|
*/
|
||||||
|
public void hook(R context) throws HookException, IOException {
|
||||||
|
for (IOHook<R> hook : list) {
|
||||||
|
hook.hook(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface ASMTransformer extends Transformer {
|
public interface ASMTransformer extends Transformer {
|
||||||
default byte[] transform(byte[] input, String classname, BuildContext context)
|
default byte[] transform(byte[] input, String classname, BuildContext context)
|
||||||
|
@ -89,46 +118,10 @@ public void transform(ClassNode cn, String classname, BuildContext context) {
|
||||||
}
|
}
|
||||||
abstract public void transformField(AnnotationNode an, FieldNode fn, ClassNode cn, String classname, BuildContext context);
|
abstract public void transformField(AnnotationNode an, FieldNode fn, ClassNode cn, String classname, BuildContext context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static class RuntimeDirVisitor extends SimpleFileVisitor<Path> {
|
|
||||||
private final ZipOutputStream output;
|
|
||||||
private final Map<String, byte[]> hashs;
|
|
||||||
private final Path sourceDir;
|
|
||||||
private final String targetDir;
|
|
||||||
|
|
||||||
private RuntimeDirVisitor(ZipOutputStream output, Map<String, byte[]> hashs, Path sourceDir, String targetDir) {
|
|
||||||
this.output = output;
|
|
||||||
this.hashs = hashs;
|
|
||||||
this.sourceDir = sourceDir;
|
|
||||||
this.targetDir = targetDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
|
||||||
String dirName = IOHelper.toString(sourceDir.relativize(dir));
|
|
||||||
output.putNextEntry(newEntry(dirName + '/'));
|
|
||||||
return super.preVisitDirectory(dir, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
||||||
String fileName = IOHelper.toString(sourceDir.relativize(file));
|
|
||||||
hashs.put(fileName, SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, file));
|
|
||||||
|
|
||||||
// Create zip entry and transfer contents
|
|
||||||
output.putNextEntry(newEntry(fileName));
|
|
||||||
IOHelper.transfer(file, output);
|
|
||||||
|
|
||||||
// Return result
|
|
||||||
return super.visitFile(file, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ZipEntry newEntry(String fileName) {
|
|
||||||
return newZipEntry( targetDir + IOHelper.CROSS_SEPARATOR + fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Set<String> blacklist = new HashSet<>();
|
public Set<String> blacklist = new HashSet<>();
|
||||||
public List<Transformer> transformers = new ArrayList<>();
|
public List<Transformer> transformers = new ArrayList<>();
|
||||||
|
public IOHookSet<BuildContext> preBuildHook = new IOHookSet<>();
|
||||||
|
public IOHookSet<BuildContext> postBuildHook = new IOHookSet<>();
|
||||||
|
|
||||||
public MainBuildTask(LaunchServer srv) {
|
public MainBuildTask(LaunchServer srv) {
|
||||||
server = srv;
|
server = srv;
|
||||||
|
@ -150,8 +143,8 @@ public Path process(Path inputJar) throws IOException {
|
||||||
ClassNode cn1 = new ClassNode();
|
ClassNode cn1 = new ClassNode();
|
||||||
new ClassReader(JarHelper.getClassBytes(SecureAutogenConfig.class)).accept(cn1, 0);
|
new ClassReader(JarHelper.getClassBytes(SecureAutogenConfig.class)).accept(cn1, 0);
|
||||||
ConfigGenerator secureConfigurator = new ConfigGenerator(cn1);
|
ConfigGenerator secureConfigurator = new ConfigGenerator(cn1);
|
||||||
BuildContext context = new BuildContext(output, launcherConfigurator, this);
|
BuildContext context = new BuildContext(output, launcherConfigurator, reader.getCp(), this);
|
||||||
server.buildHookManager.hook(context);
|
preBuildHook.hook(context);
|
||||||
launcherConfigurator.setStringField("address", server.config.netty.address);
|
launcherConfigurator.setStringField("address", server.config.netty.address);
|
||||||
launcherConfigurator.setStringField("projectname", server.config.projectName);
|
launcherConfigurator.setStringField("projectname", server.config.projectName);
|
||||||
launcherConfigurator.setStringField("secretKeyClient", SecurityHelper.randomStringAESKey());
|
launcherConfigurator.setStringField("secretKeyClient", SecurityHelper.randomStringAESKey());
|
||||||
|
@ -186,7 +179,7 @@ public Path process(Path inputJar) throws IOException {
|
||||||
//LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash));
|
//LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash));
|
||||||
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
|
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
|
||||||
launcherConfigurator.setStringField("oemUnlockKey", server.runtime.oemUnlockKey);
|
launcherConfigurator.setStringField("oemUnlockKey", server.runtime.oemUnlockKey);
|
||||||
server.buildHookManager.registerAllClientModuleClass(launcherConfigurator);
|
context.clientModules.forEach(launcherConfigurator::addModuleClass);
|
||||||
reader.getCp().add(new JarFile(inputJar.toFile()));
|
reader.getCp().add(new JarFile(inputJar.toFile()));
|
||||||
server.launcherBinary.coreLibs.forEach(e -> {
|
server.launcherBinary.coreLibs.forEach(e -> {
|
||||||
try {
|
try {
|
||||||
|
@ -197,54 +190,18 @@ public Path process(Path inputJar) throws IOException {
|
||||||
});
|
});
|
||||||
context.pushBytes(launcherConfigurator.getZipEntryPath(), launcherConfigurator.getBytecode(reader));
|
context.pushBytes(launcherConfigurator.getZipEntryPath(), launcherConfigurator.getBytecode(reader));
|
||||||
context.pushBytes(secureConfigurator.getZipEntryPath(), secureConfigurator.getBytecode(reader));
|
context.pushBytes(secureConfigurator.getZipEntryPath(), secureConfigurator.getBytecode(reader));
|
||||||
try (ZipInputStream input = new ZipInputStream(IOHelper.newInput(inputJar))) {
|
|
||||||
ZipEntry e = input.getNextEntry();
|
context.pushJarFile(inputJar, (e) -> blacklist.contains(e.getName()), (e) -> true);
|
||||||
while (e != null) {
|
|
||||||
String filename = e.getName();
|
|
||||||
if (e.isDirectory() || blacklist.contains(filename) || context.fileList.contains(filename)) {
|
|
||||||
e = input.getNextEntry();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
output.putNextEntry(IOHelper.newZipEntry(e));
|
|
||||||
} catch (ZipException ex) {
|
|
||||||
LogHelper.error(ex);
|
|
||||||
e = input.getNextEntry();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (filename.endsWith(".class")) {
|
|
||||||
String classname = filename.replace('/', '.').substring(0,
|
|
||||||
filename.length() - ".class".length());
|
|
||||||
byte[] bytes = IOHelper.read(input);
|
|
||||||
bytes = transformClass(bytes, classname, context);
|
|
||||||
output.write(bytes);
|
|
||||||
} else
|
|
||||||
IOHelper.transfer(input, output);
|
|
||||||
context.fileList.add(filename);
|
|
||||||
e = input.getNextEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// map for guard
|
// map for guard
|
||||||
Map<String, byte[]> runtime = new HashMap<>(256);
|
Map<String, byte[]> runtime = new HashMap<>(256);
|
||||||
if (server.buildHookManager.buildRuntime()) {
|
|
||||||
// Write launcher guard dir
|
// Write launcher guard dir
|
||||||
IOHelper.walk(server.launcherBinary.runtimeDir, new RuntimeDirVisitor(output, runtime, server.launcherBinary.runtimeDir, "runtime"), false);
|
context.pushDir(server.launcherBinary.runtimeDir, Launcher.RUNTIME_DIR, runtime, false);
|
||||||
IOHelper.walk(server.launcherBinary.guardDir, new RuntimeDirVisitor(output, runtime, server.launcherBinary.guardDir, "guard"), false);
|
context.pushDir(server.launcherBinary.guardDir, Launcher.GUARD_DIR, runtime, false);
|
||||||
}
|
|
||||||
// Create launcher config file
|
|
||||||
byte[] launcherConfigBytes;
|
|
||||||
try (ByteArrayOutputStream configArray = IOHelper.newByteArrayOutput()) {
|
|
||||||
try (HOutput configOutput = new HOutput(configArray)) {
|
|
||||||
new LauncherConfig(server.config.netty.address, server.publicKey, runtime, server.config.projectName)
|
|
||||||
.write(configOutput);
|
|
||||||
}
|
|
||||||
launcherConfigBytes = configArray.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write launcher config file
|
LauncherConfig launcherConfig = new LauncherConfig(server.config.netty.address, server.publicKey, runtime, server.config.projectName);
|
||||||
output.putNextEntry(newZipEntry(Launcher.CONFIG_FILE));
|
context.pushFile(Launcher.CONFIG_FILE, launcherConfig);
|
||||||
output.write(launcherConfigBytes);
|
postBuildHook.hook(context);
|
||||||
}
|
}
|
||||||
reader.close();
|
reader.close();
|
||||||
return outputJar;
|
return outputJar;
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
package pro.gravit.launchserver.manangers.hook;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.AutogenConfig;
|
|
||||||
import pro.gravit.launchserver.binary.BuildContext;
|
|
||||||
import pro.gravit.launchserver.binary.LauncherConfigurator;
|
|
||||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class BuildHookManager {
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface BuildHook {
|
|
||||||
void build(BuildContext context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Transformer {
|
|
||||||
byte[] transform(byte[] input, String classname, MainBuildTask data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean BUILDRUNTIME;
|
|
||||||
private final Set<BuildHook> HOOKS;
|
|
||||||
private final Set<Transformer> CLASS_TRANSFORMER;
|
|
||||||
private final Set<String> CLASS_BLACKLIST;
|
|
||||||
private final Set<String> MODULE_CLASS;
|
|
||||||
|
|
||||||
public BuildHookManager() {
|
|
||||||
HOOKS = new HashSet<>(4);
|
|
||||||
CLASS_BLACKLIST = new HashSet<>(4);
|
|
||||||
MODULE_CLASS = new HashSet<>(4);
|
|
||||||
CLASS_TRANSFORMER = new HashSet<>(4);
|
|
||||||
BUILDRUNTIME = true;
|
|
||||||
autoRegisterIgnoredClass(AutogenConfig.class.getName());
|
|
||||||
registerIgnoredClass("META-INF/DEPENDENCIES");
|
|
||||||
registerIgnoredClass("META-INF/LICENSE");
|
|
||||||
registerIgnoredClass("META-INF/NOTICE");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void autoRegisterIgnoredClass(String clazz) {
|
|
||||||
CLASS_BLACKLIST.add(clazz.replace('.', '/').concat(".class"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean buildRuntime() {
|
|
||||||
return BUILDRUNTIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] classTransform(byte[] clazz, String classname, MainBuildTask reader) {
|
|
||||||
byte[] result = clazz;
|
|
||||||
for (Transformer transformer : CLASS_TRANSFORMER) result = transformer.transform(result, classname, reader);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isContainsBlacklist(String clazz) {
|
|
||||||
for (String classB : CLASS_BLACKLIST) {
|
|
||||||
if (clazz.startsWith(classB)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void hook(BuildContext context) {
|
|
||||||
for (BuildHook hook : HOOKS) hook.build(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerAllClientModuleClass(LauncherConfigurator cfg) {
|
|
||||||
for (String clazz : MODULE_CLASS) cfg.addModuleClass(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerClassTransformer(Transformer transformer) {
|
|
||||||
CLASS_TRANSFORMER.add(transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerClientModuleClass(String clazz) {
|
|
||||||
MODULE_CLASS.add(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterClientModuleClass(String clazz) {
|
|
||||||
MODULE_CLASS.remove(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearClientModuleClassList() {
|
|
||||||
MODULE_CLASS.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerIgnoredClass(String clazz) {
|
|
||||||
CLASS_BLACKLIST.add(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerHook(BuildHook hook) {
|
|
||||||
HOOKS.add(hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBuildRuntime(boolean runtime) {
|
|
||||||
BUILDRUNTIME = runtime;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,6 +29,16 @@ default void saveConfig(Gson gson, Path configPath) throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default String toJsonString(Gson gson)
|
||||||
|
{
|
||||||
|
return gson.toJson(getConfig(), getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
default String toJsonString()
|
||||||
|
{
|
||||||
|
return toJsonString(Launcher.gsonManager.configGson);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
default void loadConfig(Gson gson, Path configPath) throws IOException {
|
default void loadConfig(Gson gson, Path configPath) throws IOException {
|
||||||
if (generateConfigIfNotExists(configPath)) return;
|
if (generateConfigIfNotExists(configPath)) return;
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit 9cb09c549abea86348597137e05a0ec29bc36b62
|
Subproject commit 5f6dc8312dcb91b92ee96040830a914d6038773d
|
Loading…
Reference in a new issue