[FEATURE][REFACTOR] New launcher build pipeline

This commit is contained in:
Gravita 2025-06-28 23:02:47 +07:00
parent 101d8c7275
commit bda6a35945
28 changed files with 223 additions and 260 deletions

View file

@ -2,17 +2,16 @@
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.base.events.RequestEvent;
import pro.gravit.launcher.base.events.request.ProfilesRequestEvent;
import pro.gravit.launcher.base.modules.events.ClosePhase; import pro.gravit.launcher.base.modules.events.ClosePhase;
import pro.gravit.launcher.base.profiles.ClientProfile; import pro.gravit.launcher.base.profiles.ClientProfile;
import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider; import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider;
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
import pro.gravit.launchserver.binary.EXELauncherBinary; import pro.gravit.launchserver.binary.EXELauncherBinary;
import pro.gravit.launchserver.binary.JARLauncherBinary; import pro.gravit.launchserver.binary.JARLauncherBinary;
import pro.gravit.launchserver.binary.LauncherBinary; import pro.gravit.launchserver.binary.LauncherBinary;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.helper.SignHelper; import pro.gravit.launchserver.helper.SignHelper;
import pro.gravit.launchserver.launchermodules.LauncherModuleLoader; import pro.gravit.launchserver.launchermodules.LauncherModuleLoader;
import pro.gravit.launchserver.manangers.*; import pro.gravit.launchserver.manangers.*;
@ -84,10 +83,6 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
public final Path librariesDir; public final Path librariesDir;
public final Path controlFile; public final Path controlFile;
public final Path proguardDir; public final Path proguardDir;
/**
* This object contains runtime configuration
*/
public final LaunchServerRuntimeConfig runtime;
/** /**
* Pipeline for building JAR * Pipeline for building JAR
*/ */
@ -119,7 +114,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
public final int shardId; public final int shardId;
public LaunchServerConfig config; public LaunchServerConfig config;
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager, int shardId) throws IOException { public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager, int shardId) throws IOException {
this.dir = directories.dir; this.dir = directories.dir;
this.tmpDir = directories.tmpDir; this.tmpDir = directories.tmpDir;
this.env = env; this.env = env;
@ -129,7 +124,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
this.updatesDir = directories.updatesDir; this.updatesDir = directories.updatesDir;
this.keyAgreementManager = keyAgreementManager; this.keyAgreementManager = keyAgreementManager;
this.commandHandler = commandHandler; this.commandHandler = commandHandler;
this.runtime = runtimeConfig;
this.certificateManager = certificateManager; this.certificateManager = certificateManager;
this.service = Executors.newScheduledThreadPool(config.netty.performance.schedulerThread); this.service = Executors.newScheduledThreadPool(config.netty.performance.schedulerThread);
launcherLibraries = directories.launcherLibrariesDir; launcherLibraries = directories.launcherLibrariesDir;
@ -151,7 +145,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
// Print keypair fingerprints // Print keypair fingerprints
runtime.verify();
config.verify(); config.verify();
// build hooks, anti-brutforce and other // build hooks, anti-brutforce and other
@ -260,7 +253,6 @@ public void invoke(String... args) throws Exception {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
launchServerConfigManager.writeConfig(config); launchServerConfigManager.writeConfig(config);
launchServerConfigManager.writeRuntimeConfig(runtime);
logger.info("LaunchServerConfig saved"); logger.info("LaunchServerConfig saved");
} }
}; };
@ -309,6 +301,12 @@ public Path createTempDirectory(String name) throws IOException {
return path; return path;
} }
public Path createTempFilePath(String name, String ext) throws IOException {
var path = tmpDir.resolve(String.format("launchserver-%s-%s.%s", name, SecurityHelper.randomStringToken(), ext));
IOHelper.createParentDirs(path);
return path;
}
private LauncherBinary binary() { private LauncherBinary binary() {
LaunchServerLauncherExeInit event = new LaunchServerLauncherExeInit(this, null); LaunchServerLauncherExeInit event = new LaunchServerLauncherExeInit(this, null);
modulesManager.invokeEvent(event); modulesManager.invokeEvent(event);
@ -319,8 +317,20 @@ private LauncherBinary binary() {
} }
public void buildLauncherBinaries() throws IOException { public void buildLauncherBinaries() throws IOException {
launcherBinary.build(); PipelineContext launcherContext = launcherBinary.build();
launcherEXEBinary.build(); PipelineContext exeContext = launcherEXEBinary.build();
UpdatesProvider.UpdateUploadInfo jarInfo = launcherContext.makeUploadInfo(UpdatesProvider.UpdateVariant.JAR);
UpdatesProvider.UpdateUploadInfo exeInfo = exeContext.makeUploadInfo(UpdatesProvider.UpdateVariant.EXE);
List<UpdatesProvider.UpdateUploadInfo> list = new ArrayList<>(2);
if(jarInfo != null) {
list.add(jarInfo);
}
if(exeInfo != null) {
list.add(exeInfo);
}
config.updatesProvider.pushUpdate(list);
launcherContext.clear();
exeContext.clear();
} }
public void close() throws Exception { public void close() throws Exception {
@ -330,8 +340,6 @@ public void close() throws Exception {
// Close handlers & providers // Close handlers & providers
config.close(ReloadType.FULL); config.close(ReloadType.FULL);
modulesManager.invokeEvent(new ClosePhase()); modulesManager.invokeEvent(new ClosePhase());
logger.info("Save LaunchServer runtime config");
launchServerConfigManager.writeRuntimeConfig(runtime);
// Print last message before death :( // Print last message before death :(
logger.info("LaunchServer stopped"); logger.info("LaunchServer stopped");
} }
@ -404,11 +412,7 @@ public enum LaunchServerEnv {
public interface LaunchServerConfigManager { public interface LaunchServerConfigManager {
LaunchServerConfig readConfig() throws IOException; LaunchServerConfig readConfig() throws IOException;
LaunchServerRuntimeConfig readRuntimeConfig() throws IOException;
void writeConfig(LaunchServerConfig config) throws IOException; void writeConfig(LaunchServerConfig config) throws IOException;
void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException;
} }
public static class LaunchServerDirectories { public static class LaunchServerDirectories {

View file

@ -1,7 +1,6 @@
package pro.gravit.launchserver; package pro.gravit.launchserver;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.manangers.CertificateManager; import pro.gravit.launchserver.manangers.CertificateManager;
import pro.gravit.launchserver.manangers.KeyAgreementManager; import pro.gravit.launchserver.manangers.KeyAgreementManager;
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager; import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
@ -11,7 +10,6 @@
public class LaunchServerBuilder { public class LaunchServerBuilder {
private LaunchServerConfig config; private LaunchServerConfig config;
private LaunchServerRuntimeConfig runtimeConfig;
private CommandHandler commandHandler; private CommandHandler commandHandler;
private LaunchServer.LaunchServerEnv env; private LaunchServer.LaunchServerEnv env;
private LaunchServerModulesManager modulesManager; private LaunchServerModulesManager modulesManager;
@ -36,11 +34,6 @@ public LaunchServerBuilder setModulesManager(LaunchServerModulesManager modulesM
return this; return this;
} }
public LaunchServerBuilder setRuntimeConfig(LaunchServerRuntimeConfig runtimeConfig) {
this.runtimeConfig = runtimeConfig;
return this;
}
public LaunchServerBuilder setCommandHandler(CommandHandler commandHandler) { public LaunchServerBuilder setCommandHandler(CommandHandler commandHandler) {
this.commandHandler = commandHandler; this.commandHandler = commandHandler;
return this; return this;
@ -77,7 +70,7 @@ public LaunchServer build() throws Exception {
if(shardId == null) { if(shardId == null) {
shardId = Integer.parseInt(System.getProperty("launchserver.shardId", "0")); shardId = Integer.parseInt(System.getProperty("launchserver.shardId", "0"));
} }
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, keyAgreementManager, commandHandler, certificateManager, shardId); return new LaunchServer(directories, env, config, launchServerConfigManager, modulesManager, keyAgreementManager, commandHandler, certificateManager, shardId);
} }
public LaunchServerBuilder setCertificateManager(CertificateManager certificateManager) { public LaunchServerBuilder setCertificateManager(CertificateManager certificateManager) {
@ -95,19 +88,9 @@ public LaunchServerConfig readConfig() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public LaunchServerRuntimeConfig readRuntimeConfig() {
throw new UnsupportedOperationException();
}
@Override @Override
public void writeConfig(LaunchServerConfig config) { public void writeConfig(LaunchServerConfig config) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
throw new UnsupportedOperationException();
}
} }
} }

View file

@ -19,7 +19,6 @@
import pro.gravit.launchserver.auth.updates.UpdatesProvider; import pro.gravit.launchserver.auth.updates.UpdatesProvider;
import pro.gravit.launchserver.components.Component; import pro.gravit.launchserver.components.Component;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.manangers.CertificateManager; import pro.gravit.launchserver.manangers.CertificateManager;
import pro.gravit.launchserver.manangers.LaunchServerGsonManager; import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager; import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
@ -32,7 +31,6 @@
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.*; import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.Security; import java.security.Security;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
@ -49,7 +47,7 @@ public static void main(String[] args) throws Exception {
LogHelper.printVersion("LaunchServer"); LogHelper.printVersion("LaunchServer");
LogHelper.printLicense("LaunchServer"); LogHelper.printLicense("LaunchServer");
Path dir = IOHelper.WORKING_DIR; Path dir = IOHelper.WORKING_DIR;
Path configFile, runtimeConfigFile; Path configFile;
try { try {
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider"); Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastleProvider());
@ -80,7 +78,6 @@ public static void main(String[] args) throws Exception {
} }
} }
LaunchServerRuntimeConfig runtimeConfig;
LaunchServerConfig config; LaunchServerConfig config;
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION; LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(directories.modules, dir.resolve("config"), certificateManager.trustManager); LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(directories.modules, dir.resolve("config"), certificateManager.trustManager);
@ -94,11 +91,6 @@ public static void main(String[] args) throws Exception {
} else { } else {
configFile = dir.resolve("LaunchServer.json"); configFile = dir.resolve("LaunchServer.json");
} }
if (IOHelper.exists(dir.resolve("RuntimeLaunchServer.conf"))) {
runtimeConfigFile = dir.resolve("RuntimeLaunchServer.conf");
} else {
runtimeConfigFile = dir.resolve("RuntimeLaunchServer.json");
}
CommandHandler localCommandHandler; CommandHandler localCommandHandler;
try { try {
Class.forName("org.jline.terminal.Terminal"); Class.forName("org.jline.terminal.Terminal");
@ -116,23 +108,12 @@ public static void main(String[] args) throws Exception {
try (BufferedReader reader = IOHelper.newReader(configFile)) { try (BufferedReader reader = IOHelper.newReader(configFile)) {
config = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class); config = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class);
} }
if (!Files.exists(runtimeConfigFile)) {
logger.info("Reset LaunchServer runtime config file");
runtimeConfig = new LaunchServerRuntimeConfig();
runtimeConfig.reset();
} else {
logger.info("Reading LaunchServer runtime config file");
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
runtimeConfig = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
}
}
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile, runtimeConfigFile); LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile);
LaunchServer server = new LaunchServerBuilder() LaunchServer server = new LaunchServerBuilder()
.setDirectories(directories) .setDirectories(directories)
.setEnv(env) .setEnv(env)
.setCommandHandler(localCommandHandler) .setCommandHandler(localCommandHandler)
.setRuntimeConfig(runtimeConfig)
.setConfig(config) .setConfig(config)
.setModulesManager(modulesManager) .setModulesManager(modulesManager)
.setLaunchServerConfigManager(launchServerConfigManager) .setLaunchServerConfigManager(launchServerConfigManager)
@ -270,11 +251,9 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
private static class BasicLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager { private static class BasicLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager {
private final Path configFile; private final Path configFile;
private final Path runtimeConfigFile;
public BasicLaunchServerConfigManager(Path configFile, Path runtimeConfigFile) { public BasicLaunchServerConfigManager(Path configFile) {
this.configFile = configFile; this.configFile = configFile;
this.runtimeConfigFile = runtimeConfigFile;
} }
@Override @Override
@ -286,15 +265,6 @@ public LaunchServerConfig readConfig() throws IOException {
return config1; return config1;
} }
@Override
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
LaunchServerRuntimeConfig config1;
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
}
return config1;
}
@Override @Override
public void writeConfig(LaunchServerConfig config) throws IOException { public void writeConfig(LaunchServerConfig config) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
@ -310,21 +280,5 @@ public void writeConfig(LaunchServerConfig config) throws IOException {
IOHelper.write(configFile, bytes); IOHelper.write(configFile, bytes);
} }
} }
@Override
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (Writer writer = IOHelper.newWriter(output)) {
if (Launcher.gsonManager.configGson != null) {
Launcher.gsonManager.configGson.toJson(config, writer);
} else {
logger.error("Error writing LaunchServer runtime config file. Gson is null");
}
}
byte[] bytes = output.toByteArray();
if(bytes.length > 0) {
IOHelper.write(runtimeConfigFile, bytes);
}
}
} }
} }

