mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
[REFACTOR] Mini refactoring
This commit is contained in:
parent
1cb2369bfa
commit
f1331b6d5d
6 changed files with 241 additions and 98 deletions
|
@ -40,31 +40,67 @@
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The main LaunchServer class. Contains links to all necessary objects
|
||||
* Not a singletron
|
||||
*/
|
||||
public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurable {
|
||||
|
||||
public static final Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
|
||||
/**
|
||||
* Working folder path
|
||||
*/
|
||||
public final Path dir;
|
||||
/**
|
||||
* Environment type (test / production)
|
||||
*/
|
||||
public final LaunchServerEnv env;
|
||||
/**
|
||||
* The path to the folder with libraries for the launcher
|
||||
*/
|
||||
public final Path launcherLibraries;
|
||||
/**
|
||||
* The path to the folder with compile-only libraries for the launcher
|
||||
*/
|
||||
public final Path launcherLibrariesCompile;
|
||||
public final Path caCertFile;
|
||||
|
||||
// Constant paths
|
||||
public final Path caKeyFile;
|
||||
public final Path serverCertFile;
|
||||
public final Path serverKeyFile;
|
||||
/**
|
||||
* The path to the folder with updates/webroot
|
||||
*/
|
||||
public final Path updatesDir;
|
||||
/**
|
||||
* Save/Reload LaunchServer config
|
||||
*/
|
||||
public final LaunchServerConfigManager launchServerConfigManager;
|
||||
/**
|
||||
* The path to the folder with profiles
|
||||
*/
|
||||
public final Path profilesDir;
|
||||
/**
|
||||
* This object contains runtime configuration
|
||||
*/
|
||||
public final LaunchServerRuntimeConfig runtime;
|
||||
/**
|
||||
* Public ECDSA LaunchServer key
|
||||
*/
|
||||
public final ECPublicKey publicKey;
|
||||
/**
|
||||
* Private ECDSA LaunchServer key
|
||||
*/
|
||||
public final ECPrivateKey privateKey;
|
||||
/**
|
||||
* Pipeline for building JAR
|
||||
*/
|
||||
public final JARLauncherBinary launcherBinary;
|
||||
/**
|
||||
* Pipeline for building EXE
|
||||
*/
|
||||
public final LauncherBinary launcherEXEBinary;
|
||||
|
||||
//public static LaunchServer server = null;
|
||||
public final Class<? extends LauncherBinary> launcherEXEBinaryClass;
|
||||
// Server config
|
||||
public final LauncherBinary launcherEXEBinary;
|
||||
public final SessionManager sessionManager;
|
||||
public final AuthHookManager authHookManager;
|
||||
public final LaunchServerModulesManager modulesManager;
|
||||
|
@ -106,12 +142,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
|
||||
config.setLaunchServer(this);
|
||||
|
||||
caCertFile = dir.resolve("ca.crt");
|
||||
caKeyFile = dir.resolve("ca.key");
|
||||
|
||||
serverCertFile = dir.resolve("server.crt");
|
||||
serverKeyFile = dir.resolve("server.key");
|
||||
|
||||
modulesManager.invokeEvent(new NewLaunchServerInstanceEvent(this));
|
||||
|
||||
// Print keypair fingerprints
|
||||
|
|
|
@ -72,73 +72,79 @@ private static void visit(ClassNode classNode, Map<String, Object> values) {
|
|||
classNode.fields.forEach(field -> {
|
||||
// Notice that fields that will be used with this algo should not have default
|
||||
// value by = ...;
|
||||
AnnotationNode valueAnnotation = field.invisibleAnnotations != null ? field.invisibleAnnotations.stream()
|
||||
.filter(annotation -> INJECTED_FIELD_DESC.equals(annotation.desc)).findFirst()
|
||||
.orElse(null) : null;
|
||||
if (valueAnnotation == null) {
|
||||
return;
|
||||
}
|
||||
field.invisibleAnnotations.remove(valueAnnotation);
|
||||
AtomicReference<String> valueName = new AtomicReference<>(null);
|
||||
valueAnnotation.accept(new AnnotationVisitor(Opcodes.ASM7) {
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
if ("value".equals(name)) {
|
||||
if (value.getClass() != String.class)
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Invalid annotation with value class %s", field.getClass().getName()));
|
||||
valueName.set(value.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
if (valueName.get() == null) {
|
||||
throw new IllegalArgumentException("Annotation should always contains 'value' key");
|
||||
}
|
||||
if (!values.containsKey(valueName.get())) {
|
||||
return;
|
||||
}
|
||||
Object value = values.get(valueName.get());
|
||||
if ((field.access & Opcodes.ACC_STATIC) != 0) {
|
||||
if (primitiveLDCDescriptors.contains(field.desc) && primitiveLDCClasses.contains(value.getClass())) {
|
||||
field.value = value;
|
||||
return;
|
||||
}
|
||||
List<FieldInsnNode> putStaticNodes = Arrays.stream(clinitMethod.instructions.toArray())
|
||||
.filter(node -> node instanceof FieldInsnNode && node.getOpcode() == Opcodes.PUTSTATIC).map(p -> (FieldInsnNode) p)
|
||||
.filter(node -> node.owner.equals(classNode.name) && node.name.equals(field.name) && node.desc.equals(field.desc)).collect(Collectors.toList());
|
||||
InsnList setter = serializeValue(value);
|
||||
if (putStaticNodes.isEmpty()) {
|
||||
setter.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, field.name, field.desc));
|
||||
Arrays.stream(clinitMethod.instructions.toArray()).filter(node -> node.getOpcode() == Opcodes.RETURN)
|
||||
.forEach(node -> clinitMethod.instructions.insertBefore(node, setter));
|
||||
} else {
|
||||
setter.insert(new InsnNode(Type.getType(field.desc).getSize() == 1 ? Opcodes.POP : Opcodes.POP2));
|
||||
for (FieldInsnNode fieldInsnNode : putStaticNodes) {
|
||||
clinitMethod.instructions.insertBefore(fieldInsnNode, setter);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (initMethod == null) {
|
||||
throw new IllegalArgumentException(String.format("Not found init in target: %s", classNode.name));
|
||||
}
|
||||
List<FieldInsnNode> putFieldNodes = Arrays.stream(initMethod.instructions.toArray())
|
||||
.filter(node -> node instanceof FieldInsnNode && node.getOpcode() == Opcodes.PUTFIELD).map(p -> (FieldInsnNode) p)
|
||||
.filter(node -> node.owner.equals(classNode.name) && node.name.equals(field.name) && node.desc.equals(field.desc)).collect(Collectors.toList());
|
||||
InsnList setter = serializeValue(value);
|
||||
if (putFieldNodes.isEmpty()) {
|
||||
setter.insert(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
setter.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, field.name, field.desc));
|
||||
Arrays.stream(initMethod.instructions.toArray())
|
||||
.filter(node -> node.getOpcode() == Opcodes.RETURN)
|
||||
.forEach(node -> initMethod.instructions.insertBefore(node, setter));
|
||||
} else {
|
||||
setter.insert(new InsnNode(Type.getType(field.desc).getSize() == 1 ? Opcodes.POP : Opcodes.POP2));
|
||||
for (FieldInsnNode fieldInsnNode : putFieldNodes) {
|
||||
initMethod.instructions.insertBefore(fieldInsnNode, setter);
|
||||
}
|
||||
boolean isStatic = (field.access & Opcodes.ACC_STATIC) != 0;
|
||||
injectTo(isStatic ? clinitMethod : initMethod, classNode, field, isStatic, values);
|
||||
});
|
||||
}
|
||||
|
||||
public static void injectTo(MethodNode initMethod, ClassNode classNode, FieldNode field, boolean isStatic, Map<String, Object> values) {
|
||||
AnnotationNode valueAnnotation = field.invisibleAnnotations != null ? field.invisibleAnnotations.stream()
|
||||
.filter(annotation -> INJECTED_FIELD_DESC.equals(annotation.desc)).findFirst()
|
||||
.orElse(null) : null;
|
||||
if (valueAnnotation == null) {
|
||||
return;
|
||||
}
|
||||
field.invisibleAnnotations.remove(valueAnnotation);
|
||||
AtomicReference<String> valueName = new AtomicReference<>(null);
|
||||
valueAnnotation.accept(new AnnotationVisitor(Opcodes.ASM7) {
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
if ("value".equals(name)) {
|
||||
if (value.getClass() != String.class)
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Invalid annotation with value class %s", field.getClass().getName()));
|
||||
valueName.set(value.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
if (valueName.get() == null) {
|
||||
throw new IllegalArgumentException("Annotation should always contains 'value' key");
|
||||
}
|
||||
if (!values.containsKey(valueName.get())) {
|
||||
return;
|
||||
}
|
||||
Object value = values.get(valueName.get());
|
||||
//if ((field.access & Opcodes.ACC_STATIC) != 0) {
|
||||
if (isStatic) {
|
||||
if (primitiveLDCDescriptors.contains(field.desc) && primitiveLDCClasses.contains(value.getClass())) {
|
||||
field.value = value;
|
||||
return;
|
||||
}
|
||||
List<FieldInsnNode> putStaticNodes = Arrays.stream(initMethod.instructions.toArray())
|
||||
.filter(node -> node instanceof FieldInsnNode && node.getOpcode() == Opcodes.PUTSTATIC).map(p -> (FieldInsnNode) p)
|
||||
.filter(node -> node.owner.equals(classNode.name) && node.name.equals(field.name) && node.desc.equals(field.desc)).collect(Collectors.toList());
|
||||
InsnList setter = serializeValue(value);
|
||||
if (putStaticNodes.isEmpty()) {
|
||||
setter.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, field.name, field.desc));
|
||||
Arrays.stream(initMethod.instructions.toArray()).filter(node -> node.getOpcode() == Opcodes.RETURN)
|
||||
.forEach(node -> initMethod.instructions.insertBefore(node, setter));
|
||||
} else {
|
||||
setter.insert(new InsnNode(Type.getType(field.desc).getSize() == 1 ? Opcodes.POP : Opcodes.POP2));
|
||||
for (FieldInsnNode fieldInsnNode : putStaticNodes) {
|
||||
initMethod.instructions.insertBefore(fieldInsnNode, setter);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (initMethod == null) {
|
||||
throw new IllegalArgumentException(String.format("Not found init in target: %s", classNode.name));
|
||||
}
|
||||
List<FieldInsnNode> putFieldNodes = Arrays.stream(initMethod.instructions.toArray())
|
||||
.filter(node -> node instanceof FieldInsnNode && node.getOpcode() == Opcodes.PUTFIELD).map(p -> (FieldInsnNode) p)
|
||||
.filter(node -> node.owner.equals(classNode.name) && node.name.equals(field.name) && node.desc.equals(field.desc)).collect(Collectors.toList());
|
||||
InsnList setter = serializeValue(value);
|
||||
if (putFieldNodes.isEmpty()) {
|
||||
setter.insert(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
setter.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, field.name, field.desc));
|
||||
Arrays.stream(initMethod.instructions.toArray())
|
||||
.filter(node -> node.getOpcode() == Opcodes.RETURN)
|
||||
.forEach(node -> initMethod.instructions.insertBefore(node, setter));
|
||||
} else {
|
||||
setter.insert(new InsnNode(Type.getType(field.desc).getSize() == 1 ? Opcodes.POP : Opcodes.POP2));
|
||||
for (FieldInsnNode fieldInsnNode : putFieldNodes) {
|
||||
initMethod.instructions.insertBefore(fieldInsnNode, setter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Serializer<?> serializerClass(int opcode) {
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Deprecated from 5.2.0
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class HibernateDaoProvider extends DaoProvider implements Reconfigurable, AutoCloseable {
|
||||
public String driver;
|
||||
public String url;
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.handler.MemoryAuthHandler;
|
||||
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
||||
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
|
||||
import pro.gravit.launchserver.auth.texture.NullTextureProvider;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.impl.TestLaunchServerConfigManager;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.utils.command.StdCommandHandler;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
|
||||
public class ConfigurationTest {
|
||||
@TempDir
|
||||
public static Path modulesDir;
|
||||
@TempDir
|
||||
public static Path configDir;
|
||||
@TempDir
|
||||
public static Path dir;
|
||||
public static LaunchServer launchServer;
|
||||
public static TestLaunchServerConfigManager launchServerConfigManager;
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() throws Throwable {
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(modulesDir, configDir, null);
|
||||
LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
|
||||
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
|
||||
Launcher.gsonManager.initGson();
|
||||
LaunchServerRuntimeConfig runtimeConfig = new LaunchServerRuntimeConfig();
|
||||
LaunchServerBuilder builder = new LaunchServerBuilder();
|
||||
KeyPair pair = SecurityHelper.genECKeyPair(new SecureRandom());
|
||||
ECPublicKey publicKey = (ECPublicKey) pair.getPublic();
|
||||
ECPrivateKey privateKey = (ECPrivateKey) pair.getPrivate();
|
||||
launchServerConfigManager = new TestLaunchServerConfigManager();
|
||||
builder.setDir(dir)
|
||||
.setEnv(LaunchServer.LaunchServerEnv.TEST)
|
||||
.setConfig(config)
|
||||
.setRuntimeConfig(runtimeConfig)
|
||||
.setPublicKey(publicKey)
|
||||
.setPrivateKey(privateKey)
|
||||
.setCertificateManager(new CertificateManager())
|
||||
.setLaunchServerConfigManager(launchServerConfigManager)
|
||||
.setModulesManager(modulesManager)
|
||||
.setCommandHandler(new StdCommandHandler(false));
|
||||
launchServer = builder.build();
|
||||
}
|
||||
@Test
|
||||
public static void reloadTest() throws Exception {
|
||||
AuthProvider provider = new AuthProvider() {
|
||||
@Override
|
||||
public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception {
|
||||
if(!(password instanceof AuthPlainPassword)) throw new UnsupportedOperationException();
|
||||
if(login.equals("test") && ((AuthPlainPassword) password).password.equals("test")) {
|
||||
return new AuthProviderResult(login, SecurityHelper.randomStringToken(), new ClientPermissions());
|
||||
}
|
||||
throw new AuthException("Incorrect password");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
}
|
||||
};
|
||||
AuthProviderPair pair = new AuthProviderPair(provider, new MemoryAuthHandler(), new NullTextureProvider());
|
||||
launchServerConfigManager.config.auth.put("std", pair);
|
||||
launchServer.reload(LaunchServer.ReloadType.FULL);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.impl.TestLaunchServerConfigManager;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
|
@ -46,29 +47,7 @@ public static void prepare() throws Throwable {
|
|||
.setPublicKey(publicKey)
|
||||
.setPrivateKey(privateKey)
|
||||
.setCertificateManager(new CertificateManager())
|
||||
.setLaunchServerConfigManager(new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() {
|
||||
return LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() {
|
||||
LaunchServerRuntimeConfig r = new LaunchServerRuntimeConfig();
|
||||
r.reset();
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
||||
|
||||
}
|
||||
})
|
||||
.setLaunchServerConfigManager(new TestLaunchServerConfigManager())
|
||||
.setModulesManager(modulesManager)
|
||||
.setCommandHandler(new StdCommandHandler(false));
|
||||
launchServer = builder.build();
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package pro.gravit.launchserver.impl;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager {
|
||||
public LaunchServerConfig config;
|
||||
public LaunchServerRuntimeConfig runtimeConfig;
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
|
||||
return runtimeConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
public TestLaunchServerConfigManager() {
|
||||
config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
|
||||
runtimeConfig = new LaunchServerRuntimeConfig();
|
||||
runtimeConfig.reset();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue