diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index d5eee7fe..b13fe974 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -405,6 +405,10 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La Files.createDirectory(profilesDir); syncProfilesDir(); + if (config.netty != null) + nettyServerSocketHandler = new NettyServerSocketHandler(this); + else + nettyServerSocketHandler = null; // post init modules modulesManager.invokeEvent(new LaunchServerPostInitPhase(this)); if (config.components != null) { @@ -415,11 +419,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La }); LogHelper.debug("PostInit components successful"); } - // start updater - if (config.netty != null) - nettyServerSocketHandler = new NettyServerSocketHandler(this); - else - nettyServerSocketHandler = null; } private LauncherBinary binary() { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java index c019adec..344f71f3 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -13,6 +13,7 @@ import pro.gravit.launcher.Launcher; import pro.gravit.launcher.hwid.HWIDProvider; import pro.gravit.launcher.modules.events.PreConfigPhase; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launchserver.auth.handler.AuthHandler; import pro.gravit.launchserver.auth.hwid.HWIDHandler; import pro.gravit.launchserver.auth.permissions.PermissionsHandler; @@ -190,6 +191,7 @@ public static void registerAll() WebSocketService.registerResponses(); HWIDProvider.registerHWIDs(); DaoProvider.registerProviders(); + AuthRequest.registerProviders(); } public static void generateConfigIfNotExists(Path configFile, CommandHandler commandHandler, LaunchServer.LaunchServerEnv env) throws IOException { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/StdProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/StdProtectHandler.java index 0c37166e..1c197296 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/StdProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/StdProtectHandler.java @@ -4,6 +4,7 @@ import pro.gravit.utils.helper.SecurityHelper; public class StdProtectHandler extends ProtectHandler { + public boolean checkSecure = true; @Override public String generateSecureToken(AuthResponse.AuthContext context) { return SecurityHelper.randomStringToken(); @@ -21,7 +22,7 @@ public boolean verifyClientSecureToken(String token, String secureKey) { @Override public boolean allowGetAccessToken(AuthResponse.AuthContext context) { - return (context.authType == AuthResponse.ConnectTypes.CLIENT); + return (context.authType == AuthResponse.ConnectTypes.CLIENT) && (!checkSecure || context.client.isSecure); } @Override diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AcceptAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AcceptAuthProvider.java index 44dd7c64..6a820208 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AcceptAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AcceptAuthProvider.java @@ -1,11 +1,12 @@ package pro.gravit.launchserver.auth.provider; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.utils.helper.SecurityHelper; public final class AcceptAuthProvider extends AuthProvider { @Override - public AuthProviderResult auth(String login, String password, String ip) { + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) { return new AuthProviderResult(login, SecurityHelper.randomStringToken(), srv); // Same as login } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AuthProvider.java index 28e4cd4c..aeb7abf3 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/AuthProvider.java @@ -2,6 +2,7 @@ import java.io.IOException; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.utils.ProviderMap; @@ -39,9 +40,9 @@ public static void registerProviders() { * Throws an exception {@link AuthException} {@link pro.gravit.utils.HookException} if the verification script returned a meaningful error * In other cases, throwing an exception indicates a serious error */ - public abstract AuthProviderResult auth(String login, String password, String ip) throws Exception; + public abstract AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception; - public void preAuth(String login, String password, String customText, String ip) { + public void preAuth(String login, AuthRequest.AuthPasswordInterface password, String customText, String ip) { } @Override diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java index 64c817b4..7f696a0d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java @@ -2,6 +2,8 @@ import java.io.IOException; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.dao.User; import pro.gravit.launchserver.manangers.hook.AuthHookManager; @@ -10,21 +12,22 @@ public class HibernateAuthProvider extends AuthProvider { public boolean autoReg; @Override - public AuthProviderResult auth(String login, String password, String ip) throws Exception { + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception { + if(!(password instanceof AuthPlainPassword)) throw new AuthException("This password type not supported"); User user = srv.config.dao.userService.findUserByUsername(login); if(user == null && autoReg) { - AuthHookManager.RegContext context = new AuthHookManager.RegContext(login, password, ip, false); + AuthHookManager.RegContext context = new AuthHookManager.RegContext(login, ((AuthPlainPassword) password).password, ip, false); if(srv.authHookManager.registraion.hook(context)) { - user = srv.config.dao.userService.registerNewUser(login, password); + user = srv.config.dao.userService.registerNewUser(login, ((AuthPlainPassword) password).password); } else { throw new AuthException("Registration canceled. Try again later"); } } - if(user == null || !user.verifyPassword(password)) + if(user == null || !user.verifyPassword(((AuthPlainPassword) password).password)) { if(user ==null) throw new AuthException("Username incorrect"); else throw new AuthException("Username or password incorrect"); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/JsonAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/JsonAuthProvider.java index 4cb4e163..cb509465 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/JsonAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/JsonAuthProvider.java @@ -7,6 +7,9 @@ import com.google.gson.JsonElement; import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; +import pro.gravit.launchserver.auth.AuthException; import pro.gravit.utils.HTTPRequest; import pro.gravit.utils.helper.SecurityHelper; @@ -42,8 +45,9 @@ public authRequest(String username, String password, String ip, String apiKey) { } @Override - public AuthProviderResult auth(String login, String password, String ip) throws IOException { - authRequest authRequest = new authRequest(login, password, ip, apiKey); + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws IOException { + if(!(password instanceof AuthPlainPassword)) throw new AuthException("This password type not supported"); + authRequest authRequest = new authRequest(login, ((AuthPlainPassword) password).password, ip, apiKey); JsonElement request = gson.toJsonTree(authRequest); JsonElement content = HTTPRequest.jsonRequest(request, url); if (!content.isJsonObject()) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/MySQLAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/MySQLAuthProvider.java index cac22613..d0cf2443 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/MySQLAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/MySQLAuthProvider.java @@ -6,6 +6,8 @@ import java.sql.SQLException; import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.MySQLSourceConfig; @@ -29,10 +31,11 @@ public void init(LaunchServer srv) { } @Override - public AuthProviderResult auth(String login, String password, String ip) throws SQLException, AuthException { + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws SQLException, AuthException { + if(!(password instanceof AuthPlainPassword)) throw new AuthException("This password type not supported"); try (Connection c = mySQLHolder.getConnection()) { PreparedStatement s = c.prepareStatement(query); - String[] replaceParams = {"login", login, "password", password, "ip", ip}; + String[] replaceParams = {"login", login, "password", ((AuthPlainPassword) password).password, "ip", ip}; for (int i = 0; i < queryParams.length; i++) s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams)); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/NullAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/NullAuthProvider.java index 04480fe9..00e37188 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/NullAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/NullAuthProvider.java @@ -3,13 +3,14 @@ import java.io.IOException; import java.util.Objects; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.utils.helper.VerifyHelper; public final class NullAuthProvider extends AuthProvider { private volatile AuthProvider provider; @Override - public AuthProviderResult auth(String login, String password, String ip) throws Exception { + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception { return getProvider().auth(login, password, ip); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/PostgreSQLAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/PostgreSQLAuthProvider.java index 75e81df4..47c7f6d4 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/PostgreSQLAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/PostgreSQLAuthProvider.java @@ -7,6 +7,8 @@ import java.sql.SQLException; import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.PostgreSQLSourceConfig; import pro.gravit.utils.helper.CommonHelper; @@ -20,9 +22,10 @@ public final class PostgreSQLAuthProvider extends AuthProvider { private boolean usePermission; @Override - public AuthProviderResult auth(String login, String password, String ip) throws SQLException, AuthException { + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws SQLException, AuthException { + if(!(password instanceof AuthPlainPassword)) throw new AuthException("This password type not supported"); try (Connection c = postgreSQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(query)) { - String[] replaceParams = {"login", login, "password", password, "ip", ip}; + String[] replaceParams = {"login", login, "password", ((AuthPlainPassword) password).password, "ip", ip}; for (int i = 0; i < queryParams.length; i++) { s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams)); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RejectAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RejectAuthProvider.java index f6025060..1d2874a9 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RejectAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RejectAuthProvider.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launchserver.Reconfigurable; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.utils.command.Command; @@ -23,7 +24,7 @@ public RejectAuthProvider(String message) { private ArrayList whitelist; @Override - public AuthProviderResult auth(String login, String password, String ip) throws AuthException { + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws AuthException { if (whitelist != null) { for (String username : whitelist) { if (login.equals(username)) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RequestAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RequestAuthProvider.java index 723d3a26..1892e5c2 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RequestAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/RequestAuthProvider.java @@ -6,7 +6,10 @@ import java.util.regex.Pattern; import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.AuthException; import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; @@ -27,8 +30,9 @@ public void init(LaunchServer srv) { } @Override - public AuthProviderResult auth(String login, String password, String ip) throws IOException { - String currentResponse = IOHelper.request(new URL(getFormattedURL(login, password, ip))); + public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws IOException { + if(!(password instanceof AuthPlainPassword)) throw new AuthException("This password type not supported"); + String currentResponse = IOHelper.request(new URL(getFormattedURL(login, ((AuthPlainPassword) password).password, ip))); // Match username Matcher matcher = pattern.matcher(currentResponse); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BuildContext.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BuildContext.java index 7ede8a64..0e821bf9 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BuildContext.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BuildContext.java @@ -49,7 +49,7 @@ public void pushJarFile(ZipInputStream input) throws IOException { public void pushJarFile(ZipInputStream input, Set blacklist) throws IOException { ZipEntry e = input.getNextEntry(); while (e != null) { - if (blacklist.contains(e.getName())) { + if (fileList.contains(e.getName()) || blacklist.contains(e.getName())) { e = input.getNextEntry(); continue; } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java index 56b5e6c8..49e53c53 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java @@ -87,6 +87,10 @@ private void setStringField(String name, String value) public void setGuardType(String key) { setStringField("guardType", key); } + public void setSecureCheck(String hash, String salt) { + setStringField("secureCheckHash", hash); + setStringField("secureCheckSalt", salt); + } private void push(final int value) { if (value >= -1 && value <= 5) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java index 0975bff7..f420cd7b 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java @@ -8,6 +8,7 @@ import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.jar.JarFile; @@ -133,6 +134,11 @@ public Path process(Path inputJar) throws IOException { launcherConfigurator.setGuardType(server.config.launcher.guardType); launcherConfigurator.setWarningMissArchJava(server.config.launcher.warningMissArchJava); launcherConfigurator.setEnv(server.config.env); + String launcherSalt = SecurityHelper.randomStringToken(); + byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256, + server.runtime.clientCheckSecret.concat(".").concat(launcherSalt)); + launcherConfigurator.setSecureCheck(Base64.getEncoder().encodeToString(launcherSecureHash), launcherSalt); + //LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash)); if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken(); launcherConfigurator.setOemUnlockKey(server.runtime.oemUnlockKey); server.buildHookManager.registerAllClientModuleClass(launcherConfigurator); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/auth/AuthCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/auth/AuthCommand.java index 7fc6cdbd..d7d14289 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/auth/AuthCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/auth/AuthCommand.java @@ -2,6 +2,7 @@ import java.util.UUID; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.provider.AuthProvider; @@ -37,7 +38,7 @@ public void invoke(String... args) throws Exception { // Authenticate AuthProvider provider = pair.provider; - AuthProviderResult result = provider.auth(login, password, "127.0.0.1"); + AuthProviderResult result = provider.auth(login, new AuthPlainPassword(password), "127.0.0.1"); UUID uuid = pair.handler.auth(result); // Print auth successful message diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadAssetCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadAssetCommand.java index c6f6e708..77e60c26 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadAssetCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadAssetCommand.java @@ -4,10 +4,8 @@ import java.nio.file.Path; import java.util.Collections; -import pro.gravit.launcher.profiles.ClientProfile.Version; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.command.Command; -import pro.gravit.utils.HttpDownloader; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; @@ -30,7 +28,8 @@ public String getUsageDescription() { @Override public void invoke(String... args) throws Exception { verifyArgs(args, 2); - Version version = Version.byName(args[0]); + //Version version = Version.byName(args[0]); + String versionName = args[0]; String dirName = IOHelper.verifyFileName(args[1]); Path assetDir = server.updatesDir.resolve(dirName); @@ -40,7 +39,8 @@ public void invoke(String... args) throws Exception { // Download required asset LogHelper.subInfo("Downloading asset, it may take some time"); - HttpDownloader.downloadZip(server.mirrorManager.getDefaultMirror().getAssetsURL(version.name), assetDir); + //HttpDownloader.downloadZip(server.mirrorManager.getDefaultMirror().getAssetsURL(version.name), assetDir); + server.mirrorManager.downloadZip(assetDir,"assets/%s.zip", versionName); // Finished server.syncUpdatesDir(Collections.singleton(dirName)); 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 26807bc4..99c9da7f 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 @@ -7,12 +7,11 @@ import java.nio.file.Path; import java.util.Collections; +import com.google.gson.JsonElement; import pro.gravit.launcher.Launcher; import pro.gravit.launcher.profiles.ClientProfile; -import pro.gravit.launcher.profiles.ClientProfile.Version; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.command.Command; -import pro.gravit.utils.HttpDownloader; import pro.gravit.utils.command.CommandException; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; @@ -36,7 +35,8 @@ public String getUsageDescription() { @Override public void invoke(String... args) throws IOException, CommandException { verifyArgs(args, 2); - Version version = Version.byName(args[0]); + //Version version = Version.byName(args[0]); + String versionName = args[0]; String dirName = IOHelper.verifyFileName(args[1]); Path clientDir = server.updatesDir.resolve(args[1]); @@ -46,14 +46,19 @@ public void invoke(String... args) throws IOException, CommandException { // Download required client LogHelper.subInfo("Downloading client, it may take some time"); - HttpDownloader.downloadZip(server.mirrorManager.getDefaultMirror().getClientsURL(version.name), clientDir); + //HttpDownloader.downloadZip(server.mirrorManager.getDefaultMirror().getClientsURL(version.name), clientDir); + server.mirrorManager.downloadZip(clientDir,"clients/%s.zip", versionName); // Create profile file LogHelper.subInfo("Creaing profile file: '%s'", dirName); ClientProfile client; - String profilePath = String.format("pro/gravit/launchserver/defaults/profile%s.cfg", version.name); + String profilePath = String.format("pro/gravit/launchserver/defaults/profile%s.cfg", versionName); try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL(profilePath))) { client = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class); + } catch (IOException e) + { + JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName); + client = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class); } client.setTitle(dirName); client.setDir(dirName); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java index fdc4eb42..0e600258 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java @@ -7,13 +7,16 @@ public class LaunchServerRuntimeConfig { public String clientToken; public String oemUnlockKey; public String registerApiKey; + public String clientCheckSecret; public void verify() { if (clientToken == null) LogHelper.error("[RuntimeConfig] clientToken must not be null"); + if (clientCheckSecret == null) { LogHelper.warning("[RuntimeConfig] clientCheckSecret must not be null"); clientCheckSecret = SecurityHelper.randomStringToken(); } } public void reset() { clientToken = SecurityHelper.randomStringToken(); registerApiKey = SecurityHelper.randomStringToken(); + clientCheckSecret = SecurityHelper.randomStringToken(); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java index 051657ee..0a8a7aa6 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java @@ -8,6 +8,7 @@ import pro.gravit.launcher.modules.events.PreGsonPhase; import pro.gravit.launcher.request.JsonResultSerializeAdapter; import pro.gravit.launcher.request.WebSocketEvent; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launchserver.auth.handler.AuthHandler; import pro.gravit.launchserver.auth.hwid.HWIDHandler; import pro.gravit.launchserver.auth.permissions.PermissionsHandler; @@ -42,6 +43,7 @@ public void registerAdapters(GsonBuilder builder) { builder.registerTypeAdapter(HWID.class, new UniversalJsonAdapter<>(HWIDProvider.hwids)); builder.registerTypeAdapter(WebSocketServerResponse.class, new UniversalJsonAdapter<>(WebSocketService.providers)); builder.registerTypeAdapter(WebSocketEvent.class, new JsonResultSerializeAdapter()); + builder.registerTypeAdapter(AuthRequest.AuthPasswordInterface.class, new UniversalJsonAdapter<>(AuthRequest.providers)); modulesManager.invokeEvent(new PreGsonPhase(builder)); //ClientWebSocketService.appendTypeAdapters(builder); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/MirrorManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/MirrorManager.java index 684accb3..592a5fc6 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/MirrorManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/MirrorManager.java @@ -1,33 +1,36 @@ package pro.gravit.launchserver.manangers; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; +import com.google.gson.JsonElement; +import pro.gravit.utils.HTTPRequest; +import pro.gravit.utils.HttpDownloader; import pro.gravit.utils.helper.IOHelper; +import pro.gravit.utils.helper.LogHelper; public class MirrorManager { - public class Mirror { - URL url; - String assetsURLMask; - String clientsURLMask; + public static class Mirror { + String baseUrl; boolean enabled; Mirror(String url) { - assetsURLMask = url.concat("assets/%s.zip"); - clientsURLMask = url.concat("clients/%s.zip"); + //assetsURLMask = url.concat("assets/%s.zip"); + //clientsURLMask = url.concat("clients/%s.zip"); + baseUrl = url; } - private URL formatArg(String mask, String arg) throws MalformedURLException { - return new URL(String.format(mask, IOHelper.urlEncode(arg))); + private URL formatArgs(String mask, Object... args) throws MalformedURLException { + Object[] data = Arrays.stream(args).map(e -> IOHelper.urlEncode(e.toString())).toArray(); + return new URL(baseUrl.concat(String.format(mask, data))); } - public URL getAssetsURL(String assets) throws MalformedURLException { - return formatArg(assetsURLMask, assets); - } - - public URL getClientsURL(String client) throws MalformedURLException { - return formatArg(clientsURLMask, client); + public URL getURL(String mask, Object... args) throws MalformedURLException { + return formatArgs(mask, args); } } @@ -38,13 +41,14 @@ public void addMirror(String mirror) { Mirror m = new Mirror(mirror); m.enabled = true; if (defaultMirror == null) defaultMirror = m; + list.add(m); } public void addMirror(String mirror, boolean enabled) throws MalformedURLException { Mirror m = new Mirror(mirror); - m.url = new URL(mirror); m.enabled = enabled; if (defaultMirror == null && enabled) defaultMirror = m; + list.add(m); } public Mirror getDefaultMirror() { @@ -66,4 +70,61 @@ public void enableMirror(int index) { public int size() { return list.size(); } + + public boolean downloadZip(Mirror mirror, Path path, String mask, Object... args) throws IOException + { + if(!mirror.enabled) return false; + URL url = mirror.getURL(mask, args); + LogHelper.debug("Try download %s", url.toString()); + try { + HttpDownloader.downloadZip(url, path); + } catch (IOException e) + { + LogHelper.error("Download %s failed(%s: %s)", url.toString(), e.getClass().getName(), e.getMessage()); + return false; + } + return true; + } + + public void downloadZip(Path path, String mask, Object... args) throws IOException + { + if(downloadZip(defaultMirror, path, mask, args)) + { + return; + } + for(Mirror mirror : list) + { + if(mirror != defaultMirror) + { + if(downloadZip(mirror, path, mask, args)) return; + } + } + throw new IOException(String.format("Error download %s. All mirrors return error", path.toString())); + } + public JsonElement jsonRequest(Mirror mirror, JsonElement request, String method, String mask, Object... args) throws IOException + { + if(!mirror.enabled) return null; + URL url = mirror.getURL(mask, args); + try { + return HTTPRequest.jsonRequest(request, method, url); + } catch (IOException e) + { + LogHelper.error("JsonRequest %s failed(%s: %s)", url.toString(), e.getClass().getName(), e.getMessage()); + return null; + } + } + public JsonElement jsonRequest(JsonElement request, String method, String mask, Object... args) throws IOException + { + JsonElement result = jsonRequest(defaultMirror, request, method, mask, args); + if(result != null) return result; + for(Mirror mirror : list) + { + if(mirror != defaultMirror) + { + result = jsonRequest(mirror, request, method, mask, args); + if(result != null) return result; + } + } + throw new IOException("Error jsonRequest. All mirrors return error"); + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/LauncherNettyServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/LauncherNettyServer.java index e95fa544..2e9163af 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/LauncherNettyServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/LauncherNettyServer.java @@ -56,15 +56,15 @@ public void initChannel(SocketChannel ch) { ChannelPipeline pipeline = ch.pipeline(); NettyConnectContext context = new NettyConnectContext(); //p.addLast(new LoggingHandler(LogLevel.INFO)); - pipeline.addLast(new HttpServerCodec()); - pipeline.addLast(new HttpObjectAggregator(65536)); + pipeline.addLast("http-codec", new HttpServerCodec()); + pipeline.addLast("http-codec-compressor",new HttpObjectAggregator(65536)); if (server.config.netty.ipForwarding) - pipeline.addLast(new NettyIpForwardHandler(context)); - pipeline.addLast(new WebSocketServerCompressionHandler()); - pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true)); + pipeline.addLast("forward-http", new NettyIpForwardHandler(context)); + pipeline.addLast("websock-comp", new WebSocketServerCompressionHandler()); + pipeline.addLast("websock-codec", new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true)); if (server.config.netty.fileServerEnabled) - pipeline.addLast(new FileServerHandler(server.updatesDir, true, config.showHiddenFiles)); - pipeline.addLast(new WebSocketFrameHandler(context, server, service)); + pipeline.addLast("fileserver", new FileServerHandler(server.updatesDir, true, config.showHiddenFiles)); + pipeline.addLast("launchserver", new WebSocketFrameHandler(context, server, service)); pipelineHook.hook(context, ch); } }); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java index 7b0afcd8..e4ec148a 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java @@ -11,8 +11,10 @@ import io.netty.channel.ChannelHandlerContext; import pro.gravit.launcher.events.request.AuthRequestEvent; import pro.gravit.launcher.hwid.HWID; -import pro.gravit.launcher.hwid.OshiHWID; import pro.gravit.launcher.profiles.ClientProfile; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; +import pro.gravit.launcher.request.auth.password.AuthRSAPassword; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.hwid.HWIDException; @@ -34,15 +36,7 @@ public class AuthResponse extends SimpleResponse { public String customText; public boolean getSession; - public String password; - public byte[] encryptedPassword; - - public AuthResponse(String login, String password, String auth_id, OshiHWID hwid) { - this.login = login; - this.password = password; - this.auth_id = auth_id; - this.hwid = hwid; - } + public AuthRequest.AuthPasswordInterface password; public String auth_id; public ConnectTypes authType; @@ -65,10 +59,11 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti AuthProvider.authError("Don't skip Launcher Update"); return; } - if (password == null) { + if(password instanceof AuthRSAPassword) + { try { - password = IOHelper.decode(SecurityHelper.newRSADecryptCipher(server.privateKey). - doFinal(encryptedPassword)); + password = new AuthPlainPassword(IOHelper.decode(SecurityHelper.newRSADecryptCipher(server.privateKey). + doFinal(((AuthRSAPassword) password).password))); } catch (IllegalBlockSizeException | BadPaddingException ignored) { throw new AuthException("Password decryption error"); } @@ -76,7 +71,7 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti AuthProviderPair pair; if (auth_id.isEmpty()) pair = server.config.getAuthProviderPair(); else pair = server.config.getAuthProviderPair(auth_id); - AuthContext context = new AuthContext(0, login, password.length(), customText, client, null, ip, authType); + AuthContext context = new AuthContext(clientData, login, customText, client, hwid, ip, authType); AuthProvider provider = pair.provider; server.authHookManager.preHook.hook(context, clientData); provider.preAuth(login, password, customText, ip); @@ -135,24 +130,23 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti } public static class AuthContext { - public AuthContext(long session, String login, int password_length, String customText, String client, String hwid, String ip, ConnectTypes authType) { - this.session = session; - this.login = login; - this.password_length = password_length; - this.customText = customText; + public AuthContext(Client client, String login, String customText, String profileName, HWID hwid, String ip, ConnectTypes authType) { this.client = client; + this.login = login; + this.customText = customText; + this.profileName = profileName; this.hwid = hwid; this.ip = ip; this.authType = authType; } - - public long session; public String login; + @Deprecated public int password_length; //Use AuthProvider for get password - public String client; - public String hwid; + public String profileName; + public HWID hwid; public String customText; public String ip; public ConnectTypes authType; + public Client client; } } 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 9a9de042..e8bb79e6 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 @@ -8,6 +8,7 @@ import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.SimpleResponse; import pro.gravit.utils.Version; +import pro.gravit.utils.helper.SecurityHelper; public class LauncherResponse extends SimpleResponse { public Version version; @@ -15,6 +16,9 @@ public class LauncherResponse extends SimpleResponse { public byte[] digest; public int launcher_type; + public String secureHash; + public String secureSalt; + @Override public String getType() { return "launcher"; @@ -33,6 +37,7 @@ public void execute(ChannelHandlerContext ctx, Client client) { if (hash == null) service.sendObjectAndClose(ctx, new LauncherRequestEvent(true, server.config.netty.launcherURL)); if (Arrays.equals(bytes, hash)) { client.checkSign = true; + client.isSecure = checkSecure(secureHash, secureSalt); sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL)); } else { sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL)); @@ -43,12 +48,21 @@ public void execute(ChannelHandlerContext ctx, Client client) { if (hash == null) sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL)); if (Arrays.equals(bytes, hash)) { client.checkSign = true; + client.isSecure = checkSecure(secureHash, secureSalt); sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL)); } else { sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL)); } } else sendError("Request launcher type error"); - + } + 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); + //LogHelper.debug("[checkSecure] %s vs %s", Arrays.toString(normal_hash), Arrays.toString(launcher_hash)); + return Arrays.equals(normal_hash, launcher_hash); } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java b/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java index 0d5d034e..317bd48a 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java +++ b/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java @@ -6,9 +6,6 @@ import java.nio.file.Path; import java.util.jar.JarFile; -import cpw.mods.fml.SafeExitJVMLegacy; -import net.minecraftforge.fml.SafeExitJVM; -import pro.gravit.launcher.utils.NativeJVMHalt; import pro.gravit.utils.helper.LogHelper; @LauncherAPI @@ -32,18 +29,33 @@ public boolean isAgentStarted() { public static void premain(String agentArgument, Instrumentation instrumentation) { System.out.println("Launcher Agent"); + checkAgentStacktrace(); inst = instrumentation; - SafeExitJVMLegacy.class.getName(); - SafeExitJVM.class.getName(); - NativeJVMHalt.class.getName(); - NativeJVMHalt.initFunc(); - boolean bad = false; - try { - for (StackTraceElement e : new Throwable().getStackTrace()) - if (Class.forName(e.getClassName()).getClassLoader() != Runtime.class.getClassLoader() && Class.forName(e.getClassName()) != LauncherAgent.class) bad = true; - } catch(Throwable e) { bad = true; } - if (bad) NativeJVMHalt.haltA(-17); - else isAgentStarted = true; + //SafeExitJVMLegacy.class.getName(); + //SafeExitJVM.class.getName(); + //NativeJVMHalt.class.getName(); + //NativeJVMHalt.initFunc(); + isAgentStarted = true; + } + public static void checkAgentStacktrace() + { + RuntimeException ex = new SecurityException("Error check agent stacktrace"); + boolean isFoundNative = false; + boolean foundPreMain = false; + for(StackTraceElement e : ex.getStackTrace()) + { + if(e.isNativeMethod()) + { + if(!isFoundNative) isFoundNative = true; + else throw ex; + } + if(e.getMethodName().equals("premain")) + { + if(!foundPreMain) foundPreMain = true; + else throw ex; + } + } + if(!isFoundNative || !foundPreMain) throw ex; } public static boolean isStarted() { diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java index 0ad7b597..ff1db902 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java @@ -114,7 +114,7 @@ public Params(byte[] launcherDigest, Path assetDir, Path clientDir, PlayerProfil this.clientDir = clientDir; // Client params this.pp = pp; - this.accessToken = SecurityHelper.verifyToken(accessToken); + this.accessToken = accessToken; this.autoEnter = autoEnter; this.fullScreen = fullScreen; this.ram = ram; @@ -132,8 +132,7 @@ public Params(HInput input) throws Exception { // Client params pp = new PlayerProfile(input); byte[] encryptedAccessToken = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH); - String accessTokenD = new String(SecurityHelper.decrypt(Launcher.getConfig().secretKeyClient.getBytes(), encryptedAccessToken)); - accessToken = SecurityHelper.verifyToken(accessTokenD); + accessToken = new String(SecurityHelper.decrypt(Launcher.getConfig().secretKeyClient.getBytes(), encryptedAccessToken)); autoEnter = input.readBoolean(); fullScreen = input.readBoolean(); ram = input.readVarInt(); @@ -311,9 +310,23 @@ private static void launch(ClientProfile profile, Params params) throws Throwabl mainMethod.invokeWithArguments((Object)args.toArray(new String[0])); } - private static Process process = null; + private static Process process = null; private static boolean clientStarted = false; private static Thread writeParamsThread; + + public static void setWriteParamsThread(Thread writeParamsThread) { + ClientLauncher.writeParamsThread = writeParamsThread; + ClientLauncher.writeParamsThread.start(); + } + + public static Process getProcess() { + return process; + } + + public static void setClientStarted() { + clientStarted = true; + } + public static PlayerProfile playerProfile; @LauncherAPI @@ -323,41 +336,7 @@ public static Process launch( LogHelper.debug("Writing ClientLauncher params"); ClientLauncherContext context = new ClientLauncherContext(); clientStarted = false; - if (writeParamsThread != null && writeParamsThread.isAlive()) { - writeParamsThread.interrupt(); - } - writeParamsThread = CommonHelper.newThread("Client params writter", true, () -> - { - try { - try (ServerSocket socket = new ServerSocket()) { - - socket.setReuseAddress(true); - socket.setSoTimeout(30000); - socket.bind(new InetSocketAddress(SOCKET_HOST, SOCKET_PORT)); - Socket client = socket.accept(); - if (process == null) { - LogHelper.error("Process is null"); - return; - } - if (!process.isAlive()) { - LogHelper.error("Process is not alive"); - JOptionPane.showMessageDialog(null, "Client Process crashed", "Launcher", JOptionPane.ERROR_MESSAGE); - return; - } - try (HOutput output = new HOutput(client.getOutputStream())) { - params.write(output); - output.writeString(Launcher.gsonManager.gson.toJson(profile), 0); - assetHDir.write(output); - clientHDir.write(output); - ClientHookManager.paramsOutputHook.hook(output); - } - clientStarted = true; - } - } catch (IOException e) { - LogHelper.error(e); - } - }); - writeParamsThread.start(); + container.write(new ParamContainer(params, profile, assetHDir, clientHDir)); checkJVMBitsAndVersion(); LogHelper.debug("Resolving JVM binary"); Path javaBin = LauncherGuardManager.getGuardJavaBinPath(); @@ -485,25 +464,10 @@ public static void main(String... args) throws Throwable { HWIDProvider.registerHWIDs(); LauncherGuardManager.initGuard(true); LogHelper.debug("Reading ClientLauncher params"); - Params params; - ClientProfile profile; - HashedDir assetHDir, clientHDir; - try { - try (Socket socket = IOHelper.newSocket()) { - socket.connect(new InetSocketAddress(SOCKET_HOST, SOCKET_PORT)); - try (HInput input = new HInput(socket.getInputStream())) { - params = new Params(input); - profile = Launcher.gsonManager.gson.fromJson(input.readString(0), ClientProfile.class); - assetHDir = new HashedDir(input); - clientHDir = new HashedDir(input); - ClientHookManager.paramsInputHook.hook(input); - } - } - } catch (IOException ex) { - LogHelper.error(ex); - System.exit(-98); - return; - } + ParamContainer p = container.read(); + Params params = p.params; + ClientProfile profile = p.profile; + HashedDir assetHDir = p.assetHDir, clientHDir = p.clientHDir; ClientLaunchContext context = new ClientLaunchContext(params, profile, assetHDir, clientHDir); Launcher.profile = profile; playerProfile = params.pp; @@ -635,4 +599,87 @@ public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher, private ClientLauncher() { } + + public static interface ParamsAPI { + ParamContainer read() throws Exception; + void write(ParamContainer p) throws Exception; + } + + public static ParamsAPI container = new ParamsAPI() { + @Override + public ParamContainer read() throws Exception { + ParamContainer p; + try (Socket socket = IOHelper.newSocket()) { + socket.connect(new InetSocketAddress(SOCKET_HOST, SOCKET_PORT)); + try (HInput input = new HInput(socket.getInputStream())) { + p = new ParamContainer(input); + } + } + return p; + } + @Override + public void write(ParamContainer p) throws Exception { + setWriteParamsThread(CommonHelper.newThread("Client params writter", true, () -> + { + try { + try (ServerSocket socket = new ServerSocket()) { + socket.setReuseAddress(true); + socket.setSoTimeout(30000); + socket.bind(new InetSocketAddress(SOCKET_HOST, SOCKET_PORT)); + Socket client = socket.accept(); + if (process == null) { + LogHelper.error("Process is null"); + return; + } + if (!process.isAlive()) { + LogHelper.error("Process is not alive"); + JOptionPane.showMessageDialog(null, "Client Process crashed", "Launcher", JOptionPane.ERROR_MESSAGE); + return; + } + try (HOutput output = new HOutput(client.getOutputStream())) { + p.write(output); + } + clientStarted = true; + } + } catch (IOException e) { + LogHelper.error(e); + } + })); + } + + }; + + public static class ParamContainer extends StreamObject { + + public ParamContainer(HInput input) throws Exception { + params = new Params(input); + profile = Launcher.gsonManager.gson.fromJson(input.readString(0), ClientProfile.class); + assetHDir = new HashedDir(input); + clientHDir = new HashedDir(input); + ClientHookManager.paramsInputHook.hook(input); + } + + public ParamContainer() { + } + + public ParamContainer(Params params, ClientProfile profile, HashedDir assetHDir, HashedDir clientHDir) { + this.params = params; + this.profile = profile; + this.assetHDir = assetHDir; + this.clientHDir = clientHDir; + } + + public Params params; + public ClientProfile profile; + public HashedDir assetHDir, clientHDir; + + @Override + public void write(HOutput output) throws IOException { + params.write(output); + output.writeString(Launcher.gsonManager.gson.toJson(profile), 0); + assetHDir.write(output); + clientHDir.write(output); + ClientHookManager.paramsOutputHook.hook(output); + } + } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGravitGuard.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGravitGuard.java index 4052673a..30f24026 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGravitGuard.java +++ b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGravitGuard.java @@ -50,7 +50,7 @@ public int getClientJVMBits() { public void init(boolean clientInstance) { try { String projectName = Launcher.getConfig().projectname; - UnpackHelper.unpack(Launcher.getResourceURL("wrapper32.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("64.exe"))); + UnpackHelper.unpack(Launcher.getResourceURL("wrapper64.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("64.exe"))); UnpackHelper.unpack(Launcher.getResourceURL("AntiInject64.dll", "guard"), DirBridge.getGuardDir().resolve("AntiInject64.dll")); UnpackHelper.unpack(Launcher.getResourceURL("wrapper32.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("32.exe"))); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java b/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java index 18274403..05edd785 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java @@ -10,6 +10,8 @@ public class AutogenConfig { public String guardLicenseName; public String guardLicenseKey; public String guardLicenseEncryptKey; + public String secureCheckHash; + public String secureCheckSalt; public int env; public boolean isWarningMissArchJava; // 0 - Dev (дебаг включен по умолчанию, все сообщения) diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java b/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java index 6294bf86..6019b49d 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java @@ -43,10 +43,15 @@ public static AutogenConfig getAutogenConfig() { public final String guardLicenseKey; public final String guardLicenseEncryptKey; public final String guardType; + + public final String secureCheckHash; + public final String secureCheckSalt; @LauncherAPI public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException { publicKey = SecurityHelper.toPublicRSAKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH)); + secureCheckHash = config.secureCheckHash; + secureCheckSalt = config.secureCheckSalt; projectname = config.projectname; clientPort = config.clientPort; secretKeyClient = config.secretKeyClient; @@ -92,6 +97,8 @@ public LauncherConfig(String address, RSAPublicKey publicKey, Map applies, Path dstDirFile, DownloadCallback callback, DownloadTotalCallback totalCallback) throws IOException, URISyntaxException { - try (CloseableHttpClient httpclient = HttpClients.custom() + try (CloseableHttpClient httpclient = HttpClients.custom().setUserAgent(IOHelper.USER_AGENT) .setRedirectStrategy(new LaxRedirectStrategy()) .build()) { applies.sort((a,b) -> Long.compare(a.size, b.size)); @@ -122,6 +122,7 @@ public void downloadZip(String base, List applies, Path dstDirFile continue; // Skip directories // Unpack entry String name = entry.getName(); + callback.stateChanged(name, 0L, entry.getSize()); LogHelper.subInfo("Downloading file: '%s'", name); if(fullDownload || applies.stream().anyMatch((t) -> t.apply.equals(name))) { diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java index 69e94d91..b7aef7d5 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java @@ -5,14 +5,22 @@ import pro.gravit.launcher.events.request.AuthRequestEvent; import pro.gravit.launcher.hwid.HWID; import pro.gravit.launcher.request.Request; +import pro.gravit.launcher.request.auth.password.AuthPlainPassword; +import pro.gravit.launcher.request.auth.password.AuthRSAPassword; import pro.gravit.launcher.request.websockets.WebSocketRequest; +import pro.gravit.utils.ProviderMap; import pro.gravit.utils.helper.VerifyHelper; public final class AuthRequest extends Request implements WebSocketRequest { + public static ProviderMap providers = new ProviderMap<>(); + public interface AuthPasswordInterface + { + boolean check(); + } @LauncherNetworkAPI private final String login; @LauncherNetworkAPI - private final byte[] encryptedPassword; + private final AuthPasswordInterface password; @LauncherNetworkAPI private final String auth_id; @LauncherNetworkAPI @@ -25,8 +33,6 @@ public final class AuthRequest extends Request implements WebS private final ConnectTypes authType; @LauncherNetworkAPI public boolean initProxy; - @LauncherNetworkAPI - public String password; public enum ConnectTypes { @LauncherNetworkAPI @@ -42,7 +48,7 @@ public enum ConnectTypes { @LauncherAPI public AuthRequest(String login, byte[] password, HWID hwid) { this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); - this.encryptedPassword = password.clone(); + this.password = new AuthRSAPassword(password.clone()); this.hwid = hwid; customText = ""; auth_id = ""; @@ -53,7 +59,7 @@ public AuthRequest(String login, byte[] password, HWID hwid) { @LauncherAPI public AuthRequest(String login, byte[] password, HWID hwid, String auth_id) { this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); - this.encryptedPassword = password.clone(); + this.password = new AuthRSAPassword(password.clone()); this.hwid = hwid; this.auth_id = auth_id; customText = ""; @@ -64,7 +70,7 @@ public AuthRequest(String login, byte[] password, HWID hwid, String auth_id) { @LauncherAPI public AuthRequest(String login, byte[] password, HWID hwid, String customText, String auth_id) { this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); - this.encryptedPassword = password.clone(); + this.password = new AuthRSAPassword(password.clone()); this.hwid = hwid; this.auth_id = auth_id; this.customText = customText; @@ -74,7 +80,7 @@ public AuthRequest(String login, byte[] password, HWID hwid, String customText, public AuthRequest(String login, byte[] encryptedPassword, String auth_id, ConnectTypes authType) { this.login = login; - this.encryptedPassword = encryptedPassword; + this.password = new AuthRSAPassword(encryptedPassword.clone()); this.auth_id = auth_id; this.authType = authType; this.hwid = null; @@ -84,8 +90,7 @@ public AuthRequest(String login, byte[] encryptedPassword, String auth_id, Conne public AuthRequest(String login, String password, String auth_id, ConnectTypes authType) { this.login = login; - this.password = password; - this.encryptedPassword = null; + this.password = new AuthPlainPassword(password); this.auth_id = auth_id; this.authType = authType; this.hwid = null; @@ -97,4 +102,12 @@ public AuthRequest(String login, String password, String auth_id, ConnectTypes a public String getType() { return "auth"; } + private static boolean registerProviders = false; + public static void registerProviders() { + if(!registerProviders) { + providers.register("plain", AuthPlainPassword.class); + providers.register("rsa", AuthRSAPassword.class); + registerProviders = true; + } + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/JoinServerRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/JoinServerRequest.java index 6e2ca2f4..b50ada1a 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/JoinServerRequest.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/JoinServerRequest.java @@ -21,7 +21,7 @@ public final class JoinServerRequest extends Request imp @LauncherAPI public JoinServerRequest(String username, String accessToken, String serverID) { this.username = VerifyHelper.verifyUsername(username); - this.accessToken = SecurityHelper.verifyToken(accessToken); + this.accessToken = accessToken; this.serverID = VerifyHelper.verifyServerID(serverID); } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthPlainPassword.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthPlainPassword.java new file mode 100644 index 00000000..68eb760f --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthPlainPassword.java @@ -0,0 +1,18 @@ +package pro.gravit.launcher.request.auth.password; + +import pro.gravit.launcher.LauncherNetworkAPI; +import pro.gravit.launcher.request.auth.AuthRequest; + +public class AuthPlainPassword implements AuthRequest.AuthPasswordInterface { + @LauncherNetworkAPI + public final String password; + + public AuthPlainPassword(String password) { + this.password = password; + } + + @Override + public boolean check() { + return true; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthRSAPassword.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthRSAPassword.java new file mode 100644 index 00000000..0a8a1831 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthRSAPassword.java @@ -0,0 +1,18 @@ +package pro.gravit.launcher.request.auth.password; + +import pro.gravit.launcher.LauncherNetworkAPI; +import pro.gravit.launcher.request.auth.AuthRequest; + +public class AuthRSAPassword implements AuthRequest.AuthPasswordInterface { + @LauncherNetworkAPI + public final byte[] password; + + public AuthRSAPassword(byte[] password) { + this.password = password; + } + + @Override + public boolean check() { + return true; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/update/LauncherRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/update/LauncherRequest.java index 92d03509..16273a2f 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/update/LauncherRequest.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/update/LauncherRequest.java @@ -24,6 +24,10 @@ public final class LauncherRequest extends Request impleme @LauncherNetworkAPI public byte[] digest; @LauncherNetworkAPI + public String secureHash; + @LauncherNetworkAPI + public String secureSalt; + @LauncherNetworkAPI public int launcher_type = EXE_BINARY ? 2 : 1; @LauncherAPI public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class); @@ -89,6 +93,8 @@ public LauncherRequest() { } catch (IOException e) { LogHelper.error(e); } + secureHash = Launcher.getConfig().secureCheckHash; + secureSalt = Launcher.getConfig().secureCheckSalt; } @Override 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 5b62226d..8b7743d4 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 @@ -16,6 +16,7 @@ import pro.gravit.launcher.hasher.HashedEntry; import pro.gravit.launcher.hasher.HashedEntryAdapter; import pro.gravit.launcher.request.WebSocketEvent; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.utils.ProviderMap; import pro.gravit.utils.UniversalJsonAdapter; import pro.gravit.utils.helper.LogHelper; @@ -41,6 +42,7 @@ public static void appendTypeAdapters(GsonBuilder builder) builder.registerTypeAdapter(HashedEntry.class, new HashedEntryAdapter()); builder.registerTypeAdapter(WebSocketEvent.class, new UniversalJsonAdapter<>(ClientWebSocketService.results)); builder.registerTypeAdapter(WebSocketRequest.class, new UniversalJsonAdapter<>(ClientWebSocketService.requests)); + builder.registerTypeAdapter(AuthRequest.AuthPasswordInterface.class, new UniversalJsonAdapter<>(AuthRequest.providers)); } private static URI createURL(String address) { diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StandartClientWebSocketService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StandartClientWebSocketService.java index f56717d9..554eedd3 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StandartClientWebSocketService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StandartClientWebSocketService.java @@ -12,6 +12,7 @@ import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.RequestException; import pro.gravit.launcher.request.WebSocketEvent; +import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.LogHelper; @@ -20,6 +21,7 @@ public class StandartClientWebSocketService extends ClientWebSocketService { public StandartClientWebSocketService(String address) throws SSLException { super(address); + AuthRequest.registerProviders(); } public class RequestFuture implements Future { diff --git a/LauncherCore/src/main/java/pro/gravit/utils/HTTPRequest.java b/LauncherCore/src/main/java/pro/gravit/utils/HTTPRequest.java index 662ad81c..97a33fe8 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/HTTPRequest.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/HTTPRequest.java @@ -6,7 +6,6 @@ import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import com.google.gson.JsonElement; @@ -39,19 +38,22 @@ public static int sendCrashreport(String strurl, String data) throws IOException } public static JsonElement jsonRequest(JsonElement request, URL url) throws IOException { + return jsonRequest(request, "POST", url); + } + + public static JsonElement jsonRequest(JsonElement request, String method, URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); - connection.setDoOutput(true); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); + if(request != null) connection.setDoOutput(true); + connection.setRequestMethod(method); + if(request != null) connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); connection.setRequestProperty("Accept", "application/json"); if (TIMEOUT > 0) connection.setConnectTimeout(TIMEOUT); - - OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), Charset.forName("UTF-8")); - writer.write(request.toString()); - writer.flush(); - writer.close(); + if(request != null) try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), StandardCharsets.UTF_8)) { + writer.write(request.toString()); + writer.flush(); + } InputStreamReader reader; int statusCode = connection.getResponseCode(); diff --git a/LauncherCore/src/main/java/pro/gravit/utils/HttpDownloader.java b/LauncherCore/src/main/java/pro/gravit/utils/HttpDownloader.java index 6fffb2e6..58b7d7fd 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/HttpDownloader.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/HttpDownloader.java @@ -1,59 +1,59 @@ package pro.gravit.utils; import java.io.BufferedInputStream; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.net.URL; import java.nio.file.Path; -import java.util.Observable; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; -public final class HttpDownloader extends Observable { - public static final int BUFER_SIZE = 8192; - public static final int INTERVAL = 300; - public AtomicInteger writed = new AtomicInteger(0); - private String filename; - public Thread thread; +public final class HttpDownloader { + public static final int INTERVAL = 500; + public final AtomicInteger writed; + private volatile String filename; + public final Thread thread; - public HttpDownloader(URL url, String file) { - Runnable run = () -> { + public HttpDownloader(URL url, Path file) { + writed = new AtomicInteger(0); + filename = null; + thread = new Thread(() -> { try { - filename = file; - downloadFile(url, file); + filename = IOHelper.getFileName(file); + downloadFile(url, file, writed::set); } catch (IOException e) { e.printStackTrace(); } - }; - Thread downloader = new Thread(run); - thread = downloader; - downloader.start(); + }); + thread.setDaemon(true); + thread.start(); } - public synchronized String getFilename() { + public String getFilename() { return filename; } - public void downloadFile(URL url, String file) throws IOException { - try (BufferedInputStream in = new BufferedInputStream(url.openStream()); FileOutputStream fout = new FileOutputStream(file)) { + public static void downloadFile(URL url, Path file, Consumer chanheTrack) throws IOException { + try (BufferedInputStream in = new BufferedInputStream(url.openStream()); OutputStream fout = IOHelper.newOutput(file, false)) { - final byte[] data = new byte[BUFER_SIZE]; + final byte[] data = new byte[IOHelper.BUFFER_SIZE]; int count; long timestamp = System.currentTimeMillis(); int writed_local = 0; - while ((count = in.read(data, 0, BUFER_SIZE)) != -1) { + while ((count = in.read(data, 0, IOHelper.BUFFER_SIZE)) != -1) { fout.write(data, 0, count); writed_local += count; if (System.currentTimeMillis() - timestamp > INTERVAL) { - writed.set(writed_local); + chanheTrack.accept(writed_local); LogHelper.debug("Downloaded %d", writed_local); } } - writed.set(writed_local); + chanheTrack.accept(writed_local); } } diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Version.java b/LauncherCore/src/main/java/pro/gravit/utils/Version.java index 37353c60..fd5d84a9 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/Version.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/Version.java @@ -22,7 +22,7 @@ public final class Version { public final Type release; public static final int MAJOR = 5; public static final int MINOR = 0; - public static final int PATCH = 9; + public static final int PATCH = 10; public static final int BUILD = 1; public static final Version.Type RELEASE = Type.STABLE; diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/IOHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/IOHelper.java index 1d602582..e8929abe 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/IOHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/IOHelper.java @@ -168,6 +168,7 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOExce private static final Pattern CROSS_SEPARATOR_PATTERN = Pattern.compile(CROSS_SEPARATOR, Pattern.LITERAL); private static final Pattern PLATFORM_SEPARATOR_PATTERN = Pattern.compile(PLATFORM_SEPARATOR, Pattern.LITERAL); + public static final String USER_AGENT = System.getProperty("launcher.userAgentDefault", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); @LauncherAPI public static void close(AutoCloseable closeable) { @@ -346,7 +347,7 @@ public static URLConnection newConnection(URL url) throws IOException { if (connection instanceof HttpURLConnection) { connection.setReadTimeout(HTTP_TIMEOUT); connection.setConnectTimeout(HTTP_TIMEOUT); - connection.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); // Fix for stupid servers + connection.addRequestProperty("User-Agent", USER_AGENT); // Fix for stupid servers } else connection.setUseCaches(false); connection.setDoInput(true); diff --git a/build.gradle b/build.gradle index f3dd636e..4747dbb5 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ id 'signing' } group = 'pro.gravit.launcher' -version = '5.0.9' +version = '5.0.10' configure(subprojects.findAll { it.name != 'modules' }) { apply plugin: 'idea' diff --git a/modules b/modules index 8d7a95d0..6d0b3e25 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit 8d7a95d0707539ab18fba83bef6ef9f09b70c0ad +Subproject commit 6d0b3e25fa59503d67f4177b587934ad288218ff