View file

@ -14,15 +14,8 @@
public abstract class BinaryPipeline { public abstract class BinaryPipeline {
public final List<LauncherBuildTask> tasks = new ArrayList<>(); public final List<LauncherBuildTask> tasks = new ArrayList<>();
public final Path buildDir;
public final String nameFormat;
protected transient final Logger logger = LogManager.getLogger(); protected transient final Logger logger = LogManager.getLogger();
public BinaryPipeline(Path buildDir, String nameFormat) {
this.buildDir = buildDir;
this.nameFormat = nameFormat;
}
public void addCounted(int count, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) { public void addCounted(int count, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
List<LauncherBuildTask> indexes = new ArrayList<>(); List<LauncherBuildTask> indexes = new ArrayList<>();
tasks.stream().filter(pred).forEach(indexes::add); tasks.stream().filter(pred).forEach(indexes::add);
@ -77,20 +70,4 @@ public Optional<LauncherBuildTask> getTaskBefore(Predicate<LauncherBuildTask> pr
} }
return Optional.empty(); return Optional.empty();
} }
public String nextName(String taskName) {
return nameFormat.formatted(taskName);
}
public Path nextPath(String taskName) {
return buildDir.resolve(nextName(taskName));
}
public Path nextPath(LauncherBuildTask task) {
return nextPath(task.getName());
}
public Path nextLowerPath(LauncherBuildTask task) {
return nextPath(CommonHelper.low(task.getName()));
}
} }

