mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 11:39:11 +03:00
Merge pull request #355 from GravitLauncher/feature/newProp
[FEATURE] Переход на новое API хранения данных на уровне байткода.
This commit is contained in:
commit
63ea1f59b0
16 changed files with 150 additions and 309 deletions
|
@ -1,84 +0,0 @@
|
||||||
package pro.gravit.launchserver.asm;
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
import org.objectweb.asm.tree.*;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ConfigGenerator {
|
|
||||||
protected static final String stringDesc = Type.getDescriptor(String.class);
|
|
||||||
protected static final String byteArrDesc = Type.getDescriptor(byte[].class);
|
|
||||||
protected static final String base64DecDesc = "(" + stringDesc + ")" + byteArrDesc;
|
|
||||||
protected final ClassNode configclass;
|
|
||||||
protected final MethodNode constructor;
|
|
||||||
|
|
||||||
public ConfigGenerator(ClassNode configclass) {
|
|
||||||
this.configclass = configclass;
|
|
||||||
constructor = this.configclass.methods.stream().filter(e -> "<init>".equals(e.name)).findFirst().get();
|
|
||||||
constructor.instructions = new InsnList();
|
|
||||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
|
||||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytecode(ClassMetadataReader reader) {
|
|
||||||
constructor.instructions.add(new InsnNode(Opcodes.RETURN));
|
|
||||||
ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
|
|
||||||
configclass.accept(cw);
|
|
||||||
return cw.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getZipEntryPath() {
|
|
||||||
return configclass.name.concat(".class");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStringField(String name, String value) {
|
|
||||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
|
||||||
constructor.instructions.add(NodeUtils.getSafeStringInsnList(value));
|
|
||||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, configclass.name, name, stringDesc));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setByteArrayField(String name, byte[] value) {
|
|
||||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
|
||||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false));
|
|
||||||
constructor.instructions.add(NodeUtils.getSafeStringInsnList(Base64.getEncoder().encodeToString(value)));
|
|
||||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", base64DecDesc, false));
|
|
||||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, configclass.name, name, stringDesc));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setByteArrayListField(String name, List<byte[]> b) {
|
|
||||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
|
||||||
constructor.instructions.add(new TypeInsnNode(Opcodes.NEW, "java/util/ArrayList"));
|
|
||||||
constructor.instructions.add(new InsnNode(Opcodes.DUP)); // +1
|
|
||||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V"));
|
|
||||||
for (byte[] value : b) {
|
|
||||||
constructor.instructions.add(new InsnNode(Opcodes.DUP)); // +1-1
|
|
||||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false));
|
|
||||||
constructor.instructions.add(NodeUtils.getSafeStringInsnList(Base64.getEncoder().encodeToString(value)));
|
|
||||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", base64DecDesc, false));
|
|
||||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true));
|
|
||||||
constructor.instructions.add(new InsnNode(Opcodes.POP));
|
|
||||||
}
|
|
||||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, configclass.name, name, "Ljava/util/List;"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIntegerField(String name, int value) {
|
|
||||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
|
||||||
constructor.instructions.add(NodeUtils.push(value));
|
|
||||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, configclass.name, name, Type.INT_TYPE.getInternalName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLongField(String name, long value) {
|
|
||||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
|
||||||
constructor.instructions.add(new LdcInsnNode(value));
|
|
||||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, configclass.name, name, Type.INT_TYPE.getInternalName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBooleanField(String name, boolean b) {
|
|
||||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
|
||||||
constructor.instructions.add(new InsnNode(b ? Opcodes.ICONST_1 : Opcodes.ICONST_0));
|
|
||||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, configclass.name, name, Type.BOOLEAN_TYPE.getInternalName()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -123,6 +123,11 @@ public void visit(final String name, final Object value) {
|
||||||
serializers.put(byte[].class, new ByteArraySerializer());
|
serializers.put(byte[].class, new ByteArraySerializer());
|
||||||
serializers.put(Short.class, serializerClass(Opcodes.I2S));
|
serializers.put(Short.class, serializerClass(Opcodes.I2S));
|
||||||
serializers.put(Byte.class, serializerClass(Opcodes.I2B));
|
serializers.put(Byte.class, serializerClass(Opcodes.I2B));
|
||||||
|
serializers.put(Type.class, (Serializer<Type>) e -> { // ow.Type == java.lang.Class in LDC
|
||||||
|
InsnList ret = new InsnList();
|
||||||
|
ret.add(new LdcInsnNode(e));
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
serializers.put(Boolean.class, (Serializer<Boolean>) e -> {
|
serializers.put(Boolean.class, (Serializer<Boolean>) e -> {
|
||||||
InsnList ret = new InsnList();
|
InsnList ret = new InsnList();
|
||||||
ret.add(new InsnNode(e ? Opcodes.ICONST_1 : Opcodes.ICONST_0));
|
ret.add(new InsnNode(e ? Opcodes.ICONST_1 : Opcodes.ICONST_0));
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
|
|
||||||
public class BuildContext {
|
public class BuildContext {
|
||||||
public final ZipOutputStream output;
|
public final ZipOutputStream output;
|
||||||
public final LauncherConfigurator config;
|
|
||||||
public final List<JarFile> readerClassPath;
|
public final List<JarFile> readerClassPath;
|
||||||
public final MainBuildTask task;
|
public final MainBuildTask task;
|
||||||
public final HashSet<String> fileList;
|
public final HashSet<String> fileList;
|
||||||
|
@ -78,9 +77,8 @@ private ZipEntry newEntry(String fileName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public BuildContext(ZipOutputStream output, LauncherConfigurator config, List<JarFile> readerClassPath, MainBuildTask task) {
|
public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainBuildTask task) {
|
||||||
this.output = output;
|
this.output = output;
|
||||||
this.config = config;
|
|
||||||
this.readerClassPath = readerClassPath;
|
this.readerClassPath = readerClassPath;
|
||||||
this.task = task;
|
this.task = task;
|
||||||
fileList = new HashSet<>(1024);
|
fileList = new HashSet<>(1024);
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
package pro.gravit.launchserver.binary;
|
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
import org.objectweb.asm.tree.*;
|
|
||||||
import pro.gravit.launcher.LauncherConfig;
|
|
||||||
import pro.gravit.launcher.modules.LauncherModule;
|
|
||||||
import pro.gravit.launchserver.asm.ClassMetadataReader;
|
|
||||||
import pro.gravit.launchserver.asm.ConfigGenerator;
|
|
||||||
|
|
||||||
public class LauncherConfigurator extends ConfigGenerator {
|
|
||||||
private static final String modulesManagerName = "pro/gravit/launcher/modules/LauncherModulesManager";
|
|
||||||
private static final String launcherName = "pro/gravit/launcher/LauncherEngine";
|
|
||||||
private static final String modulesManagerDesc = "Lpro/gravit/launcher/client/ClientModuleManager;";
|
|
||||||
private static final String registerModDesc = Type.getMethodDescriptor(Type.getType(LauncherModule.class), Type.getType(LauncherModule.class));
|
|
||||||
private final MethodNode initModuleMethod;
|
|
||||||
|
|
||||||
public LauncherConfigurator(ClassNode configclass) {
|
|
||||||
super(configclass);
|
|
||||||
initModuleMethod = configclass.methods.stream().filter(e -> "initModules".equals(e.name)).findFirst().get();
|
|
||||||
initModuleMethod.instructions = new InsnList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addModuleClass(String fullName) {
|
|
||||||
initModuleMethod.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, launcherName, "modulesManager", modulesManagerDesc));
|
|
||||||
initModuleMethod.instructions.add(new TypeInsnNode(Opcodes.NEW, fullName.replace('.', '/')));
|
|
||||||
initModuleMethod.instructions.add(new InsnNode(Opcodes.DUP));
|
|
||||||
initModuleMethod.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, fullName.replace('.', '/'), "<init>", "()V"));
|
|
||||||
initModuleMethod.instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, modulesManagerName, "loadModule", registerModDesc));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getBytecode(ClassMetadataReader reader) {
|
|
||||||
initModuleMethod.instructions.add(new InsnNode(Opcodes.RETURN));
|
|
||||||
return super.getBytecode(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnv(LauncherConfig.LauncherEnvironment env) {
|
|
||||||
int i = 2;
|
|
||||||
switch (env) {
|
|
||||||
case DEV:
|
|
||||||
i = 0;
|
|
||||||
break;
|
|
||||||
case DEBUG:
|
|
||||||
i = 1;
|
|
||||||
break;
|
|
||||||
case STD:
|
|
||||||
i = 2;
|
|
||||||
break;
|
|
||||||
case PROD:
|
|
||||||
i = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
setIntegerField("env", i);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,23 +2,19 @@
|
||||||
|
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
import org.objectweb.asm.tree.AnnotationNode;
|
import org.objectweb.asm.tree.AnnotationNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.FieldNode;
|
import org.objectweb.asm.tree.FieldNode;
|
||||||
import pro.gravit.launcher.AutogenConfig;
|
|
||||||
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.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.InjectClassAcceptor;
|
import pro.gravit.launchserver.asm.InjectClassAcceptor;
|
||||||
import pro.gravit.launchserver.asm.SafeClassWriter;
|
import pro.gravit.launchserver.asm.SafeClassWriter;
|
||||||
import pro.gravit.launchserver.binary.BuildContext;
|
import pro.gravit.launchserver.binary.BuildContext;
|
||||||
import pro.gravit.launchserver.binary.LauncherConfigurator;
|
|
||||||
import pro.gravit.utils.HookException;
|
import pro.gravit.utils.HookException;
|
||||||
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.LogHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
|
@ -137,49 +133,11 @@ public String getName() {
|
||||||
public Path process(Path inputJar) throws IOException {
|
public Path process(Path inputJar) throws IOException {
|
||||||
Path outputJar = server.launcherBinary.nextPath("main");
|
Path outputJar = server.launcherBinary.nextPath("main");
|
||||||
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) {
|
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) {
|
||||||
ClassNode cn = new ClassNode();
|
BuildContext context = new BuildContext(output, reader.getCp(), this);
|
||||||
new ClassReader(JarHelper.getClassBytes(AutogenConfig.class)).accept(cn, 0);
|
initProps();
|
||||||
LauncherConfigurator launcherConfigurator = new LauncherConfigurator(cn);
|
|
||||||
ClassNode cn1 = new ClassNode();
|
|
||||||
new ClassReader(JarHelper.getClassBytes(SecureAutogenConfig.class)).accept(cn1, 0);
|
|
||||||
ConfigGenerator secureConfigurator = new ConfigGenerator(cn1);
|
|
||||||
BuildContext context = new BuildContext(output, launcherConfigurator, reader.getCp(), this);
|
|
||||||
preBuildHook.hook(context);
|
preBuildHook.hook(context);
|
||||||
launcherConfigurator.setStringField("address", server.config.netty.address);
|
properties.put("launcher.modules", context.clientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList()));
|
||||||
launcherConfigurator.setStringField("projectname", server.config.projectName);
|
postInitProps();
|
||||||
launcherConfigurator.setStringField("secretKeyClient", SecurityHelper.randomStringAESKey());
|
|
||||||
launcherConfigurator.setIntegerField("clientPort", 32148 + SecurityHelper.newRandom().nextInt(512));
|
|
||||||
launcherConfigurator.setStringField("guardType", server.config.launcher.guardType);
|
|
||||||
launcherConfigurator.setBooleanField("isWarningMissArchJava", server.config.launcher.warningMissArchJava);
|
|
||||||
launcherConfigurator.setEnv(server.config.env);
|
|
||||||
launcherConfigurator.setStringField("passwordEncryptKey", server.runtime.passwordEncryptKey);
|
|
||||||
List<byte[]> certificates = Arrays.stream(server.certificateManager.trustManager.getTrusted()).map(e -> {
|
|
||||||
try {
|
|
||||||
return e.getEncoded();
|
|
||||||
} catch (CertificateEncodingException e2) {
|
|
||||||
LogHelper.error(e2);
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
if(!server.config.sign.enabled)
|
|
||||||
{
|
|
||||||
CertificateAutogenTask task = server.launcherBinary.getTaskByClass(CertificateAutogenTask.class).get();
|
|
||||||
try {
|
|
||||||
certificates.add(task.certificate.getEncoded());
|
|
||||||
} catch (CertificateEncodingException e) {
|
|
||||||
throw new InternalError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
secureConfigurator.setByteArrayListField("certificates", certificates);
|
|
||||||
String launcherSalt = SecurityHelper.randomStringToken();
|
|
||||||
byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
|
|
||||||
server.runtime.clientCheckSecret.concat(".").concat(launcherSalt));
|
|
||||||
launcherConfigurator.setStringField("secureCheckHash", Base64.getEncoder().encodeToString(launcherSecureHash));
|
|
||||||
launcherConfigurator.setStringField("secureCheckSalt", launcherSalt);
|
|
||||||
//LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash));
|
|
||||||
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
|
|
||||||
launcherConfigurator.setStringField("oemUnlockKey", server.runtime.oemUnlockKey);
|
|
||||||
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 {
|
||||||
|
@ -188,9 +146,6 @@ public Path process(Path inputJar) throws IOException {
|
||||||
LogHelper.error(e1);
|
LogHelper.error(e1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
context.pushBytes(launcherConfigurator.getZipEntryPath(), launcherConfigurator.getBytecode(reader));
|
|
||||||
context.pushBytes(secureConfigurator.getZipEntryPath(), secureConfigurator.getBytecode(reader));
|
|
||||||
|
|
||||||
context.pushJarFile(inputJar, (e) -> blacklist.contains(e.getName()), (e) -> true);
|
context.pushJarFile(inputJar, (e) -> blacklist.contains(e.getName()), (e) -> true);
|
||||||
|
|
||||||
// map for guard
|
// map for guard
|
||||||
|
@ -207,7 +162,49 @@ public Path process(Path inputJar) throws IOException {
|
||||||
return outputJar;
|
return outputJar;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] transformClass(byte[] bytes, String classname, BuildContext context)
|
protected void postInitProps() {
|
||||||
|
List<byte[]> certificates = Arrays.stream(server.certificateManager.trustManager.getTrusted()).map(e -> {
|
||||||
|
try {
|
||||||
|
return e.getEncoded();
|
||||||
|
} catch (CertificateEncodingException e2) {
|
||||||
|
LogHelper.error(e2);
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
if(!server.config.sign.enabled)
|
||||||
|
{
|
||||||
|
CertificateAutogenTask task = server.launcherBinary.getTaskByClass(CertificateAutogenTask.class).get();
|
||||||
|
try {
|
||||||
|
certificates.add(task.certificate.getEncoded());
|
||||||
|
} catch (CertificateEncodingException e) {
|
||||||
|
throw new InternalError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties.put("launchercore.certificates", certificates);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initProps() {
|
||||||
|
properties.clear();
|
||||||
|
properties.put("launcher.address", server.config.netty.address);
|
||||||
|
properties.put("launcher.projectName", server.config.projectName);
|
||||||
|
properties.put("runtimeconfig.secretKeyClient", SecurityHelper.randomStringAESKey());
|
||||||
|
properties.put("launcher.port", 32148 + SecurityHelper.newRandom().nextInt(512));
|
||||||
|
properties.put("launcher.guardType", server.config.launcher.guardType);
|
||||||
|
properties.put("launcher.isWarningMissArchJava", server.config.launcher.warningMissArchJava);
|
||||||
|
properties.put("launchercore.env" ,server.config.env);
|
||||||
|
properties.put("runtimeconfig.passwordEncryptKey", server.runtime.passwordEncryptKey);
|
||||||
|
String launcherSalt = SecurityHelper.randomStringToken();
|
||||||
|
byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
|
||||||
|
server.runtime.clientCheckSecret.concat(".").concat(launcherSalt));
|
||||||
|
properties.put("runtimeconfig.secureCheckHash", Base64.getEncoder().encodeToString(launcherSecureHash));
|
||||||
|
properties.put("runtimeconfig.secureCheckSalt", launcherSalt);
|
||||||
|
//LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash));
|
||||||
|
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
|
||||||
|
properties.put("runtimeconfig.oemUnlockKey", server.runtime.oemUnlockKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] transformClass(byte[] bytes, String classname, BuildContext context)
|
||||||
{
|
{
|
||||||
byte[] result = bytes;
|
byte[] result = bytes;
|
||||||
ClassReader cr = null;
|
ClassReader cr = null;
|
||||||
|
|
|
@ -27,13 +27,9 @@ public void clear() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// URL constants
|
|
||||||
public static final String DOWNLOAD_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"; // Oracle
|
public static final String DOWNLOAD_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"; // Oracle
|
||||||
// JRE 8
|
|
||||||
// File constants
|
|
||||||
private final Path faviconFile;
|
private final Path faviconFile;
|
||||||
|
|
||||||
// File constants
|
|
||||||
private final LaunchServer server;
|
private final LaunchServer server;
|
||||||
|
|
||||||
public Launch4JTask(LaunchServer launchServer) {
|
public Launch4JTask(LaunchServer launchServer) {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"version": "1.15.2",
|
||||||
|
"assetIndex": "1.15.2",
|
||||||
|
"assetDir": "asset1.15.2",
|
||||||
|
"dir": "HiTech",
|
||||||
|
"info": "Информация о сервере",
|
||||||
|
"sortIndex": 0,
|
||||||
|
"title": "xxxxxxxx",
|
||||||
|
"serverAddress": "localhost",
|
||||||
|
"serverPort": 25565,
|
||||||
|
"update": [
|
||||||
|
"servers.dat"
|
||||||
|
],
|
||||||
|
"updateExclusions": [],
|
||||||
|
"updateShared": [],
|
||||||
|
"updateVerify": [
|
||||||
|
"libraries",
|
||||||
|
"natives",
|
||||||
|
"minecraft.jar"
|
||||||
|
],
|
||||||
|
"updateOptional": [],
|
||||||
|
"updateFastCheck": true,
|
||||||
|
"useWhitelist": false,
|
||||||
|
"mainClass": "net.minecraft.client.main.Main",
|
||||||
|
"jvmArgs": [
|
||||||
|
"-XX:+UseConcMarkSweepGC",
|
||||||
|
"-XX:+CMSIncrementalMode",
|
||||||
|
"-XX:-UseAdaptiveSizePolicy",
|
||||||
|
"-Xmn128M",
|
||||||
|
"-XX:+DisableAttachMechanism"
|
||||||
|
],
|
||||||
|
"classPath": [
|
||||||
|
"minecraft.jar",
|
||||||
|
"libraries"
|
||||||
|
],
|
||||||
|
"clientArgs": [],
|
||||||
|
"whitelist": []
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep
|
||||||
EnvHelper.checkDangerousParams();
|
EnvHelper.checkDangerousParams();
|
||||||
LauncherConfig config = Launcher.getConfig();
|
LauncherConfig config = Launcher.getConfig();
|
||||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||||
LauncherConfig.getAutogenConfig().initModules();
|
LauncherConfig.initModules(LauncherEngine.modulesManager);
|
||||||
|
|
||||||
LogHelper.info("Launcher for project %s", config.projectName);
|
LogHelper.info("Launcher for project %s", config.projectName);
|
||||||
if (config.environment.equals(LauncherConfig.LauncherEnvironment.PROD)) {
|
if (config.environment.equals(LauncherConfig.LauncherEnvironment.PROD)) {
|
||||||
|
|
|
@ -80,7 +80,7 @@ public static void main(String... args) throws Throwable {
|
||||||
LauncherEngine.checkClass(LauncherAgent.class);
|
LauncherEngine.checkClass(LauncherAgent.class);
|
||||||
LauncherEngine.checkClass(ClientLauncher.class);
|
LauncherEngine.checkClass(ClientLauncher.class);
|
||||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||||
LauncherConfig.getAutogenConfig().initModules();
|
LauncherConfig.initModules(LauncherEngine.modulesManager);
|
||||||
LauncherEngine.modulesManager.initModules(null);
|
LauncherEngine.modulesManager.initModules(null);
|
||||||
// Start Launcher
|
// Start Launcher
|
||||||
initGson(LauncherEngine.modulesManager);
|
initGson(LauncherEngine.modulesManager);
|
||||||
|
|
|
@ -443,7 +443,7 @@ public static void main(String... args) throws Throwable {
|
||||||
LauncherEngine.checkClass(LauncherAgent.class);
|
LauncherEngine.checkClass(LauncherAgent.class);
|
||||||
LauncherEngine.checkClass(ClientLauncher.class);
|
LauncherEngine.checkClass(ClientLauncher.class);
|
||||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||||
LauncherConfig.getAutogenConfig().initModules(); //INIT
|
LauncherConfig.initModules(LauncherEngine.modulesManager); //INIT
|
||||||
LauncherEngine.modulesManager.initModules(null);
|
LauncherEngine.modulesManager.initModules(null);
|
||||||
initGson(LauncherEngine.modulesManager);
|
initGson(LauncherEngine.modulesManager);
|
||||||
LauncherEngine.verifyNoAgent();
|
LauncherEngine.verifyNoAgent();
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package pro.gravit.launcher;
|
|
||||||
|
|
||||||
public class AutogenConfig {
|
|
||||||
public String projectname;
|
|
||||||
public String address;
|
|
||||||
public int clientPort;
|
|
||||||
public String guardType;
|
|
||||||
public String secretKeyClient;
|
|
||||||
public String oemUnlockKey;
|
|
||||||
public String secureCheckHash;
|
|
||||||
public String secureCheckSalt;
|
|
||||||
public String passwordEncryptKey;
|
|
||||||
public int env;
|
|
||||||
public boolean isWarningMissArchJava;
|
|
||||||
// 0 - Dev (дебаг включен по умолчанию, все сообщения)
|
|
||||||
// 1 - Debug (дебаг включен по умолчанию, основные сообщения)
|
|
||||||
// 2 - Std (дебаг выключен по умолчанию, основные сообщения)
|
|
||||||
// 3 - Production (дебаг выключен, минимальный объем сообщений, stacktrace не выводится)
|
|
||||||
|
|
||||||
AutogenConfig() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initModules() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +1,38 @@
|
||||||
package pro.gravit.launcher;
|
package pro.gravit.launcher;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.modules.LauncherModule;
|
||||||
|
import pro.gravit.launcher.modules.LauncherModulesManager;
|
||||||
import pro.gravit.launcher.serialize.HInput;
|
import pro.gravit.launcher.serialize.HInput;
|
||||||
import pro.gravit.launcher.serialize.HOutput;
|
import pro.gravit.launcher.serialize.HOutput;
|
||||||
import pro.gravit.launcher.serialize.stream.StreamObject;
|
import pro.gravit.launcher.serialize.stream.StreamObject;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
import pro.gravit.utils.helper.VerifyHelper;
|
import pro.gravit.utils.helper.VerifyHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.interfaces.ECPublicKey;
|
import java.security.interfaces.ECPublicKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public final class LauncherConfig extends StreamObject {
|
public final class LauncherConfig extends StreamObject {
|
||||||
private static final AutogenConfig config = new AutogenConfig();
|
@LauncherInject("launchercore.env")
|
||||||
private static final SecureAutogenConfig secureConfig = new SecureAutogenConfig();
|
private static final int cenv = -1;
|
||||||
|
@LauncherInject("launchercore.certificates")
|
||||||
|
private static final List<byte[]> secureConfigCertificates = null;
|
||||||
public static AutogenConfig getAutogenConfig() {
|
@LauncherInject("launcher.modules")
|
||||||
return config;
|
private static final List<Class<?>> modulesClasses = null;
|
||||||
}
|
@LauncherInject("launcher.address")
|
||||||
|
public String address;
|
||||||
// Instance
|
@LauncherInject("launcher.projectName")
|
||||||
public String address;
|
|
||||||
|
|
||||||
public final String projectName;
|
public final String projectName;
|
||||||
|
@LauncherInject("launcher.port")
|
||||||
public final int clientPort;
|
public final int clientPort;
|
||||||
|
@LauncherInject("runtimeconfig.secretKeyClient")
|
||||||
public String secretKeyClient;
|
public String secretKeyClient;
|
||||||
|
@LauncherInject("runtimeconfig.oemUnlockKey")
|
||||||
public String oemUnlockKey;
|
public String oemUnlockKey;
|
||||||
public final LauncherTrustManager trustManager;
|
public final LauncherTrustManager trustManager;
|
||||||
|
|
||||||
|
@ -34,40 +40,43 @@ public static AutogenConfig getAutogenConfig() {
|
||||||
|
|
||||||
|
|
||||||
public final Map<String, byte[]> runtime;
|
public final Map<String, byte[]> runtime;
|
||||||
|
@LauncherInject("launcher.isWarningMissArchJava")
|
||||||
public final boolean isWarningMissArchJava;
|
public final boolean isWarningMissArchJava;
|
||||||
public boolean isNettyEnabled;
|
|
||||||
public LauncherEnvironment environment;
|
public LauncherEnvironment environment;
|
||||||
|
@LauncherInject("launcher.guardType")
|
||||||
public final String guardType;
|
public final String guardType;
|
||||||
|
@LauncherInject("runtimeconfig.secureCheckHash")
|
||||||
public final String secureCheckHash;
|
public final String secureCheckHash;
|
||||||
|
@LauncherInject("runtimeconfig.secureCheckSalt")
|
||||||
public final String secureCheckSalt;
|
public final String secureCheckSalt;
|
||||||
|
@LauncherInject("runtimeconfig.passwordEncryptKey")
|
||||||
public final String passwordEncryptKey;
|
public final String passwordEncryptKey;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@LauncherInjectionConstructor
|
||||||
public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException {
|
public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException {
|
||||||
publicKey = SecurityHelper.toPublicECKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
|
publicKey = SecurityHelper.toPublicECKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
|
||||||
secureCheckHash = config.secureCheckHash;
|
secureCheckHash = null;
|
||||||
secureCheckSalt = config.secureCheckSalt;
|
secureCheckSalt = null;
|
||||||
passwordEncryptKey = config.passwordEncryptKey;
|
passwordEncryptKey = null;
|
||||||
projectName = config.projectname;
|
projectName = null;
|
||||||
clientPort = config.clientPort;
|
clientPort = -1;
|
||||||
secretKeyClient = config.secretKeyClient;
|
secretKeyClient = null;
|
||||||
oemUnlockKey = config.oemUnlockKey;
|
oemUnlockKey = null;
|
||||||
try {
|
try {
|
||||||
trustManager = new LauncherTrustManager(secureConfig.certificates);
|
trustManager = new LauncherTrustManager(secureConfigCertificates);
|
||||||
} catch (CertificateException e) {
|
} catch (CertificateException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
isWarningMissArchJava = config.isWarningMissArchJava;
|
isWarningMissArchJava = false;
|
||||||
guardType = config.guardType;
|
guardType = null;
|
||||||
address = config.address;
|
address = null;
|
||||||
LauncherEnvironment env;
|
LauncherEnvironment env;
|
||||||
if (config.env == 0) env = LauncherEnvironment.DEV;
|
if (cenv == 0) env = LauncherEnvironment.DEV;
|
||||||
else if (config.env == 1) env = LauncherEnvironment.DEBUG;
|
else if (cenv == 1) env = LauncherEnvironment.DEBUG;
|
||||||
else if (config.env == 2) env = LauncherEnvironment.STD;
|
else if (cenv == 2) env = LauncherEnvironment.STD;
|
||||||
else if (config.env == 3) env = LauncherEnvironment.PROD;
|
else if (cenv == 3) env = LauncherEnvironment.PROD;
|
||||||
else env = LauncherEnvironment.STD;
|
else env = LauncherEnvironment.STD;
|
||||||
Launcher.applyLauncherEnv(env);
|
Launcher.applyLauncherEnv(env);
|
||||||
environment = env;
|
environment = env;
|
||||||
|
@ -92,7 +101,6 @@ public LauncherConfig(String address, ECPublicKey publicKey, Map<String, byte[]>
|
||||||
this.clientPort = 32148;
|
this.clientPort = 32148;
|
||||||
guardType = "no";
|
guardType = "no";
|
||||||
isWarningMissArchJava = true;
|
isWarningMissArchJava = true;
|
||||||
isNettyEnabled = false;
|
|
||||||
environment = LauncherEnvironment.STD;
|
environment = LauncherEnvironment.STD;
|
||||||
secureCheckSalt = null;
|
secureCheckSalt = null;
|
||||||
secureCheckHash = null;
|
secureCheckHash = null;
|
||||||
|
@ -116,4 +124,17 @@ public void write(HOutput output) throws IOException {
|
||||||
public enum LauncherEnvironment {
|
public enum LauncherEnvironment {
|
||||||
DEV, DEBUG, STD, PROD
|
DEV, DEBUG, STD, PROD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final MethodType VOID_TYPE = MethodType.methodType(void.class);
|
||||||
|
|
||||||
|
public static void initModules(LauncherModulesManager modulesManager) {
|
||||||
|
for (Class<?> clazz : modulesClasses)
|
||||||
|
try {
|
||||||
|
modulesManager.loadModule((LauncherModule) MethodHandles.publicLookup().findConstructor(clazz, VOID_TYPE).invokeWithArguments(Collections.emptyList()));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
// This method should be called once at exec time.
|
||||||
|
modulesClasses.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
package pro.gravit.launcher;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SecureAutogenConfig {
|
|
||||||
public static final Charset KEY_CHARSET = StandardCharsets.US_ASCII; // ? Какая из них, но выбрать надо однозачно проверить методом тыка!!!
|
|
||||||
public final List<byte[]> certificates;
|
|
||||||
|
|
||||||
public SecureAutogenConfig() {
|
|
||||||
//Пока не реализован SecureLauncherConfigurator
|
|
||||||
certificates = null;/*Arrays.asList(
|
|
||||||
("-----BEGIN CERTIFICATE-----\n" +
|
|
||||||
"MIIFyjCCA7KgAwIBAgIRALnsjNjfvOTXfla3fX1fNEUwDQYJKoZIhvcNAQELBQAw\n" +
|
|
||||||
"WTELMAkGA1UEBhMCUlUxFzAVBgNVBAoTDkdyYXZpdFRydXN0IENBMRAwDgYDVQQL\n" +
|
|
||||||
"EwdSb290IENBMR8wHQYDVQQDExZHcmF2aXQgQ2VudHJhbCBSb290IENBMCAXDTE5\n" +
|
|
||||||
"MDYwOTAyNDIwMFoYDzIwNTEwNjA5MDI0MjAwWjBZMQswCQYDVQQGEwJSVTEXMBUG\n" +
|
|
||||||
"A1UEChMOR3Jhdml0VHJ1c3QgQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHzAdBgNVBAMT\n" +
|
|
||||||
"FkdyYXZpdCBDZW50cmFsIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" +
|
|
||||||
"ggIKAoICAQDA3Qm9OH8Xz3YM3bKkZuQI7T/aL3ulMOdY5GFADYgHrOVZXVSJi/4P\n" +
|
|
||||||
"PruBsut4WXN6TGQdpJtNZ2kyWTYzENGTm/TMzBcIchor1M3JW5Uv/C0r5gSEU1uP\n" +
|
|
||||||
"DPe7oEpeKtb3FXML/pGoGpLv/sonTKky4AKZnK7B15bZ+oVZNwh7UKANpNrVA8k5\n" +
|
|
||||||
"0gb4BisFcegLidYL9Y00H1x5WzUxldQAA1IQuwdkL3NP0NPQrSVJ2Ka2EtebE2HP\n" +
|
|
||||||
"fXHtbftvvnvSWyh4CXAxTfEmJgut0gSPQPm9wVt6pIWWd4O0hHwVmxkKQidgnP6A\n" +
|
|
||||||
"+d05FnJGsBw0ztMCifIteqNiHF0D8E0GuSz6NtcuV47J3p43qkvKr2vPc8o6WMN8\n" +
|
|
||||||
"PAb0eVHc/AX8qqOwYQyHlj4M0SDhCltHeeYRWmuZmRFIIelv6VAocaQLlPQrhJNp\n" +
|
|
||||||
"feIzmXLy60a+84vpe/eQKQx+D8a1elarQkoHMxI7x/9AJvxcnJ4KuXc2rkiu3Zv9\n" +
|
|
||||||
"KMhixtkLc+pA6jY023U211v+c20RjTqwKIZoMFc7BZipoinAOn1bdsTzXlhOMv1O\n" +
|
|
||||||
"zj5WoW6DsQQONMZNyLQAkaX6SYZE/kQVJ9YMPhNdaXjxxzfrY05IrWAaWhtPbW8z\n" +
|
|
||||||
"5nb4/JyO+bJq3v2rav9p03s8P/lQ4k/0af5vOkGkEO0+YKx97ZP8FQIDAQABo4GK\n" +
|
|
||||||
"MIGHMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFjMGCvHXAE/vGJih+Lfdo2s\n" +
|
|
||||||
"YnzsMAsGA1UdDwQEAwIBBjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vY2EuZ3Jh\n" +
|
|
||||||
"dml0LnByby9jZW50cmFscm9vdC5jcmwwEQYJYIZIAYb4QgEBBAQDAgAHMA0GCSqG\n" +
|
|
||||||
"SIb3DQEBCwUAA4ICAQAexCGpThx85skEllva1UskmdlRh3rud9u59AUiwNZF0b0I\n" +
|
|
||||||
"+7eeyLNaLHarg2Zm30TSCF53ksyPTE5QNdmozs1fl3MddFqunkbUm4G6hwedZMSi\n" +
|
|
||||||
"4IXIb2QK3z3gZG5ZNdHaDG2u00Jdkc39h3jQFp1rpn4+0DcnYJAe+lw5G+XHURY2\n" +
|
|
||||||
"j15wcmUFp/Ywgw3pfCWmH5+rxq21e/LG8JiQrxekkFI2GUD+Qw7+Hq3o1Fgg3kfh\n" +
|
|
||||||
"Lg4B5WEbEICQ1FC+dHYHasEI3q3c96Qpqu2k3pO0l1fr6Cys+AGjoI2WrgXkGlmA\n" +
|
|
||||||
"F+Wi2ndoZbvspGAwxmrNMtLE3OYNuMXFF410QSPf4o9QqpGDC3a2mccTXb231a18\n" +
|
|
||||||
"5vDJixeZpuzEm5ECXg8j6aj53X3rtm7C8yfOsg5UTKJJj+pSNz4YTp91IDHm0nTP\n" +
|
|
||||||
"2KhrgS7jujgKdJn9xv07e/API3kLWkVmMwHBiaSCIaHOfAN0RJMQVV+YgnSp2sIa\n" +
|
|
||||||
"OATWgSKH0qTkleE/v7k+USs0a+KV8wmC5wwliqH+uLO++yIP/9bjDctyLulQX5Ee\n" +
|
|
||||||
"+EhD7tb1R/yyWY4uhkzlsr3N2Kl34aQAEBMn8Z1mHsyyu1FcbEaNLU8jcS3pHPVM\n" +
|
|
||||||
"gQRn3m1iDnQlFciAMxW0pW6mW/4xKYzhXk5BTSolnqMVylxHgWXuBwdDDQQVnQ==\n" +
|
|
||||||
"-----END CERTIFICATE-----").getBytes(KEY_CHARSET));*/
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,7 +41,8 @@ public enum Version {
|
||||||
MC1143("1.14.3", 490),
|
MC1143("1.14.3", 490),
|
||||||
MC1144("1.14.4", 498),
|
MC1144("1.14.4", 498),
|
||||||
MC115("1.15", 573),
|
MC115("1.15", 573),
|
||||||
MC1151("1.15.1", 575);
|
MC1151("1.15.1", 575),
|
||||||
|
MC1152("1.15.2", 578);
|
||||||
private static final Map<String, Version> VERSIONS;
|
private static final Map<String, Version> VERSIONS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -196,7 +196,6 @@ public void updateLauncherConfig() {
|
||||||
if(IOHelper.isFile(publicKeyFile))
|
if(IOHelper.isFile(publicKeyFile))
|
||||||
publicKey = SecurityHelper.toPublicECKey(IOHelper.read(publicKeyFile));
|
publicKey = SecurityHelper.toPublicECKey(IOHelper.read(publicKeyFile));
|
||||||
cfg = new LauncherConfig(config.address, publicKey, new HashMap<>(), config.projectname);
|
cfg = new LauncherConfig(config.address, publicKey, new HashMap<>(), config.projectname);
|
||||||
cfg.isNettyEnabled = true;
|
|
||||||
cfg.address = config.address;
|
cfg.address = config.address;
|
||||||
} catch (InvalidKeySpecException | IOException e) {
|
} catch (InvalidKeySpecException | IOException e) {
|
||||||
LogHelper.error(e);
|
LogHelper.error(e);
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit 5464417b18e27d7ae8ce91861e42f167e11b8215
|
Subproject commit 0fbc3fb26c505800a61976cdf1310cad6ab7808d
|
Loading…
Reference in a new issue