diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/session/UserSessionSupportKeys.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/session/UserSessionSupportKeys.java new file mode 100644 index 00000000..7da7bb2a --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/session/UserSessionSupportKeys.java @@ -0,0 +1,11 @@ +package pro.gravit.launchserver.auth.core.interfaces.session; + +import java.security.PrivateKey; +import java.security.PublicKey; + +public interface UserSessionSupportKeys { + ClientProfileKeys getClientProfileKeys(); + record ClientProfileKeys(PublicKey publicKey, PrivateKey privateKey, byte[] signature /* V2 */, long expiresAt, long refreshedAfter) { + + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java index 3e7fd4e4..ec587e7b 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java @@ -122,7 +122,7 @@ public String createHardwareToken(String username, UserHardware hardware) { return Jwts.builder() .setIssuer("LaunchServer") .setSubject(username) - .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8)) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * server.config.netty.security.hardwareTokenExpire)) .claim("hardware", hardware.getId()) .signWith(server.keyAgreementManager.ecdsaPrivateKey) .compact(); @@ -132,7 +132,7 @@ public String createPublicKeyToken(String username, byte[] publicKey) { return Jwts.builder() .setIssuer("LaunchServer") .setSubject(username) - .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8)) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * server.config.netty.security.publicKeyTokenExpire)) .claim("publicKey", Base64.getEncoder().encodeToString(publicKey)) .signWith(server.keyAgreementManager.ecdsaPrivateKey) .compact(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java index f5307730..36fb964a 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java @@ -71,7 +71,7 @@ public void invoke(String... args) throws IOException, CommandException { if (version.compareTo(ClientProfile.Version.MC164) <= 0) { logger.warn("Minecraft 1.6.4 and below not supported. Use at your own risk"); } - MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(clientDir, version); + MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(clientDir, version, Files.exists(server.updatesDir.resolve("assets"))); for (MakeProfileHelper.MakeProfileOption option : options) { logger.debug("Detected option {}", option.getClass().getSimpleName()); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/MakeProfileCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/MakeProfileCommand.java index f97b8967..8d70af88 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/MakeProfileCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/MakeProfileCommand.java @@ -10,6 +10,7 @@ import pro.gravit.utils.helper.IOHelper; import java.io.Writer; +import java.nio.file.Files; public class MakeProfileCommand extends Command { private transient final Logger logger = LogManager.getLogger(); @@ -32,7 +33,7 @@ public String getUsageDescription() { public void invoke(String... args) throws Exception { verifyArgs(args, 3); ClientProfile.Version version = ClientProfile.Version.byName(args[1]); - MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(server.updatesDir.resolve(args[2]), version); + MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(server.updatesDir.resolve(args[2]), version, Files.exists(server.updatesDir.resolve("assets"))); for (MakeProfileHelper.MakeProfileOption option : options) { logger.info("Detected option {}", option); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java index 15cd985a..1b40186f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -47,7 +47,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { LaunchServerConfig newConfig = new LaunchServerConfig(); newConfig.mirrors = new String[]{"https://mirror.gravit.pro/5.2.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"}; newConfig.launch4j = new LaunchServerConfig.ExeConf(); - newConfig.launch4j.enabled = true; + newConfig.launch4j.enabled = false; newConfig.launch4j.copyright = "© GravitLauncher Team"; newConfig.launch4j.fileDesc = "GravitLauncher ".concat(Version.getVersion().getVersionString()); newConfig.launch4j.fileVer = Version.getVersion().getVersionString().concat(".").concat(String.valueOf(Version.getVersion().patch)); @@ -289,6 +289,8 @@ public static class NettyConfig { public String address; public Map bindings = new HashMap<>(); public NettyPerformanceConfig performance; + + public NettySecurityConfig security = new NettySecurityConfig(); public NettyBindAddress[] binds; public LogLevel logLevel = LogLevel.DEBUG; } @@ -298,7 +300,6 @@ public static class NettyPerformanceConfig { public int bossThread; public int workerThread; public int schedulerThread; - public long sessionLifetimeMs = 24 * 60 * 60 * 1000; public int maxWebSocketRequestBytes = 1024 * 1024; } @@ -311,4 +312,11 @@ public NettyBindAddress(String address, int port) { this.port = port; } } + + public static class NettySecurityConfig { + public long hardwareTokenExpire = 60 * 60 * 8; + public long publicKeyTokenExpire = 60 * 60 * 8; + + public long launcherTokenExpire = 60 * 60 * 8; + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java index 0887c82a..12f95b29 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java @@ -18,7 +18,11 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti ClientProfileBuilder builder = new ClientProfileBuilder(); builder.setVersion(version.name); builder.setDir(title); - builder.setAssetDir("asset" + version.name); + if(findOption(options, MakeProfileOptionGlobalAssets.class).isPresent()) { + builder.setAssetDir("assets"); + } else { + builder.setAssetDir("asset" + version.name); + } builder.setAssetIndex(version.name); builder.setInfo("Информация о сервере"); builder.setTitle(title); @@ -42,11 +46,16 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti Set optionals = new HashSet<>(); jvmArgs.add("-XX:+DisableAttachMechanism"); // Official Mojang launcher java arguments - jvmArgs.add("-XX:+UseG1GC"); - jvmArgs.add("-XX:+UnlockExperimentalVMOptions"); - jvmArgs.add("-XX:G1NewSizePercent=20"); - jvmArgs.add("-XX:MaxGCPauseMillis=50"); - jvmArgs.add("-XX:G1HeapRegionSize=32M"); + if(version.compareTo(ClientProfile.Version.MC112) <= 0) { + jvmArgs.add("-XX:+UseConcMarkSweepGC"); + jvmArgs.add("-XX:+CMSIncrementalMode"); + } else if(version.compareTo(ClientProfile.Version.MC118) <= 0) { // 1.13 - 1.16.5 + jvmArgs.add("-XX:+UseG1GC"); + jvmArgs.add("-XX:+UnlockExperimentalVMOptions"); + } else { // 1.18+ + jvmArgs.add("-XX:+UseShenandoahGC"); + jvmArgs.add("-XX:+UnlockExperimentalVMOptions"); + } // ----------- Optional forge = findOption(options, MakeProfileOptionForge.class); Optional fabric = findOption(options, MakeProfileOptionFabric.class); @@ -192,7 +201,7 @@ private static String getLog4jVersion(Path dir) throws IOException { return null; } - public static MakeProfileOption[] getMakeProfileOptionsFromDir(Path dir, ClientProfile.Version version) throws IOException { + public static MakeProfileOption[] getMakeProfileOptionsFromDir(Path dir, ClientProfile.Version version, boolean globalAssets) throws IOException { List options = new ArrayList<>(2); if (Files.exists(dir.resolve("forge.jar"))) { options.add(new MakeProfileOptionForge()); @@ -302,6 +311,10 @@ public static class MakeProfileOptionLaunchWrapper implements MakeProfileOption } + public static class MakeProfileOptionGlobalAssets implements MakeProfileOption { + + } + public static class MakeProfileOptionFabric implements MakeProfileOption { public String jimfsPath; public String guavaPath; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java index ca066ed1..ece49017 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -16,6 +16,7 @@ import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.core.User; import pro.gravit.launchserver.auth.core.UserSession; +import pro.gravit.launchserver.auth.core.interfaces.session.UserSessionSupportKeys; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportProperties; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures; import pro.gravit.launchserver.auth.texture.TextureProvider; @@ -26,7 +27,13 @@ import pro.gravit.utils.helper.SecurityHelper; import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.*; public class AuthManager { @@ -180,6 +187,10 @@ public void internalAuth(Client client, AuthResponse.ConnectTypes authType, Auth client.uuid = uuid; } + public UserSessionSupportKeys.ClientProfileKeys createClientProfileKeys(UUID playerUUID) { + throw new UnsupportedOperationException("Minecraft 1.19.1 signature"); // TODO + } + public CheckServerReport checkServer(Client client, String username, String serverID) throws IOException { if (client.auth == null) return null; User user = client.auth.core.checkServer(client, username, serverID); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java index 10d04a25..afd24448 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java @@ -20,6 +20,7 @@ import pro.gravit.launchserver.socket.response.WebSocketServerResponse; import pro.gravit.launchserver.socket.response.auth.*; import pro.gravit.launchserver.socket.response.management.FeaturesResponse; +import pro.gravit.launchserver.socket.response.management.GetPublicKeyResponse; import pro.gravit.launchserver.socket.response.management.ServerStatusResponse; import pro.gravit.launchserver.socket.response.profile.BatchProfileByUsername; import pro.gravit.launchserver.socket.response.profile.ProfileByUUIDResponse; @@ -88,6 +89,8 @@ public static void registerResponses() { providers.register("refreshToken", RefreshTokenResponse.class); providers.register("restore", RestoreResponse.class); providers.register("additionalData", AdditionalDataResponse.class); + providers.register("clientProfileKey", FetchClientProfileKeyResponse.class); + providers.register("getPublicKey", GetPublicKeyResponse.class); } public void forEachActiveChannels(BiConsumer callback) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/FetchClientProfileKeyResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/FetchClientProfileKeyResponse.java new file mode 100644 index 00000000..b217ce61 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/FetchClientProfileKeyResponse.java @@ -0,0 +1,32 @@ +package pro.gravit.launchserver.socket.response.auth; + +import io.netty.channel.ChannelHandlerContext; +import pro.gravit.launcher.events.request.FetchClientProfileKeyRequestEvent; +import pro.gravit.launchserver.auth.core.User; +import pro.gravit.launchserver.auth.core.UserSession; +import pro.gravit.launchserver.auth.core.interfaces.session.UserSessionSupportKeys; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.SimpleResponse; + +public class FetchClientProfileKeyResponse extends SimpleResponse { + @Override + public String getType() { + return "clientProfileKey"; + } + + @Override + public void execute(ChannelHandlerContext ctx, Client client) throws Exception { + if (!client.isAuth || client.type != AuthResponse.ConnectTypes.CLIENT) { + sendError("Permissions denied"); + return; + } + UserSession session = client.sessionObject; + UserSessionSupportKeys.ClientProfileKeys keys; + if(session instanceof UserSessionSupportKeys support) { + keys = support.getClientProfileKeys(); + } else { + keys = server.authManager.createClientProfileKeys(client.uuid); + } + sendResult(new FetchClientProfileKeyRequestEvent(keys.publicKey(), keys.privateKey(), keys.signature(), keys.expiresAt(), keys.refreshedAfter())); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/management/GetPublicKeyResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/management/GetPublicKeyResponse.java new file mode 100644 index 00000000..daebed27 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/management/GetPublicKeyResponse.java @@ -0,0 +1,18 @@ +package pro.gravit.launchserver.socket.response.management; + +import io.netty.channel.ChannelHandlerContext; +import pro.gravit.launcher.events.request.GetPublicKeyRequestEvent; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.SimpleResponse; + +public class GetPublicKeyResponse extends SimpleResponse { + @Override + public String getType() { + return "getPublicKey"; + } + + @Override + public void execute(ChannelHandlerContext ctx, Client client) throws Exception { + sendResult(new GetPublicKeyRequestEvent(server.keyAgreementManager.rsaPublicKey, server.keyAgreementManager.ecdsaPublicKey)); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java index c8aa53a3..f011283c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java @@ -71,7 +71,7 @@ public String createLauncherExtendedToken() { return Jwts.builder() .setIssuer("LaunchServer") .claim("checkSign", true) - .setExpiration(Date.from(LocalDateTime.now().plusHours(8).toInstant(ZoneOffset.UTC))) + .setExpiration(Date.from(LocalDateTime.now().plusSeconds(server.config.netty.security.launcherTokenExpire).toInstant(ZoneOffset.UTC))) .signWith(server.keyAgreementManager.ecdsaPrivateKey, SignatureAlgorithm.ES256) .compact(); } diff --git a/Launcher/build.gradle b/Launcher/build.gradle index bb5f83d3..e8ca4f7f 100644 --- a/Launcher/build.gradle +++ b/Launcher/build.gradle @@ -42,7 +42,6 @@ task javadocJar(type: Jar) { shadowJar { duplicatesStrategy = 'EXCLUDE' archiveClassifier.set(null) - relocate 'org.objectweb.asm', 'pro.gravit.repackage.org.objectweb.asm' relocate 'io.netty', 'pro.gravit.repackage.io.netty' configurations = [project.configurations.pack] exclude 'module-info.class' @@ -52,7 +51,6 @@ task javadocJar(type: Jar) { pack project(':LauncherAPI') bundle group: 'com.github.oshi', name: 'oshi-core', version: rootProject['verOshiCore'] pack group: 'io.netty', name: 'netty-codec-http', version: rootProject['verNetty'] - pack group: 'org.ow2.asm', name: 'asm-tree', version: rootProject['verAsm'] } task genRuntimeJS(type: Zip) { diff --git a/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java b/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java index 9e3f995d..63d96485 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java +++ b/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java @@ -1,6 +1,5 @@ package pro.gravit.launcher; -import pro.gravit.launcher.patches.FMLPatcher; import pro.gravit.launcher.utils.NativeJVMHalt; import pro.gravit.utils.helper.LogHelper; @@ -30,7 +29,6 @@ public static void premain(String agentArgument, Instrumentation instrumentation checkAgentStacktrace(); inst = instrumentation; NativeJVMHalt.initFunc(); - FMLPatcher.apply(); isAgentStarted = true; } diff --git a/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java b/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java index 561d966a..50e8120e 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java +++ b/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java @@ -5,10 +5,10 @@ import pro.gravit.launcher.client.events.ClientExitPhase; import pro.gravit.launcher.client.events.ClientPreGuiPhase; import pro.gravit.launcher.console.GetPublicKeyCommand; +import pro.gravit.launcher.console.ModulesCommand; import pro.gravit.launcher.console.SignDataCommand; import pro.gravit.launcher.events.request.*; -import pro.gravit.launcher.guard.LauncherGuardInterface; -import pro.gravit.launcher.guard.LauncherGuardManager; +import pro.gravit.launcher.guard.LauncherGuard; import pro.gravit.launcher.guard.LauncherNoGuard; import pro.gravit.launcher.guard.LauncherWrapperGuard; import pro.gravit.launcher.gui.NoRuntimeProvider; @@ -28,7 +28,6 @@ import pro.gravit.launcher.request.secure.GetSecureLevelInfoRequest; import pro.gravit.launcher.request.secure.SecurityReportRequest; import pro.gravit.launcher.request.update.LauncherRequest; -import pro.gravit.launcher.request.websockets.ClientWebSocketService; import pro.gravit.launcher.request.websockets.OfflineRequestService; import pro.gravit.launcher.request.websockets.StdWebSocketService; import pro.gravit.launcher.utils.NativeJVMHalt; @@ -50,7 +49,7 @@ public class LauncherEngine { public static ClientLauncherProcess.ClientParams clientParams; - public static LauncherGuardInterface guard; + public static LauncherGuard guard; public static ClientModuleManager modulesManager; public final boolean clientInstance; // Instance @@ -86,7 +85,10 @@ public static void checkClass(Class clazz) throws SecurityException { } public static void exitLauncher(int code) { - modulesManager.invokeEvent(new ClientExitPhase(code)); + try { + modulesManager.invokeEvent(new ClientExitPhase(code)); + } catch (Throwable ignored) { + } try { System.exit(code); } catch (Throwable e) //Forge Security Manager? @@ -143,7 +145,7 @@ public static void verifyNoAgent() { throw new SecurityException("JavaAgent found"); } - public static LauncherGuardInterface tryGetStdGuard() { + public static LauncherGuard tryGetStdGuard() { switch (Launcher.getConfig().guardType) { case "no": return new LauncherNoGuard(); @@ -264,7 +266,6 @@ public void start(String... args) throws Throwable { registerCommands(); LauncherEngine.modulesManager.invokeEvent(new ClientEngineInitPhase(this)); runtimeProvider.preLoad(); - LauncherGuardManager.initGuard(clientInstance); LogHelper.debug("Dir: %s", DirBridge.dir); runtimeProvider.run(args); } @@ -272,5 +273,6 @@ public void start(String... args) throws Throwable { private void registerCommands() { ConsoleManager.handler.registerCommand("getpublickey", new GetPublicKeyCommand(this)); ConsoleManager.handler.registerCommand("signdata", new SignDataCommand(this)); + ConsoleManager.handler.registerCommand("modules", new ModulesCommand()); } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/api/ClientService.java b/Launcher/src/main/java/pro/gravit/launcher/api/ClientService.java index bb98191e..20e29eb6 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/api/ClientService.java +++ b/Launcher/src/main/java/pro/gravit/launcher/api/ClientService.java @@ -1,5 +1,7 @@ package pro.gravit.launcher.api; +import pro.gravit.launcher.utils.ApiBridgeService; + import java.lang.instrument.Instrumentation; import java.net.URL; @@ -12,4 +14,8 @@ public class ClientService { public static ClassLoader getClassLoader() { return classLoader; } + + public static String findLibrary(String name) { + return ApiBridgeService.findLibrary(classLoader, name); + } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java index 06fe6b91..b3ea44ad 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java @@ -3,10 +3,10 @@ import pro.gravit.launcher.*; import pro.gravit.launcher.api.AuthService; import pro.gravit.launcher.api.ClientService; +import pro.gravit.launcher.api.KeyService; import pro.gravit.launcher.client.events.client.*; import pro.gravit.launcher.events.request.ProfileByUUIDRequestEvent; import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent; -import pro.gravit.launcher.guard.LauncherGuardManager; import pro.gravit.launcher.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedEntry; @@ -15,7 +15,6 @@ import pro.gravit.launcher.modules.LauncherModulesManager; import pro.gravit.launcher.modules.events.OfflineModeEvent; import pro.gravit.launcher.modules.events.PreConfigPhase; -import pro.gravit.launcher.patches.FMLPatcher; import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.profiles.optional.actions.OptionalAction; import pro.gravit.launcher.profiles.optional.actions.OptionalActionClassPath; @@ -26,7 +25,6 @@ import pro.gravit.launcher.request.RequestService; import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest; -import pro.gravit.launcher.request.uuid.BatchProfileByUsernameRequest; import pro.gravit.launcher.request.uuid.ProfileByUUIDRequest; import pro.gravit.launcher.request.uuid.ProfileByUsernameRequest; import pro.gravit.launcher.request.websockets.OfflineRequestService; @@ -87,7 +85,6 @@ public static void main(String[] args) throws Throwable { ConsoleManager.initConsole(); LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase()); engine.readKeys(); - LauncherGuardManager.initGuard(true); LogHelper.debug("Reading ClientLauncher params"); ClientLauncherProcess.ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort)); if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) { @@ -143,13 +140,14 @@ public static void main(String[] args) throws Throwable { } }; } + LogHelper.debug("Natives dir %s", params.nativesDir); ClientProfile.ClassLoaderConfig classLoaderConfig = profile.getClassLoaderConfig(); if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) { ClientClassLoader classLoader = new ClientClassLoader(classpathURLs.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator))); ClientLauncherEntryPoint.classLoader = classLoader; Thread.currentThread().setContextClassLoader(classLoader); - classLoader.nativePath = clientDir.resolve("natives").toString(); + classLoader.nativePath = params.nativesDir; LauncherEngine.modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(engine, classLoader, profile)); ClientService.classLoader = classLoader; ClientService.nativePath = classLoader.nativePath; @@ -162,7 +160,7 @@ public static void main(String[] args) throws Throwable { LauncherAgent.addJVMClassPath(Paths.get(url.toURI())); } ClientService.instrumentation = LauncherAgent.inst; - ClientService.nativePath = clientDir.resolve("natives").toString(); + ClientService.nativePath = params.nativesDir; LauncherEngine.modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(engine, classLoader, profile)); ClientService.classLoader = classLoader; ClientService.baseURLs = classpathURLs.toArray(new URL[0]); @@ -170,9 +168,11 @@ public static void main(String[] args) throws Throwable { ClientLauncherEntryPoint.classLoader = ClassLoader.getSystemClassLoader(); ClientService.classLoader = ClassLoader.getSystemClassLoader(); ClientService.baseURLs = classpathURLs.toArray(new URL[0]); + ClientService.nativePath = params.nativesDir; } AuthService.username = params.playerProfile.username; AuthService.uuid = params.playerProfile.uuid; + KeyService.serverRsaPublicKey = Launcher.getConfig().rsaPublicKey; if (params.profile.getRuntimeInClientConfig() != ClientProfile.RuntimeInClientConfig.NONE) { CommonHelper.newThread("Client Launcher Thread", true, () -> { try { @@ -251,28 +251,26 @@ public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher, HashedDir currentHDir = new HashedDir(dir, matcher, true, digest); HashedDir.Diff diff = hdir.diff(currentHDir, matcher); if (!diff.isSame()) { - if (LogHelper.isDebugEnabled()) { - diff.extra.walk(File.separator, (e, k, v) -> { - if (v.getType().equals(HashedEntry.Type.FILE)) { - LogHelper.error("Extra file %s", e); - } else LogHelper.error("Extra %s", e); - return HashedDir.WalkAction.CONTINUE; - }); - diff.mismatch.walk(File.separator, (e, k, v) -> { - if (v.getType().equals(HashedEntry.Type.FILE)) { - LogHelper.error("Mismatch file %s", e); - } else LogHelper.error("Mismatch %s", e); - return HashedDir.WalkAction.CONTINUE; - }); - } + diff.extra.walk(File.separator, (e, k, v) -> { + if (v.getType().equals(HashedEntry.Type.FILE)) { + LogHelper.error("Extra file %s", e); + } else LogHelper.error("Extra %s", e); + return HashedDir.WalkAction.CONTINUE; + }); + diff.mismatch.walk(File.separator, (e, k, v) -> { + if (v.getType().equals(HashedEntry.Type.FILE)) { + LogHelper.error("Mismatch file %s", e); + } else LogHelper.error("Mismatch %s", e); + return HashedDir.WalkAction.CONTINUE; + }); throw new SecurityException(String.format("Forbidden modification: '%s'", IOHelper.getFileName(dir))); } } public static boolean checkJVMBitsAndVersion(int minVersion, int recommendVersion, int maxVersion, boolean showMessage) { boolean ok = true; - if (JVMHelper.JVM_BITS != JVMHelper.OS_BITS) { - String error = String.format("У Вас установлена Java %d, но Ваша система определена как %d. Установите Java правильной разрядности", JVMHelper.JVM_BITS, JVMHelper.OS_BITS); + if (JVMHelper.JVM_BITS == 64 && JVMHelper.ARCH_TYPE == JVMHelper.ARCH.X86) { + String error = "У Вас установлена Java x64, но Ваша система определена как x32. Установите Java правильной разрядности"; LogHelper.error(error); if (showMessage) JOptionPane.showMessageDialog(null, error); @@ -282,7 +280,7 @@ public static boolean checkJVMBitsAndVersion(int minVersion, int recommendVersio LogHelper.info(jvmVersion); int version = JVMHelper.getVersion(); if (version < minVersion || version > maxVersion) { - String error = String.format("У Вас установлена Java %s. Для правильной работы необходима Java %d", JVMHelper.RUNTIME_MXBEAN.getVmVersion(), recommendVersion); + String error = String.format("У Вас установлена Java %d, но этот клиент требует Java %d", JVMHelper.getVersion(), recommendVersion); LogHelper.error(error); if (showMessage) JOptionPane.showMessageDialog(null, error); @@ -347,7 +345,6 @@ private static void launch(ClientProfile profile, ClientLauncherProcess.ClientPa LogHelper.dev("ClassLoader URL: %s", u.toString()); } } - FMLPatcher.apply(); LauncherEngine.modulesManager.invokeEvent(new ClientProcessPreInvokeMainClassEvent(params, profile, args)); // Invoke main method try { diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherProcess.java b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherProcess.java index 06aa81af..846a0299 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherProcess.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherProcess.java @@ -1,6 +1,7 @@ package pro.gravit.launcher.client; import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.LauncherConfig; import pro.gravit.launcher.LauncherEngine; import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.client.events.client.ClientProcessBuilderCreateEvent; @@ -25,6 +26,7 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; @@ -42,42 +44,45 @@ public class ClientLauncherProcess { private final transient Boolean[] waitWriteParams = new Boolean[]{false}; public Path executeFile; public Path workDir; - public Path javaDir; - public int bits; + public JavaHelper.JavaVersion javaVersion; public boolean useLegacyJavaClassPathProperty; public boolean isStarted; - public JavaHelper.JavaVersion javaVersion; private transient Process process; - public ClientLauncherProcess(Path executeFile, Path workDir, Path javaDir, String mainClass) { + public ClientLauncherProcess(Path executeFile, Path workDir, JavaHelper.JavaVersion javaVersion, String mainClass) { this.executeFile = executeFile; this.workDir = workDir; - this.javaDir = javaDir; + this.javaVersion = javaVersion; this.mainClass = mainClass; } - public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, + public ClientLauncherProcess(Path clientDir, Path assetDir, JavaHelper.JavaVersion javaVersion, ClientProfile profile, PlayerProfile playerProfile, String accessToken, HashedDir clientHDir, HashedDir assetHDir, HashedDir jvmHDir) { - this(clientDir, assetDir, javaDir, clientDir.resolve("resourcepacks"), profile, playerProfile, null, accessToken, clientHDir, assetHDir, jvmHDir); + this(clientDir, assetDir, javaVersion, clientDir.resolve("resourcepacks"), profile, playerProfile, null, accessToken, clientHDir, assetHDir, jvmHDir); } public ClientLauncherProcess(Path clientDir, Path assetDir, ClientProfile profile, PlayerProfile playerProfile, String accessToken, HashedDir clientHDir, HashedDir assetHDir, HashedDir jvmHDir) { - this(clientDir, assetDir, Paths.get(System.getProperty("java.home")), clientDir.resolve("resourcepacks"), profile, playerProfile, null, accessToken, clientHDir, assetHDir, jvmHDir); + this(clientDir, assetDir, JavaHelper.JavaVersion.getCurrentJavaVersion(), clientDir.resolve("resourcepacks"), profile, playerProfile, null, accessToken, clientHDir, assetHDir, jvmHDir); } - public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, Path resourcePackDir, + public ClientLauncherProcess(Path clientDir, Path assetDir, JavaHelper.JavaVersion javaVersion, Path resourcePackDir, ClientProfile profile, PlayerProfile playerProfile, OptionalView view, String accessToken, HashedDir clientHDir, HashedDir assetHDir, HashedDir jvmHDir) { + this.javaVersion = javaVersion; this.workDir = clientDir.toAbsolutePath(); - this.javaDir = javaDir; - this.executeFile = IOHelper.resolveJavaBin(this.javaDir); + this.executeFile = IOHelper.resolveJavaBin(this.javaVersion.jvmDir); this.mainClass = ClientLauncherEntryPoint.class.getName(); this.params.clientDir = this.workDir.toString(); this.params.resourcePackDir = resourcePackDir.toAbsolutePath().toString(); this.params.assetDir = assetDir.toAbsolutePath().toString(); + Path nativesPath = workDir.resolve("natives").resolve(JVMHelper.OS_TYPE.name).resolve(javaVersion.arch.name); + if(!Files.isDirectory(nativesPath)) { + nativesPath = workDir.resolve("natives"); + } + this.params.nativesDir = nativesPath.toString(); this.params.profile = profile; this.params.playerProfile = playerProfile; this.params.accessToken = accessToken; @@ -87,16 +92,6 @@ public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, Path r if (view != null) { this.params.actions = view.getEnabledActions(); } - try { - javaVersion = JavaHelper.JavaVersion.getByPath(javaDir); - } catch (IOException e) { - LogHelper.error(e); - javaVersion = null; - } - if (javaVersion == null) { - javaVersion = JavaHelper.JavaVersion.getCurrentJavaVersion(); - } - this.bits = JVMHelper.JVM_BITS; applyClientProfile(); } @@ -115,7 +110,7 @@ private void applyClientProfile() { this.jvmArgs.addAll(((OptionalActionJvmArgs) a).args); } } - this.systemEnv.put("JAVA_HOME", javaDir.toString()); + this.systemEnv.put("JAVA_HOME", javaVersion.jvmDir.toString()); Collections.addAll(this.systemClassPath, this.params.profile.getAlternativeClassPath()); if (params.ram > 0) { this.jvmArgs.add("-Xmx" + params.ram + 'M'); @@ -154,11 +149,17 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException { applyJava9Params(processArgs); } //ADD CLASSPATH + processArgs.add(JVMHelper.jvmProperty("java.library.path", this.params.nativesDir)); if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.AGENT) { processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString())); } else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) { systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(workDir, params.actions, params.profile).map(Path::toString).collect(Collectors.toList())); } + if(Launcher.getConfig().environment != LauncherConfig.LauncherEnvironment.PROD) { + processArgs.add(JVMHelper.jvmProperty(LogHelper.DEV_PROPERTY, String.valueOf(LogHelper.isDevEnabled()))); + processArgs.add(JVMHelper.jvmProperty(LogHelper.DEBUG_PROPERTY, String.valueOf(LogHelper.isDebugEnabled()))); + processArgs.add(JVMHelper.jvmProperty(LogHelper.STACKTRACE_PROPERTY, String.valueOf(LogHelper.isStacktraceEnabled()))); + } if (useLegacyJavaClassPathProperty) { processArgs.add("-Djava.class.path=".concat(String.join(getPathSeparator(), systemClassPath))); } else { @@ -176,7 +177,7 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException { LogHelper.debug("Commandline: %s", Arrays.toString(processArgs.toArray())); ProcessBuilder processBuilder = new ProcessBuilder(processArgs); EnvHelper.addEnv(processBuilder); - processBuilder.environment().put("JAVA_HOME", javaDir.toAbsolutePath().toString()); + processBuilder.environment().put("JAVA_HOME", javaVersion.jvmDir.toAbsolutePath().toString()); processBuilder.environment().putAll(systemEnv); processBuilder.directory(workDir.toFile()); processBuilder.inheritIO(); @@ -256,6 +257,8 @@ public static class ClientParams { public String resourcePackDir; + public String nativesDir; + // Client params public PlayerProfile playerProfile; diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java b/Launcher/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java index 932a93e5..62df10ca 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java @@ -7,6 +7,8 @@ import pro.gravit.launcher.modules.impl.SimpleModuleManager; import java.nio.file.Path; +import java.util.Collections; +import java.util.List; public final class ClientModuleManager extends SimpleModuleManager { public ClientModuleManager() { @@ -28,6 +30,10 @@ public LauncherModule loadModule(LauncherModule module) { return super.loadModule(module); } + public List getModules() { + return Collections.unmodifiableList(modules); + } + @Override public final boolean verifyClassCheckResult(LauncherTrustManager.CheckClassResult result) { return result.type == LauncherTrustManager.CheckClassResultType.SUCCESS; diff --git a/Launcher/src/main/java/pro/gravit/launcher/console/ModulesCommand.java b/Launcher/src/main/java/pro/gravit/launcher/console/ModulesCommand.java new file mode 100644 index 00000000..dc722cd1 --- /dev/null +++ b/Launcher/src/main/java/pro/gravit/launcher/console/ModulesCommand.java @@ -0,0 +1,49 @@ +package pro.gravit.launcher.console; + +import pro.gravit.launcher.LauncherEngine; +import pro.gravit.launcher.LauncherTrustManager; +import pro.gravit.launcher.managers.ConsoleManager; +import pro.gravit.launcher.modules.LauncherModule; +import pro.gravit.launcher.modules.LauncherModuleInfo; +import pro.gravit.utils.command.Command; +import pro.gravit.utils.helper.LogHelper; + +import java.security.cert.X509Certificate; +import java.util.Arrays; + +public class ModulesCommand extends Command { + @Override + public String getArgsDescription() { + return "[]"; + } + + @Override + public String getUsageDescription() { + return "show modules"; + } + + @Override + public void invoke(String... args) throws Exception { + for(LauncherModule module : LauncherEngine.modulesManager.getModules()) { + LauncherModuleInfo info = module.getModuleInfo(); + LauncherTrustManager.CheckClassResult checkStatus = module.getCheckResult(); + if(!ConsoleManager.isConsoleUnlock) { + LogHelper.info("[MODULE] %s v: %s", info.name, info.version.getVersionString()); + } else { + LogHelper.info("[MODULE] %s v: %s p: %d deps: %s sig: %s", info.name, info.version.getVersionString(), info.priority, Arrays.toString(info.dependencies), checkStatus == null ? "null" : checkStatus.type); + printCheckStatusInfo(checkStatus); + } + } + } + + private void printCheckStatusInfo(LauncherTrustManager.CheckClassResult checkStatus) { + if (checkStatus != null && checkStatus.endCertificate != null) { + X509Certificate cert = checkStatus.endCertificate; + LogHelper.info("[MODULE CERT] Module signer: %s", cert.getSubjectX500Principal().getName()); + } + if (checkStatus != null && checkStatus.rootCertificate != null) { + X509Certificate cert = checkStatus.rootCertificate; + LogHelper.info("[MODULE CERT] Module signer CA: %s", cert.getSubjectX500Principal().getName()); + } + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardInterface.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuard.java similarity index 80% rename from Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardInterface.java rename to Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuard.java index b277d656..899cf1af 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardInterface.java +++ b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuard.java @@ -2,7 +2,7 @@ import pro.gravit.launcher.client.ClientLauncherProcess; -public interface LauncherGuardInterface { +public interface LauncherGuard { String getName(); void applyGuardParams(ClientLauncherProcess process); diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardManager.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardManager.java deleted file mode 100644 index 2713bf57..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardManager.java +++ /dev/null @@ -1,8 +0,0 @@ -package pro.gravit.launcher.guard; - -public class LauncherGuardManager { - public static LauncherGuardInterface guard; - - public static void initGuard(boolean clientInstance) { - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherNoGuard.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherNoGuard.java index 2e2d8789..d43bff54 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherNoGuard.java +++ b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherNoGuard.java @@ -2,7 +2,7 @@ import pro.gravit.launcher.client.ClientLauncherProcess; -public class LauncherNoGuard implements LauncherGuardInterface { +public class LauncherNoGuard implements LauncherGuard { @Override public String getName() { return "noGuard"; diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java index 762449a6..0991673a 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java +++ b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java @@ -8,7 +8,7 @@ import java.io.IOException; -public class LauncherWrapperGuard implements LauncherGuardInterface { +public class LauncherWrapperGuard implements LauncherGuard { public LauncherWrapperGuard() { try { diff --git a/Launcher/src/main/java/pro/gravit/launcher/patches/FMLPatcher.java b/Launcher/src/main/java/pro/gravit/launcher/patches/FMLPatcher.java deleted file mode 100644 index 1715bd7d..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/patches/FMLPatcher.java +++ /dev/null @@ -1,107 +0,0 @@ -package pro.gravit.launcher.patches; - -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import pro.gravit.utils.helper.SecurityHelper; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.nio.ByteBuffer; -import java.util.Locale; -import java.util.Random; -import java.util.Vector; - -public class FMLPatcher extends ClassLoader implements Opcodes { - public static final MethodType EXITMH = MethodType.methodType(void.class, int.class); - public static final String[] PACKAGES = new String[]{"cpw.mods.fml.", "net.minecraftforge.fml.", "cpw.mods."}; - public static final Vector MHS = new Vector<>(); - public static volatile FMLPatcher INSTANCE = null; - - public FMLPatcher(final ClassLoader cl) { - super(cl); - } - - public static void apply() { - INSTANCE = new FMLPatcher(null); // Never cause ClassFormatError (fuck forge 1.14!!!) - for (String s : PACKAGES) { - String rMethod = randomStr(16); - try { - MHS.add(MethodHandles.publicLookup().findStatic(INSTANCE.def(s + randomStr(16), rMethod), rMethod, - EXITMH)); - } catch (NoSuchMethodException | IllegalAccessException e) { - // Simple ignore - other Forge - } - } - } - - public static void exit(final int code) { - for (MethodHandle mh : MHS) - try { - mh.invoke(code); - } catch (Throwable ignored) { - } - } - - private static byte[] gen(final String name, final String exName) { // "cpw/mods/fml/SafeExitJVMLegacy", "exit" - - final ClassWriter classWriter = new ClassWriter(0); - MethodVisitor methodVisitor; - - classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); - - { - methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "", "()V", null, null); - methodVisitor.visitCode(); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - methodVisitor.visitInsn(RETURN); - methodVisitor.visitMaxs(1, 1); - methodVisitor.visitEnd(); - } - { - methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, exName, "(I)V", null, null); - methodVisitor.visitCode(); - final Label label0 = new Label(); - final Label label1 = new Label(); - final Label label2 = new Label(); - methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/Throwable"); - methodVisitor.visitLabel(label0); - methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", - false); - methodVisitor.visitVarInsn(ILOAD, 0); - methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "halt", "(I)V", false); - methodVisitor.visitLabel(label1); - final Label label3 = new Label(); - methodVisitor.visitJumpInsn(GOTO, label3); - methodVisitor.visitLabel(label2); - methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"}); - methodVisitor.visitVarInsn(ASTORE, 1); - methodVisitor.visitVarInsn(ILOAD, 0); - methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/System", "exit", "(I)V", false); - methodVisitor.visitLabel(label3); - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - methodVisitor.visitInsn(RETURN); - methodVisitor.visitMaxs(2, 2); - methodVisitor.visitEnd(); - } - classWriter.visitEnd(); - return classWriter.toByteArray(); - } - - public static String randomStr(final int lenght) { - String alphabet = "abcdefghijklmnopqrstuvwxyz"; - alphabet += alphabet.toUpperCase(Locale.US); - final StringBuilder sb = new StringBuilder(lenght); - final Random random = SecurityHelper.newRandom(); - for (int i = 0; i < lenght; i++) - sb.append(alphabet.charAt(random.nextInt(26))); - return sb.toString(); - } - - public Class def(final String name, final String exName) { - return super.defineClass(name, ByteBuffer.wrap(gen(name.replace('.', '/'), exName)), null); - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java b/Launcher/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java index 8e0dcab9..99c81596 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java +++ b/Launcher/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java @@ -2,6 +2,7 @@ import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherTrustManager; +import pro.gravit.launcher.client.ClientClassLoader; import java.security.cert.X509Certificate; @@ -15,4 +16,12 @@ public static void checkCertificatesSuccess(X509Certificate[] certs) throws Exce LauncherTrustManager trustManager = Launcher.getConfig().trustManager; trustManager.checkCertificatesSuccess(certs, trustManager::stdCertificateChecker); } + + public static String findLibrary(ClassLoader classLoader, String library) { + if(classLoader instanceof ClientClassLoader) { + ClientClassLoader clientClassLoader = (ClientClassLoader) classLoader; + return clientClassLoader.findLibrary(library); + } + return null; + } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/utils/DirWatcher.java b/Launcher/src/main/java/pro/gravit/launcher/utils/DirWatcher.java index d61a60aa..512d0bb1 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/utils/DirWatcher.java +++ b/Launcher/src/main/java/pro/gravit/launcher/utils/DirWatcher.java @@ -1,5 +1,6 @@ package pro.gravit.launcher.utils; +import pro.gravit.launcher.LauncherEngine; import pro.gravit.launcher.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedEntry; @@ -46,7 +47,7 @@ public DirWatcher(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean dig private static void handleError(Throwable e) { LogHelper.error(e); - NativeJVMHalt.haltA(-123); + LauncherEngine.exitLauncher(-123); } private static Deque toPath(Iterable path) { diff --git a/Launcher/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java b/Launcher/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java index 1d719a23..df22b64b 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java +++ b/Launcher/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java @@ -1,11 +1,11 @@ package pro.gravit.launcher.utils; -import pro.gravit.launcher.patches.FMLPatcher; import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.LogHelper; -import javax.swing.*; -import java.awt.event.WindowEvent; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; public final class NativeJVMHalt { public final int haltCode; @@ -15,51 +15,24 @@ public NativeJVMHalt(int haltCode) { System.out.println("JVM exit code " + haltCode); } + public static void initFunc() { + + } + public static void haltA(int code) { Throwable[] th = new Throwable[3]; NativeJVMHalt halt = new NativeJVMHalt(code); try { - JVMHelper.RUNTIME.exit(code); - } catch (Throwable exitExc) { - th[0] = exitExc; - try { - new WindowShutdown(); - } catch (Throwable windowExc) { - th[1] = windowExc; + LogHelper.dev("Try invoke Shutdown.exit"); + Class clazz = Class.forName("java.lang.Shutdown", true, ClassLoader.getSystemClassLoader()); + Method exitMethod = clazz.getDeclaredMethod("exit", int.class); + exitMethod.setAccessible(true); + exitMethod.invoke(null, code); + } catch (Throwable e) { + th[1] = e; + if(LogHelper.isDevEnabled()) { + LogHelper.error(e); } } - try { - FMLPatcher.exit(code); - } catch (Throwable fmlExc) { - th[2] = fmlExc; - } - for (Throwable t : th) { - if (t != null) LogHelper.error(t); - } - boolean a = halt.aaabBooleanC_D(); - System.out.println(a); - halt.aaabbb38C_D(); - - } - - public static boolean initFunc() { - return true; - } - - public native void aaabbb38C_D(); - - @SuppressWarnings("null") - private boolean aaabBooleanC_D() { - return (boolean) (Boolean) null; - } - - public static class WindowShutdown extends JFrame { - private static final long serialVersionUID = 6321323663070818367L; - - public WindowShutdown() { - super(); - super.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - super.processWindowEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); - } } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/api/KeyService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/api/KeyService.java new file mode 100644 index 00000000..aea481d8 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/api/KeyService.java @@ -0,0 +1,7 @@ +package pro.gravit.launcher.api; + +import java.security.interfaces.RSAPublicKey; + +public class KeyService { + public static RSAPublicKey serverRsaPublicKey; +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/FetchClientProfileKeyRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/FetchClientProfileKeyRequestEvent.java new file mode 100644 index 00000000..82958bac --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/FetchClientProfileKeyRequestEvent.java @@ -0,0 +1,35 @@ +package pro.gravit.launcher.events.request; + +import pro.gravit.launcher.events.RequestEvent; + +import java.security.PrivateKey; +import java.security.PublicKey; + +public class FetchClientProfileKeyRequestEvent extends RequestEvent { + public byte[] publicKey; + public byte[] privateKey; + public byte[] signature /* V2 */; + public long expiresAt; + public long refreshedAfter; + + public FetchClientProfileKeyRequestEvent(byte[] publicKey, byte[] privateKey, byte[] signature, long expiresAt, long refreshedAfter) { + this.publicKey = publicKey; + this.privateKey = privateKey; + this.signature = signature; + this.expiresAt = expiresAt; + this.refreshedAfter = refreshedAfter; + } + + public FetchClientProfileKeyRequestEvent(PublicKey publicKey, PrivateKey privateKey, byte[] signature, long expiresAt, long refreshedAfter) { + this.publicKey = publicKey.getEncoded(); + this.privateKey = privateKey.getEncoded(); + this.signature = signature; + this.expiresAt = expiresAt; + this.refreshedAfter = refreshedAfter; + } + + @Override + public String getType() { + return "clientProfileKey"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetPublicKeyRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetPublicKeyRequestEvent.java new file mode 100644 index 00000000..aef691ca --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetPublicKeyRequestEvent.java @@ -0,0 +1,26 @@ +package pro.gravit.launcher.events.request; + +import pro.gravit.launcher.events.RequestEvent; + +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; + +public class GetPublicKeyRequestEvent extends RequestEvent { + public byte[] rsaPublicKey; + public byte[] ecdsaPublicKey; + + public GetPublicKeyRequestEvent(byte[] rsaPublicKey, byte[] ecdsaPublicKey) { + this.rsaPublicKey = rsaPublicKey; + this.ecdsaPublicKey = ecdsaPublicKey; + } + + public GetPublicKeyRequestEvent(RSAPublicKey rsaPublicKey, ECPublicKey ecdsaPublicKey) { + this.rsaPublicKey = rsaPublicKey.getEncoded(); + this.ecdsaPublicKey = ecdsaPublicKey.getEncoded(); + } + + @Override + public String getType() { + return "getPublicKey"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/FetchClientProfileKeyRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/FetchClientProfileKeyRequest.java new file mode 100644 index 00000000..32fcf698 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/FetchClientProfileKeyRequest.java @@ -0,0 +1,14 @@ +package pro.gravit.launcher.request.auth; + +import pro.gravit.launcher.events.request.FetchClientProfileKeyRequestEvent; +import pro.gravit.launcher.request.Request; + +public class FetchClientProfileKeyRequest extends Request { + public FetchClientProfileKeyRequest() { + } + + @Override + public String getType() { + return "clientProfileKey"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/GetPublicKeyRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/GetPublicKeyRequest.java new file mode 100644 index 00000000..5119696c --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/GetPublicKeyRequest.java @@ -0,0 +1,14 @@ +package pro.gravit.launcher.request.auth; + +import pro.gravit.launcher.events.request.GetPublicKeyRequestEvent; +import pro.gravit.launcher.request.Request; + +public class GetPublicKeyRequest extends Request { + public GetPublicKeyRequest() { + } + + @Override + public String getType() { + return "getPublicKey"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java index d9571c2d..4cd44b77 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java @@ -108,6 +108,8 @@ public void registerResults() { results.register("refreshToken", RefreshTokenRequestEvent.class); results.register("restore", RestoreRequestEvent.class); results.register("additionalData", AdditionalDataRequestEvent.class); + results.register("clientProfileKey", FetchClientProfileKeyRequestEvent.class); + results.register("getPublicKey", GetPublicKeyRequestEvent.class); resultsRegistered = true; } } diff --git a/LauncherCore/src/main/java/pro/gravit/utils/command/CommandException.java b/LauncherCore/src/main/java/pro/gravit/utils/command/CommandException.java index c0fe5122..55fd8dc2 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/command/CommandException.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/command/CommandException.java @@ -5,7 +5,7 @@ public final class CommandException extends Exception { public CommandException(String message) { - super(message); + super(message, null, false, false); } diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java index 801676bb..43b6db98 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java @@ -16,27 +16,9 @@ public final class CommonHelper { - private static ScriptEngineFactory nashornFactory; - - static { - try { - ScriptEngineManager scriptManager = new ScriptEngineManager(); - nashornFactory = getEngineFactories(scriptManager); - } catch (Throwable e) { - nashornFactory = null; - } - } - private CommonHelper() { } - private static ScriptEngineFactory getEngineFactories(ScriptEngineManager manager) { - // Метод похож на костыль но таковым не является, ибо единоразовое получение фактории быстрее, чем её переполучение на ходу. - for (ScriptEngineFactory fact : manager.getEngineFactories()) - if (fact.getNames().contains("nashorn") || fact.getNames().contains("Nashorn")) return fact; - return null; - } - public static String low(String s) { return s.toLowerCase(Locale.US); } @@ -57,11 +39,9 @@ public static String multiReplace(Pattern[] pattern, String from, String replace return tmp != null ? tmp : from; } + @Deprecated public static ScriptEngine newScriptEngine() { - if (nashornFactory == null) { - throw new UnsupportedOperationException("ScriptEngine not supported"); - } - return nashornFactory.getScriptEngine(); + throw new UnsupportedOperationException("ScriptEngine not supported"); } public static Thread newThread(String name, boolean daemon, Runnable runnable) { diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/CryptoHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/CryptoHelper.java deleted file mode 100644 index 1ef0e134..00000000 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/CryptoHelper.java +++ /dev/null @@ -1,66 +0,0 @@ -package pro.gravit.utils.helper; - -import java.util.Objects; -import java.util.function.LongSupplier; - -public final class CryptoHelper { - private CryptoHelper() { - } - - public static byte[] encode(byte[] txt, String pKey) { - Objects.requireNonNull(txt); - Objects.requireNonNull(pKey); - byte[] key = SecurityHelper.fromHex(pKey); - byte[] res = new byte[txt.length]; - for (int i = 0; i < txt.length; i++) - res[i] = (byte) (txt[i] ^ key[i % key.length]); - return res; - } - - public static byte[] decode(byte[] pText, String pKey) { - Objects.requireNonNull(pText); - Objects.requireNonNull(pKey); - byte[] res = new byte[pText.length]; - byte[] key = SecurityHelper.fromHex(pKey); - for (int i = 0; i < pText.length; i++) - res[i] = (byte) (pText[i] ^ key[i % key.length]); - return res; - } - - public static void encodeOrig(byte[] txt, String pKey) { - Objects.requireNonNull(txt); - Objects.requireNonNull(pKey); - byte[] key = SecurityHelper.fromHex(pKey); - for (int i = 0; i < txt.length; i++) - txt[i] = (byte) (txt[i] ^ key[i % key.length]); - } - - public static void decodeOrig(byte[] pText, String pKey) { - Objects.requireNonNull(pText); - Objects.requireNonNull(pKey); - byte[] key = SecurityHelper.fromHex(pKey); - for (int i = 0; i < pText.length; i++) - pText[i] = (byte) (pText[i] ^ key[i % key.length]); - } - - public static String randomToken(int depth) { - VerifyHelper.verifyInt(depth, VerifyHelper.POSITIVE, "Depth must be positive"); - return SecurityHelper.toHex(SecurityHelper.randomBytes(SecurityHelper.TOKEN_LENGTH * depth)); - } - - public static class StaticRandom implements LongSupplier { - private volatile long rnd; - - public StaticRandom(long rnd) { - this.rnd = rnd; - } - - @Override - public long getAsLong() { - this.rnd ^= (this.rnd << 21); - this.rnd ^= (this.rnd >>> 35); - this.rnd ^= (this.rnd << 4); - return this.rnd; - } - } -} diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java index e4de1756..ac161aa9 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java @@ -22,7 +22,11 @@ public final class JVMHelper { public static final OS OS_TYPE = OS.byName(OPERATING_SYSTEM_MXBEAN.getName()); // System properties public static final String OS_VERSION = OPERATING_SYSTEM_MXBEAN.getVersion(); + + @Deprecated public static final int OS_BITS = getCorrectOSArch(); + + public static final ARCH ARCH_TYPE = getArch(System.getProperty("os.arch")); public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model")); public static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); // Public static fields @@ -42,6 +46,24 @@ public final class JVMHelper { private JVMHelper() { } + public enum ARCH { + X86("x86"), X86_64("x86-64"), ARM64("arm64"), ARM32("arm32"); + + public final String name; + + ARCH(String name) { + this.name = name; + } + } + + public static ARCH getArch(String arch) { + if(arch.equals("amd64") || arch.equals("x86-64") || arch.equals("x86_64")) return ARCH.X86_64; + if(arch.equals("i386") || arch.equals("i686") || arch.equals("x86")) return ARCH.X86; + if(arch.startsWith("armv8") || arch.startsWith("aarch64")) return ARCH.ARM64; + if(arch.startsWith("arm") || arch.startsWith("aarch32")) return ARCH.ARM32; + throw new InternalError(String.format("Unsupported arch '%s'", arch)); + } + public static int getVersion() { String version = System.getProperty("java.version"); if (version.startsWith("1.")) { @@ -132,6 +154,7 @@ public static void checkStackTrace(Class mainClass) { } } + @Deprecated private static int getCorrectOSArch() { // As always, mustdie must die if (OS_TYPE == OS.MUSTDIE) @@ -147,6 +170,7 @@ public static String getEnvPropertyCaseSensitive(String name) { } + @Deprecated public static boolean isJVMMatchesSystemArch() { return JVM_BITS == OS_BITS; } @@ -178,10 +202,6 @@ public static void verifySystemProperties(Class mainClass, boolean requireSys // Verify system and java architecture LogHelper.debug("Verifying JVM architecture"); - if (!isJVMMatchesSystemArch()) { - LogHelper.warning("Java and OS architecture mismatch"); - LogHelper.warning("It's recommended to download %d-bit JRE", OS_BITS); - } } public enum OS { diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/JavaHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/JavaHelper.java index ad70ca4f..8676f82e 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/JavaHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/JavaHelper.java @@ -185,14 +185,14 @@ public static class JavaVersion { public final Path jvmDir; public final int version; public final int build; - public final int bitness; + public final JVMHelper.ARCH arch; public boolean enabledJavaFX; public JavaVersion(Path jvmDir, int version) { this.jvmDir = jvmDir; this.version = version; this.build = 0; - this.bitness = JVMHelper.OS_BITS; + this.arch = JVMHelper.ARCH_TYPE; this.enabledJavaFX = true; } @@ -200,20 +200,20 @@ public JavaVersion(Path jvmDir, int version, int build, boolean enabledJavaFX) { this.jvmDir = jvmDir; this.version = version; this.build = build; - this.bitness = JVMHelper.OS_BITS; + this.arch = JVMHelper.ARCH_TYPE; this.enabledJavaFX = enabledJavaFX; } - public JavaVersion(Path jvmDir, int version, int build, int bitness, boolean enabledJavaFX) { + public JavaVersion(Path jvmDir, int version, int build, JVMHelper.ARCH arch, boolean enabledJavaFX) { this.jvmDir = jvmDir; this.version = version; this.build = build; - this.bitness = bitness; + this.arch = arch; this.enabledJavaFX = enabledJavaFX; } public static JavaVersion getCurrentJavaVersion() { - return new JavaVersion(Paths.get(System.getProperty("java.home")), JVMHelper.getVersion(), JVMHelper.JVM_BUILD, JVMHelper.JVM_BITS, isCurrentJavaSupportJavaFX()); + return new JavaVersion(Paths.get(System.getProperty("java.home")), JVMHelper.getVersion(), JVMHelper.JVM_BUILD, JVMHelper.ARCH_TYPE, isCurrentJavaSupportJavaFX()); } private static boolean isCurrentJavaSupportJavaFX() { @@ -238,21 +238,20 @@ public static JavaVersion getByPath(Path jvmDir) throws IOException { } Path releaseFile = jvmDir.resolve("release"); JavaVersionAndBuild versionAndBuild; - int bitness = JVMHelper.OS_BITS; + JVMHelper.ARCH arch = JVMHelper.ARCH_TYPE; if (IOHelper.isFile(releaseFile)) { Properties properties = new Properties(); properties.load(IOHelper.newReader(releaseFile)); versionAndBuild = getJavaVersion(properties.getProperty("JAVA_VERSION").replaceAll("\"", "")); - String arch = properties.getProperty("JAVA_VERSION").replaceAll("\"", ""); - if (arch.contains("x86_64")) { - bitness = 64; - } else if (arch.contains("x86") || arch.contains("x32")) { - bitness = 32; + try { + arch = JVMHelper.getArch(properties.getProperty("OS_ARCH").replaceAll("\"", "")); + } catch (Throwable ignored) { + arch = null; } } else { versionAndBuild = new JavaVersionAndBuild(isExistExtJavaLibrary(jvmDir, "jfxrt") ? 8 : 9, 0); } - JavaVersion resultJavaVersion = new JavaVersion(jvmDir, versionAndBuild.version, versionAndBuild.build, bitness, false); + JavaVersion resultJavaVersion = new JavaVersion(jvmDir, versionAndBuild.version, versionAndBuild.build, arch, false); if (versionAndBuild.version <= 8) { resultJavaVersion.enabledJavaFX = isExistExtJavaLibrary(jvmDir, "jfxrt"); } else { diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java index 091c1862..f21eb4fc 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java @@ -387,6 +387,16 @@ public static byte[] sign(byte[] bytes, ECPrivateKey privateKey) { } } + public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) { + Signature signature = newRSASignSignature(privateKey); + try { + signature.update(bytes); + return signature.sign(); + } catch (SignatureException e) { + throw new InternalError(e); + } + } + public static String toHex(byte[] bytes) { if (bytes == null) { diff --git a/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java b/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java index 78001387..756e7fc3 100644 --- a/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java +++ b/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java @@ -22,7 +22,12 @@ public final class JVMHelper { public static final OS OS_TYPE = OS.byName(OPERATING_SYSTEM_MXBEAN.getName()); // System properties public static final String OS_VERSION = OPERATING_SYSTEM_MXBEAN.getVersion(); + + @Deprecated public static final int OS_BITS = getCorrectOSArch(); + + public static final ARCH ARCH_TYPE = getArch(System.getProperty("os.arch")); + public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model")); // Public static fields public static final Runtime RUNTIME = Runtime.getRuntime(); @@ -41,6 +46,24 @@ public final class JVMHelper { private JVMHelper() { } + public enum ARCH { + X86("x86"), X86_64("x86-64"), ARM64("arm64"), ARM32("arm32"); + + public final String name; + + ARCH(String name) { + this.name = name; + } + } + + public static ARCH getArch(String arch) { + if(arch.equals("amd64") || arch.equals("x86-64") || arch.equals("x86_64")) return ARCH.X86_64; + if(arch.equals("i386") || arch.equals("i686") || arch.equals("x86")) return ARCH.X86; + if(arch.startsWith("armv8") || arch.startsWith("aarch64")) return ARCH.ARM64; + if(arch.startsWith("arm") || arch.startsWith("aarch32")) return ARCH.ARM32; + throw new InternalError(String.format("Unsupported arch '%s'", arch)); + } + public static int getVersion() { //System.out.println("[DEBUG] JVMHelper 11 version"); return Runtime.version().feature(); @@ -108,6 +131,7 @@ public static void checkStackTrace(Class mainClass) { } } + @Deprecated private static int getCorrectOSArch() { // As always, mustdie must die if (OS_TYPE == OS.MUSTDIE) @@ -123,6 +147,7 @@ public static String getEnvPropertyCaseSensitive(String name) { } + @Deprecated public static boolean isJVMMatchesSystemArch() { return JVM_BITS == OS_BITS; } @@ -154,10 +179,6 @@ public static void verifySystemProperties(Class mainClass, boolean requireSys // Verify system and java architecture LogHelper.debug("Verifying JVM architecture"); - if (!isJVMMatchesSystemArch()) { - LogHelper.warning("Java and OS architecture mismatch"); - LogHelper.warning("It's recommended to download %d-bit JRE", OS_BITS); - } } public enum OS { diff --git a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java index 45c9aeeb..84d4288f 100644 --- a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java @@ -3,6 +3,7 @@ import pro.gravit.launcher.ClientPermissions; import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherConfig; +import pro.gravit.launcher.api.KeyService; import pro.gravit.launcher.config.JsonConfigurable; import pro.gravit.launcher.events.request.AuthRequestEvent; import pro.gravit.launcher.events.request.ProfilesRequestEvent; @@ -24,6 +25,7 @@ import pro.gravit.utils.PublicURLClassLoader; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; +import pro.gravit.utils.helper.SecurityHelper; import java.lang.reflect.Type; import java.nio.file.Path; @@ -134,6 +136,9 @@ public void run(String... args) throws Throwable { restore(); getProfiles(); } + if(config.encodedServerRsaPublicKey != null) { + KeyService.serverRsaPublicKey = SecurityHelper.toPublicRSAKey(config.encodedServerRsaPublicKey); + } String classname = (config.mainclass == null || config.mainclass.isEmpty()) ? args[0] : config.mainclass; if (classname.length() == 0) { LogHelper.error("MainClass not found. Please set MainClass for ServerWrapper.json or first commandline argument"); @@ -231,6 +236,10 @@ public static final class Config { public Map extendedTokens; public LauncherConfig.LauncherEnvironment env; public ModuleConf moduleConf = new ModuleConf(); + + public byte[] encodedServerRsaPublicKey; + + public byte[] encodedServerEcPublicKey; } public static final class ModuleConf { diff --git a/ServerWrapper/src/main/java/pro/gravit/launcher/server/setup/ServerWrapperSetup.java b/ServerWrapper/src/main/java/pro/gravit/launcher/server/setup/ServerWrapperSetup.java index 6a4e6047..aa0ebe21 100644 --- a/ServerWrapper/src/main/java/pro/gravit/launcher/server/setup/ServerWrapperSetup.java +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/setup/ServerWrapperSetup.java @@ -1,7 +1,9 @@ package pro.gravit.launcher.server.setup; +import pro.gravit.launcher.events.request.GetPublicKeyRequestEvent; import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.request.Request; +import pro.gravit.launcher.request.auth.GetPublicKeyRequest; import pro.gravit.launcher.request.websockets.StdWebSocketService; import pro.gravit.launcher.server.ServerWrapper; import pro.gravit.utils.PublicURLClassLoader; @@ -79,6 +81,9 @@ public void run() throws Exception { try { wrapper.restore(); wrapper.getProfiles(); + GetPublicKeyRequestEvent publicKeyRequestEvent = new GetPublicKeyRequest().request(); + wrapper.config.encodedServerRsaPublicKey = publicKeyRequestEvent.rsaPublicKey; + wrapper.config.encodedServerEcPublicKey = publicKeyRequestEvent.ecdsaPublicKey; break; } catch (Throwable e) { LogHelper.error(e); diff --git a/build.gradle b/build.gradle index 893b7811..42f8013e 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ id 'org.openjfx.javafxplugin' version '0.0.10' apply false } group = 'pro.gravit.launcher' -version = '5.2.13' +version = '5.3.0-SNAPSHOT' apply from: 'props.gradle' diff --git a/modules b/modules index d3722bf1..54630405 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit d3722bf136b8c8c8da3dea879d5d2015e84b0f8c +Subproject commit 54630405c075ff3c988fdeb8d03be8f77fbbe6d0