View file

@ -5,6 +5,7 @@
import pro.gravit.launcher.base.Launcher; import pro.gravit.launcher.base.Launcher;
import pro.gravit.launcher.core.serialize.HOutput; import pro.gravit.launcher.core.serialize.HOutput;
import pro.gravit.launcher.core.serialize.stream.StreamObject; import pro.gravit.launcher.core.serialize.stream.StreamObject;
import pro.gravit.launchserver.asm.InjectClassAcceptor;
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.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
@ -27,9 +28,7 @@
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.HashSet; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
@ -40,16 +39,20 @@
import static pro.gravit.utils.helper.IOHelper.newZipEntry; import static pro.gravit.utils.helper.IOHelper.newZipEntry;
public class BuildContext { public class BuildContext {
public final PipelineContext pipelineContext;
public final ZipOutputStream output; public final ZipOutputStream output;
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;
public final HashSet<String> clientModules; public final HashSet<String> clientModules;
public final HashSet<String> legacyClientModules; public final HashSet<String> legacyClientModules;
public final Map<String, Object> properties;
public final List<MainBuildTask.Transformer> transformers = new ArrayList<>();
private Path runtimeDir; private Path runtimeDir;
private boolean deleteRuntimeDir; private boolean deleteRuntimeDir;
public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainBuildTask task, Path runtimeDir) { public BuildContext(PipelineContext pipelineContext, ZipOutputStream output, List<JarFile> readerClassPath, MainBuildTask task, Path runtimeDir) {
this.pipelineContext = pipelineContext;
this.output = output; this.output = output;
this.readerClassPath = readerClassPath; this.readerClassPath = readerClassPath;
this.task = task; this.task = task;
@ -57,6 +60,9 @@ public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainB
fileList = new HashSet<>(1024); fileList = new HashSet<>(1024);
clientModules = new HashSet<>(); clientModules = new HashSet<>();
legacyClientModules = new HashSet<>(); legacyClientModules = new HashSet<>();
properties = new HashMap<>();
InjectClassAcceptor injectClassAcceptor = new InjectClassAcceptor(properties);
transformers.add(injectClassAcceptor);
} }
public void pushFile(String filename, InputStream inputStream) throws IOException { public void pushFile(String filename, InputStream inputStream) throws IOException {

View file

@ -10,7 +10,7 @@
public class EXELauncherBinary extends LauncherBinary { public class EXELauncherBinary extends LauncherBinary {
public EXELauncherBinary(LaunchServer server) { public EXELauncherBinary(LaunchServer server) {
super(server, "Launcher-%s.exe"); super(server);
} }
@Override @Override
@ -19,7 +19,8 @@ public UpdatesProvider.UpdateVariant getVariant() {
} }
@Override @Override
public void build() throws IOException { public PipelineContext build() throws IOException {
return new PipelineContext(server);
} }
} }

View file

@ -24,7 +24,7 @@ public final class JARLauncherBinary extends LauncherBinary {
public final Map<String, Path> files; public final Map<String, Path> files;
public JARLauncherBinary(LaunchServer server) throws IOException { public JARLauncherBinary(LaunchServer server) throws IOException {
super(server, "Launcher-%s.jar"); super(server);
count = new AtomicLong(0); count = new AtomicLong(0);
runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR); runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR);
buildDir = server.dir.resolve("build"); buildDir = server.dir.resolve("build");

View file

@ -13,39 +13,36 @@
public abstract class LauncherBinary extends BinaryPipeline { public abstract class LauncherBinary extends BinaryPipeline {
public final LaunchServer server; public final LaunchServer server;
public final PipelineContext context;
protected LauncherBinary(LaunchServer server, String nameFormat) { protected LauncherBinary(LaunchServer server) {
super(server.tmpDir.resolve("build"), nameFormat);
this.server = server; this.server = server;
this.context = new PipelineContext(server);
} }
public static Path resolve(LaunchServer server, String ext) { public static Path resolve(LaunchServer server, String ext) {
return Path.of(server.config.binaryName + ext); return Path.of(server.config.binaryName + ext);
} }
public void build() throws IOException { public PipelineContext build() throws IOException {
logger.info("Building launcher binary file"); logger.info("Building launcher binary file");
Path thisPath = null;
long time_start = System.currentTimeMillis(); long time_start = System.currentTimeMillis();
long time_this = time_start; long time_this = time_start;
for (LauncherBuildTask task : tasks) { for (LauncherBuildTask task : tasks) {
logger.info("Task {}", task.getName()); logger.info("Task {}", task.getName());
Path oldPath = thisPath; Path newPath = task.process(context);
thisPath = task.process(oldPath); if(newPath != null) {
context.setLastest(newPath);
context.putArtifact(task.getName(), newPath);
}
long time_task_end = System.currentTimeMillis(); long time_task_end = System.currentTimeMillis();
long time_task = time_task_end - time_this; long time_task = time_task_end - time_this;
time_this = time_task_end; time_this = time_task_end;
logger.info("Task {} processed from {} millis", task.getName(), time_task); logger.info("Task {} processed from {} millis", task.getName(), time_task);
} }
long time_end = System.currentTimeMillis(); long time_end = System.currentTimeMillis();
if(thisPath != null) {
// TODO fix me
server.config.updatesProvider.pushUpdate(List.of(new UpdatesProvider.UpdateUploadInfo(thisPath, getVariant(), new UpdatesProvider.BuildSecrets(server.runtime.clientCheckSecret, null))));
} else {
logger.warn("Missing {} binary file", getVariant());
}
IOHelper.deleteDir(buildDir, false);
logger.info("Build successful from {} millis", time_end - time_start); logger.info("Build successful from {} millis", time_end - time_start);
return this.context;
} }
public abstract UpdatesProvider.UpdateVariant getVariant(); public abstract UpdatesProvider.UpdateVariant getVariant();

View file

@ -0,0 +1,94 @@
package pro.gravit.launchserver.binary;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
import pro.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class PipelineContext {
private final Logger logger = LogManager.getLogger();
private final LaunchServer launchServer;
private final Map<String, Path> artifacts = new HashMap<>();
private final Map<String, Object> properties = new HashMap<>();
private Set<Path> tempFiles = new HashSet<>();
private Path lastest;
public PipelineContext(LaunchServer launchServer) {
this.launchServer = launchServer;
}
public Path makeTempPath(String name, String ext) throws IOException {
return this.launchServer.createTempFilePath(name, ext);
}
public Map<String, Path> getArtifacts() {
return artifacts;
}
public Path getLastest() {
return lastest;
}
public void setLastest(Path lastest) {
this.lastest = lastest;
}
public void putArtifact(String name, Path path) {
artifacts.put(name, path);
}
public void putProperty(String name, Object prop) {
properties.put(name, prop);
}
public void putProperties(Map<String, Object> properties) {
this.properties.putAll(properties);
}
public LaunchServer getLaunchServer() {
return launchServer;
}
@SuppressWarnings("unchecked")
public<T> T getProperty(String name) {
return (T) properties.get(name);
}
public UpdatesProvider.UpdateUploadInfo makeUploadInfo(UpdatesProvider.UpdateVariant variant) {
if(getLastest() == null) {
return null;
}
try {
byte[] hash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, getLastest());
return new UpdatesProvider.UpdateUploadInfo(getLastest(), variant, new UpdatesProvider.BuildSecrets(
getProperty("checkClientSecret"), hash
));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void clear() {
for(var p : tempFiles) {
if(Files.exists(p)) {
try {
Files.delete(p);
} catch (IOException e) {
logger.error("Couldn't delete file {}", p, e);
}
}
}
tempFiles.clear();
properties.clear();
artifacts.clear();
}
}

View file

@ -6,6 +6,7 @@
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.SafeClassWriter; import pro.gravit.launchserver.asm.SafeClassWriter;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import java.io.IOException; import java.io.IOException;
@ -66,8 +67,9 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
Path out = server.launcherBinary.nextPath("post-fixed"); Path inputFile = context.getLastest();
Path out = context.makeTempPath("post-fixed", ".jar");
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(out))) { try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(out))) {
apply(inputFile, inputFile, output, server, (e) -> false, true); apply(inputFile, inputFile, output, server, (e) -> false, true);
} }

View file

@ -1,6 +1,7 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import java.io.IOException; import java.io.IOException;
@ -32,8 +33,9 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
Path outputFile = srv.launcherBinary.nextPath("attached"); Path inputFile = context.getLastest();
Path outputFile = context.makeTempPath("attached", ".jar");
try (ZipInputStream input = IOHelper.newZipInput(inputFile); try (ZipInputStream input = IOHelper.newZipInput(inputFile);
ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputFile))) { ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputFile))) {
ZipEntry e = input.getNextEntry(); ZipEntry e = input.getNextEntry();

View file

@ -18,6 +18,7 @@
import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.launchserver.helper.SignHelper; import pro.gravit.launchserver.helper.SignHelper;
import java.io.IOException; import java.io.IOException;
@ -49,8 +50,8 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
if (signedDataGenerator != null) return inputFile; if (signedDataGenerator != null) return null;
try { try {
logger.warn("You are using an auto-generated certificate (sign.enabled false). It is not good"); logger.warn("You are using an auto-generated certificate (sign.enabled false). It is not good");
logger.warn("It is highly recommended that you use the correct certificate (sign.enabled true)"); logger.warn("It is highly recommended that you use the correct certificate (sign.enabled true)");
@ -79,6 +80,6 @@ public Path process(Path inputFile) throws IOException {
} catch (OperatorCreationException | CMSException | CertificateException e) { } catch (OperatorCreationException | CMSException | CertificateException e) {
logger.error("Certificate generate failed", e); logger.error("Certificate generate failed", e);
} }
return inputFile; return null;
} }
} }

