[REFACTOR] Mini refactoring

This commit is contained in:
Gravita 2021-04-06 17:39:14 +07:00
parent 1cb2369bfa
commit f1331b6d5d
6 changed files with 241 additions and 98 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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();
}
}