View file

@ -1,6 +1,7 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import java.io.IOException; import java.io.IOException;
@ -23,8 +24,9 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
Path output = server.launcherBinary.nextPath(this); Path inputFile = context.getLastest();
Path output = context.makeTempPath("compress", ".jar");
try (ZipOutputStream outputStream = new ZipOutputStream(IOHelper.newOutput(output))) { try (ZipOutputStream outputStream = new ZipOutputStream(IOHelper.newOutput(output))) {
outputStream.setMethod(ZipOutputStream.DEFLATED); outputStream.setMethod(ZipOutputStream.DEFLATED);
outputStream.setLevel(Deflater.BEST_COMPRESSION); outputStream.setLevel(Deflater.BEST_COMPRESSION);

View file

@ -1,10 +1,12 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import pro.gravit.launchserver.binary.PipelineContext;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
public interface LauncherBuildTask { public interface LauncherBuildTask {
String getName(); String getName();
Path process(Path inputFile) throws IOException; Path process(PipelineContext context) throws IOException;
} }

View file

@ -15,6 +15,7 @@
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.PipelineContext;
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.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
@ -30,18 +31,14 @@
public class MainBuildTask implements LauncherBuildTask { public class MainBuildTask implements LauncherBuildTask {
public final ClassMetadataReader reader; public final ClassMetadataReader reader;
public final Set<String> blacklist = new HashSet<>(); public final Set<String> blacklist = new HashSet<>();
public final List<Transformer> transformers = new ArrayList<>();
public final IOHookSet<BuildContext> preBuildHook = new IOHookSet<>(); public final IOHookSet<BuildContext> preBuildHook = new IOHookSet<>();
public final IOHookSet<BuildContext> postBuildHook = new IOHookSet<>(); public final IOHookSet<BuildContext> postBuildHook = new IOHookSet<>();
public final Map<String, Object> properties = new HashMap<>();
private final LaunchServer server; private final LaunchServer server;
private transient final Logger logger = LogManager.getLogger(); private transient final Logger logger = LogManager.getLogger();
public MainBuildTask(LaunchServer srv) { public MainBuildTask(LaunchServer srv) {
server = srv; server = srv;
reader = new ClassMetadataReader(); reader = new ClassMetadataReader();
InjectClassAcceptor injectClassAcceptor = new InjectClassAcceptor(properties);
transformers.add(injectClassAcceptor);
} }
@Override @Override
@ -50,15 +47,16 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputJar) throws IOException { public Path process(PipelineContext pipelineContext) throws IOException {
Path outputJar = server.launcherBinary.nextPath(this); Path inputJar = pipelineContext.getLastest();
Path outputJar = pipelineContext.makeTempPath("main", ".jar");
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) { try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) {
BuildContext context = new BuildContext(output, reader.getCp(), this, server.launcherBinary.runtimeDir); BuildContext context = new BuildContext(pipelineContext, output, reader.getCp(), this, server.launcherBinary.runtimeDir);
initProps(); initProps(context);
preBuildHook.hook(context); preBuildHook.hook(context);
properties.put("launcher.legacymodules", context.legacyClientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList())); context.properties.put("launcher.legacymodules", context.legacyClientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList()));
properties.put("launcher.modules", context.clientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList())); context.properties.put("launcher.modules", context.clientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList()));
postInitProps(); postInitProps(context);
reader.getCp().add(new JarFile(inputJar.toFile())); reader.getCp().add(new JarFile(inputJar.toFile()));
for (Path e : server.launcherBinary.coreLibs) { for (Path e : server.launcherBinary.coreLibs) {
reader.getCp().add(new JarFile(e.toFile())); reader.getCp().add(new JarFile(e.toFile()));
@ -69,7 +67,8 @@ public Path process(Path inputJar) throws IOException {
Map<String, byte[]> runtime = new HashMap<>(256); Map<String, byte[]> runtime = new HashMap<>(256);
// Write launcher guard dir // Write launcher guard dir
if (server.config.launcher.encryptRuntime) { if (server.config.launcher.encryptRuntime) {
context.pushEncryptedDir(context.getRuntimeDir(), Launcher.RUNTIME_DIR, server.runtime.runtimeEncryptKey, runtime, false); String runtimeEncryptKey = context.pipelineContext.getProperty("runtimeEncryptKey");
context.pushEncryptedDir(context.getRuntimeDir(), Launcher.RUNTIME_DIR, runtimeEncryptKey, runtime, false);
} else { } else {
context.pushDir(context.getRuntimeDir(), Launcher.RUNTIME_DIR, runtime, false); context.pushDir(context.getRuntimeDir(), Launcher.RUNTIME_DIR, runtime, false);
} }
@ -85,7 +84,7 @@ public Path process(Path inputJar) throws IOException {
return outputJar; return outputJar;
} }
protected void postInitProps() { protected void postInitProps(BuildContext context) {
List<byte[]> certificates = Arrays.stream(server.certificateManager.trustManager.getTrusted()).map(e -> { List<byte[]> certificates = Arrays.stream(server.certificateManager.trustManager.getTrusted()).map(e -> {
try { try {
return e.getEncoded(); return e.getEncoded();
@ -102,41 +101,42 @@ protected void postInitProps() {
throw new InternalError(e); throw new InternalError(e);
} }
} }
properties.put("launchercore.certificates", certificates); context.properties.put("launchercore.certificates", certificates);
} }
protected void initProps() { protected void initProps(BuildContext context) {
properties.clear(); context.properties.clear();
properties.put("launcher.address", server.config.netty.address); context.properties.put("launcher.address", server.config.netty.address);
properties.put("launcher.projectName", server.config.projectName); context.properties.put("launcher.projectName", server.config.projectName);
properties.put("runtimeconfig.secretKeyClient", SecurityHelper.randomStringAESKey()); context.properties.put("runtimeconfig.secretKeyClient", SecurityHelper.randomStringAESKey());
properties.put("launcher.port", 32148 + SecurityHelper.newRandom().nextInt(512)); context.properties.put("launcher.port", 32148 + SecurityHelper.newRandom().nextInt(512));
properties.put("launchercore.env", server.config.env); context.properties.put("launchercore.env", server.config.env);
properties.put("launcher.memory", server.config.launcher.memoryLimit); context.properties.put("launcher.memory", server.config.launcher.memoryLimit);
properties.put("launcher.customJvmOptions", server.config.launcher.customJvmOptions); context.properties.put("launcher.customJvmOptions", server.config.launcher.customJvmOptions);
if (server.config.launcher.encryptRuntime) { if (server.config.launcher.encryptRuntime) {
if (server.runtime.runtimeEncryptKey == null) String runtimeEncryptKey = SecurityHelper.randomStringToken();
server.runtime.runtimeEncryptKey = SecurityHelper.randomStringToken(); context.pipelineContext.putProperty("runtimeEncryptKey", runtimeEncryptKey);
properties.put("runtimeconfig.runtimeEncryptKey", server.runtime.runtimeEncryptKey); context.properties.put("runtimeconfig.runtimeEncryptKey", runtimeEncryptKey);
} }
properties.put("launcher.certificatePinning", server.config.launcher.certificatePinning); context.properties.put("launcher.certificatePinning", server.config.launcher.certificatePinning);
properties.put("runtimeconfig.passwordEncryptKey", server.runtime.passwordEncryptKey); String checkClientSecret = SecurityHelper.randomStringToken();
context.pipelineContext.putProperty("checkClientSecret", checkClientSecret);
String launcherSalt = SecurityHelper.randomStringToken(); String launcherSalt = SecurityHelper.randomStringToken();
byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256, byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
server.runtime.clientCheckSecret.concat(".").concat(launcherSalt)); checkClientSecret.concat(".").concat(launcherSalt));
properties.put("runtimeconfig.secureCheckHash", Base64.getEncoder().encodeToString(launcherSecureHash)); context.properties.put("runtimeconfig.secureCheckHash", Base64.getEncoder().encodeToString(launcherSecureHash));
properties.put("runtimeconfig.secureCheckSalt", launcherSalt); context.properties.put("runtimeconfig.secureCheckSalt", launcherSalt);
if (server.runtime.unlockSecret == null) server.runtime.unlockSecret = SecurityHelper.randomStringToken(); String unlockSecret = SecurityHelper.randomStringToken();
properties.put("runtimeconfig.unlockSecret", server.runtime.unlockSecret); context.pipelineContext.putProperty("unlockSecret", unlockSecret);
server.runtime.buildNumber++; context.properties.put("runtimeconfig.unlockSecret", unlockSecret);
properties.put("runtimeconfig.buildNumber", server.runtime.buildNumber); context.properties.put("runtimeconfig.buildNumber", 1);
} }
public byte[] transformClass(byte[] bytes, String classname, BuildContext context) { public byte[] transformClass(byte[] bytes, String classname, BuildContext context) {
byte[] result = bytes; byte[] result = bytes;
ClassWriter writer; ClassWriter writer;
ClassNode cn = null; ClassNode cn = null;
for (Transformer t : transformers) { for (Transformer t : context.transformers) {
if (t instanceof ASMTransformer asmTransformer) { if (t instanceof ASMTransformer asmTransformer) {
if (cn == null) { if (cn == null) {
ClassReader cr = new ClassReader(result); ClassReader cr = new ClassReader(result);

View file

@ -3,6 +3,7 @@
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.UnpackHelper; import pro.gravit.utils.helper.UnpackHelper;
@ -29,7 +30,7 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
server.launcherBinary.coreLibs.clear(); server.launcherBinary.coreLibs.clear();
server.launcherBinary.addonLibs.clear(); server.launcherBinary.addonLibs.clear();
server.launcherBinary.files.clear(); server.launcherBinary.files.clear();

View file

@ -6,6 +6,7 @@
import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.OperatorCreationException;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.launchserver.binary.SignerJar; import pro.gravit.launchserver.binary.SignerJar;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.helper.SignHelper; import pro.gravit.launchserver.helper.SignHelper;
@ -52,8 +53,9 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
Path toRet = srv.launcherBinary.nextPath("signed"); Path inputFile = context.getLastest();
Path toRet = context.makeTempPath("signed", ".jar");
sign(config, inputFile, toRet); sign(config, inputFile, toRet);
return toRet; return toRet;
} }

View file

@ -206,7 +206,7 @@ public void invoke(String... args) {
logger.warn("Write access to LaunchServer.jar. Please use 'chmod 755 LaunchServer.jar'"); logger.warn("Write access to LaunchServer.jar. Please use 'chmod 755 LaunchServer.jar'");
} }
if (Files.exists(server.dir.resolve(".keys")) && checkOtherReadOrWriteAccess(server.dir.resolve(".keys"))) { if (Files.exists(server.dir.resolve(".keys")) && checkOtherReadOrWriteAccess(server.dir.resolve(".keys"))) {
logger.warn("Write or read access to .keys directory. Please use 'find .keys -type d -exec chmod 700 {} \; && find .keys -type f -exec chmod 600 {} \;'"); logger.warn("Write or read access to .keys directory. Please use 'chmod -r 700.keys");
} }
if (Files.exists(server.dir.resolve("LaunchServerConfig.json")) && checkOtherReadOrWriteAccess(server.dir.resolve("LaunchServerConfig.json"))) { if (Files.exists(server.dir.resolve("LaunchServerConfig.json")) && checkOtherReadOrWriteAccess(server.dir.resolve("LaunchServerConfig.json"))) {
logger.warn("Write or read access to LaunchServerConfig.json. Please use 'chmod 600 LaunchServerConfig.json'"); logger.warn("Write or read access to LaunchServerConfig.json. Please use 'chmod 600 LaunchServerConfig.json'");

View file

@ -4,6 +4,7 @@
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.Reconfigurable; import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.binary.PipelineContext;
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask; import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
import pro.gravit.utils.command.Command; import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.SubCommand; import pro.gravit.utils.command.SubCommand;
@ -137,19 +138,18 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
if (!component.enabled) { if (!component.enabled) {
return inputFile; return null;
} }
LauncherBuildTask task = server.launcherBinary.getTaskBefore((x) -> proguardTaskName.equals(x.getName())).get(); Path lastPath = context.getLastest();
Path lastPath = server.launcherBinary.nextPath(task);
if(Files.notExists(lastPath)) { if(Files.notExists(lastPath)) {
logger.error("{} not exist. Multi-Release JAR fix not applied!", lastPath); logger.error("{} not exist. Multi-Release JAR fix not applied!", lastPath);
return inputFile; return null;
} }
Path outputPath = server.launcherBinary.nextPath(this); Path outputPath = context.makeTempPath("multirelease-fix", "jar");
try(ZipOutputStream output = new ZipOutputStream(new FileOutputStream(outputPath.toFile()))) { try(ZipOutputStream output = new ZipOutputStream(new FileOutputStream(outputPath.toFile()))) {
try(ZipInputStream input = new ZipInputStream(new FileInputStream(inputFile.toFile()))) { try(ZipInputStream input = new ZipInputStream(new FileInputStream(lastPath.toFile()))) {
ZipEntry entry = input.getNextEntry(); ZipEntry entry = input.getNextEntry();
while(entry != null) { while(entry != null) {
ZipEntry newEntry = new ZipEntry(entry.getName()); ZipEntry newEntry = new ZipEntry(entry.getName());
@ -193,8 +193,8 @@ public String getName() {
} }
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(PipelineContext context) throws IOException {
Path outputJar = server.launcherBinary.nextLowerPath(this); Path outputJar = context.makeTempPath("proguard", "jar");
if (component.enabled) { if (component.enabled) {
if (!checkJMods(IOHelper.JVM_DIR.resolve("jmods"))) { if (!checkJMods(IOHelper.JVM_DIR.resolve("jmods"))) {
throw new RuntimeException("Java path: %s is not JDK! Please install JDK".formatted(IOHelper.JVM_DIR)); throw new RuntimeException("Java path: %s is not JDK! Please install JDK".formatted(IOHelper.JVM_DIR));
@ -221,7 +221,7 @@ public Path process(Path inputFile) throws IOException {
); );
} }
args.add("proguard.ProGuard"); args.add("proguard.ProGuard");
proguardConf.buildConfig(args, inputFile, outputJar, jfxPath == null ? new Path[0] : new Path[]{jfxPath}); proguardConf.buildConfig(args, context.getLastest(), outputJar, jfxPath == null ? new Path[0] : new Path[]{jfxPath});
Process process = new ProcessBuilder() Process process = new ProcessBuilder()
.command(args) .command(args)
@ -240,8 +240,9 @@ public Path process(Path inputFile) throws IOException {
} catch (Exception e) { } catch (Exception e) {
logger.error(e); logger.error(e);
} }
} else } else {
IOHelper.copy(inputFile, outputJar); return null;
}
return outputJar; return outputJar;
} }
} }

View file

@ -1,31 +0,0 @@
package pro.gravit.launchserver.config;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.utils.helper.SecurityHelper;
public class LaunchServerRuntimeConfig {
private transient final Logger logger = LogManager.getLogger();
public String passwordEncryptKey;
public String runtimeEncryptKey;
public String unlockSecret;
public String registerApiKey;
public String clientCheckSecret;
public long buildNumber;
public void verify() {
if (passwordEncryptKey == null) logger.error("[RuntimeConfig] passwordEncryptKey must not be null");
if (clientCheckSecret == null) {
logger.warn("[RuntimeConfig] clientCheckSecret must not be null");
clientCheckSecret = SecurityHelper.randomStringToken();
}
}
public void reset() {
passwordEncryptKey = SecurityHelper.randomStringToken();
runtimeEncryptKey = SecurityHelper.randomStringAESKey();
registerApiKey = SecurityHelper.randomStringToken();
clientCheckSecret = SecurityHelper.randomStringToken();
buildNumber = 0;
}
}

View file

@ -47,7 +47,7 @@ public void init() {
MainBuildTask mainTask = server.launcherBinary.getTaskByClass(MainBuildTask.class).get(); MainBuildTask mainTask = server.launcherBinary.getTaskByClass(MainBuildTask.class).get();
mainTask.preBuildHook.registerHook((buildContext) -> { mainTask.preBuildHook.registerHook((buildContext) -> {
for (ModuleEntity e : launcherModules) { for (ModuleEntity e : launcherModules) {
if (e.propertyMap != null) buildContext.task.properties.putAll(e.propertyMap); if (e.propertyMap != null) buildContext.properties.putAll(e.propertyMap);
if(e.modernModule) { if(e.modernModule) {
buildContext.clientModules.add(e.moduleMainClass); buildContext.clientModules.add(e.moduleMainClass);
} else { } else {

View file

@ -282,14 +282,6 @@ public AuthRequest.AuthPasswordInterface decryptPassword(AuthRequest.AuthPasswor
} }
private AuthRequest.AuthPasswordInterface tryDecryptPasswordPlain(AuthRequest.AuthPasswordInterface password) throws AuthException { private AuthRequest.AuthPasswordInterface tryDecryptPasswordPlain(AuthRequest.AuthPasswordInterface password) throws AuthException {
if (password instanceof AuthAESPassword authAESPassword) {
try {
return new AuthPlainPassword(IOHelper.decode(SecurityHelper.decrypt(server.runtime.passwordEncryptKey
, authAESPassword.password)));
} catch (Exception ignored) {
throw new AuthException("Password decryption error");
}
}
if (password instanceof AuthRSAPassword authRSAPassword) { if (password instanceof AuthRSAPassword authRSAPassword) {
try { try {
Cipher cipher = SecurityHelper.newRSADecryptCipher(server.keyAgreementManager.rsaPrivateKey); Cipher cipher = SecurityHelper.newRSADecryptCipher(server.keyAgreementManager.rsaPrivateKey);

View file

@ -67,14 +67,6 @@ public String createLauncherExtendedToken() {
.compact(); .compact();
} }
private boolean checkSecure(String hash, String salt) {
if (hash == null || salt == null) return false;
byte[] normal_hash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
server.runtime.clientCheckSecret.concat(".").concat(salt));
byte[] launcher_hash = Base64.getDecoder().decode(hash);
return Arrays.equals(normal_hash, launcher_hash);
}
public static class LauncherTokenVerifier implements RestoreResponse.ExtendedTokenProvider { public static class LauncherTokenVerifier implements RestoreResponse.ExtendedTokenProvider {
private final JwtParser parser; private final JwtParser parser;
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();

View file

@ -6,7 +6,6 @@
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import pro.gravit.launcher.base.Launcher; import pro.gravit.launcher.base.Launcher;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.impl.TestLaunchServerConfigManager; import pro.gravit.launchserver.impl.TestLaunchServerConfigManager;
import pro.gravit.launchserver.manangers.CertificateManager; import pro.gravit.launchserver.manangers.CertificateManager;
import pro.gravit.launchserver.manangers.LaunchServerGsonManager; import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
@ -33,13 +32,11 @@ public static void prepare() throws Throwable {
LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST); LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager); Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
Launcher.gsonManager.initGson(); Launcher.gsonManager.initGson();
LaunchServerRuntimeConfig runtimeConfig = new LaunchServerRuntimeConfig();
LaunchServerBuilder builder = new LaunchServerBuilder(); LaunchServerBuilder builder = new LaunchServerBuilder();
launchServerConfigManager = new TestLaunchServerConfigManager(); launchServerConfigManager = new TestLaunchServerConfigManager();
builder.setDir(dir) builder.setDir(dir)
.setEnv(LaunchServer.LaunchServerEnv.TEST) .setEnv(LaunchServer.LaunchServerEnv.TEST)
.setConfig(config) .setConfig(config)
.setRuntimeConfig(runtimeConfig)
.setCertificateManager(new CertificateManager()) .setCertificateManager(new CertificateManager())
.setLaunchServerConfigManager(launchServerConfigManager) .setLaunchServerConfigManager(launchServerConfigManager)
.setModulesManager(modulesManager) .setModulesManager(modulesManager)

View file

@ -7,7 +7,6 @@
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import pro.gravit.launcher.base.Launcher; import pro.gravit.launcher.base.Launcher;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.impl.TestLaunchServerConfigManager; import pro.gravit.launchserver.impl.TestLaunchServerConfigManager;
import pro.gravit.launchserver.manangers.CertificateManager; import pro.gravit.launchserver.manangers.CertificateManager;
import pro.gravit.launchserver.manangers.LaunchServerGsonManager; import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
@ -33,12 +32,10 @@ public static void prepare() throws Throwable {
LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST); LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager); Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
Launcher.gsonManager.initGson(); Launcher.gsonManager.initGson();
LaunchServerRuntimeConfig runtimeConfig = new LaunchServerRuntimeConfig();
LaunchServerBuilder builder = new LaunchServerBuilder(); LaunchServerBuilder builder = new LaunchServerBuilder();
builder.setDir(dir) builder.setDir(dir)
.setEnv(LaunchServer.LaunchServerEnv.TEST) .setEnv(LaunchServer.LaunchServerEnv.TEST)
.setConfig(config) .setConfig(config)
.setRuntimeConfig(runtimeConfig)
.setCertificateManager(new CertificateManager()) .setCertificateManager(new CertificateManager())
.setLaunchServerConfigManager(new TestLaunchServerConfigManager()) .setLaunchServerConfigManager(new TestLaunchServerConfigManager())
.setModulesManager(modulesManager) .setModulesManager(modulesManager)

View file

@ -2,16 +2,12 @@
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
public class TestLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager { public class TestLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager {
public LaunchServerConfig config; public LaunchServerConfig config;
public LaunchServerRuntimeConfig runtimeConfig;
public TestLaunchServerConfigManager() { public TestLaunchServerConfigManager() {
config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST); config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
runtimeConfig = new LaunchServerRuntimeConfig();
runtimeConfig.reset();
} }
@Override @Override
@ -19,18 +15,8 @@ public LaunchServerConfig readConfig() {
return config; return config;
} }
@Override
public LaunchServerRuntimeConfig readRuntimeConfig() {
return runtimeConfig;
}
@Override @Override
public void writeConfig(LaunchServerConfig config) { public void writeConfig(LaunchServerConfig config) {
} }
@Override
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
}
} }

View file

@ -3,6 +3,7 @@
import pro.gravit.launcher.core.LauncherNetworkAPI; import pro.gravit.launcher.core.LauncherNetworkAPI;
import pro.gravit.launcher.base.request.auth.AuthRequest; import pro.gravit.launcher.base.request.auth.AuthRequest;
@Deprecated
public class AuthAESPassword implements AuthRequest.AuthPasswordInterface { public class AuthAESPassword implements AuthRequest.AuthPasswordInterface {
@LauncherNetworkAPI @LauncherNetworkAPI
public final byte[] password; public final byte[] password;

@ -1 +1 @@
Subproject commit 53103486065ff7dde30e480d2b24f6afb2decddb Subproject commit 3ce7d4feb1b95152917c9ed85a5186c145a9376c