diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index c16d4b55..e432fedc 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -16,10 +16,10 @@ jobs: path: ~/.gradle/caches key: gravit-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}-launcher - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: 17 + java-version: 21 - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/LaunchServer/build.gradle b/LaunchServer/build.gradle index db37159c..b522f651 100644 --- a/LaunchServer/build.gradle +++ b/LaunchServer/build.gradle @@ -15,8 +15,8 @@ } } -sourceCompatibility = '17' -targetCompatibility = '17' +sourceCompatibility = '21' +targetCompatibility = '21' configurations { compileOnlyA @@ -75,6 +75,7 @@ dependencies { pack project(':LauncherAPI') + pack project(':LauncherModernCore') bundle group: 'me.tongfei', name: 'progressbar', version: '0.9.2' bundle group: 'com.github.Marcono1234', name: 'gson-record-type-adapter-factory', version: 'v0.2.0' bundle group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi'] @@ -85,7 +86,7 @@ pack project(':LauncherAPI') bundle group: 'org.ow2.asm', name: 'asm-commons', version: rootProject['verAsm'] bundle group: 'io.netty', name: 'netty-all', version: rootProject['verNetty'] bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j'] - bundle group: 'mysql', name: 'mysql-connector-java', version: rootProject['verMySQLConn'] + bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn'] bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn'] bundle group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard'] bundle group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'] @@ -93,6 +94,7 @@ pack project(':LauncherAPI') bundle group: 'io.jsonwebtoken', name: 'jjwt-api', version: rootProject['verJwt'] bundle group: 'io.jsonwebtoken', name: 'jjwt-impl', version: rootProject['verJwt'] bundle group: 'io.jsonwebtoken', name: 'jjwt-gson', version: rootProject['verJwt'] + annotationProcessor(group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j']) testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit'] hikari 'io.micrometer:micrometer-core:1.8.4' diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java b/LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java index ad57e971..9bac27ff 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java @@ -21,6 +21,10 @@ public SimpleErrorHandler makeEH(Class clazz) { return new SimpleErrorHandler<>(clazz); } + public SimpleErrorHandler makeEH(Type clazz) { + return new SimpleErrorHandler<>(clazz); + } + public HttpRequest get(String url, String token) { try { var requestBuilder = HttpRequest.newBuilder() @@ -59,6 +63,10 @@ public HttpHelper.HttpOptional send(HttpRequest request, Cla return HttpHelper.send(httpClient, request, makeEH(clazz)); } + public HttpHelper.HttpOptional send(HttpRequest request, Type type) throws IOException { + return HttpHelper.send(httpClient, request, makeEH(type)); + } + public static class SimpleErrorHandler implements HttpHelper.HttpJsonErrorHandler { private final Type type; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index 9a4615cb..d016db56 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -16,6 +16,7 @@ import pro.gravit.launchserver.binary.LauncherBinary; import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; +import pro.gravit.launchserver.helper.SignHelper; import pro.gravit.launchserver.launchermodules.LauncherModuleLoader; import pro.gravit.launchserver.manangers.*; import pro.gravit.launchserver.manangers.hook.AuthHookManager; @@ -36,13 +37,15 @@ import java.io.BufferedReader; import java.io.IOException; import java.lang.ProcessBuilder.Redirect; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; +import java.security.KeyStore; +import java.time.Duration; +import java.time.Instant; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -185,6 +188,10 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La } launcherModuleLoader.init(); nettyServerSocketHandler = new NettyServerSocketHandler(this); + if(config.sign.checkCertificateExpired) { + checkCertificateExpired(); + service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS); + } // post init modules modulesManager.invokeEvent(new LaunchServerPostInitPhase(this)); } @@ -234,7 +241,6 @@ public void invoke(String... args) throws Exception { } switch (args[0]) { case "full" -> reload(ReloadType.FULL); - case "no_auth" -> reload(ReloadType.NO_AUTH); case "no_components" -> reload(ReloadType.NO_COMPONENTS); default -> reload(ReloadType.NO_AUTH); } @@ -269,6 +275,25 @@ public void invoke(String... args) throws Exception { return commands; } + public void checkCertificateExpired() { + if(!config.sign.enabled) { + return; + } + try { + KeyStore keyStore = SignHelper.getStore(Paths.get(config.sign.keyStore), config.sign.keyStorePass, config.sign.keyStoreType); + Instant date = SignHelper.getCertificateExpired(keyStore, config.sign.keyAlias); + if(date == null) { + logger.debug("The certificate will expire at unlimited"); + } else if(date.minus(Duration.ofDays(30)).isBefore(Instant.now())) { + logger.warn("The certificate will expire at {}", date.toString()); + } else { + logger.debug("The certificate will expire at {}", date.toString()); + } + } catch (Throwable e) { + logger.error("Can't get certificate expire date", e); + } + } + private LauncherBinary binary() { LaunchServerLauncherExeInit event = new LaunchServerLauncherExeInit(this, null); modulesManager.invokeEvent(event); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java index 6faec029..19b7b01d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -11,6 +11,7 @@ import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest; import pro.gravit.launchserver.auth.core.AuthCoreProvider; +import pro.gravit.launchserver.auth.mix.MixProvider; import pro.gravit.launchserver.auth.password.PasswordVerifier; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.texture.TextureProvider; @@ -212,6 +213,7 @@ public static void registerAll() { GetAvailabilityAuthRequest.registerProviders(); OptionalAction.registerProviders(); OptionalTrigger.registerProviders(); + MixProvider.registerProviders(); } private static void printExperimentalBranch() { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/asm/InjectClassAcceptor.java b/LaunchServer/src/main/java/pro/gravit/launchserver/asm/InjectClassAcceptor.java index 750d4aff..c0e6d454 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/asm/InjectClassAcceptor.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/asm/InjectClassAcceptor.java @@ -11,7 +11,6 @@ import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; @SuppressWarnings("rawtypes") public class InjectClassAcceptor implements MainBuildTask.ASMTransformer { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/asm/NodeUtils.java b/LaunchServer/src/main/java/pro/gravit/launchserver/asm/NodeUtils.java index bf1464cd..88893c87 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/asm/NodeUtils.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/asm/NodeUtils.java @@ -149,10 +149,7 @@ public static int opcodeEmulation(AbstractInsnNode e) { break; case INVOKEVIRTUAL: case INVOKESPECIAL: - case INVOKEINTERFACE: - stackSize += doMethodEmulation(((MethodInsnNode) e).desc); - break; - case INVOKESTATIC: + case INVOKEINTERFACE, INVOKESTATIC: stackSize += doMethodEmulation(((MethodInsnNode) e).desc); break; case INVOKEDYNAMIC: diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java index 4a52a8d8..9645fa01 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java @@ -4,6 +4,7 @@ import org.apache.logging.log4j.Logger; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.core.AuthCoreProvider; +import pro.gravit.launchserver.auth.mix.MixProvider; import pro.gravit.launchserver.auth.texture.TextureProvider; import java.io.IOException; @@ -16,6 +17,7 @@ public final class AuthProviderPair { public boolean isDefault = true; public AuthCoreProvider core; public TextureProvider textureProvider; + public Map mixes; public Map links; public transient String name; public transient Set features; @@ -36,12 +38,14 @@ public static Set getFeatures(Class clazz) { return list; } + public Set getFeatures() { + return features; + } + public static void getFeatures(Class clazz, Set list) { - Features features = clazz.getAnnotation(Features.class); - if (features != null) { - for (Feature feature : features.value()) { - list.add(feature.value()); - } + Feature[] features = clazz.getAnnotationsByType(Feature.class); + for (Feature feature : features) { + list.add(feature.value()); } Class superClass = clazz.getSuperclass(); if (superClass != null && superClass != Object.class) { @@ -55,8 +59,15 @@ public static void getFeatures(Class clazz, Set list) { public final T isSupport(Class clazz) { if (core == null) return null; - T result = null; - if (result == null) result = core.isSupport(clazz); + T result = core.isSupport(clazz); + if (result == null && mixes != null) { + for(var m : mixes.values()) { + result = m.isSupport(clazz); + if(result != null) { + break; + } + } + } return result; } @@ -66,6 +77,12 @@ public final void init(LaunchServer srv, String name) { core.init(srv); features = new HashSet<>(); getFeatures(core.getClass(), features); + if(mixes != null) { + for(var m : mixes.values()) { + m.init(srv, core); + getFeatures(m.getClass(), features); + } + } } public final void link(LaunchServer srv) { @@ -87,5 +104,10 @@ public final void close() throws IOException { if (textureProvider != null) { textureProvider.close(); } + if(mixes != null) { + for(var m : mixes.values()) { + m.close(); + } + } } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AbstractSQLCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AbstractSQLCoreProvider.java index 6950b88f..4028feeb 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AbstractSQLCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AbstractSQLCoreProvider.java @@ -14,6 +14,7 @@ import pro.gravit.launchserver.auth.password.PasswordVerifier; import pro.gravit.launchserver.helper.LegacySessionHelper; import pro.gravit.launchserver.manangers.AuthManager; +import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.utils.helper.SecurityHelper; @@ -162,6 +163,25 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c } } + @Override + public User checkServer(Client client, String username, String serverID) throws IOException { + SQLUser user = (SQLUser) getUserByUsername(username); + if (user == null) { + return null; + } + if (user.getUsername().equals(username) && user.getServerId().equals(serverID)) { + return user; + } + return null; + } + + @Override + public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException { + SQLUser user = (SQLUser) client.getUser(); + if (user == null) return false; + return user.getUsername().equals(username) && user.getAccessToken().equals(accessToken) && updateServerID(user, serverID); + } + @Override public void init(LaunchServer server) { this.server = server; @@ -225,7 +245,6 @@ protected void updateAuth(User user, String accessToken) throws IOException { } } - @Override protected boolean updateServerID(User user, String serverID) throws IOException { try (Connection c = getSQLConfig().getConnection()) { SQLUser SQLUser = (SQLUser) user; @@ -328,12 +347,10 @@ public UUID getUUID() { return uuid; } - @Override public String getServerId() { return serverId; } - @Override public String getAccessToken() { return accessToken; } @@ -372,6 +389,11 @@ public User getUser() { return user; } + @Override + public String getMinecraftAccessToken() { + return user.getAccessToken(); + } + @Override public long getExpireIn() { return 0; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java index a6c210b0..99805cc2 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java @@ -45,7 +45,6 @@ public static void registerProviders() { providers.register("mysql", MySQLCoreProvider.class); providers.register("postgresql", PostgresSQLCoreProvider.class); providers.register("memory", MemoryAuthCoreProvider.class); - providers.register("http", HttpAuthCoreProvider.class); providers.register("merge", MergeAuthCoreProvider.class); registredProviders = true; } @@ -75,11 +74,6 @@ public AuthManager.AuthReport authorize(User user, AuthResponse.AuthContext cont public abstract void init(LaunchServer server); - // Auth Handler methods - protected boolean updateServerID(User user, String serverID) throws IOException { - throw new UnsupportedOperationException(); - } - public List getDetails(Client client) { return List.of(new AuthPasswordDetails()); } @@ -292,22 +286,9 @@ public void invoke(String... args) throws Exception { return map; } - public User checkServer(Client client, String username, String serverID) throws IOException { - User user = getUserByUsername(username); - if (user == null) { - return null; - } - if (user.getUsername().equals(username) && user.getServerId().equals(serverID)) { - return user; - } - return null; - } + public abstract User checkServer(Client client, String username, String serverID) throws IOException; - public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { - User user = client.getUser(); - if (user == null) return false; - return user.getUsername().equals(username) && user.getAccessToken().equals(accessToken) && updateServerID(user, serverID); - } + public abstract boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException; @SuppressWarnings("unchecked") public T isSupport(Class clazz) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java deleted file mode 100644 index ffb9bfb8..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java +++ /dev/null @@ -1,646 +0,0 @@ -package pro.gravit.launchserver.auth.core; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import pro.gravit.launcher.ClientPermissions; -import pro.gravit.launcher.events.request.AuthRequestEvent; -import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent; -import pro.gravit.launcher.profiles.Texture; -import pro.gravit.launcher.request.auth.AuthRequest; -import pro.gravit.launcher.request.secure.HardwareReportRequest; -import pro.gravit.launchserver.HttpRequester; -import pro.gravit.launchserver.LaunchServer; -import pro.gravit.launchserver.auth.AuthException; -import pro.gravit.launchserver.auth.core.interfaces.UserHardware; -import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware; -import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportRemoteClientAccess; -import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware; -import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportProperties; -import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures; -import pro.gravit.launchserver.helper.HttpHelper; -import pro.gravit.launchserver.manangers.AuthManager; -import pro.gravit.launchserver.socket.Client; -import pro.gravit.launchserver.socket.response.auth.AuthResponse; -import pro.gravit.utils.helper.CommonHelper; - -import java.io.IOException; -import java.util.*; - -public class HttpAuthCoreProvider extends AuthCoreProvider implements AuthSupportHardware, AuthSupportRemoteClientAccess { - private transient final Logger logger = LogManager.getLogger(); - public String bearerToken; - public String getUserByUsernameUrl; - public String getUserByLoginUrl; - public String getUserByUUIDUrl; - public String getUserByTokenUrl; - public String getAuthDetailsUrl; - public String refreshTokenUrl; - public String authorizeUrl; - public String joinServerUrl; - public String checkServerUrl; - public String updateServerIdUrl; - //below fields can be empty if advanced protect handler disabled - public String getHardwareInfoByPublicKeyUrl; - public String getHardwareInfoByDataUrl; - public String getHardwareInfoByIdUrl; - public String createHardwareInfoUrl; - public String connectUserAndHardwareUrl; - public String addPublicKeyToHardwareInfoUrl; - public String getUsersByHardwareInfoUrl; - public String banHardwareUrl; - public String unbanHardwareUrl; - public String apiUrl; - public List apiFeatures; - private transient HttpRequester requester; - - @Override - public User getUserByUsername(String username) { - try { - return requester.send(requester.get(CommonHelper.replace(getUserByUsernameUrl, "username", username), null), HttpUser.class).getOrThrow(); - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public User getUserByLogin(String login) { - if (getUserByLoginUrl != null) { - try { - return requester.send(requester.get(CommonHelper.replace(getUserByLoginUrl, "login", login), null), HttpUser.class).getOrThrow(); - } catch (IOException e) { - logger.error(e); - return null; - } - } - return super.getUserByLogin(login); - } - - @Override - public User getUserByUUID(UUID uuid) { - try { - return requester.send(requester.get(CommonHelper.replace(getUserByUUIDUrl, "uuid", uuid.toString()), null), HttpUser.class).getOrThrow(); - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public List getDetails(Client client) { - if (getAuthDetailsUrl == null) { - return super.getDetails(client); - } - try { - var result = requester.send(requester.get(getAuthDetailsUrl, bearerToken), GetAuthDetailsResponse.class).getOrThrow(); - return result.details; - } catch (IOException e) { - logger.error(e); - return super.getDetails(client); - } - } - - @Override - public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired { - if (getUserByTokenUrl == null) { - return null; - } - try { - var result = requester.send(requester.get(getUserByTokenUrl, accessToken), HttpUserSession.class); - if (!result.isSuccessful()) { - var error = result.error().error; - if (error.equals(AuthRequestEvent.OAUTH_TOKEN_EXPIRE)) { - throw new OAuthAccessTokenExpired(); - } - return null; - } - return result.getOrThrow(); - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { - if (refreshTokenUrl == null) { - return null; - } - try { - return requester.send(requester.post(refreshTokenUrl, new RefreshTokenRequest(refreshToken, context), - null), HttpAuthReport.class).getOrThrow().toAuthReport(); - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException { - var result = requester.send(requester.post(authorizeUrl, new AuthorizeRequest(login, context, password, minecraftAccess), - bearerToken), HttpAuthReport.class); - if (!result.isSuccessful()) { - var error = result.error().error; - if (error != null) { - throw new AuthException(error); - } - } - return result.getOrThrow().toAuthReport(); - } - - @Override - public UserHardware getHardwareInfoByPublicKey(byte[] publicKey) { - if (getHardwareInfoByPublicKeyUrl == null) { - return null; - } - try { - return requester.send(requester.post(getHardwareInfoByPublicKeyUrl, new HardwareRequest(publicKey), - bearerToken), HttpUserHardware.class).getOrThrow(); - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public UserHardware getHardwareInfoByData(HardwareReportRequest.HardwareInfo info) { - if (getHardwareInfoByDataUrl == null) { - return null; - } - try { - HardwareRequest request = new HardwareRequest(new HttpUserHardware(info)); - HttpHelper.HttpOptional hardware = - requester.send(requester.post(getHardwareInfoByDataUrl, request, - bearerToken), HttpUserHardware.class); - //should return null if not found - return hardware.isSuccessful() ? hardware.getOrThrow() : null; - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public UserHardware getHardwareInfoById(String id) { - if (getHardwareInfoByIdUrl == null) { - return null; - } - try { - return requester.send(requester.post(getHardwareInfoByIdUrl, new HardwareRequest(new HttpUserHardware(Long.parseLong(id))), - bearerToken), HttpUserHardware.class).getOrThrow(); - } catch (IOException | NumberFormatException e) { - logger.error(e); - return null; - } - } - - @Override - public UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo info, byte[] publicKey) { - if (createHardwareInfoUrl == null) { - return null; - } - try { - return requester.send(requester.post(createHardwareInfoUrl, new HardwareRequest(new HttpUserHardware(info, - publicKey, false)), bearerToken), HttpUserHardware.class).getOrThrow(); - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public void connectUserAndHardware(UserSession userSession, UserHardware hardware) { - if (connectUserAndHardwareUrl == null) { - return; - } - try { - requester.send(requester.post(connectUserAndHardwareUrl, new HardwareRequest((HttpUserHardware) hardware, (HttpUserSession) userSession), bearerToken), Void.class); - } catch (IOException e) { - logger.error(e); - } - } - - @Override - public void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey) { - if (addPublicKeyToHardwareInfoUrl == null) { - return; - } - try { - requester.send(requester.post(addPublicKeyToHardwareInfoUrl, new HardwareRequest((HttpUserHardware) hardware, publicKey), bearerToken), Void.class); - } catch (IOException e) { - logger.error(e); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - @Override - public Iterable getUsersByHardwareInfo(UserHardware hardware) { - if (getUsersByHardwareInfoUrl == null) { - return null; - } - try { - return (List) (List) requester.send(requester - .post(getUsersByHardwareInfoUrl, new HardwareRequest((HttpUserHardware) hardware), bearerToken), GetHardwareListResponse.class).getOrThrow().list; - } catch (IOException e) { - logger.error(e); - return null; - } - } - - @Override - public void banHardware(UserHardware hardware) { - if (banHardwareUrl == null) { - return; - } - try { - requester.send(requester.post(banHardwareUrl, new HardwareRequest((HttpUserHardware) hardware), bearerToken), Void.class); - } catch (IOException e) { - logger.error(e); - } - } - - @Override - public void unbanHardware(UserHardware hardware) { - if (unbanHardwareUrl == null) { - return; - } - try { - requester.send(requester.post(unbanHardwareUrl, new HardwareRequest((HttpUserHardware) hardware), bearerToken), Void.class); - } catch (IOException e) { - logger.error(e); - } - } - - @Override - public String getClientApiUrl() { - return apiUrl; - } - - @Override - public List getClientApiFeatures() { - return apiFeatures; - } - - @Override - protected boolean updateServerID(User user, String serverID) throws IOException { - var result = requester.send(requester.post(updateServerIdUrl, new UpdateServerIdRequest(user.getUsername(), user.getUUID(), serverID), - null), Void.class); - return result.isSuccessful(); - } - - @Override - public User checkServer(Client client, String username, String serverID) throws IOException { - return requester.send(requester.post(checkServerUrl, new CheckServerRequest(username, serverID), bearerToken), HttpUser.class).getOrThrow(); - } - - @Override - public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { - var result = requester.send(requester.post(joinServerUrl, new JoinServerRequest(username, accessToken, serverID), bearerToken), Void.class); - return result.isSuccessful(); - } - - @Override - public void init(LaunchServer server) { - requester = new HttpRequester(); - if (getUserByUsernameUrl == null) { - throw new IllegalArgumentException("'getUserByUsernameUrl' can't be null"); - } - if (getUserByUUIDUrl == null) { - throw new IllegalArgumentException("'getUserByUUIDUrl' can't be null"); - } - if (authorizeUrl == null) { - throw new IllegalArgumentException("'authorizeUrl' can't be null"); - } - if (checkServerUrl == null && joinServerUrl == null && updateServerIdUrl == null) { - throw new IllegalArgumentException("Please set 'checkServerUrl' and 'joinServerUrl' or 'updateServerIdUrl'"); - } - } - - @Override - public void close() { - - } - - public record HttpAuthReport(String minecraftAccessToken, String oauthAccessToken, - String oauthRefreshToken, long oauthExpire, - HttpUserSession session) { - public AuthManager.AuthReport toAuthReport() { - return new AuthManager.AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, session); - } - } - - public static class UpdateServerIdRequest { - public String username; - public UUID uuid; - public String serverId; - - public UpdateServerIdRequest(String username, UUID uuid, String serverId) { - this.username = username; - this.uuid = uuid; - this.serverId = serverId; - } - } - - public static class CheckServerRequest { - public String username; - public String serverId; - - public CheckServerRequest(String username, String serverId) { - this.username = username; - this.serverId = serverId; - } - } - - public static class GetAuthDetailsResponse { - public List details; - } - - public static class GetHardwareListResponse { - public List list; - } - - public static class JoinServerRequest { - public String username; - public String accessToken; - public String serverId; - - public JoinServerRequest(String username, String accessToken, String serverId) { - this.username = username; - this.accessToken = accessToken; - this.serverId = serverId; - } - } - - public static class AuthorizeRequest { - public String login; - public AuthResponse.AuthContext context; - public AuthRequest.AuthPasswordInterface password; - public boolean minecraftAccess; - - public AuthorizeRequest() { - } - - public AuthorizeRequest(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) { - this.login = login; - this.context = context; - this.password = password; - this.minecraftAccess = minecraftAccess; - } - } - - public static class RefreshTokenRequest { - public String refreshToken; - public AuthResponse.AuthContext context; - - public RefreshTokenRequest(String refreshToken, AuthResponse.AuthContext context) { - this.refreshToken = refreshToken; - this.context = context; - } - } - - public record HardwareRequest(HttpUserHardware userHardware, byte[] key, HttpUserSession userSession) { - - public HardwareRequest(HttpUserHardware userHardware) { - this(userHardware, null, null); - } - - public HardwareRequest(HttpUserHardware userHardware, byte[] key) { - this(userHardware, key, null); - } - - public HardwareRequest(HttpUserHardware userHardware, HttpUserSession userSession) { - this(userHardware, null, userSession); - } - - public HardwareRequest(byte[] key) { - this(null, key, null); - } - - } - - public static class HttpUserSession implements UserSession { - private String id; - private HttpUser user; - private long expireIn; - - public HttpUserSession() { - } - - public HttpUserSession(String id, HttpUser user, long expireIn) { - this.id = id; - this.user = user; - this.expireIn = expireIn; - } - - @Override - public String getID() { - return id; - } - - @Override - public User getUser() { - return user; - } - - @Override - public long getExpireIn() { - return expireIn; - } - - @Override - public String toString() { - return "HttpUserSession{" + - "id='" + id + '\'' + - ", user=" + user + - ", expireIn=" + expireIn + - '}'; - } - } - - public static class HttpUserHardware implements UserHardware { - private final HardwareReportRequest.HardwareInfo hardwareInfo; - private final long id; - private byte[] publicKey; - private boolean banned; - - public HttpUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, long id, boolean banned) { - this.hardwareInfo = hardwareInfo; - this.publicKey = publicKey; - this.id = id; - this.banned = banned; - } - - public HttpUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo) { - this.hardwareInfo = hardwareInfo; - this.id = Long.MIN_VALUE; - } - - public HttpUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, boolean banned) { - this.hardwareInfo = hardwareInfo; - this.publicKey = publicKey; - this.banned = banned; - this.id = Long.MIN_VALUE; - } - - public HttpUserHardware(long id) { - this.id = id; - this.hardwareInfo = null; - } - - @Override - public HardwareReportRequest.HardwareInfo getHardwareInfo() { - return hardwareInfo; - } - - @Override - public byte[] getPublicKey() { - return publicKey; - } - - @Override - public String getId() { - return String.valueOf(id); - } - - @Override - public boolean isBanned() { - return banned; - } - - @Override - public String toString() { - return "HttpUserHardware{" + - "hardwareInfo=" + hardwareInfo + - ", publicKey=" + (publicKey == null ? null : new String(Base64.getEncoder().encode(publicKey))) + - ", id=" + id + - ", banned=" + banned + - '}'; - } - } - - public class HttpUser implements User, UserSupportTextures, UserSupportProperties, UserSupportHardware { - private String username; - private UUID uuid; - private String serverId; - private String accessToken; - private ClientPermissions permissions; - private Map assets; - private Map properties; - private long hwidId; - private transient HttpUserHardware hardware; - - public HttpUser() { - } - - public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, long hwidId) { - this.username = username; - this.uuid = uuid; - this.serverId = serverId; - this.accessToken = accessToken; - this.permissions = permissions; - this.hwidId = hwidId; - } - - public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Texture skin, Texture cloak, long hwidId) { - this.username = username; - this.uuid = uuid; - this.serverId = serverId; - this.accessToken = accessToken; - this.permissions = permissions; - this.hwidId = hwidId; - } - - public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Texture skin, Texture cloak, Map properties, long hwidId) { - this.username = username; - this.uuid = uuid; - this.serverId = serverId; - this.accessToken = accessToken; - this.permissions = permissions; - this.properties = properties; - this.hwidId = hwidId; - } - - public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Map assets, Map properties, long hwidId) { - this.username = username; - this.uuid = uuid; - this.serverId = serverId; - this.accessToken = accessToken; - this.permissions = permissions; - this.assets = assets; - this.properties = properties; - this.hwidId = hwidId; - } - - @Override - public String getUsername() { - return username; - } - - @Override - public UUID getUUID() { - return uuid; - } - - @Override - public String getServerId() { - return serverId; - } - - @Override - public String getAccessToken() { - return accessToken; - } - - @Override - public ClientPermissions getPermissions() { - return permissions; - } - - @Override - public Texture getSkinTexture() { - return assets.get("SKIN"); - } - - @Override - public Texture getCloakTexture() { - return assets.get("CAPE"); - } - - public Map getAssets() { - if (assets == null) { - return new HashMap<>(); - } - return assets; - } - - @Override - public Map getProperties() { - if (properties == null) { - return new HashMap<>(); - } - return properties; - } - - @Override - public String toString() { - return "HttpUser{" + - "username='" + username + '\'' + - ", uuid=" + uuid + - ", serverId='" + serverId + '\'' + - ", accessToken='" + accessToken + '\'' + - ", permissions=" + permissions + - ", assets=" + getAssets() + - ", properties=" + properties + - ", hwidId=" + hwidId + - '}'; - } - - @Override - public UserHardware getHardware() { - if (hardware != null) return hardware; - HttpAuthCoreProvider.HttpUserHardware result = (HttpUserHardware) getHardwareInfoById(String.valueOf(hwidId)); - hardware = result; - return result; - } - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java index 62c3391c..01dc17ad 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java @@ -94,13 +94,6 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c } } - @Override - protected boolean updateServerID(User user, String serverID) { - MemoryUser memoryUser = (MemoryUser) user; - memoryUser.serverId = serverID; - return true; - } - @Override public User checkServer(Client client, String username, String serverID) { synchronized (memory) { @@ -116,7 +109,7 @@ public User checkServer(Client client, String username, String serverID) { } @Override - public boolean joinServer(Client client, String username, String accessToken, String serverID) { + public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) { return true; } @@ -158,16 +151,6 @@ public UUID getUUID() { return uuid; } - @Override - public String getServerId() { - return serverId; - } - - @Override - public String getAccessToken() { - return accessToken; - } - @Override public ClientPermissions getPermissions() { return permissions; @@ -208,6 +191,11 @@ public User getUser() { return user; } + @Override + public String getMinecraftAccessToken() { + return "IGNORED"; + } + @Override public long getExpireIn() { return expireIn; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MergeAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MergeAuthCoreProvider.java index 1989b942..fe0a26cc 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MergeAuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MergeAuthCoreProvider.java @@ -67,7 +67,7 @@ public User checkServer(Client client, String username, String serverID) throws } @Override - public boolean joinServer(Client client, String username, String accessToken, String serverID) { + public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) { return false; // Authorization not supported } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java index 69697c7e..0a95d12f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java @@ -4,6 +4,7 @@ import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.manangers.AuthManager; +import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.auth.AuthResponse; import java.io.IOException; @@ -46,7 +47,12 @@ public void init(LaunchServer server) { } @Override - protected boolean updateServerID(User user, String serverID) { + public User checkServer(Client client, String username, String serverID) throws IOException { + return null; + } + + @Override + public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException { return false; } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/User.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/User.java index ead51933..acf69db6 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/User.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/User.java @@ -9,10 +9,6 @@ public interface User { UUID getUUID(); - String getServerId(); - - String getAccessToken(); - ClientPermissions getPermissions(); default boolean isBanned() { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/UserSession.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/UserSession.java index 97763e0f..031b627d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/UserSession.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/UserSession.java @@ -5,5 +5,7 @@ public interface UserSession { User getUser(); + String getMinecraftAccessToken(); + long getExpireIn(); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportAssetUpload.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportAssetUpload.java new file mode 100644 index 00000000..f738804f --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportAssetUpload.java @@ -0,0 +1,22 @@ +package pro.gravit.launchserver.auth.core.interfaces.provider; + +import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent; +import pro.gravit.launcher.events.request.AuthRequestEvent; +import pro.gravit.launcher.events.request.GetAssetUploadUrlRequestEvent; +import pro.gravit.launchserver.auth.Feature; +import pro.gravit.launchserver.auth.core.User; + +import java.util.Set; + +@Feature(GetAssetUploadUrlRequestEvent.FEATURE_NAME) +public interface AuthSupportAssetUpload { + String getAssetUploadUrl(String name, User user); + + default AuthRequestEvent.OAuthRequestEvent getAssetUploadToken(String name, User user) { + return null; + } + + default AssetUploadInfoRequestEvent getAssetUploadInfo(User user) { + return new AssetUploadInfoRequestEvent(Set.of("SKIN", "CAPE"), AssetUploadInfoRequestEvent.SlimSupportConf.USER); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportGetSessionsFromUser.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportGetSessionsFromUser.java deleted file mode 100644 index a8155eea..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportGetSessionsFromUser.java +++ /dev/null @@ -1,12 +0,0 @@ -package pro.gravit.launchserver.auth.core.interfaces.provider; - -import pro.gravit.launchserver.auth.Feature; -import pro.gravit.launchserver.auth.core.User; -import pro.gravit.launchserver.auth.core.UserSession; - -import java.util.List; - -@Feature("sessions") -public interface AuthSupportGetSessionsFromUser extends AuthSupport { - List getSessionsByUser(User user); -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportUserBan.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportUserBan.java deleted file mode 100644 index 489d6cbd..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportUserBan.java +++ /dev/null @@ -1,20 +0,0 @@ -package pro.gravit.launchserver.auth.core.interfaces.provider; - -import pro.gravit.launchserver.auth.core.User; -import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportBanInfo; - -import java.time.LocalDateTime; - -public interface AuthSupportUserBan extends AuthSupport { - UserSupportBanInfo.UserBanInfo banUser(User user, String reason, String moderator, LocalDateTime startTime, LocalDateTime endTime); - - default UserSupportBanInfo.UserBanInfo banUser(User user) { - return banUser(user, null, null, LocalDateTime.now(), null); - } - - void unbanUser(User user); - - default UserSupportBanInfo fetchUserBanInfo(User user) { - return (UserSupportBanInfo) user; - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/user/UserSupportBanInfo.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/user/UserSupportBanInfo.java deleted file mode 100644 index 77899389..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/user/UserSupportBanInfo.java +++ /dev/null @@ -1,27 +0,0 @@ -package pro.gravit.launchserver.auth.core.interfaces.user; - -import java.time.LocalDateTime; - -public interface UserSupportBanInfo { - UserBanInfo getBanInfo(); - - interface UserBanInfo { - String getId(); - - default String getReason() { - return null; - } - - default String getModerator() { - return null; - } - - default LocalDateTime getStartDate() { - return null; - } - - default LocalDateTime getEndDate() { - return null; - } - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/mix/MixProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/mix/MixProvider.java new file mode 100644 index 00000000..993c787a --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/mix/MixProvider.java @@ -0,0 +1,31 @@ +package pro.gravit.launchserver.auth.mix; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.core.AuthCoreProvider; +import pro.gravit.utils.ProviderMap; + +public abstract class MixProvider implements AutoCloseable{ + public static final ProviderMap providers = new ProviderMap<>("MixProvider"); + private static final Logger logger = LogManager.getLogger(); + private static boolean registredProviders = false; + + public static void registerProviders() { + if (!registredProviders) { + providers.register("uploadAsset", UploadAssetMixProvider.class); + registredProviders = true; + } + } + + public abstract void init(LaunchServer server, AuthCoreProvider core); + + @SuppressWarnings("unchecked") + public T isSupport(Class clazz) { + if (clazz.isAssignableFrom(getClass())) return (T) this; + return null; + } + + @Override + public abstract void close(); +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/mix/UploadAssetMixProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/mix/UploadAssetMixProvider.java new file mode 100644 index 00000000..ef67994f --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/mix/UploadAssetMixProvider.java @@ -0,0 +1,34 @@ +package pro.gravit.launchserver.auth.mix; + +import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.core.AuthCoreProvider; +import pro.gravit.launchserver.auth.core.User; +import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportAssetUpload; + +import java.util.Map; + +public class UploadAssetMixProvider extends MixProvider implements AuthSupportAssetUpload { + public Map urls; + public AssetUploadInfoRequestEvent.SlimSupportConf slimSupportConf; + + @Override + public String getAssetUploadUrl(String name, User user) { + return urls.get(name); + } + + @Override + public AssetUploadInfoRequestEvent getAssetUploadInfo(User user) { + return new AssetUploadInfoRequestEvent(urls.keySet(), slimSupportConf); + } + + @Override + public void init(LaunchServer server, AuthCoreProvider core) { + + } + + @Override + public void close() { + + } +} 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 37b610f2..1899292a 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 @@ -20,6 +20,7 @@ import java.util.Base64; import java.util.Date; +import java.util.UUID; import static java.util.concurrent.TimeUnit.SECONDS; @@ -41,7 +42,7 @@ public boolean allowGetSecureLevelInfo(Client client) { @Override public void onHardwareReport(HardwareReportResponse response, Client client) { if (!enableHardwareFeature) { - response.sendResult(new HardwareReportRequestEvent(null)); + response.sendResult(new HardwareReportRequestEvent()); return; } if (!client.isAuth || client.trustLevel == null || client.trustLevel.publicKey == null) { @@ -63,7 +64,7 @@ public void onHardwareReport(HardwareReportResponse response, Client client) { throw new SecurityException("Your hardware banned"); } client.trustLevel.hardwareInfo = hardware.getHardwareInfo(); - response.sendResult(new HardwareReportRequestEvent(createHardwareToken(client.username, hardware))); + response.sendResult(new HardwareReportRequestEvent(createHardwareToken(client.username, hardware), SECONDS.toMillis(server.config.netty.security.hardwareTokenExpire))); } else { logger.error("AuthCoreProvider not supported hardware"); response.sendError("AuthCoreProvider not supported hardware"); @@ -78,22 +79,22 @@ public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) { if (authSupportHardware != null) { UserHardware hardware = authSupportHardware.getHardwareInfoByPublicKey(client.trustLevel.publicKey); if (hardware == null) //HWID not found? - return new VerifySecureLevelKeyRequestEvent(true, false, createPublicKeyToken(client.username, client.trustLevel.publicKey)); + return new VerifySecureLevelKeyRequestEvent(true, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), SECONDS.toMillis(server.config.netty.security.publicKeyTokenExpire)); if (hardware.isBanned()) { throw new SecurityException("Your hardware banned"); } client.trustLevel.hardwareInfo = hardware.getHardwareInfo(); authSupportHardware.connectUserAndHardware(client.sessionObject, hardware); - return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), createHardwareToken(client.username, hardware)); + return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), SECONDS.toMillis(server.config.netty.security.publicKeyTokenExpire)); } else { logger.warn("AuthCoreProvider not supported hardware. HardwareInfo not checked!"); } } - return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey)); + return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), SECONDS.toMillis(server.config.netty.security.publicKeyTokenExpire)); } @Override - public boolean onJoinServer(String serverID, String username, Client client) { + public boolean onJoinServer(String serverID, String username, UUID uuid, Client client) { return !enableHardwareFeature || (client.trustLevel != null && client.trustLevel.hardwareInfo != null); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/NoProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/NoProtectHandler.java index 2cacc3bf..d278d76b 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/NoProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/NoProtectHandler.java @@ -1,5 +1,6 @@ package pro.gravit.launchserver.auth.protect; +import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.auth.AuthResponse; public class NoProtectHandler extends ProtectHandler { @@ -9,4 +10,8 @@ public boolean allowGetAccessToken(AuthResponse.AuthContext context) { return true; } + @Override + public boolean allowJoinServer(Client client) { + return true; + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java index ab3edf69..cf660e52 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java @@ -1,6 +1,7 @@ package pro.gravit.launchserver.auth.protect; import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.utils.ProviderMap; @@ -19,6 +20,9 @@ public static void registerHandlers() { } public abstract boolean allowGetAccessToken(AuthResponse.AuthContext context); + public boolean allowJoinServer(Client client) { + return client.isAuth && client.type == AuthResponse.ConnectTypes.CLIENT; + } public void init(LaunchServer server) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/interfaces/JoinServerProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/interfaces/JoinServerProtectHandler.java index e33a9e11..1d152980 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/interfaces/JoinServerProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/interfaces/JoinServerProtectHandler.java @@ -2,8 +2,10 @@ import pro.gravit.launchserver.socket.Client; +import java.util.UUID; + public interface JoinServerProtectHandler { - default boolean onJoinServer(String serverID, String username, Client client) { + default boolean onJoinServer(String serverID, String username, UUID uuid, Client client) { return true; } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/texture/JsonTextureProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/texture/JsonTextureProvider.java index ca27671b..4f31c526 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/texture/JsonTextureProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/texture/JsonTextureProvider.java @@ -3,22 +3,23 @@ import com.google.gson.reflect.TypeToken; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import pro.gravit.launcher.HTTPRequest; -import pro.gravit.launcher.Launcher; import pro.gravit.launcher.profiles.Texture; +import pro.gravit.launchserver.HttpRequester; +import pro.gravit.utils.helper.SecurityHelper; import java.io.IOException; import java.lang.reflect.Type; -import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.UUID; public class JsonTextureProvider extends TextureProvider { - private static final Type MAP_TYPE = new TypeToken>() { + private static final Type MAP_TYPE = new TypeToken>() { }.getType(); private transient final Logger logger = LogManager.getLogger(); + private transient final HttpRequester requester = new HttpRequester(); public String url; + public String bearerToken; @Override public void close() { @@ -40,24 +41,28 @@ public Texture getSkinTexture(UUID uuid, String username, String client) { @Override public Map getAssets(UUID uuid, String username, String client) { try { - var result = HTTPRequest.jsonRequest(null, "GET", new URL(RequestTextureProvider.getTextureURL(url, uuid, username, client))); - - Map map = Launcher.gsonManager.gson.fromJson(result, MAP_TYPE); - if (map == null) { - return new HashMap<>(); - } - if (map.get("skin") != null) { // Legacy script - map.put("SKIN", map.get("skin")); - map.remove("skin"); - } - if (map.get("cloak") != null) { - map.put("CAPE", map.get("cloak")); - map.remove("cloak"); - } - return map; + Map map = requester.>send(requester.get(RequestTextureProvider.getTextureURL(url, uuid, username, client), bearerToken), MAP_TYPE).getOrThrow(); + return JsonTexture.convertMap(map); } catch (IOException e) { logger.error("JsonTextureProvider", e); return new HashMap<>(); } } + + public record JsonTexture(String url, String digest, Map metadata) { + public Texture toTexture() { + return new Texture(url, digest == null ? null : SecurityHelper.fromHex(digest), metadata); + } + + public static Map convertMap(Map map) { + if (map == null) { + return new HashMap<>(); + } + Map res = new HashMap<>(); + for(var e : map.entrySet()) { + res.put(e.getKey(), e.getValue().toTexture()); + } + return res; + } + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java index c3f8437b..dec8e0e2 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java @@ -18,7 +18,6 @@ public class BinaryPipeline { public final List tasks = new ArrayList<>(); - public final AtomicLong count = new AtomicLong(0); public final Path buildDir; public final String nameFormat; private transient final Logger logger = LogManager.getLogger(); @@ -72,11 +71,20 @@ public Optional getTaskByClass(Class taskCla return tasks.stream().filter(taskClass::isInstance).map(taskClass::cast).findFirst(); } + public Optional getTaskBefore(Predicate pred) { + LauncherBuildTask last = null; + for(var e : tasks) { + if(pred.test(e)) { + return Optional.ofNullable(last); + } + last = e; + } + return Optional.empty(); + } + public void build(Path target, boolean deleteTempFiles) throws IOException { logger.info("Building launcher binary file"); - count.set(0); // set jar number Path thisPath = null; - boolean isNeedDelete = false; long time_start = System.currentTimeMillis(); long time_this = time_start; for (LauncherBuildTask task : tasks) { @@ -86,19 +94,17 @@ public void build(Path target, boolean deleteTempFiles) throws IOException { long time_task_end = System.currentTimeMillis(); long time_task = time_task_end - time_this; time_this = time_task_end; - if (isNeedDelete && deleteTempFiles && oldPath != thisPath) Files.deleteIfExists(oldPath); - isNeedDelete = task.allowDelete(); logger.info("Task {} processed from {} millis", task.getName(), time_task); } long time_end = System.currentTimeMillis(); - if (isNeedDelete && deleteTempFiles) IOHelper.move(thisPath, target); + if (deleteTempFiles) IOHelper.move(thisPath, target); else IOHelper.copy(thisPath, target); IOHelper.deleteDir(buildDir, false); logger.info("Build successful from {} millis", time_end - time_start); } public String nextName(String taskName) { - return nameFormat.formatted(taskName, count.getAndIncrement()); + return nameFormat.formatted(taskName); } public Path nextPath(String taskName) { 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 ac538e84..6d00a5cc 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BuildContext.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BuildContext.java @@ -45,6 +45,7 @@ public class BuildContext { public final MainBuildTask task; public final HashSet fileList; public final HashSet clientModules; + public final HashSet legacyClientModules; public BuildContext(ZipOutputStream output, List readerClassPath, MainBuildTask task) { this.output = output; @@ -52,6 +53,7 @@ public BuildContext(ZipOutputStream output, List readerClassPath, MainB this.task = task; fileList = new HashSet<>(1024); clientModules = new HashSet<>(); + legacyClientModules = new HashSet<>(); } public void pushFile(String filename, InputStream inputStream) throws IOException { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXEL4JLauncherBinary.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXEL4JLauncherBinary.java index c9a0a3e2..26a2b457 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXEL4JLauncherBinary.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXEL4JLauncherBinary.java @@ -7,7 +7,7 @@ public final class EXEL4JLauncherBinary extends LauncherBinary { public EXEL4JLauncherBinary(LaunchServer server) { - super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s-%d.exe"); + super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s.exe"); } @Override diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXELauncherBinary.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXELauncherBinary.java index 2a33ba81..763d9912 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXELauncherBinary.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/EXELauncherBinary.java @@ -9,7 +9,7 @@ public class EXELauncherBinary extends LauncherBinary { public EXELauncherBinary(LaunchServer server) { - super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s-%d.exe"); + super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s.exe"); } @Override diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java index 72f60338..b7bf3e0f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java @@ -23,7 +23,7 @@ public final class JARLauncherBinary extends LauncherBinary { public final Map files; public JARLauncherBinary(LaunchServer server) throws IOException { - super(server, resolve(server, ".jar"), "Launcher-%s-%d.jar"); + super(server, resolve(server, ".jar"), "Launcher-%s.jar"); count = new AtomicLong(0); runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR); buildDir = server.dir.resolve("build"); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/SignerJar.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/SignerJar.java index 34f342db..2596d484 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/SignerJar.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/SignerJar.java @@ -69,7 +69,6 @@ public SignerJar(ZipOutputStream out, Supplier gen, Stri * * @param filename name of the file to add (use forward slash as a path separator) * @param contents contents of the file - * @throws IOException * @throws NullPointerException if any of the arguments is {@code null} */ public void addFileContents(String filename, byte[] contents) throws IOException { @@ -82,7 +81,6 @@ public void addFileContents(String filename, byte[] contents) throws IOException * * @param filename name of the file to add (use forward slash as a path separator) * @param contents contents of the file - * @throws IOException * @throws NullPointerException if any of the arguments is {@code null} */ public void addFileContents(String filename, InputStream contents) throws IOException { @@ -95,7 +93,6 @@ public void addFileContents(String filename, InputStream contents) throws IOExce * * @param entry name of the file to add (use forward slash as a path separator) * @param contents contents of the file - * @throws IOException * @throws NullPointerException if any of the arguments is {@code null} */ public void addFileContents(ZipEntry entry, byte[] contents) throws IOException { @@ -108,7 +105,6 @@ public void addFileContents(ZipEntry entry, byte[] contents) throws IOException * * @param entry name of the file to add (use forward slash as a path separator) * @param contents contents of the file - * @throws IOException * @throws NullPointerException if any of the arguments is {@code null} */ public void addFileContents(ZipEntry entry, InputStream contents) throws IOException { @@ -134,7 +130,6 @@ public void addManifestAttribute(String name, String value) { * Closes the JAR file by writing the manifest and signature data to it and finishing the ZIP entries. It closes the * underlying stream. * - * @throws IOException * @throws RuntimeException if the signing goes wrong */ @Override @@ -148,7 +143,6 @@ public void close() throws IOException { * Finishes the JAR file by writing the manifest and signature data to it and finishing the ZIP entries. It leaves the * underlying stream open. * - * @throws IOException * @throws RuntimeException if the signing goes wrong */ public void finish() throws IOException { @@ -205,7 +199,6 @@ private byte[] signSigFile(byte[] sigContents) throws Exception { * Writes the manifest to the JAR. It also calculates the digests that are required to be placed in the the signature * file. * - * @throws IOException */ private void writeManifest() throws IOException { zos.putNextEntry(IOHelper.newZipEntry(MANIFEST_FN)); @@ -268,7 +261,6 @@ private byte[] writeSigFile() throws IOException { /** * Signs the .SIG file and writes the signature (.RSA file) to the JAR. * - * @throws IOException * @throws RuntimeException if the signing failed */ private void writeSignature(byte[] sigFile) throws IOException { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java index a94ac0c9..fdb2c3ee 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java @@ -74,9 +74,4 @@ public Path process(Path inputFile) throws IOException { return out; } - @Override - public boolean allowDelete() { - return true; - } - } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AttachJarsTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AttachJarsTask.java index 4904283d..b5705fd9 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AttachJarsTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AttachJarsTask.java @@ -68,11 +68,6 @@ private boolean filter(String name) { return exclusions.stream().anyMatch(name::startsWith); } - @Override - public boolean allowDelete() { - return true; - } - public List getJars() { return jars; } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CertificateAutogenTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CertificateAutogenTask.java index 4ab793af..b78940a2 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CertificateAutogenTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CertificateAutogenTask.java @@ -81,9 +81,4 @@ public Path process(Path inputFile) throws IOException { } return inputFile; } - - @Override - public boolean allowDelete() { - return false; - } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CompressBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CompressBuildTask.java index a53ee660..beb9f3b4 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CompressBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CompressBuildTask.java @@ -43,9 +43,4 @@ public Path process(Path inputFile) throws IOException { } return output; } - - @Override - public boolean allowDelete() { - return true; - } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/LauncherBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/LauncherBuildTask.java index 5642b002..9317a4a8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/LauncherBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/LauncherBuildTask.java @@ -7,6 +7,4 @@ public interface LauncherBuildTask { String getName(); Path process(Path inputFile) throws IOException; - - boolean allowDelete(); } 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 478217ec..0d1f6e85 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 @@ -51,11 +51,12 @@ public String getName() { @Override public Path process(Path inputJar) throws IOException { - Path outputJar = server.launcherBinary.nextPath("main"); + Path outputJar = server.launcherBinary.nextPath(this); try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) { BuildContext context = new BuildContext(output, reader.getCp(), this); initProps(); preBuildHook.hook(context); + properties.put("launcher.legacymodules", context.legacyClientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList())); properties.put("launcher.modules", context.clientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList())); postInitProps(); reader.getCp().add(new JarFile(inputJar.toFile())); @@ -160,11 +161,6 @@ public byte[] transformClass(byte[] bytes, String classname, BuildContext contex return result; } - @Override - public boolean allowDelete() { - return true; - } - @FunctionalInterface public interface Transformer { byte[] transform(byte[] input, String classname, BuildContext context); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java index c5a63fbf..09473e54 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java @@ -53,11 +53,6 @@ public Path process(Path inputFile) throws IOException { return result; } - @Override - public boolean allowDelete() { - return false; - } - public void tryUnpack() throws IOException { logger.info("Unpacking launcher native guard list and runtime"); UnpackHelper.unpackZipNoCheck("runtime.zip", server.launcherBinary.runtimeDir); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java index 517adc48..3e349884 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java @@ -104,9 +104,4 @@ private void autoSign(Path inputFile, Path signedFile) throws IOException { } } } - - @Override - public boolean allowDelete() { - return true; - } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/exe/Launch4JTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/exe/Launch4JTask.java index f5bbf4f5..400d529c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/exe/Launch4JTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/exe/Launch4JTask.java @@ -59,11 +59,6 @@ public Path process(Path inputFile) throws IOException { return output; } - @Override - public boolean allowDelete() { - return true; - } - private Path setConfig() { Path path = server.launcherEXEBinary.nextPath(getName()); Config config = new Config(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/Command.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/Command.java index d2ddc498..b4f7f5a3 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/Command.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/Command.java @@ -3,11 +3,10 @@ import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarStyle; -import pro.gravit.launcher.AsyncDownloader; import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.modern.Downloader; import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launchserver.LaunchServer; -import pro.gravit.utils.Downloader; import pro.gravit.utils.command.CommandException; import java.io.IOException; @@ -45,9 +44,9 @@ protected boolean showApplyDialog(String text) throws IOException { return response.equals("y"); } - protected Downloader downloadWithProgressBar(String taskName, List list, String baseUrl, Path targetDir) throws Exception { + protected Downloader downloadWithProgressBar(String taskName, List list, String baseUrl, Path targetDir) throws Exception { long total = 0; - for (AsyncDownloader.SizedFile file : list) { + for (Downloader.SizedFile file : list) { total += file.size; } long totalFiles = list.size(); 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 206bdef0..249ea173 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 @@ -3,12 +3,11 @@ import com.google.gson.JsonObject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import pro.gravit.launcher.AsyncDownloader; import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.modern.Downloader; import pro.gravit.launchserver.HttpRequester; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.command.Command; -import pro.gravit.utils.Downloader; import pro.gravit.utils.helper.IOHelper; import java.io.Writer; @@ -85,7 +84,7 @@ public void invoke(String... args) throws Exception { logger.info("Copy {} into {}", indexPath, targetPath); Files.copy(indexPath, targetPath, StandardCopyOption.REPLACE_EXISTING); } - List toDownload = new ArrayList<>(128); + List toDownload = new ArrayList<>(128); for (var e : objects.entrySet()) { var value = e.getValue().getAsJsonObject(); var hash = value.get("hash").getAsString(); @@ -101,7 +100,7 @@ public void invoke(String... args) throws Exception { continue; } } - toDownload.add(new AsyncDownloader.SizedFile(hash, path, size)); + toDownload.add(new Downloader.SizedFile(hash, path, size)); } logger.info("Download {} files", toDownload.size()); Downloader downloader = downloadWithProgressBar(dirName, toDownload, RESOURCES_DOWNLOAD_URL, assetDir); 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 43f147d0..5ac22a87 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 @@ -14,7 +14,6 @@ import java.io.BufferedWriter; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; import java.util.UUID; 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 476024f9..78f6973d 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,7 +10,6 @@ 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(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SecurityCheckCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SecurityCheckCommand.java index bebfbecc..95d6cf99 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SecurityCheckCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SecurityCheckCommand.java @@ -27,7 +27,6 @@ import java.util.List; import java.util.Set; import java.util.StringTokenizer; -import java.util.stream.Collectors; public class SecurityCheckCommand extends Command { private static final Logger logger = LogManager.getLogger(); @@ -113,7 +112,7 @@ public void invoke(String... args) { List certChain = Arrays.stream(certChainPlain).map(e -> (X509Certificate) e).toList(); X509Certificate cert = certChain.get(0); cert.checkValidity(); - if (certChain.size() <= 1) { + if (certChain.size() == 1) { printCheckResult("sign", "certificate chain contains <2 element(recommend 2 and more)", false); bad = true; } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java b/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java index 78f63344..520a80f4 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java @@ -15,9 +15,7 @@ import proguard.ConfigurationParser; import proguard.ProGuard; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -26,6 +24,9 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; public class ProGuardComponent extends Component implements AutoCloseable, Reconfigurable { private static final Logger logger = LogManager.getLogger(); @@ -36,6 +37,7 @@ public class ProGuardComponent extends Component implements AutoCloseable, Recon public transient ProguardConf proguardConf; private transient LaunchServer launchServer; private transient ProGuardBuildTask buildTask; + private transient ProGuardMultiReleaseFixer fixerTask; public static boolean checkFXJMods(Path path) { if (!IOHelper.exists(path.resolve("javafx.base.jmod"))) @@ -75,7 +77,9 @@ public void init(LaunchServer launchServer) { this.launchServer = launchServer; proguardConf = new ProguardConf(launchServer, this); this.buildTask = new ProGuardBuildTask(launchServer, proguardConf, this); + this.fixerTask = new ProGuardMultiReleaseFixer(launchServer, this, "ProGuard.".concat(componentName)); launchServer.launcherBinary.addAfter((v) -> v.getName().startsWith(modeAfter), buildTask); + launchServer.launcherBinary.addAfter((v) -> v.getName().equals("ProGuard.".concat(componentName)), fixerTask); } @Override @@ -111,6 +115,62 @@ public void invoke(String... args) throws Exception { return null; } + public static class ProGuardMultiReleaseFixer implements LauncherBuildTask { + private final LaunchServer server; + private final ProGuardComponent component; + private final String proguardTaskName; + + public ProGuardMultiReleaseFixer(LaunchServer server, ProGuardComponent component, String proguardTaskName) { + this.server = server; + this.component = component; + this.proguardTaskName = proguardTaskName; + } + + @Override + public String getName() { + return "ProGuardMultiReleaseFixer.".concat(component.componentName); + } + + @Override + public Path process(Path inputFile) throws IOException { + if (!component.enabled) { + return inputFile; + } + LauncherBuildTask task = server.launcherBinary.getTaskBefore((x) -> proguardTaskName.equals(x.getName())).get(); + Path lastPath = server.launcherBinary.nextPath(task); + if(Files.notExists(lastPath)) { + logger.error("{} not exist. Multi-Release JAR fix not applied!", lastPath); + return inputFile; + } + Path outputPath = server.launcherBinary.nextPath(this); + try(ZipOutputStream output = new ZipOutputStream(new FileOutputStream(outputPath.toFile()))) { + try(ZipInputStream input = new ZipInputStream(new FileInputStream(inputFile.toFile()))) { + ZipEntry entry = input.getNextEntry(); + while(entry != null) { + ZipEntry newEntry = new ZipEntry(entry.getName()); + output.putNextEntry(newEntry); + input.transferTo(output); + entry = input.getNextEntry(); + } + } + try(ZipInputStream input = new ZipInputStream(new FileInputStream(lastPath.toFile()))) { + ZipEntry entry = input.getNextEntry(); + while(entry != null) { + if(!entry.getName().startsWith("META-INF/versions")) { + entry = input.getNextEntry(); + continue; + } + ZipEntry newEntry = new ZipEntry(entry.getName()); + output.putNextEntry(newEntry); + input.transferTo(output); + entry = input.getNextEntry(); + } + } + } + return outputPath; + } + } + public static class ProGuardBuildTask implements LauncherBuildTask { private final LaunchServer server; private final ProGuardComponent component; @@ -157,11 +217,6 @@ public Path process(Path inputFile) throws IOException { IOHelper.copy(inputFile, outputJar); return outputJar; } - - @Override - public boolean allowDelete() { - return true; - } } public static class ProguardConf { 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 49966b8e..502889f8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -27,7 +27,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; public final class LaunchServerConfig { - private final static List oldMirrorList = List.of("https://mirror.gravit.pro/5.2.x/", "https://mirror.gravit.pro/5.3.x/", "https://mirror.gravitlauncher.com/5.2.x/", "https://mirror.gravitlauncher.com/5.3.x/"); + private final static List oldMirrorList = List.of("https://mirror.gravit.pro/5.2.x/", "https://mirror.gravit.pro/5.3.x/", "https://mirror.gravitlauncher.com/5.2.x/", "https://mirror.gravitlauncher.com/5.3.x/", "https://mirror.gravitlauncher.com/5.4.x/"); private transient final Logger logger = LogManager.getLogger(); public String projectName; public String[] mirrors; @@ -49,7 +49,7 @@ public final class LaunchServerConfig { public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { LaunchServerConfig newConfig = new LaunchServerConfig(); - newConfig.mirrors = new String[]{"https://mirror.gravitlauncher.com/5.4.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"}; + newConfig.mirrors = new String[]{"https://mirror.gravitlauncher.com/5.5.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"}; newConfig.launch4j = new LaunchServerConfig.ExeConf(); newConfig.launch4j.enabled = false; newConfig.launch4j.copyright = "© GravitLauncher Team"; @@ -61,7 +61,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { newConfig.launch4j.txtProductVersion = "%s, build %d"; newConfig.launch4j.productName = "GravitLauncher"; newConfig.launch4j.productVer = newConfig.launch4j.fileVer; - newConfig.launch4j.maxVersion = "1.8.999"; + newConfig.launch4j.maxVersion = "99.0.0"; newConfig.env = LauncherConfig.LauncherEnvironment.STD; newConfig.startScript = JVMHelper.OS_TYPE.equals(JVMHelper.OS.MUSTDIE) ? "." + File.separator + "start.bat" : "." + File.separator + "start.sh"; newConfig.auth = new HashMap<>(); @@ -171,8 +171,8 @@ public void verify() { if (!updateMirror) { for (int i = 0; i < mirrors.length; ++i) { if (mirrors[i] != null && oldMirrorList.contains(mirrors[i])) { - logger.warn("Replace mirror '{}' to 'https://mirror.gravitlauncher.com/5.4.x/'. If you really need to use original url, use '-Dlaunchserver.config.disableUpdateMirror=true'", mirrors[i]); - mirrors[i] = "https://mirror.gravitlauncher.com/5.4.x/"; + logger.warn("Replace mirror '{}' to 'https://mirror.gravitlauncher.com/5.5.x/'. If you really need to use original url, use '-Dlaunchserver.config.disableUpdateMirror=true'", mirrors[i]); + mirrors[i] = "https://mirror.gravitlauncher.com/5.5.x/"; } } } @@ -234,7 +234,7 @@ public static class ExeConf { public boolean enabled; public boolean setMaxVersion; public String maxVersion; - public String minVersion = "1.8.0"; + public String minVersion = "17.0.0"; public String supportURL = null; public String downloadUrl = Launch4JTask.DOWNLOAD_URL; public String productName; @@ -259,6 +259,7 @@ public static class JarSignerConf { public String metaInfKeyName = "SIGNUMO.RSA"; public String metaInfSfName = "SIGNUMO.SF"; public String signAlgo = "SHA256WITHRSA"; + public boolean checkCertificateExpired = true; } public static class NettyUpdatesBind { 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 2b4453f5..6f2354ad 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java @@ -49,9 +49,7 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti } else if (version.compareTo(ClientProfileVersions.MINECRAFT_1_18) <= 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"); + } else { } // ----------- Optional forge = findOption(options, MakeProfileOptionForge.class); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java index d2f16da1..3466fe29 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java @@ -21,8 +21,10 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.List; public class SignHelper { @@ -46,6 +48,24 @@ public static KeyStore getStore(Path file, String storepass, String algo) throws } } + + + public static Instant getCertificateExpired(KeyStore keyStore, String keyAlias) throws KeyStoreException { + List certChain = new ArrayList<>(Arrays.asList(keyStore.getCertificateChain(keyAlias))); + Date date = null; + for(var e : certChain) { + if(e instanceof X509Certificate x509Certificate) { + if(x509Certificate.getNotAfter() == null) { + continue; + } + if(date == null || date.after(x509Certificate.getNotAfter())) { + date = x509Certificate.getNotAfter(); + } + } + } + return date == null ? null : date.toInstant(); + } + /** * Creates the beast that can actually sign the data (for JKS, for other make it). */ diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/launchermodules/LauncherModuleLoader.java b/LaunchServer/src/main/java/pro/gravit/launchserver/launchermodules/LauncherModuleLoader.java index 52580dc4..de2555f0 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/launchermodules/LauncherModuleLoader.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/launchermodules/LauncherModuleLoader.java @@ -4,7 +4,6 @@ import org.apache.logging.log4j.Logger; import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherTrustManager; -import pro.gravit.launcher.modules.LauncherModule; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.asm.InjectClassAcceptor; import pro.gravit.launchserver.binary.tasks.MainBuildTask; @@ -50,7 +49,11 @@ public void init() { mainTask.preBuildHook.registerHook((buildContext) -> { for (ModuleEntity e : launcherModules) { if (e.propertyMap != null) buildContext.task.properties.putAll(e.propertyMap); - buildContext.clientModules.add(e.moduleMainClass); + if(e.modernModule) { + buildContext.clientModules.add(e.moduleMainClass); + } else { + buildContext.legacyClientModules.add(e.moduleMainClass); + } buildContext.readerClassPath.add(new JarFile(e.path.toFile())); } }); @@ -94,6 +97,7 @@ public static class ModuleEntity { public String moduleMainClass; public String moduleConfigClass; public String moduleConfigName; + public boolean modernModule; public Map propertyMap; } @@ -104,7 +108,6 @@ private ModulesVisitor() { } @Override - @SuppressWarnings("unchecked") public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.toFile().getName().endsWith(".jar")) try (JarFile f = new JarFile(file.toFile())) { @@ -120,6 +123,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO entity.path = file; entity.moduleMainClass = mainClass; entity.moduleConfigClass = attributes.getValue("Module-Config-Class"); + String requiredModernJava = attributes.getValue("Required-Modern-Java"); + entity.modernModule = Boolean.parseBoolean(requiredModernJava); if (entity.moduleConfigClass != null) { entity.moduleConfigName = attributes.getValue("Module-Config-Name"); if (entity.moduleConfigName == null) { 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 6fec80e5..8c24e6d6 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -115,7 +115,7 @@ public AuthReport auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswor context.client.sessionObject = session; internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), true); if (context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) { - return AuthReport.ofMinecraftAccessToken(user.getAccessToken(), session); + return AuthReport.ofMinecraftAccessToken(session.getMinecraftAccessToken(), session); } return AuthReport.ofMinecraftAccessToken(null, session); } @@ -166,9 +166,9 @@ public CheckServerReport checkServer(Client client, String username, String serv else return CheckServerReport.ofUser(user, getPlayerProfile(client.auth, user)); } - public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { + public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException { if (client.auth == null) return false; - return client.auth.core.joinServer(client, username, accessToken, serverID); + return client.auth.core.joinServer(client, username, uuid, accessToken, serverID); } public PlayerProfile getPlayerProfile(Client client) { 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 106abb2d..8b5e3c14 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java @@ -13,6 +13,7 @@ import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest; import pro.gravit.launchserver.auth.core.AuthCoreProvider; +import pro.gravit.launchserver.auth.mix.MixProvider; import pro.gravit.launchserver.auth.password.PasswordVerifier; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.texture.TextureProvider; @@ -48,6 +49,7 @@ public void registerAdapters(GsonBuilder builder) { builder.registerTypeAdapter(GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails.class, new UniversalJsonAdapter<>(GetAvailabilityAuthRequest.providers)); builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers)); builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers)); + builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.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 98ed7deb..07932e2d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/MirrorManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/MirrorManager.java @@ -3,20 +3,27 @@ import com.google.gson.JsonElement; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import pro.gravit.launcher.HTTPRequest; -import pro.gravit.utils.HttpDownloader; +import pro.gravit.launcher.Launcher; import pro.gravit.utils.helper.IOHelper; import java.io.IOException; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public class MirrorManager { protected final ArrayList list = new ArrayList<>(); private transient final Logger logger = LogManager.getLogger(); + private transient final HttpClient client = HttpClient.newBuilder().build(); private Mirror defaultMirror; public void addMirror(String mirror) { @@ -58,7 +65,7 @@ public boolean downloadZip(Mirror mirror, Path path, String mask, Object... args URL url = mirror.getURL(mask, args); logger.debug("Try download {}", url.toString()); try { - HttpDownloader.downloadZip(url, path); + downloadZip(url, path); } catch (IOException e) { logger.error("Download {} failed({}: {})", url.toString(), e.getClass().getName(), e.getMessage()); return false; @@ -82,8 +89,12 @@ public JsonElement jsonRequest(Mirror mirror, JsonElement request, String method if (!mirror.enabled) return null; URL url = mirror.getURL(mask, args); try { - return HTTPRequest.jsonRequest(request, method, url); - } catch (IOException e) { + var response = client.send(HttpRequest.newBuilder() + .method(method, request == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request))) + .uri(url.toURI()) + .build(), HttpResponse.BodyHandlers.ofString()); + return Launcher.gsonManager.gson.fromJson(response.body(), JsonElement.class); + } catch (IOException | URISyntaxException | InterruptedException e) { logger.error("JsonRequest {} failed({}: {})", url.toString(), e.getClass().getName(), e.getMessage()); return null; } @@ -101,6 +112,22 @@ public JsonElement jsonRequest(JsonElement request, String method, String mask, throw new IOException("Error jsonRequest. All mirrors return error"); } + private void downloadZip(URL url, Path dir) throws IOException { + try (ZipInputStream input = IOHelper.newZipInput(url)) { + Files.createDirectory(dir); + for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) { + if (entry.isDirectory()) { + Files.createDirectory(dir.resolve(IOHelper.toPath(entry.getName()))); + continue; + } + // Unpack entry + String name = entry.getName(); + logger.debug("Downloading file: '{}'", name); + IOHelper.transfer(input, dir.resolve(IOHelper.toPath(name))); + } + } + } + public static class Mirror { final String baseUrl; boolean enabled; 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 02c4cfb3..03de2060 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java @@ -18,6 +18,8 @@ import pro.gravit.launchserver.socket.response.SimpleResponse; import pro.gravit.launchserver.socket.response.WebSocketServerResponse; import pro.gravit.launchserver.socket.response.auth.*; +import pro.gravit.launchserver.socket.response.cabinet.AssetUploadInfoResponse; +import pro.gravit.launchserver.socket.response.cabinet.GetAssetUploadInfoResponse; import pro.gravit.launchserver.socket.response.management.FeaturesResponse; import pro.gravit.launchserver.socket.response.management.GetPublicKeyResponse; import pro.gravit.launchserver.socket.response.profile.BatchProfileByUsername; @@ -65,7 +67,6 @@ public static void registerResponses() { providers.register("updateList", UpdateListResponse.class); providers.register("setProfile", SetProfileResponse.class); providers.register("update", UpdateResponse.class); - providers.register("restoreSession", RestoreSessionResponse.class); providers.register("batchProfileByUsername", BatchProfileByUsername.class); providers.register("profileByUsername", ProfileByUsername.class); providers.register("profileByUUID", ProfileByUUIDResponse.class); @@ -82,6 +83,8 @@ public static void registerResponses() { providers.register("additionalData", AdditionalDataResponse.class); providers.register("clientProfileKey", FetchClientProfileKeyResponse.class); providers.register("getPublicKey", GetPublicKeyResponse.class); + providers.register("getAssetUploadUrl", GetAssetUploadInfoResponse.class); + providers.register("assetUploadInfo", AssetUploadInfoResponse.class); } public static String getIPFromContext(ChannelHandlerContext ctx) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java index 424f0e3f..fcc16ae8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java @@ -20,14 +20,8 @@ public String getType() { public void execute(ChannelHandlerContext ctx, Client client) { List list = new ArrayList<>(); for (AuthProviderPair pair : server.config.auth.values()) { - var rca = pair.isSupport(AuthSupportRemoteClientAccess.class); - if (rca != null) { - list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName, - pair.visible, pair.core.getDetails(client), rca.getClientApiUrl(), rca.getClientApiFeatures())); - } else { - list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName, - pair.visible, pair.core.getDetails(client))); - } + list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.core.getDetails(client), pair.name, pair.displayName, + pair.visible, pair.getFeatures())); } sendResult(new GetAvailabilityAuthRequestEvent(list)); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java index 1a9c3851..72a480a2 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java @@ -10,11 +10,14 @@ import pro.gravit.launchserver.socket.response.SimpleResponse; import pro.gravit.utils.HookException; +import java.util.UUID; + public class JoinServerResponse extends SimpleResponse { private transient final Logger logger = LogManager.getLogger(); public String serverID; public String accessToken; public String username; + public UUID uuid; @Override public String getType() { @@ -23,11 +26,11 @@ public String getType() { @Override public void execute(ChannelHandlerContext ctx, Client client) { - if (!client.isAuth || client.type != AuthResponse.ConnectTypes.CLIENT) { + if (!server.config.protectHandler.allowJoinServer(client)) { sendError("Permissions denied"); return; } - if (username == null || accessToken == null || serverID == null) { + if ((username == null && uuid == null) || accessToken == null || serverID == null) { sendError("Invalid request"); return; } @@ -35,13 +38,13 @@ public void execute(ChannelHandlerContext ctx, Client client) { try { server.authHookManager.joinServerHook.hook(this, client); if (server.config.protectHandler instanceof JoinServerProtectHandler joinServerProtectHandler) { - success = joinServerProtectHandler.onJoinServer(serverID, username, client); + success = joinServerProtectHandler.onJoinServer(serverID, username, uuid, client); if (!success) { sendResult(new JoinServerRequestEvent(false)); return; } } - success = server.authManager.joinServer(client, username, accessToken, serverID); + success = server.authManager.joinServer(client, username, uuid, accessToken, serverID); if (success) { logger.debug("joinServer: {} accessToken: {} serverID: {}", username, accessToken, serverID); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java deleted file mode 100644 index e28955df..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java +++ /dev/null @@ -1,24 +0,0 @@ -package pro.gravit.launchserver.socket.response.auth; - -import io.netty.channel.ChannelHandlerContext; -import pro.gravit.launcher.LauncherNetworkAPI; -import pro.gravit.launchserver.socket.Client; -import pro.gravit.launchserver.socket.response.SimpleResponse; - -import java.util.UUID; - -public class RestoreSessionResponse extends SimpleResponse { - @LauncherNetworkAPI - public UUID session; - public boolean needUserInfo; - - @Override - public String getType() { - return "restoreSession"; - } - - @Override - public void execute(ChannelHandlerContext ctx, Client client) { - sendError("Legacy session system removed"); - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/cabinet/AssetUploadInfoResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/cabinet/AssetUploadInfoResponse.java new file mode 100644 index 00000000..690c9c6e --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/cabinet/AssetUploadInfoResponse.java @@ -0,0 +1,27 @@ +package pro.gravit.launchserver.socket.response.cabinet; + +import io.netty.channel.ChannelHandlerContext; +import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportAssetUpload; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.SimpleResponse; + +public class AssetUploadInfoResponse extends SimpleResponse { + @Override + public String getType() { + return "assetUploadInfo"; + } + + @Override + public void execute(ChannelHandlerContext ctx, Client client) throws Exception { + if(!client.isAuth || client.auth == null || client.getUser() == null) { + sendError("Access denied"); + return; + } + var support = client.auth.isSupport(AuthSupportAssetUpload.class); + if(support == null) { + sendError("Not supported"); + return; + } + sendResult(support.getAssetUploadInfo(client.getUser())); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/cabinet/GetAssetUploadInfoResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/cabinet/GetAssetUploadInfoResponse.java new file mode 100644 index 00000000..60260f11 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/cabinet/GetAssetUploadInfoResponse.java @@ -0,0 +1,29 @@ +package pro.gravit.launchserver.socket.response.cabinet; + +import io.netty.channel.ChannelHandlerContext; +import pro.gravit.launcher.events.request.GetAssetUploadUrlRequestEvent; +import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportAssetUpload; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.SimpleResponse; + +public class GetAssetUploadInfoResponse extends SimpleResponse { + public String name; + @Override + public String getType() { + return "getAssetUploadUrl"; + } + + @Override + public void execute(ChannelHandlerContext ctx, Client client) throws Exception { + if(!client.isAuth || client.auth == null || client.getUser() == null) { + sendError("Access denied"); + return; + } + var support = client.auth.isSupport(AuthSupportAssetUpload.class); + if(support == null) { + sendError("Not supported"); + return; + } + sendResult(new GetAssetUploadUrlRequestEvent(support.getAssetUploadUrl(name, client.getUser()), support.getAssetUploadToken(name, client.getUser()))); + } +} 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 31274399..8849c61a 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 @@ -50,9 +50,9 @@ public void execute(ChannelHandlerContext ctx, Client client) { service.sendObjectAndClose(ctx, new LauncherRequestEvent(true, server.config.netty.launcherURL)); if (Arrays.equals(bytes, hash) && checkSecure(secureHash, secureSalt)) { client.checkSign = true; - sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken())); + sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); } else { - sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken())); + sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); } } else if (launcher_type == 2) //EXE { @@ -60,9 +60,9 @@ public void execute(ChannelHandlerContext ctx, Client client) { if (hash == null) sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL)); if (Arrays.equals(bytes, hash) && checkSecure(secureHash, secureSalt)) { client.checkSign = true; - sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken())); + sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); } else { - sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken())); + sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); } } else sendError("Request launcher type error"); } diff --git a/LaunchServer/src/main/resources/log4j2.xml b/LaunchServer/src/main/resources/log4j2.xml index 5f4deee6..818dd51f 100644 --- a/LaunchServer/src/main/resources/log4j2.xml +++ b/LaunchServer/src/main/resources/log4j2.xml @@ -1,5 +1,5 @@ - + basicRuntimeProvider; - private LauncherEngine(boolean clientInstance) { - + private LauncherEngine(boolean clientInstance, Class basicRuntimeProvider) { this.clientInstance = clientInstance; + this.basicRuntimeProvider = basicRuntimeProvider; } //JVMHelper.getCertificates @@ -101,19 +94,32 @@ public static void exitLauncher(int code) { forceExit(code); } + public static boolean contains(String[] array, String value) { + for(String s : array) { + if(s.equals(value)) { + return true; + } + } + return false; + } + public static void main(String... args) throws Throwable { - JVMHelper.checkStackTrace(LauncherEngine.class); + JVMHelper.checkStackTrace(LauncherEngineWrapper.class); JVMHelper.verifySystemProperties(Launcher.class, true); EnvHelper.checkDangerousParams(); //if(!LauncherAgent.isStarted()) throw new SecurityException("JavaAgent not set"); verifyNoAgent(); + if(contains(args, "--log-output") && Launcher.getConfig().environment != LauncherConfig.LauncherEnvironment.PROD) { + LogHelper.addOutput(Paths.get("Launcher.log")); + } LogHelper.printVersion("Launcher"); LogHelper.printLicense("Launcher"); + LauncherEngine.checkClass(LauncherEngineWrapper.class); LauncherEngine.checkClass(LauncherEngine.class); LauncherEngine.checkClass(LauncherAgent.class); LauncherEngine.checkClass(ClientLauncherEntryPoint.class); - LauncherEngine.modulesManager = new ClientModuleManager(); - LauncherEngine.modulesManager.loadModule(new ClientLauncherCoreModule()); + LauncherEngine.modulesManager = new RuntimeModuleManager(); + LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule()); LauncherConfig.initModules(LauncherEngine.modulesManager); LauncherEngine.modulesManager.initModules(null); // Start Launcher @@ -123,7 +129,7 @@ public static void main(String... args) throws Throwable { Launcher.getConfig(); // init config long startTime = System.currentTimeMillis(); try { - new LauncherEngine(false).start(args); + newInstance(false).start(args); } catch (Exception e) { LogHelper.error(e); return; @@ -133,12 +139,12 @@ public static void main(String... args) throws Throwable { LauncherEngine.exitLauncher(0); } - public static void initGson(ClientModuleManager modulesManager) { + public static void initGson(RuntimeModuleManager modulesManager) { AuthRequest.registerProviders(); GetAvailabilityAuthRequest.registerProviders(); OptionalAction.registerProviders(); OptionalTrigger.registerProviders(); - Launcher.gsonManager = new ClientGsonManager(modulesManager); + Launcher.gsonManager = new RuntimeGsonManager(modulesManager); Launcher.gsonManager.initGson(); } @@ -149,39 +155,18 @@ public static void verifyNoAgent() { public static RequestService initOffline() { OfflineRequestService service = new OfflineRequestService(); - applyBasicOfflineProcessors(service); + ClientLauncherMethods.applyBasicOfflineProcessors(service); OfflineModeEvent event = new OfflineModeEvent(service); modulesManager.invokeEvent(event); return event.service; } - public static void applyBasicOfflineProcessors(OfflineRequestService service) { - service.registerRequestProcessor(LauncherRequest.class, (r) -> new LauncherRequestEvent(false, (String) null)); - service.registerRequestProcessor(CheckServerRequest.class, (r) -> { - throw new RequestException("CheckServer disabled in offline mode"); - }); - service.registerRequestProcessor(GetAvailabilityAuthRequest.class, (r) -> { - List details = new ArrayList<>(); - details.add(new AuthLoginOnlyDetails()); - GetAvailabilityAuthRequestEvent.AuthAvailability authAvailability = new GetAvailabilityAuthRequestEvent.AuthAvailability("offline", "Offline Mode", true, details); - List list = new ArrayList<>(1); - list.add(authAvailability); - return new GetAvailabilityAuthRequestEvent(list); - }); - service.registerRequestProcessor(JoinServerRequest.class, (r) -> new JoinServerRequestEvent(false)); - service.registerRequestProcessor(ExitRequest.class, (r) -> new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT)); - service.registerRequestProcessor(SetProfileRequest.class, (r) -> new SetProfileRequestEvent(null)); - service.registerRequestProcessor(FeaturesRequest.class, (r) -> new FeaturesRequestEvent()); - service.registerRequestProcessor(GetSecureLevelInfoRequest.class, (r) -> new GetSecureLevelInfoRequestEvent(null, false)); - service.registerRequestProcessor(SecurityReportRequest.class, (r) -> new SecurityReportRequestEvent(SecurityReportRequestEvent.ReportAction.NONE)); - } - - public static LauncherEngine clientInstance() { - return new LauncherEngine(true); - } - public static LauncherEngine newInstance(boolean clientInstance) { - return new LauncherEngine(clientInstance); + return new LauncherEngine(clientInstance, NoRuntimeProvider.class); + } + + public static LauncherEngine newInstance(boolean clientInstance, Class basicRuntimeProvider) { + return new LauncherEngine(clientInstance, basicRuntimeProvider); } public ECPublicKey getClientPublicKey() { @@ -219,7 +204,7 @@ public void start(String... args) throws Throwable { ClientPreGuiPhase event = new ClientPreGuiPhase(null); LauncherEngine.modulesManager.invokeEvent(event); runtimeProvider = event.runtimeProvider; - if (runtimeProvider == null) runtimeProvider = new NoRuntimeProvider(); + if (runtimeProvider == null) runtimeProvider = basicRuntimeProvider.getConstructor().newInstance(); runtimeProvider.init(clientInstance); //runtimeProvider.preLoad(); if (!Request.isAvailable()) { @@ -248,8 +233,9 @@ public void start(String... args) throws Throwable { } }; } - service.registerEventHandler(new BasicLauncherEventHandler()); } + Request.startAutoRefresh(); + Request.getRequestService().registerEventHandler(new BasicLauncherEventHandler()); Objects.requireNonNull(args, "args"); if (started.getAndSet(true)) throw new IllegalStateException("Launcher has been already started"); diff --git a/Launcher/src/main/java/pro/gravit/launcher/LauncherEngineWrapper.java b/Launcher/src/main/java/pro/gravit/launcher/LauncherEngineWrapper.java new file mode 100644 index 00000000..25906d97 --- /dev/null +++ b/Launcher/src/main/java/pro/gravit/launcher/LauncherEngineWrapper.java @@ -0,0 +1,8 @@ +package pro.gravit.launcher; + +@LauncherNetworkAPI +public class LauncherEngineWrapper { + public static void main(String[] args) throws Throwable { + LauncherEngine.main(args); + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/NewLauncherSettings.java b/Launcher/src/main/java/pro/gravit/launcher/NewLauncherSettings.java index 02168315..e7019d0a 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/NewLauncherSettings.java +++ b/Launcher/src/main/java/pro/gravit/launcher/NewLauncherSettings.java @@ -10,33 +10,8 @@ import java.util.Map; public class NewLauncherSettings { - @LauncherNetworkAPI - public final transient List lastHDirs = new ArrayList<>(16); @LauncherNetworkAPI public Map userSettings = new HashMap<>(); @LauncherNetworkAPI - public List features = new ArrayList<>(); - @LauncherNetworkAPI public String consoleUnlockKey; - - public void putHDir(String name, Path path, HashedDir dir) { - String fullPath = path.toAbsolutePath().toString(); - lastHDirs.removeIf((e) -> e.fullPath.equals(fullPath) && e.name.equals(name)); - HashedStoreEntry e = new HashedStoreEntry(dir, name, fullPath); - e.needSave = true; - lastHDirs.add(e); - } - - public static class HashedStoreEntry { - public final HashedDir hdir; - public final String name; - public final String fullPath; - public transient boolean needSave = false; - - public HashedStoreEntry(HashedDir hdir, String name, String fullPath) { - this.hdir = hdir; - this.name = name; - this.fullPath = fullPath; - } - } } 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 c064c471..a224e176 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherProcess.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherProcess.java @@ -7,18 +7,14 @@ import pro.gravit.launcher.client.events.client.ClientProcessBuilderLaunchedEvent; import pro.gravit.launcher.client.events.client.ClientProcessBuilderParamsWrittedEvent; import pro.gravit.launcher.client.events.client.ClientProcessBuilderPreLaunchEvent; -import pro.gravit.launcher.events.request.AuthRequestEvent; import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.profiles.ClientProfile; -import pro.gravit.launcher.profiles.ClientProfileVersions; import pro.gravit.launcher.profiles.PlayerProfile; import pro.gravit.launcher.profiles.optional.OptionalView; import pro.gravit.launcher.profiles.optional.actions.OptionalAction; -import pro.gravit.launcher.profiles.optional.actions.OptionalActionClientArgs; import pro.gravit.launcher.profiles.optional.actions.OptionalActionJvmArgs; import pro.gravit.launcher.request.Request; import pro.gravit.launcher.serialize.HOutput; -import pro.gravit.utils.Version; import pro.gravit.utils.helper.*; import java.io.File; @@ -238,120 +234,4 @@ public Process getProcess() { return process; } - public static class ClientParams { - public String assetDir; - - public String clientDir; - - public String resourcePackDir; - - public String nativesDir; - - // Client params - - public PlayerProfile playerProfile; - - public ClientProfile profile; - - public String accessToken; - - //==Minecraft params== - - public boolean autoEnter; - - public boolean fullScreen; - - public int ram; - - public int width; - - public int height; - - public Set actions = new HashSet<>(); - - //======== - - public UUID session; - - public AuthRequestEvent.OAuthRequestEvent oauth; - - public String authId; - - public long oauthExpiredTime; - - public Map extendedTokens; - - public boolean offlineMode; - - public transient HashedDir assetHDir; - - public transient HashedDir clientHDir; - - public transient HashedDir javaHDir; - - public void addClientArgs(Collection args) { - if (profile.getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_6_4) >= 0) - addModernClientArgs(args); - else - addClientLegacyArgs(args); - } - - public void addClientLegacyArgs(Collection args) { - args.add(playerProfile.username); - args.add(accessToken); - - // Add args for tweaker - Collections.addAll(args, "--version", profile.getVersion().toString()); - Collections.addAll(args, "--gameDir", clientDir); - Collections.addAll(args, "--assetsDir", assetDir); - } - - private void addModernClientArgs(Collection args) { - - // Add version-dependent args - ClientProfile.Version version = profile.getVersion(); - Collections.addAll(args, "--username", playerProfile.username); - if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_2) >= 0) { - Collections.addAll(args, "--uuid", Launcher.toHash(playerProfile.uuid)); - Collections.addAll(args, "--accessToken", accessToken); - - // Add 1.7.10+ args (user properties, asset index) - if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) >= 0) { - // Add user properties - Collections.addAll(args, "--userType", "mojang"); - Collections.addAll(args, "--userProperties", "{}"); - - // Add asset index - Collections.addAll(args, "--assetIndex", profile.getAssetIndex()); - } - } else - Collections.addAll(args, "--session", accessToken); - - // Add version and dirs args - Collections.addAll(args, "--version", profile.getVersion().toString()); - Collections.addAll(args, "--gameDir", clientDir); - Collections.addAll(args, "--assetsDir", assetDir); - Collections.addAll(args, "--resourcePackDir", resourcePackDir); - if (version.compareTo(ClientProfileVersions.MINECRAFT_1_9_4) >= 0) - Collections.addAll(args, "--versionType", "Launcher v" + Version.getVersion().getVersionString()); - - // Add server args - if (autoEnter) { - Collections.addAll(args, "--server", profile.getServerAddress()); - Collections.addAll(args, "--port", Integer.toString(profile.getServerPort())); - } - for (OptionalAction a : actions) { - if (a instanceof OptionalActionClientArgs) { - args.addAll(((OptionalActionClientArgs) a).args); - } - } - // Add window size args - if (fullScreen) - Collections.addAll(args, "--fullscreen", Boolean.toString(true)); - if (width > 0 && height > 0) { - Collections.addAll(args, "--width", Integer.toString(width)); - Collections.addAll(args, "--height", Integer.toString(height)); - } - } - } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/RuntimeGsonManager.java b/Launcher/src/main/java/pro/gravit/launcher/client/RuntimeGsonManager.java new file mode 100644 index 00000000..b8789cf4 --- /dev/null +++ b/Launcher/src/main/java/pro/gravit/launcher/client/RuntimeGsonManager.java @@ -0,0 +1,23 @@ +package pro.gravit.launcher.client; + +import com.google.gson.GsonBuilder; +import pro.gravit.launcher.managers.GsonManager; +import pro.gravit.launcher.modules.events.PreGsonPhase; +import pro.gravit.launcher.request.websockets.ClientWebSocketService; +import pro.gravit.utils.UniversalJsonAdapter; + +public class RuntimeGsonManager extends GsonManager { + private final RuntimeModuleManager moduleManager; + + public RuntimeGsonManager(RuntimeModuleManager moduleManager) { + this.moduleManager = moduleManager; + } + + @Override + public void registerAdapters(GsonBuilder builder) { + super.registerAdapters(builder); + builder.registerTypeAdapter(UserSettings.class, new UniversalJsonAdapter<>(UserSettings.providers)); + ClientWebSocketService.appendTypeAdapters(builder); + moduleManager.invokeEvent(new PreGsonPhase(builder)); + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/RuntimeLauncherCoreModule.java b/Launcher/src/main/java/pro/gravit/launcher/client/RuntimeLauncherCoreModule.java new file mode 100644 index 00000000..76b85182 --- /dev/null +++ b/Launcher/src/main/java/pro/gravit/launcher/client/RuntimeLauncherCoreModule.java @@ -0,0 +1,17 @@ +package pro.gravit.launcher.client; + +import pro.gravit.launcher.modules.LauncherInitContext; +import pro.gravit.launcher.modules.LauncherModule; +import pro.gravit.launcher.modules.LauncherModuleInfo; +import pro.gravit.utils.Version; + +public class RuntimeLauncherCoreModule extends LauncherModule { + public RuntimeLauncherCoreModule() { + super(new LauncherModuleInfo("ClientLauncherCore", Version.getVersion())); + } + + @Override + public void init(LauncherInitContext initContext) { + + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessInitPhase.java b/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessInitPhase.java deleted file mode 100644 index 69378d97..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessInitPhase.java +++ /dev/null @@ -1,15 +0,0 @@ -package pro.gravit.launcher.client.events.client; - -import pro.gravit.launcher.LauncherEngine; -import pro.gravit.launcher.client.ClientLauncherProcess; -import pro.gravit.launcher.modules.events.InitPhase; - -public class ClientProcessInitPhase extends InitPhase { - public final LauncherEngine clientInstance; - public final ClientLauncherProcess.ClientParams params; - - public ClientProcessInitPhase(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) { - this.clientInstance = clientInstance; - this.params = params; - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessLaunchEvent.java b/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessLaunchEvent.java deleted file mode 100644 index 5e66f7f6..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessLaunchEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package pro.gravit.launcher.client.events.client; - -import pro.gravit.launcher.LauncherEngine; -import pro.gravit.launcher.client.ClientLauncherProcess; -import pro.gravit.launcher.modules.LauncherModule; - -public class ClientProcessLaunchEvent extends LauncherModule.Event { - public final LauncherEngine clientInstance; - public final ClientLauncherProcess.ClientParams params; - - public ClientProcessLaunchEvent(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) { - this.clientInstance = clientInstance; - this.params = params; - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessReadyEvent.java b/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessReadyEvent.java deleted file mode 100644 index d16961e4..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessReadyEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package pro.gravit.launcher.client.events.client; - -import pro.gravit.launcher.LauncherEngine; -import pro.gravit.launcher.client.ClientLauncherProcess; -import pro.gravit.launcher.modules.events.PostInitPhase; - -public class ClientProcessReadyEvent extends PostInitPhase { - public final LauncherEngine clientInstance; - public final ClientLauncherProcess.ClientParams params; - - public ClientProcessReadyEvent(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) { - this.clientInstance = clientInstance; - this.params = params; - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/debug/ClientRuntimeProvider.java b/Launcher/src/main/java/pro/gravit/launcher/debug/ClientRuntimeProvider.java new file mode 100644 index 00000000..3fad11ca --- /dev/null +++ b/Launcher/src/main/java/pro/gravit/launcher/debug/ClientRuntimeProvider.java @@ -0,0 +1,114 @@ +package pro.gravit.launcher.debug; + +import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.LauncherEngine; +import pro.gravit.launcher.api.AuthService; +import pro.gravit.launcher.events.request.AuthRequestEvent; +import pro.gravit.launcher.events.request.ProfilesRequestEvent; +import pro.gravit.launcher.gui.RuntimeProvider; +import pro.gravit.launcher.profiles.ClientProfile; +import pro.gravit.launcher.request.Request; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.update.ProfilesRequest; +import pro.gravit.utils.helper.LogHelper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.UUID; + +public class ClientRuntimeProvider implements RuntimeProvider { + @Override + public void run(String[] args) { + ArrayList newArgs = new ArrayList<>(Arrays.asList(args)); + try { + String username = System.getProperty("launcher.runtime.username", null); + String uuid = System.getProperty("launcher.runtime.uuid", null); + String login = System.getProperty("launcher.runtime.login", username); + String password = System.getProperty("launcher.runtime.password", "Player"); + String authId = System.getProperty("launcher.runtime.auth.authid", "std"); + String accessToken = System.getProperty("launcher.runtime.auth.accesstoken", null); + String refreshToken = System.getProperty("launcher.runtime.auth.refreshtoken", null); + String minecraftAccessToken = System.getProperty("launcher.runtime.auth.minecraftaccesstoken", "DEBUG"); + long expire = Long.parseLong(System.getProperty("launcher.runtime.auth.expire", "0")); + String profileUUID = System.getProperty("launcher.runtime.profileuuid", null); + String mainClass = System.getProperty("launcher.runtime.mainclass", null); + ClientPermissions permissions = new ClientPermissions(); + if(mainClass == null) { + throw new NullPointerException("Add `-Dlauncher.runtime.mainclass=YOUR_MAIN_CLASS` to jvmArgs"); + } + if(uuid == null) { + if(accessToken != null) { + Request.setOAuth(authId, new AuthRequestEvent.OAuthRequestEvent(accessToken, refreshToken, expire)); + Request.RequestRestoreReport report = Request.restore(true, false); + permissions = report.userInfo.permissions; + username = report.userInfo.playerProfile.username; + uuid = report.userInfo.playerProfile.uuid.toString(); + if(report.userInfo.accessToken != null) { + minecraftAccessToken = report.userInfo.accessToken; + } + } else { + AuthRequest request = new AuthRequest(login, password, authId, AuthRequest.ConnectTypes.API); + AuthRequestEvent event = request.request(); + Request.setOAuth(authId, event.oauth); + if(event.accessToken != null) { + minecraftAccessToken = event.accessToken; + } + username = event.playerProfile.username; + uuid = event.playerProfile.uuid.toString(); + } + } + if(profileUUID != null) { + UUID profileUuid = UUID.fromString(profileUUID); + ProfilesRequest profiles = new ProfilesRequest(); + ProfilesRequestEvent event = profiles.request(); + for(ClientProfile profile : event.profiles) { + if(profile.getUUID().equals(profileUuid)) { + AuthService.profile = profile; + } + } + } + if(username == null) { + username = "Player"; + } + if(uuid == null) { + uuid = "a7899336-e61c-4e51-b480-0c815b18aed8"; + } + replaceOrCreateArgument(newArgs, "--username", username); + replaceOrCreateArgument(newArgs, "--uuid", uuid); + replaceOrCreateArgument(newArgs, "--accessToken", minecraftAccessToken); + AuthService.uuid = UUID.fromString(uuid); + AuthService.username = username; + AuthService.permissions = permissions; + Class mainClazz = Class.forName(mainClass); + mainClazz.getMethod("main", String[].class).invoke(null, (Object) newArgs.toArray(new String[0])); + } catch (Throwable e) { + LogHelper.error(e); + LauncherEngine.exitLauncher(-15); + } + } + + public void replaceOrCreateArgument(ArrayList args, String name, String value) { + int index = args.indexOf(name); + if(index < 0) { + args.add(name); + if(value != null) { + args.add(value); + } + return; + } + if(value != null) { + int valueIndex = index+1; + args.set(valueIndex, value); + } + } + + @Override + public void preLoad() { + + } + + @Override + public void init(boolean clientInstance) { + + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/debug/DebugMain.java b/Launcher/src/main/java/pro/gravit/launcher/debug/DebugMain.java index c5559229..e3529e76 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/debug/DebugMain.java +++ b/Launcher/src/main/java/pro/gravit/launcher/debug/DebugMain.java @@ -1,10 +1,11 @@ package pro.gravit.launcher.debug; +import pro.gravit.launcher.ClientLauncherMethods; import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherConfig; import pro.gravit.launcher.LauncherEngine; -import pro.gravit.launcher.client.ClientLauncherCoreModule; -import pro.gravit.launcher.client.ClientModuleManager; +import pro.gravit.launcher.client.RuntimeLauncherCoreModule; +import pro.gravit.launcher.client.RuntimeModuleManager; import pro.gravit.launcher.managers.ConsoleManager; import pro.gravit.launcher.modules.LauncherModule; import pro.gravit.launcher.modules.events.OfflineModeEvent; @@ -28,6 +29,7 @@ public class DebugMain { public static String projectName = System.getProperty("launcherdebug.projectname", "Minecraft"); public static String unlockSecret = System.getProperty("launcherdebug.unlocksecret", ""); public static boolean offlineMode = Boolean.getBoolean("launcherdebug.offlinemode"); + public static boolean disableAutoRefresh = Boolean.getBoolean("launcherdebug.disableautorefresh"); public static String[] moduleClasses = System.getProperty("launcherdebug.modules", "").split(","); public static String[] moduleFiles = System.getProperty("launcherdebug.modulefiles", "").split(","); public static LauncherConfig.LauncherEnvironment environment = LauncherConfig.LauncherEnvironment.valueOf(System.getProperty("launcherdebug.env", "STD")); @@ -42,8 +44,8 @@ public static void main(String[] args) throws Throwable { config.unlockSecret = unlockSecret; Launcher.setConfig(config); Launcher.applyLauncherEnv(environment); - LauncherEngine.modulesManager = new ClientModuleManager(); - LauncherEngine.modulesManager.loadModule(new ClientLauncherCoreModule()); + LauncherEngine.modulesManager = new RuntimeModuleManager(); + LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule()); for (String moduleClassName : moduleClasses) { if (moduleClassName.isEmpty()) continue; LauncherEngine.modulesManager.loadModule(newModule(moduleClassName)); @@ -59,7 +61,7 @@ public static void main(String[] args) throws Throwable { RequestService service; if (offlineMode) { OfflineRequestService offlineRequestService = new OfflineRequestService(); - LauncherEngine.applyBasicOfflineProcessors(offlineRequestService); + ClientLauncherMethods.applyBasicOfflineProcessors(offlineRequestService); OfflineModeEvent event = new OfflineModeEvent(offlineRequestService); LauncherEngine.modulesManager.invokeEvent(event); service = event.service; @@ -67,9 +69,13 @@ public static void main(String[] args) throws Throwable { service = StdWebSocketService.initWebSockets(webSocketURL).get(); } Request.setRequestService(service); + if(!disableAutoRefresh) { + Request.startAutoRefresh(); + } LogHelper.debug("Initialization LauncherEngine"); - LauncherEngine instance = LauncherEngine.newInstance(false); + LauncherEngine instance = LauncherEngine.newInstance(false, ClientRuntimeProvider.class); instance.start(args); + LauncherEngine.exitLauncher(0); } @SuppressWarnings("unchecked") diff --git a/Launcher/src/main/java/pro/gravit/launcher/gui/NoRuntimeProvider.java b/Launcher/src/main/java/pro/gravit/launcher/gui/NoRuntimeProvider.java index 0ac704d9..14e75afb 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/gui/NoRuntimeProvider.java +++ b/Launcher/src/main/java/pro/gravit/launcher/gui/NoRuntimeProvider.java @@ -5,7 +5,7 @@ public class NoRuntimeProvider implements RuntimeProvider { @Override public void run(String[] args) { - JOptionPane.showMessageDialog(null, "GUI часть лаунчера не найдена.\nС 5.1.0 вам необходимо самостоятельно установить модуль, отвечающий за GUI. Рантайм на JS более не поддерживается"); + JOptionPane.showMessageDialog(null, "Модуль графического интерфейса лаунчера отсутствует"); } @Override diff --git a/Launcher/src/main/java/pro/gravit/launcher/managers/SettingsManager.java b/Launcher/src/main/java/pro/gravit/launcher/managers/SettingsManager.java index d545c54a..54185d6f 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/managers/SettingsManager.java +++ b/Launcher/src/main/java/pro/gravit/launcher/managers/SettingsManager.java @@ -44,48 +44,4 @@ public void setConfig(NewLauncherSettings config) { public NewLauncherSettings getDefaultConfig() { return new NewLauncherSettings(); } - - public void loadHDirStore(Path storePath) throws IOException { - Files.createDirectories(storePath); - IOHelper.walk(storePath, new StoreFileVisitor(), false); - } - - public void saveHDirStore(Path storeProjectPath) throws IOException { - Files.createDirectories(storeProjectPath); - for (NewLauncherSettings.HashedStoreEntry e : settings.lastHDirs) { - if (!e.needSave) continue; - Path file = storeProjectPath.resolve(e.name.concat(".bin")); - if (!Files.exists(file)) Files.createFile(file); - try (HOutput output = new HOutput(IOHelper.newOutput(file))) { - output.writeString(e.name, 128); - output.writeString(e.fullPath, 1024); - e.hdir.write(output); - } - } - } - - public void loadHDirStore() throws IOException { - loadHDirStore(DirBridge.dirStore); - } - - public void saveHDirStore() throws IOException { - saveHDirStore(DirBridge.dirProjectStore); - } - - public static class StoreFileVisitor extends SimpleFileVisitor { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - try (HInput input = new HInput(IOHelper.newInput(file))) { - String dirName = input.readString(128); - String fullPath = input.readString(1024); - HashedDir dir = new HashedDir(input); - settings.lastHDirs.add(new NewLauncherSettings.HashedStoreEntry(dir, dirName, fullPath)); - } catch (IOException e) { - LogHelper.error("Skip file %s exception: %s", file.toAbsolutePath().toString(), e.getMessage()); - } - return super.visitFile(file, attrs); - } - - } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/utils/LauncherUpdater.java b/Launcher/src/main/java/pro/gravit/launcher/utils/LauncherUpdater.java index b4194ab5..f2712a0e 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/utils/LauncherUpdater.java +++ b/Launcher/src/main/java/pro/gravit/launcher/utils/LauncherUpdater.java @@ -1,6 +1,5 @@ package pro.gravit.launcher.utils; -import pro.gravit.launcher.AsyncDownloader; import pro.gravit.launcher.LauncherEngine; import pro.gravit.launcher.LauncherInject; import pro.gravit.launcher.request.update.LauncherRequest; @@ -23,6 +22,8 @@ import java.util.Arrays; import java.util.List; +import static pro.gravit.launcher.modern.Downloader.makeSSLSocketFactory; + public class LauncherUpdater { @LauncherInject("launcher.certificatePinning") private static boolean isCertificatePinning; @@ -49,7 +50,7 @@ public static Path prepareUpdate(URL url) throws Exception { if (isCertificatePinning) { HttpsURLConnection connection1 = (HttpsURLConnection) connection; try { - connection1.setSSLSocketFactory(AsyncDownloader.makeSSLSocketFactory()); + connection1.setSSLSocketFactory(makeSSLSocketFactory()); } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | KeyManagementException e) { throw new IOException(e); } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/Launcher.java b/LauncherAPI/src/main/java/pro/gravit/launcher/Launcher.java index 27457da0..165f2bfb 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/Launcher.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/Launcher.java @@ -6,13 +6,11 @@ import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.LogHelper; -import pro.gravit.utils.helper.SecurityHelper; import java.io.IOException; import java.net.URL; import java.nio.file.NoSuchFileException; import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -22,23 +20,9 @@ public final class Launcher { // Authlib constants - public static final String SKIN_URL_PROPERTY = "skinURL"; - - public static final String SKIN_DIGEST_PROPERTY = "skinDigest"; - - public static final String SKIN_METADATA_PROPERTY = "skinMetadata"; - - public static final String CLOAK_URL_PROPERTY = "cloakURL"; - - public static final String CLOAK_DIGEST_PROPERTY = "cloakDigest"; - - public static final String CLOAK_METADATA_PROPERTY = "cloakMetadata"; - // Used to determine from clientside is launched from launcher public static final AtomicBoolean LAUNCHED = new AtomicBoolean(false); - public static final int PROTOCOL_MAGIC_LEGACY = 0x724724_00 + 24; - public static final int PROTOCOL_MAGIC = 0xA205B064; // e = 2.718281828 public static final String RUNTIME_DIR = "runtime"; // Constants diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java b/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java index 0e57587d..10fbcea4 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java @@ -5,6 +5,7 @@ import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.stream.StreamObject; +import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.VerifyHelper; @@ -21,7 +22,7 @@ public final class LauncherConfig extends StreamObject { @LauncherInject("launchercore.certificates") private static final List secureConfigCertificates = null; - @LauncherInject("launcher.modules") + @LauncherInject("launcher.legacymodules") private static final List> modulesClasses = null; private static final MethodType VOID_TYPE = MethodType.methodType(void.class); @LauncherInject("launcher.projectName") @@ -51,6 +52,11 @@ public final class LauncherConfig extends StreamObject { @LauncherInject("runtimeconfig.buildNumber") public long buildNumber; + private static class ModernModulesClass { + @LauncherInject("launcher.modules") + private static final List> modulesClasses = null; + } + @LauncherInjectionConstructor public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException { @@ -114,6 +120,9 @@ public LauncherConfig(String address, Map runtime, String projec } public static void initModules(LauncherModulesManager modulesManager) { + if(JVMHelper.JVM_VERSION >= 17) { + modulesClasses.addAll(ModernModulesClass.modulesClasses); + } for (Class clazz : modulesClasses) try { modulesManager.loadModule((LauncherModule) MethodHandles.publicLookup().findConstructor(clazz, VOID_TYPE).invokeWithArguments(Collections.emptyList())); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/config/JsonConfigurableInterface.java b/LauncherAPI/src/main/java/pro/gravit/launcher/config/JsonConfigurableInterface.java index 67b160f2..65c15c92 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/config/JsonConfigurableInterface.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/config/JsonConfigurableInterface.java @@ -41,7 +41,13 @@ default String toJsonString() { default void loadConfig(Gson gson, Path configPath) throws IOException { if (generateConfigIfNotExists(configPath)) return; try (BufferedReader reader = IOHelper.newReader(configPath)) { - setConfig(gson.fromJson(reader, getType())); + T value = gson.fromJson(reader, getType()); + if(value == null) { + LogHelper.warning("Config %s is null", configPath); + resetConfig(configPath); + return; + } + setConfig(value); } catch (Exception e) { LogHelper.error(e); resetConfig(configPath); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/ExtendedTokenRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/ExtendedTokenRequestEvent.java index 09df5190..084d4a72 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/ExtendedTokenRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/ExtendedTokenRequestEvent.java @@ -4,4 +4,6 @@ public interface ExtendedTokenRequestEvent { String getExtendedTokenName(); String getExtendedToken(); + + long getExtendedTokenExpire(); } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/AssetUploadInfoRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/AssetUploadInfoRequestEvent.java new file mode 100644 index 00000000..34446fcc --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/AssetUploadInfoRequestEvent.java @@ -0,0 +1,24 @@ +package pro.gravit.launcher.events.request; + +import pro.gravit.launcher.events.RequestEvent; + +import java.util.Set; + +public class AssetUploadInfoRequestEvent extends RequestEvent { + public Set available; + public SlimSupportConf slimSupportConf; + + public AssetUploadInfoRequestEvent(Set available, SlimSupportConf slimSupportConf) { + this.available = available; + this.slimSupportConf = slimSupportConf; + } + + @Override + public String getType() { + return "assetUploadInfo"; + } + + public enum SlimSupportConf { + UNSUPPORTED, USER, SERVER + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAssetUploadUrlRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAssetUploadUrlRequestEvent.java new file mode 100644 index 00000000..9d4a7e66 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAssetUploadUrlRequestEvent.java @@ -0,0 +1,22 @@ +package pro.gravit.launcher.events.request; + +import pro.gravit.launcher.events.RequestEvent; + +public class GetAssetUploadUrlRequestEvent extends RequestEvent { + public static final String FEATURE_NAME = "assetupload"; + public String url; + public AuthRequestEvent.OAuthRequestEvent token; + + public GetAssetUploadUrlRequestEvent() { + } + + public GetAssetUploadUrlRequestEvent(String url, AuthRequestEvent.OAuthRequestEvent token) { + this.url = url; + this.token = token; + } + + @Override + public String getType() { + return "getAssetUploadUrl"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java index b2709e04..c0768207 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java @@ -5,6 +5,7 @@ import pro.gravit.utils.TypeSerializeInterface; import java.util.List; +import java.util.Set; public class GetAvailabilityAuthRequestEvent extends RequestEvent { @LauncherNetworkAPI @@ -49,24 +50,14 @@ public static class AuthAvailability { @LauncherNetworkAPI public boolean visible; @LauncherNetworkAPI - public String apiUrl; - @LauncherNetworkAPI - public List apiFeatures; + public Set features; - public AuthAvailability(String name, String displayName, boolean visible, List details) { - this.name = name; - this.displayName = displayName; - this.visible = visible; - this.details = details; - } - - public AuthAvailability(String name, String displayName, boolean visible, List details, String apiUrl, List apiFeatures) { - this.visible = visible; + public AuthAvailability(List details, String name, String displayName, boolean visible, Set features) { this.details = details; this.name = name; this.displayName = displayName; - this.apiUrl = apiUrl; - this.apiFeatures = apiFeatures; + this.visible = visible; + this.features = features; } } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/HardwareReportRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/HardwareReportRequestEvent.java index 75ec5458..e9198109 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/HardwareReportRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/HardwareReportRequestEvent.java @@ -1,19 +1,37 @@ package pro.gravit.launcher.events.request; +import pro.gravit.launcher.events.ExtendedTokenRequestEvent; import pro.gravit.launcher.events.RequestEvent; -public class HardwareReportRequestEvent extends RequestEvent { +public class HardwareReportRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent { public String extendedToken; + public long expire; public HardwareReportRequestEvent() { } - public HardwareReportRequestEvent(String extendedToken) { + public HardwareReportRequestEvent(String extendedToken, long expire) { this.extendedToken = extendedToken; + this.expire = expire; } @Override public String getType() { return "hardwareReport"; } + + @Override + public String getExtendedTokenName() { + return "hardware"; + } + + @Override + public String getExtendedToken() { + return extendedToken; + } + + @Override + public long getExtendedTokenExpire() { + return expire; + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/LauncherRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/LauncherRequestEvent.java index 9a25e534..17d94488 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/LauncherRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/LauncherRequestEvent.java @@ -1,12 +1,13 @@ package pro.gravit.launcher.events.request; import pro.gravit.launcher.LauncherNetworkAPI; +import pro.gravit.launcher.events.ExtendedTokenRequestEvent; import pro.gravit.launcher.events.RequestEvent; import java.util.UUID; -public class LauncherRequestEvent extends RequestEvent { +public class LauncherRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent { public static final String LAUNCHER_EXTENDED_TOKEN_NAME = "launcher"; @SuppressWarnings("unused") private static final UUID uuid = UUID.fromString("d54cc12a-4f59-4f23-9b10-f527fdd2e38f"); @@ -19,6 +20,7 @@ public class LauncherRequestEvent extends RequestEvent { @LauncherNetworkAPI public boolean needUpdate; public String launcherExtendedToken; + public long launcherExtendedTokenExpire; public LauncherRequestEvent(boolean needUpdate, String url) { this.needUpdate = needUpdate; @@ -30,10 +32,11 @@ public LauncherRequestEvent(boolean b, byte[] digest) { this.digest = digest; } - public LauncherRequestEvent(boolean needUpdate, String url, String launcherExtendedToken) { + public LauncherRequestEvent(boolean needUpdate, String url, String launcherExtendedToken, long expire) { this.url = url; this.needUpdate = needUpdate; this.launcherExtendedToken = launcherExtendedToken; + this.launcherExtendedTokenExpire = expire; } public LauncherRequestEvent(byte[] binary, byte[] digest) { //Legacy support constructor @@ -45,4 +48,19 @@ public LauncherRequestEvent(byte[] binary, byte[] digest) { //Legacy support con public String getType() { return "launcher"; } + + @Override + public String getExtendedTokenName() { + return "launcher"; + } + + @Override + public String getExtendedToken() { + return launcherExtendedToken; + } + + @Override + public long getExtendedTokenExpire() { + return launcherExtendedTokenExpire; + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/SecurityReportRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/SecurityReportRequestEvent.java index 7266ea4b..2c9af856 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/SecurityReportRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/SecurityReportRequestEvent.java @@ -31,6 +31,7 @@ public enum ReportAction { LOGOUT, TOKEN_EXPIRED, EXIT, + @Deprecated CRASH, OTHER } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureLevelKeyRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureLevelKeyRequestEvent.java index 0c40dccd..2c818107 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureLevelKeyRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureLevelKeyRequestEvent.java @@ -1,12 +1,13 @@ package pro.gravit.launcher.events.request; +import pro.gravit.launcher.events.ExtendedTokenRequestEvent; import pro.gravit.launcher.events.RequestEvent; -public class VerifySecureLevelKeyRequestEvent extends RequestEvent { +public class VerifySecureLevelKeyRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent { public boolean needHardwareInfo; public boolean onlyStatisticInfo; public String extendedToken; - public String hardwareExtendedToken; + public long expire; public VerifySecureLevelKeyRequestEvent() { } @@ -15,21 +16,30 @@ public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo) { this.needHardwareInfo = needHardwareInfo; } - public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo, boolean onlyStatisticInfo, String extendedToken) { + public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo, boolean onlyStatisticInfo, String extendedToken, long expire) { this.needHardwareInfo = needHardwareInfo; this.onlyStatisticInfo = onlyStatisticInfo; this.extendedToken = extendedToken; - } - - public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo, boolean onlyStatisticInfo, String extendedToken, String hardwareExtendedToken) { - this.needHardwareInfo = needHardwareInfo; - this.onlyStatisticInfo = onlyStatisticInfo; - this.extendedToken = extendedToken; - this.hardwareExtendedToken = hardwareExtendedToken; + this.expire = expire; } @Override public String getType() { return "verifySecureLevelKey"; } + + @Override + public String getExtendedTokenName() { + return "publicKey"; + } + + @Override + public String getExtendedToken() { + return extendedToken; + } + + @Override + public long getExtendedTokenExpire() { + return expire; + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/ClientProfileVersions.java b/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/ClientProfileVersions.java index ef038715..7d44b68d 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/ClientProfileVersions.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/ClientProfileVersions.java @@ -16,4 +16,5 @@ private ClientProfileVersions() { public static final ClientProfile.Version MINECRAFT_1_18 = ClientProfile.Version.of("1.18"); public static final ClientProfile.Version MINECRAFT_1_19 = ClientProfile.Version.of("1.19"); public static final ClientProfile.Version MINECRAFT_1_20 = ClientProfile.Version.of("1.20"); + public static final ClientProfile.Version MINECRAFT_1_20_2 = ClientProfile.Version.of("1.20.2"); } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/optional/OptionalFile.java b/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/optional/OptionalFile.java index bbe85fc9..36b57c83 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/optional/OptionalFile.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/profiles/optional/OptionalFile.java @@ -38,6 +38,9 @@ public class OptionalFile { @LauncherNetworkAPI public boolean limited; + @LauncherNetworkAPI + public String category; + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/Request.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/Request.java index 0c6f1cc5..9500de2f 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/Request.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/Request.java @@ -2,6 +2,7 @@ import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.events.request.AuthRequestEvent; +import pro.gravit.launcher.events.request.CurrentUserRequestEvent; import pro.gravit.launcher.events.request.RefreshTokenRequestEvent; import pro.gravit.launcher.events.request.RestoreRequestEvent; import pro.gravit.launcher.request.auth.RefreshTokenRequest; @@ -11,32 +12,55 @@ import pro.gravit.utils.helper.LogHelper; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiConsumer; public abstract class Request implements WebSocketRequest { private static final List extendedTokenCallbacks = new ArrayList<>(4); private static final List> oauthChangeHandlers = new ArrayList<>(4); - @Deprecated - public static StdWebSocketService service; - private static RequestService requestService; - private static AuthRequestEvent.OAuthRequestEvent oauth; - private static Map extendedTokens; - private static String authId; - private static long tokenExpiredTime; + + private static volatile RequestService requestService; + private static volatile AuthRequestEvent.OAuthRequestEvent oauth; + private static volatile Map extendedTokens; + private static volatile String authId; + private static volatile long tokenExpiredTime; + private static volatile ScheduledExecutorService executorService; + private static volatile boolean autoRefreshRunning; @LauncherNetworkAPI public final UUID requestUUID = UUID.randomUUID(); private transient final AtomicBoolean started = new AtomicBoolean(false); + public static synchronized void startAutoRefresh() { + if(!autoRefreshRunning) { + if(executorService == null) { + executorService = Executors.newSingleThreadScheduledExecutor((t) -> { + Thread thread = new Thread(t); + thread.setName("AutoRefresh thread"); + thread.setDaemon(true); + return thread; + }); + } + executorService.scheduleAtFixedRate(() -> { + try { + restore(false, true); + } catch (Exception e) { + LogHelper.error(e); + } + }, 5, 5, TimeUnit.SECONDS); + autoRefreshRunning = true; + } + } + public static RequestService getRequestService() { return requestService; } public static void setRequestService(RequestService service) { requestService = service; - if (service instanceof StdWebSocketService) { - Request.service = (StdWebSocketService) service; - } } public static boolean isAvailable() { @@ -64,7 +88,7 @@ public static String getAuthId() { return authId; } - public static Map getExtendedTokens() { + public static Map getExtendedTokens() { if (extendedTokens != null) { return Collections.unmodifiableMap(extendedTokens); } else { @@ -72,22 +96,34 @@ public static Map getExtendedTokens() { } } + public static Map getStringExtendedTokens() { + if(extendedTokens != null) { + Map map = new HashMap<>(); + for(Map.Entry e : extendedTokens.entrySet()) { + map.put(e.getKey(), e.getValue().token); + } + return map; + } else { + return null; + } + } + public static void clearExtendedTokens() { if (extendedTokens != null) { extendedTokens.clear(); } } - public static void addExtendedToken(String name, String token) { + public static void addExtendedToken(String name, ExtendedToken token) { if (extendedTokens == null) { - extendedTokens = new HashMap<>(); + extendedTokens = new ConcurrentHashMap<>(); } extendedTokens.put(name, token); } - public static void addAllExtendedToken(Map map) { + public static void addAllExtendedToken(Map map) { if (extendedTokens == null) { - extendedTokens = new HashMap<>(); + extendedTokens = new ConcurrentHashMap<>(); } extendedTokens.putAll(map); } @@ -117,11 +153,32 @@ public static String getRefreshToken() { } public static void reconnect() throws Exception { - service.open(); + + getRequestService().open(); restore(); } public static RequestRestoreReport restore() throws Exception { + return restore(false, false); + } + + private synchronized static Map getExpiredExtendedTokens() { + if(extendedTokens == null) { + return new HashMap<>(); + } + Set set = new HashSet<>(); + for(Map.Entry e : extendedTokens.entrySet()) { + if(e.getValue().expire != 0 && e.getValue().expire < System.currentTimeMillis()) { + set.add(e.getKey()); + } + } + if(set.isEmpty()) { + return new HashMap<>(); + } + return makeNewTokens(set); + } + + public static synchronized RequestRestoreReport restore(boolean needUserInfo, boolean refreshOnly) throws Exception { boolean refreshed = false; RestoreRequest request; if (oauth != null) { @@ -131,26 +188,18 @@ public static RequestRestoreReport restore() throws Exception { setOAuth(authId, event.oauth); refreshed = true; } - request = new RestoreRequest(authId, oauth.accessToken, extendedTokens, false); + request = new RestoreRequest(authId, oauth.accessToken, refreshOnly ? getExpiredExtendedTokens() : getStringExtendedTokens(), needUserInfo); } else { - request = new RestoreRequest(authId, null, extendedTokens, false); + request = new RestoreRequest(authId, null, refreshOnly ? getExpiredExtendedTokens() : getStringExtendedTokens(), false); + } + if(refreshOnly && (request.extended == null || request.extended.isEmpty())) { + return new RequestRestoreReport(refreshed, null, null); } RestoreRequestEvent event = request.request(); List invalidTokens = null; if (event.invalidTokens != null && event.invalidTokens.size() > 0) { - boolean needRequest = false; - Map tokens = new HashMap<>(); - for (ExtendedTokenCallback cb : extendedTokenCallbacks) { - for (String tokenName : event.invalidTokens) { - String newToken = cb.tryGetNewToken(tokenName); - if (newToken != null) { - needRequest = true; - tokens.put(tokenName, newToken); - addExtendedToken(tokenName, newToken); - } - } - } - if (needRequest) { + Map tokens = makeNewTokens(event.invalidTokens); + if (!tokens.isEmpty()) { request = new RestoreRequest(authId, null, tokens, false); event = request.request(); if (event.invalidTokens != null && event.invalidTokens.size() > 0) { @@ -159,7 +208,21 @@ public static RequestRestoreReport restore() throws Exception { } invalidTokens = event.invalidTokens; } - return new RequestRestoreReport(false, refreshed, invalidTokens); + return new RequestRestoreReport(refreshed, invalidTokens, event.userInfo); + } + + private synchronized static Map makeNewTokens(Collection keys) { + Map tokens = new HashMap<>(); + for (ExtendedTokenCallback cb : extendedTokenCallbacks) { + for (String tokenName : keys) { + ExtendedToken newToken = cb.tryGetNewToken(tokenName); + if (newToken != null) { + tokens.put(tokenName, newToken.token); + addExtendedToken(tokenName, newToken); + } + } + } + return tokens; } public static void requestError(String message) throws RequestException { @@ -209,18 +272,29 @@ protected R requestDo(RequestService service) throws Exception { } public interface ExtendedTokenCallback { - String tryGetNewToken(String name); + ExtendedToken tryGetNewToken(String name); } public static class RequestRestoreReport { - public final boolean legacySession; public final boolean refreshed; public final List invalidExtendedTokens; + public final CurrentUserRequestEvent.UserInfo userInfo; - public RequestRestoreReport(boolean legacySession, boolean refreshed, List invalidExtendedTokens) { - this.legacySession = legacySession; + public RequestRestoreReport(boolean refreshed, List invalidExtendedTokens, CurrentUserRequestEvent.UserInfo userInfo) { this.refreshed = refreshed; this.invalidExtendedTokens = invalidExtendedTokens; + this.userInfo = userInfo; + } + } + + public static class ExtendedToken { + public final String token; + public final long expire; + + public ExtendedToken(String token, long expire) { + this.token = token; + long time = System.currentTimeMillis(); + this.expire = expire < time/2 ? time+expire : expire; } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/RequestService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/RequestService.java index 2f8d4bab..41142326 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/RequestService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/RequestService.java @@ -6,6 +6,7 @@ public interface RequestService { CompletableFuture request(Request request) throws IOException; + void open() throws Exception; void registerEventHandler(EventHandler handler); 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 6a3cf1ab..54c8df02 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 @@ -6,12 +6,16 @@ import pro.gravit.launcher.request.websockets.WebSocketRequest; import pro.gravit.utils.helper.VerifyHelper; +import java.util.UUID; + public final class JoinServerRequest extends Request implements WebSocketRequest { // Instance @LauncherNetworkAPI public final String username; @LauncherNetworkAPI + public final UUID uuid; + @LauncherNetworkAPI public final String accessToken; @LauncherNetworkAPI public final String serverID; @@ -19,10 +23,18 @@ public final class JoinServerRequest extends Request imp public JoinServerRequest(String username, String accessToken, String serverID) { this.username = username; + this.uuid = null; this.accessToken = accessToken; this.serverID = VerifyHelper.verifyServerID(serverID); } + public JoinServerRequest(UUID uuid, String accessToken, String serverID) { + this.username = null; + this.uuid = uuid; + this.accessToken = accessToken; + this.serverID = serverID; + } + @Override public String getType() { return "joinServer"; diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/cabinet/AssetUploadInfoRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/cabinet/AssetUploadInfoRequest.java new file mode 100644 index 00000000..3827e762 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/cabinet/AssetUploadInfoRequest.java @@ -0,0 +1,11 @@ +package pro.gravit.launcher.request.cabinet; + +import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent; +import pro.gravit.launcher.request.Request; + +public class AssetUploadInfoRequest extends Request { + @Override + public String getType() { + return "assetUploadInfo"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/cabinet/GetAssetUploadUrl.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/cabinet/GetAssetUploadUrl.java new file mode 100644 index 00000000..56d9d976 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/cabinet/GetAssetUploadUrl.java @@ -0,0 +1,20 @@ +package pro.gravit.launcher.request.cabinet; + +import pro.gravit.launcher.events.request.GetAssetUploadUrlRequestEvent; +import pro.gravit.launcher.request.Request; + +public class GetAssetUploadUrl extends Request { + public String name; + + public GetAssetUploadUrl() { + } + + public GetAssetUploadUrl(String name) { + this.name = name; + } + + @Override + public String getType() { + return "getAssetUploadUrl"; + } +} 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 4296684b..c7c269fa 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 @@ -111,6 +111,8 @@ public void registerResults() { results.register("additionalData", AdditionalDataRequestEvent.class); results.register("clientProfileKey", FetchClientProfileKeyRequestEvent.class); results.register("getPublicKey", GetPublicKeyRequestEvent.class); + results.register("getAssetUploadUrl", GetAssetUploadUrlRequestEvent.class); + results.register("assetUploadInfo", AssetUploadInfoRequestEvent.class); resultsRegistered = true; } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/OfflineRequestService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/OfflineRequestService.java index bb86a8c2..66fb69e5 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/OfflineRequestService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/OfflineRequestService.java @@ -44,6 +44,11 @@ public CompletableFuture request(Request reques return future; } + @Override + public void open() { + + } + @Override public void registerEventHandler(EventHandler handler) { eventHandlers.add(handler); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StdWebSocketService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StdWebSocketService.java index 26515464..1ee786f8 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StdWebSocketService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/StdWebSocketService.java @@ -46,7 +46,7 @@ public static CompletableFuture initWebSockets(String addre LogHelper.error(e); } })); - }, (error) -> future.completeExceptionally(error)); + }, future::completeExceptionally); return future; } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/VoidRequestService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/VoidRequestService.java index b45c5dc5..4d098833 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/VoidRequestService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/VoidRequestService.java @@ -25,6 +25,11 @@ public CompletableFuture request(Request reques return future; } + @Override + public void open() { + + } + @Override public void registerEventHandler(EventHandler handler) { diff --git a/LauncherAPI/src/test/java/pro/gravit/launcher/ClientVersionTest.java b/LauncherAPI/src/test/java/pro/gravit/launcher/ClientVersionTest.java index b676e662..205b495a 100644 --- a/LauncherAPI/src/test/java/pro/gravit/launcher/ClientVersionTest.java +++ b/LauncherAPI/src/test/java/pro/gravit/launcher/ClientVersionTest.java @@ -14,14 +14,14 @@ public void parseTest() { @Test public void compareTest() { - Assertions.assertTrue(ClientProfile.Version.of("1.0.0").compareTo(ClientProfile.Version.of("1.0.0")) == 0); + Assertions.assertEquals(0, ClientProfile.Version.of("1.0.0").compareTo(ClientProfile.Version.of("1.0.0"))); Assertions.assertTrue(ClientProfile.Version.of("1.1.0").compareTo(ClientProfile.Version.of("1.0.0")) > 0); Assertions.assertTrue(ClientProfile.Version.of("2.0.0").compareTo(ClientProfile.Version.of("1.0.0")) > 0); Assertions.assertTrue(ClientProfile.Version.of("1.0.0").compareTo(ClientProfile.Version.of("1.0.1")) < 0); Assertions.assertTrue(ClientProfile.Version.of("1.1.0").compareTo(ClientProfile.Version.of("1.0.0")) > 0); Assertions.assertTrue(ClientProfile.Version.of("1.0.0").compareTo(ClientProfile.Version.of("1.1.0")) < 0); - Assertions.assertTrue(ClientProfile.Version.of("1.0").compareTo(ClientProfile.Version.of("1.0.0")) == 0); - Assertions.assertTrue(ClientProfile.Version.of("1.0.0").compareTo(ClientProfile.Version.of("1.0")) == 0); + Assertions.assertEquals(0, ClientProfile.Version.of("1.0").compareTo(ClientProfile.Version.of("1.0.0"))); + Assertions.assertEquals(0, ClientProfile.Version.of("1.0.0").compareTo(ClientProfile.Version.of("1.0"))); Assertions.assertTrue(ClientProfile.Version.of("1.0.1").compareTo(ClientProfile.Version.of("1.0")) > 0); Assertions.assertTrue(ClientProfile.Version.of("1.0").compareTo(ClientProfile.Version.of("1.0.1")) < 0); Assertions.assertTrue(ClientProfile.Version.of("1.0").compareTo(ClientProfile.Version.of("1.0.1")) < 0); diff --git a/LauncherClient/build.gradle b/LauncherClient/build.gradle new file mode 100644 index 00000000..5c62ac48 --- /dev/null +++ b/LauncherClient/build.gradle @@ -0,0 +1,79 @@ +apply plugin: 'org.openjfx.javafxplugin' + +String mainClassName = "pro.gravit.launcher.ClientLauncherWrapper" +String mainAgentName = "pro.gravit.launcher.LauncherAgent" + +repositories { + maven { + url "https://repo.spring.io/plugins-release/" + } +} +sourceCompatibility = '1.8' +targetCompatibility = '1.8' + +jar { + archiveClassifier.set('clean') + manifest.attributes("Main-Class": mainClassName, + "Premain-Class": mainAgentName, + "Multi-Release": "true") +} + +tasks.register('sourcesJar', Jar) { + from sourceSets.main.allJava + archiveClassifier.set('sources') +} + +tasks.register('javadocJar', Jar) { + from javadoc + archiveClassifier.set('javadoc') +} + +dependencies { + implementation project(':LauncherAPI') +} + +publishing { + publications { + launcherclientstarter(MavenPublication) { + artifactId = 'launcher-client-starter-api' + artifact(jar) { + classifier "" + } + artifact sourcesJar + artifact javadocJar + pom { + name = 'GravitLauncher Client API' + description = 'GravitLauncher Client Module API' + url = 'https://gravitlauncher.com' + licenses { + license { + name = 'GNU General Public License, Version 3.0' + url = 'https://www.gnu.org/licenses/gpl-3.0.html' + } + } + developers { + developer { + id = 'gravita' + name = 'Gravita' + email = 'gravita@gravit.pro' + } + developer { + id = 'zaxar163' + name = 'Zaxar163' + email = 'zahar.vcherachny@yandex.ru' + } + } + scm { + connection = 'scm:git:https://github.com/GravitLauncher/Launcher.git' + developerConnection = 'scm:git:ssh://git@github.com:GravitLauncher/Launcher.git' + url = 'https://gravitlauncher.com/' + } + } + } + } +} + + +signing { + sign publishing.publications.launcherclientstarter +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/BasicLauncherEventHandler.java b/LauncherClient/src/main/java/pro/gravit/launcher/BasicLauncherEventHandler.java similarity index 89% rename from Launcher/src/main/java/pro/gravit/launcher/BasicLauncherEventHandler.java rename to LauncherClient/src/main/java/pro/gravit/launcher/BasicLauncherEventHandler.java index c02deec7..3e5e5cd2 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/BasicLauncherEventHandler.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/BasicLauncherEventHandler.java @@ -15,9 +15,7 @@ public class BasicLauncherEventHandler implements RequestService.EventHandler { public boolean eventHandle(T event) { if (event instanceof SecurityReportRequestEvent) { SecurityReportRequestEvent event1 = (SecurityReportRequestEvent) event; - if (event1.action == SecurityReportRequestEvent.ReportAction.CRASH) { - LauncherEngine.exitLauncher(80); - } else if (event1.action == SecurityReportRequestEvent.ReportAction.TOKEN_EXPIRED) { + if (event1.action == SecurityReportRequestEvent.ReportAction.TOKEN_EXPIRED) { try { Request.restore(); } catch (Exception e) { @@ -28,7 +26,7 @@ public boolean eventHandle(T event) { ExtendedTokenRequestEvent event1 = (ExtendedTokenRequestEvent) event; String token = event1.getExtendedToken(); if (token != null) { - Request.addExtendedToken(event1.getExtendedTokenName(), token); + Request.addExtendedToken(event1.getExtendedTokenName(), new Request.ExtendedToken(event1.getExtendedToken(), event1.getExtendedTokenExpire())); } } else if (event instanceof NotificationEvent) { NotificationEvent n = (NotificationEvent) event; diff --git a/LauncherClient/src/main/java/pro/gravit/launcher/ClientLauncherMethods.java b/LauncherClient/src/main/java/pro/gravit/launcher/ClientLauncherMethods.java new file mode 100644 index 00000000..3715b1e5 --- /dev/null +++ b/LauncherClient/src/main/java/pro/gravit/launcher/ClientLauncherMethods.java @@ -0,0 +1,139 @@ +package pro.gravit.launcher; + +import pro.gravit.launcher.client.ClientGsonManager; +import pro.gravit.launcher.client.ClientLauncherEntryPoint; +import pro.gravit.launcher.client.ClientModuleManager; +import pro.gravit.launcher.client.ClientParams; +import pro.gravit.launcher.client.events.ClientExitPhase; +import pro.gravit.launcher.events.request.*; +import pro.gravit.launcher.modules.LauncherModulesManager; +import pro.gravit.launcher.modules.events.OfflineModeEvent; +import pro.gravit.launcher.profiles.optional.actions.OptionalAction; +import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger; +import pro.gravit.launcher.request.RequestException; +import pro.gravit.launcher.request.RequestService; +import pro.gravit.launcher.request.auth.*; +import pro.gravit.launcher.request.auth.details.AuthLoginOnlyDetails; +import pro.gravit.launcher.request.management.FeaturesRequest; +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.uuid.ProfileByUUIDRequest; +import pro.gravit.launcher.request.uuid.ProfileByUsernameRequest; +import pro.gravit.launcher.request.websockets.OfflineRequestService; +import pro.gravit.launcher.utils.NativeJVMHalt; +import pro.gravit.utils.helper.JVMHelper; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +public class ClientLauncherMethods { + + public static void verifyNoAgent() { + if (JVMHelper.RUNTIME_MXBEAN.getInputArguments().stream().filter(e -> e != null && !e.isEmpty()).anyMatch(e -> e.contains("javaagent"))) + throw new SecurityException("JavaAgent found"); + } + + //JVMHelper.getCertificates + public static X509Certificate[] getCertificates(Class clazz) { + Object[] signers = clazz.getSigners(); + if (signers == null) return null; + return Arrays.stream(signers).filter((c) -> c instanceof X509Certificate).map((c) -> (X509Certificate) c).toArray(X509Certificate[]::new); + } + + + + public static void beforeExit(int code) { + try { + ClientLauncherEntryPoint.modulesManager.invokeEvent(new ClientExitPhase(code)); + } catch (Throwable ignored) { + } + } + + public static void forceExit(int code) { + try { + System.exit(code); + } catch (Throwable e) //Forge Security Manager? + { + NativeJVMHalt.haltA(code); + } + } + + public static void exitLauncher(int code) { + beforeExit(code); + forceExit(code); + } + + public static void checkClass(Class clazz) throws SecurityException { + LauncherTrustManager trustManager = Launcher.getConfig().trustManager; + if (trustManager == null) return; + X509Certificate[] certificates = getCertificates(clazz); + if (certificates == null) { + throw new SecurityException(String.format("Class %s not signed", clazz.getName())); + } + try { + trustManager.checkCertificatesSuccess(certificates, trustManager::stdCertificateChecker); + } catch (Exception e) { + throw new SecurityException(e); + } + } + + public static void initGson(ClientModuleManager moduleManager) { + AuthRequest.registerProviders(); + GetAvailabilityAuthRequest.registerProviders(); + OptionalAction.registerProviders(); + OptionalTrigger.registerProviders(); + Launcher.gsonManager = new ClientGsonManager(moduleManager); + Launcher.gsonManager.initGson(); + } + + public static RequestService initOffline(LauncherModulesManager modulesManager, ClientParams params) { + OfflineRequestService service = new OfflineRequestService(); + applyBasicOfflineProcessors(service); + applyClientOfflineProcessors(service, params); + OfflineModeEvent event = new OfflineModeEvent(service); + modulesManager.invokeEvent(event); + return event.service; + } + + public static void applyClientOfflineProcessors(OfflineRequestService service, ClientParams params) { + service.registerRequestProcessor(ProfileByUsernameRequest.class, (r) -> { + if (params.playerProfile.username.equals(r.username)) { + return new ProfileByUsernameRequestEvent(params.playerProfile); + } + throw new RequestException("User not found"); + }); + service.registerRequestProcessor(ProfileByUUIDRequest.class, (r) -> { + if (params.playerProfile.uuid.equals(r.uuid)) { + return new ProfileByUUIDRequestEvent(params.playerProfile); + } + throw new RequestException("User not found"); + }); + } + + + + public static void applyBasicOfflineProcessors(OfflineRequestService service) { + service.registerRequestProcessor(LauncherRequest.class, (r) -> new LauncherRequestEvent(false, (String) null)); + service.registerRequestProcessor(CheckServerRequest.class, (r) -> { + throw new RequestException("CheckServer disabled in offline mode"); + }); + service.registerRequestProcessor(GetAvailabilityAuthRequest.class, (r) -> { + List details = new ArrayList<>(); + details.add(new AuthLoginOnlyDetails()); + GetAvailabilityAuthRequestEvent.AuthAvailability authAvailability = new GetAvailabilityAuthRequestEvent.AuthAvailability(details, "offline", "Offline Mode", true, new HashSet<>()); + List list = new ArrayList<>(1); + list.add(authAvailability); + return new GetAvailabilityAuthRequestEvent(list); + }); + service.registerRequestProcessor(JoinServerRequest.class, (r) -> new JoinServerRequestEvent(false)); + service.registerRequestProcessor(ExitRequest.class, (r) -> new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT)); + service.registerRequestProcessor(SetProfileRequest.class, (r) -> new SetProfileRequestEvent(null)); + service.registerRequestProcessor(FeaturesRequest.class, (r) -> new FeaturesRequestEvent()); + service.registerRequestProcessor(GetSecureLevelInfoRequest.class, (r) -> new GetSecureLevelInfoRequestEvent(null, false)); + service.registerRequestProcessor(SecurityReportRequest.class, (r) -> new SecurityReportRequestEvent(SecurityReportRequestEvent.ReportAction.NONE)); + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java b/LauncherClient/src/main/java/pro/gravit/launcher/LauncherAgent.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/LauncherAgent.java rename to LauncherClient/src/main/java/pro/gravit/launcher/LauncherAgent.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/api/AuthService.java b/LauncherClient/src/main/java/pro/gravit/launcher/api/AuthService.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/api/AuthService.java rename to LauncherClient/src/main/java/pro/gravit/launcher/api/AuthService.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/api/CertificateService.java b/LauncherClient/src/main/java/pro/gravit/launcher/api/CertificateService.java similarity index 93% rename from Launcher/src/main/java/pro/gravit/launcher/api/CertificateService.java rename to LauncherClient/src/main/java/pro/gravit/launcher/api/CertificateService.java index 4bf651fd..b21cb0b5 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/api/CertificateService.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/api/CertificateService.java @@ -1,19 +1,18 @@ package pro.gravit.launcher.api; +import pro.gravit.launcher.ClientLauncherMethods; import pro.gravit.launcher.LauncherTrustManager; import pro.gravit.launcher.utils.ApiBridgeService; import java.security.cert.X509Certificate; -import static pro.gravit.launcher.LauncherEngine.getCertificates; - public class CertificateService { private CertificateService() { throw new UnsupportedOperationException(); } public static CheckClassResultApi checkClass(Class clazz) throws SecurityException { - X509Certificate[] certificates = getCertificates(clazz); + X509Certificate[] certificates = ClientLauncherMethods.getCertificates(clazz); if (certificates == null) { return new CheckClassResultApi(CheckClassResultTypeApi.NOT_SIGNED, null, null); } @@ -25,7 +24,7 @@ public static CheckClassResultApi checkClass(Class clazz) throws SecurityExce } public static void checkClassSuccess(Class clazz) { - X509Certificate[] certificates = getCertificates(clazz); + X509Certificate[] certificates = ClientLauncherMethods.getCertificates(clazz); if (certificates == null) { throw new SecurityException(String.format("Class %s not signed", clazz.getName())); } diff --git a/Launcher/src/main/java/pro/gravit/launcher/api/ClientService.java b/LauncherClient/src/main/java/pro/gravit/launcher/api/ClientService.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/api/ClientService.java rename to LauncherClient/src/main/java/pro/gravit/launcher/api/ClientService.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/api/DialogService.java b/LauncherClient/src/main/java/pro/gravit/launcher/api/DialogService.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/api/DialogService.java rename to LauncherClient/src/main/java/pro/gravit/launcher/api/DialogService.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/api/SystemService.java b/LauncherClient/src/main/java/pro/gravit/launcher/api/SystemService.java similarity index 66% rename from Launcher/src/main/java/pro/gravit/launcher/api/SystemService.java rename to LauncherClient/src/main/java/pro/gravit/launcher/api/SystemService.java index dfdd74b3..9d8aed49 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/api/SystemService.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/api/SystemService.java @@ -1,6 +1,6 @@ package pro.gravit.launcher.api; -import pro.gravit.launcher.LauncherEngine; +import pro.gravit.launcher.ClientLauncherMethods; public class SystemService { private SystemService() { @@ -8,6 +8,6 @@ private SystemService() { } public static void exit(int code) { - LauncherEngine.exitLauncher(code); + ClientLauncherMethods.exitLauncher(code); } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientClassLoader.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientClassLoader.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/client/ClientClassLoader.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/ClientClassLoader.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/managers/ClientGsonManager.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientGsonManager.java similarity index 68% rename from Launcher/src/main/java/pro/gravit/launcher/managers/ClientGsonManager.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/ClientGsonManager.java index ef917aae..bcd99ccc 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/managers/ClientGsonManager.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientGsonManager.java @@ -1,11 +1,9 @@ -package pro.gravit.launcher.managers; +package pro.gravit.launcher.client; import com.google.gson.GsonBuilder; -import pro.gravit.launcher.client.ClientModuleManager; -import pro.gravit.launcher.client.UserSettings; +import pro.gravit.launcher.managers.GsonManager; import pro.gravit.launcher.modules.events.PreGsonPhase; import pro.gravit.launcher.request.websockets.ClientWebSocketService; -import pro.gravit.utils.UniversalJsonAdapter; public class ClientGsonManager extends GsonManager { private final ClientModuleManager moduleManager; @@ -17,7 +15,6 @@ public ClientGsonManager(ClientModuleManager moduleManager) { @Override public void registerAdapters(GsonBuilder builder) { super.registerAdapters(builder); - builder.registerTypeAdapter(UserSettings.class, new UniversalJsonAdapter<>(UserSettings.providers)); ClientWebSocketService.appendTypeAdapters(builder); moduleManager.invokeEvent(new PreGsonPhase(builder)); } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherCoreModule.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherCoreModule.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherCoreModule.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherCoreModule.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java similarity index 76% rename from Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java index 285e94a2..41bc3ab7 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java @@ -5,30 +5,18 @@ 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.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedEntry; -import pro.gravit.launcher.managers.ClientGsonManager; -import pro.gravit.launcher.managers.ConsoleManager; -import pro.gravit.launcher.modules.LauncherModulesManager; -import pro.gravit.launcher.modules.events.OfflineModeEvent; import pro.gravit.launcher.modules.events.PreConfigPhase; import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.profiles.ClientProfileVersions; import pro.gravit.launcher.profiles.optional.actions.OptionalAction; import pro.gravit.launcher.profiles.optional.actions.OptionalActionClassPath; import pro.gravit.launcher.profiles.optional.actions.OptionalActionClientArgs; -import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger; import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.RequestException; 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.ProfileByUUIDRequest; -import pro.gravit.launcher.request.uuid.ProfileByUsernameRequest; -import pro.gravit.launcher.request.websockets.OfflineRequestService; import pro.gravit.launcher.request.websockets.StdWebSocketService; import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.utils.DirWatcher; @@ -52,13 +40,15 @@ public class ClientLauncherEntryPoint { private static ClassLoader classLoader; + public static ClientModuleManager modulesManager; + public static ClientParams clientParams; - private static ClientLauncherProcess.ClientParams readParams(SocketAddress address) throws IOException { + private static ClientParams readParams(SocketAddress address) throws IOException { try (Socket socket = IOHelper.newSocket()) { socket.connect(address); try (HInput input = new HInput(socket.getInputStream())) { byte[] serialized = input.readByteArray(0); - ClientLauncherProcess.ClientParams params = Launcher.gsonManager.gson.fromJson(IOHelper.decode(serialized), ClientLauncherProcess.ClientParams.class); + ClientParams params = Launcher.gsonManager.gson.fromJson(IOHelper.decode(serialized), ClientParams.class); params.clientHDir = new HashedDir(input); params.assetHDir = new HashedDir(input); boolean isNeedReadJavaDir = input.readBoolean(); @@ -70,31 +60,26 @@ private static ClientLauncherProcess.ClientParams readParams(SocketAddress addre } public static void main(String[] args) throws Throwable { - LauncherEngine engine = LauncherEngine.clientInstance(); JVMHelper.verifySystemProperties(ClientLauncherEntryPoint.class, true); EnvHelper.checkDangerousParams(); JVMHelper.checkStackTrace(ClientLauncherEntryPoint.class); LogHelper.printVersion("Client Launcher"); - LauncherEngine.checkClass(LauncherEngine.class); - LauncherEngine.checkClass(LauncherAgent.class); - LauncherEngine.checkClass(ClientLauncherEntryPoint.class); - LauncherEngine.modulesManager = new ClientModuleManager(); - LauncherEngine.modulesManager.loadModule(new ClientLauncherCoreModule()); - LauncherConfig.initModules(LauncherEngine.modulesManager); //INIT - LauncherEngine.modulesManager.initModules(null); - initGson(LauncherEngine.modulesManager); - ConsoleManager.initConsole(); - LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase()); - engine.readKeys(); + ClientLauncherMethods.checkClass(ClientLauncherEntryPoint.class); + modulesManager = new ClientModuleManager(); + modulesManager.loadModule(new ClientLauncherCoreModule()); + LauncherConfig.initModules(modulesManager); //INIT + modulesManager.initModules(null); + ClientLauncherMethods.initGson(modulesManager); + modulesManager.invokeEvent(new PreConfigPhase()); LogHelper.debug("Reading ClientLauncher params"); - ClientLauncherProcess.ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort)); + ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort)); if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) { - LauncherEngine.verifyNoAgent(); + ClientLauncherMethods.verifyNoAgent(); } ClientProfile profile = params.profile; Launcher.profile = profile; AuthService.profile = profile; - LauncherEngine.clientParams = params; + clientParams = params; if (params.oauth != null) { LogHelper.info("Using OAuth"); if (params.oauthExpiredTime != 0) { @@ -108,7 +93,7 @@ public static void main(String[] args) throws Throwable { } else if (params.session != null) { throw new UnsupportedOperationException("Legacy session not supported"); } - LauncherEngine.modulesManager.invokeEvent(new ClientProcessInitPhase(engine, params)); + modulesManager.invokeEvent(new ClientProcessInitPhase(params)); Path clientDir = Paths.get(params.clientDir); Path assetDir = Paths.get(params.assetDir); @@ -122,7 +107,7 @@ public static void main(String[] args) throws Throwable { // Start client with WatchService monitoring RequestService service; if (params.offlineMode) { - service = initOffline(LauncherEngine.modulesManager, params); + service = ClientLauncherMethods.initOffline(modulesManager, params); Request.setRequestService(service); } else { service = StdWebSocketService.initWebSockets(Launcher.getConfig().address).get(); @@ -149,7 +134,7 @@ public static void main(String[] args) throws Throwable { ClientLauncherEntryPoint.classLoader = classLoader; Thread.currentThread().setContextClassLoader(classLoader); classLoader.nativePath = params.nativesDir; - LauncherEngine.modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(engine, classLoader, profile)); + modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(classLoader, profile)); ClientService.classLoader = classLoader; ClientService.nativePath = classLoader.nativePath; classLoader.addURL(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL()); @@ -162,7 +147,7 @@ public static void main(String[] args) throws Throwable { } ClientService.instrumentation = LauncherAgent.inst; ClientService.nativePath = params.nativesDir; - LauncherEngine.modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(engine, classLoader, profile)); + modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(classLoader, profile)); ClientService.classLoader = classLoader; ClientService.baseURLs = classpathURLs.toArray(new URL[0]); } else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) { @@ -174,7 +159,7 @@ public static void main(String[] args) throws Throwable { AuthService.username = params.playerProfile.username; AuthService.uuid = params.playerProfile.uuid; KeyService.serverRsaPublicKey = Launcher.getConfig().rsaPublicKey; - LauncherEngine.modulesManager.invokeEvent(new ClientProcessReadyEvent(engine, params)); + modulesManager.invokeEvent(new ClientProcessReadyEvent(params)); LogHelper.debug("Starting JVM and client WatchService"); FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher(); FileNameMatcher clientMatcher = profile.getClientUpdateMatcher(); @@ -197,44 +182,11 @@ public static void main(String[] args) throws Throwable { verifyHDir(clientDir, params.clientHDir, clientMatcher, false, true); if (javaWatcher != null) verifyHDir(javaDir, params.javaHDir, null, false, true); - LauncherEngine.modulesManager.invokeEvent(new ClientProcessLaunchEvent(engine, params)); + modulesManager.invokeEvent(new ClientProcessLaunchEvent(params)); launch(profile, params); } } - private static void initGson(ClientModuleManager moduleManager) { - AuthRequest.registerProviders(); - GetAvailabilityAuthRequest.registerProviders(); - OptionalAction.registerProviders(); - OptionalTrigger.registerProviders(); - Launcher.gsonManager = new ClientGsonManager(moduleManager); - Launcher.gsonManager.initGson(); - } - - public static RequestService initOffline(LauncherModulesManager modulesManager, ClientLauncherProcess.ClientParams params) { - OfflineRequestService service = new OfflineRequestService(); - LauncherEngine.applyBasicOfflineProcessors(service); - applyClientOfflineProcessors(service, params); - OfflineModeEvent event = new OfflineModeEvent(service); - modulesManager.invokeEvent(event); - return event.service; - } - - public static void applyClientOfflineProcessors(OfflineRequestService service, ClientLauncherProcess.ClientParams params) { - service.registerRequestProcessor(ProfileByUsernameRequest.class, (r) -> { - if (params.playerProfile.username.equals(r.username)) { - return new ProfileByUsernameRequestEvent(params.playerProfile); - } - throw new RequestException("User not found"); - }); - service.registerRequestProcessor(ProfileByUUIDRequest.class, (r) -> { - if (params.playerProfile.uuid.equals(r.uuid)) { - return new ProfileByUUIDRequestEvent(params.playerProfile); - } - throw new RequestException("User not found"); - }); - } - public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest, boolean checkExtra) throws IOException { //if (matcher != null) // matcher = matcher.verifyOnly(); @@ -288,7 +240,7 @@ public static Stream resolveClassPath(Path clientDir, Set return result; } - private static void launch(ClientProfile profile, ClientLauncherProcess.ClientParams params) throws Throwable { + private static void launch(ClientProfile profile, ClientParams params) throws Throwable { // Add client args Collection args = new LinkedList<>(); if (profile.getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_6_4) >= 0) @@ -318,7 +270,7 @@ private static void launch(ClientProfile profile, ClientLauncherProcess.ClientPa LogHelper.dev("ClassLoader URL: %s", u.toString()); } } - LauncherEngine.modulesManager.invokeEvent(new ClientProcessPreInvokeMainClassEvent(params, profile, args)); + modulesManager.invokeEvent(new ClientProcessPreInvokeMainClassEvent(params, profile, args)); // Invoke main method try { { @@ -338,7 +290,7 @@ private static void launch(ClientProfile profile, ClientLauncherProcess.ClientPa LogHelper.error(e); throw e; } finally { - LauncherEngine.exitLauncher(0); + ClientLauncherMethods.exitLauncher(0); } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java similarity index 76% rename from Launcher/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java index 62df10ca..648685e7 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientModuleManager.java @@ -1,6 +1,5 @@ package pro.gravit.launcher.client; -import pro.gravit.launcher.ClientLauncherWrapper; import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherTrustManager; import pro.gravit.launcher.modules.LauncherModule; @@ -38,12 +37,4 @@ public List getModules() { public final boolean verifyClassCheckResult(LauncherTrustManager.CheckClassResult result) { return result.type == LauncherTrustManager.CheckClassResultType.SUCCESS; } - - public void callWrapper(ClientLauncherWrapper.ClientLauncherWrapperContext context) { - for (LauncherModule module : modules) { - if (module instanceof ClientWrapperModule) { - ((ClientWrapperModule) module).wrapperPhase(context); - } - } - } } diff --git a/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientParams.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientParams.java new file mode 100644 index 00000000..d464dfba --- /dev/null +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientParams.java @@ -0,0 +1,135 @@ +package pro.gravit.launcher.client; + +import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.events.request.AuthRequestEvent; +import pro.gravit.launcher.hasher.HashedDir; +import pro.gravit.launcher.profiles.ClientProfile; +import pro.gravit.launcher.profiles.ClientProfileVersions; +import pro.gravit.launcher.profiles.PlayerProfile; +import pro.gravit.launcher.profiles.optional.actions.OptionalAction; +import pro.gravit.launcher.profiles.optional.actions.OptionalActionClientArgs; +import pro.gravit.launcher.request.Request; +import pro.gravit.utils.Version; + +import java.util.*; + +public class ClientParams { + public String assetDir; + + public String clientDir; + + public String resourcePackDir; + + public String nativesDir; + + // Client params + + public PlayerProfile playerProfile; + + public ClientProfile profile; + + public String accessToken; + + //==Minecraft params== + + public boolean autoEnter; + + public boolean fullScreen; + + public int ram; + + public int width; + + public int height; + + public Set actions = new HashSet<>(); + + //======== + + public UUID session; + + public AuthRequestEvent.OAuthRequestEvent oauth; + + public String authId; + + public long oauthExpiredTime; + + public Map extendedTokens; + + public boolean offlineMode; + + public transient HashedDir assetHDir; + + public transient HashedDir clientHDir; + + public transient HashedDir javaHDir; + + public void addClientArgs(Collection args) { + if (profile.getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_6_4) >= 0) + addModernClientArgs(args); + else + addClientLegacyArgs(args); + } + + public void addClientLegacyArgs(Collection args) { + args.add(playerProfile.username); + args.add(accessToken); + + // Add args for tweaker + Collections.addAll(args, "--version", profile.getVersion().toString()); + Collections.addAll(args, "--gameDir", clientDir); + Collections.addAll(args, "--assetsDir", assetDir); + } + + private void addModernClientArgs(Collection args) { + + // Add version-dependent args + ClientProfile.Version version = profile.getVersion(); + Collections.addAll(args, "--username", playerProfile.username); + if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_2) >= 0) { + Collections.addAll(args, "--uuid", Launcher.toHash(playerProfile.uuid)); + Collections.addAll(args, "--accessToken", accessToken); + + // Add 1.7.10+ args (user properties, asset index) + if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) >= 0) { + // Add user properties + Collections.addAll(args, "--userType", "mojang"); + Collections.addAll(args, "--userProperties", "{}"); + + // Add asset index + Collections.addAll(args, "--assetIndex", profile.getAssetIndex()); + } + } else + Collections.addAll(args, "--session", accessToken); + + // Add version and dirs args + Collections.addAll(args, "--version", profile.getVersion().toString()); + Collections.addAll(args, "--gameDir", clientDir); + Collections.addAll(args, "--assetsDir", assetDir); + Collections.addAll(args, "--resourcePackDir", resourcePackDir); + if (version.compareTo(ClientProfileVersions.MINECRAFT_1_9_4) >= 0) + Collections.addAll(args, "--versionType", "Launcher v" + Version.getVersion().getVersionString()); + + // Add server args + if (autoEnter) { + if (version.compareTo(ClientProfileVersions.MINECRAFT_1_20) <= 0) { + Collections.addAll(args, "--server", profile.getServerAddress()); + Collections.addAll(args, "--port", Integer.toString(profile.getServerPort())); + } else { + Collections.addAll(args, "--quickPlayMultiplayer", String.format("%s:%d", profile.getServerAddress(), profile.getServerPort())); + } + } + for (OptionalAction a : actions) { + if (a instanceof OptionalActionClientArgs) { + args.addAll(((OptionalActionClientArgs) a).args); + } + } + // Add window size args + if (fullScreen) + Collections.addAll(args, "--fullscreen", Boolean.toString(true)); + if (width > 0 && height > 0) { + Collections.addAll(args, "--width", Integer.toString(width)); + Collections.addAll(args, "--height", Integer.toString(height)); + } + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/DirBridge.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/DirBridge.java similarity index 81% rename from Launcher/src/main/java/pro/gravit/launcher/client/DirBridge.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/DirBridge.java index 348815e5..397c056d 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/DirBridge.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/DirBridge.java @@ -19,10 +19,6 @@ public class DirBridge { public static Path dir; - public static Path dirStore; - - public static Path dirProjectStore; - public static Path dirUpdates; public static Path defaultUpdatesDir; @@ -36,10 +32,6 @@ public class DirBridge { if (!IOHelper.exists(DirBridge.dir)) Files.createDirectories(DirBridge.dir); DirBridge.defaultUpdatesDir = DirBridge.dir.resolve("updates"); if (!IOHelper.exists(DirBridge.defaultUpdatesDir)) Files.createDirectories(DirBridge.defaultUpdatesDir); - DirBridge.dirStore = getStoreDir(projectName); - if (!IOHelper.exists(DirBridge.dirStore)) Files.createDirectories(DirBridge.dirStore); - DirBridge.dirProjectStore = getProjectStoreDir(projectName); - if (!IOHelper.exists(DirBridge.dirProjectStore)) Files.createDirectories(DirBridge.dirProjectStore); } catch (IOException e) { LogHelper.error(e); } @@ -95,19 +87,6 @@ public static Path getLauncherDir(String projectname) throws IOException { return getAppDataDir().resolve(projectname); } - public static Path getStoreDir(String projectname) throws IOException { - if (JVMHelper.OS_TYPE == JVMHelper.OS.LINUX) - return getAppDataDir().resolve("store"); - else if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) - return getAppDataDir().resolve("GravitLauncherStore"); - else - return getAppDataDir().resolve("minecraftStore"); - } - - public static Path getProjectStoreDir(String projectname) throws IOException { - return getStoreDir(projectname).resolve(projectname); - } - public static Path getGuardDir() { return dir.resolve("guard"); } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/events/ClientExitPhase.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/ClientExitPhase.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/client/events/ClientExitPhase.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/events/ClientExitPhase.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessClassLoaderEvent.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessClassLoaderEvent.java similarity index 60% rename from Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessClassLoaderEvent.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessClassLoaderEvent.java index 3cffc0aa..9a97c1e7 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessClassLoaderEvent.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessClassLoaderEvent.java @@ -1,16 +1,13 @@ package pro.gravit.launcher.client.events.client; -import pro.gravit.launcher.LauncherEngine; import pro.gravit.launcher.modules.LauncherModule; import pro.gravit.launcher.profiles.ClientProfile; public class ClientProcessClassLoaderEvent extends LauncherModule.Event { - public final LauncherEngine clientInstance; public final ClassLoader clientClassLoader; public final ClientProfile profile; - public ClientProcessClassLoaderEvent(LauncherEngine clientInstance, ClassLoader clientClassLoader, ClientProfile profile) { - this.clientInstance = clientInstance; + public ClientProcessClassLoaderEvent(ClassLoader clientClassLoader, ClientProfile profile) { this.clientClassLoader = clientClassLoader; this.profile = profile; } diff --git a/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessInitPhase.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessInitPhase.java new file mode 100644 index 00000000..613d696f --- /dev/null +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessInitPhase.java @@ -0,0 +1,12 @@ +package pro.gravit.launcher.client.events.client; + +import pro.gravit.launcher.client.ClientParams; +import pro.gravit.launcher.modules.events.InitPhase; + +public class ClientProcessInitPhase extends InitPhase { + public final ClientParams params; + + public ClientProcessInitPhase(ClientParams params) { + this.params = params; + } +} diff --git a/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessLaunchEvent.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessLaunchEvent.java new file mode 100644 index 00000000..c43a9c5c --- /dev/null +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessLaunchEvent.java @@ -0,0 +1,12 @@ +package pro.gravit.launcher.client.events.client; + +import pro.gravit.launcher.client.ClientParams; +import pro.gravit.launcher.modules.LauncherModule; + +public class ClientProcessLaunchEvent extends LauncherModule.Event { + public final ClientParams params; + + public ClientProcessLaunchEvent(ClientParams params) { + this.params = params; + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessPreInvokeMainClassEvent.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessPreInvokeMainClassEvent.java similarity index 63% rename from Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessPreInvokeMainClassEvent.java rename to LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessPreInvokeMainClassEvent.java index 0ac25094..731f2c84 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessPreInvokeMainClassEvent.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessPreInvokeMainClassEvent.java @@ -1,17 +1,17 @@ package pro.gravit.launcher.client.events.client; -import pro.gravit.launcher.client.ClientLauncherProcess; +import pro.gravit.launcher.client.ClientParams; import pro.gravit.launcher.modules.LauncherModule; import pro.gravit.launcher.profiles.ClientProfile; import java.util.Collection; public class ClientProcessPreInvokeMainClassEvent extends LauncherModule.Event { - public final ClientLauncherProcess.ClientParams params; + public final ClientParams params; public final ClientProfile profile; public final Collection args; - public ClientProcessPreInvokeMainClassEvent(ClientLauncherProcess.ClientParams params, ClientProfile profile, Collection args) { + public ClientProcessPreInvokeMainClassEvent(ClientParams params, ClientProfile profile, Collection args) { this.params = params; this.profile = profile; this.args = args; diff --git a/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessReadyEvent.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessReadyEvent.java new file mode 100644 index 00000000..574814a6 --- /dev/null +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/events/client/ClientProcessReadyEvent.java @@ -0,0 +1,12 @@ +package pro.gravit.launcher.client.events.client; + +import pro.gravit.launcher.client.ClientParams; +import pro.gravit.launcher.modules.events.PostInitPhase; + +public class ClientProcessReadyEvent extends PostInitPhase { + public final ClientParams params; + + public ClientProcessReadyEvent(ClientParams params) { + this.params = params; + } +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java b/LauncherClient/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java rename to LauncherClient/src/main/java/pro/gravit/launcher/utils/ApiBridgeService.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/utils/DirWatcher.java b/LauncherClient/src/main/java/pro/gravit/launcher/utils/DirWatcher.java similarity index 97% rename from Launcher/src/main/java/pro/gravit/launcher/utils/DirWatcher.java rename to LauncherClient/src/main/java/pro/gravit/launcher/utils/DirWatcher.java index 84107d9b..1ee0949b 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/utils/DirWatcher.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/utils/DirWatcher.java @@ -1,6 +1,6 @@ package pro.gravit.launcher.utils; -import pro.gravit.launcher.LauncherEngine; +import pro.gravit.launcher.ClientLauncherMethods; import pro.gravit.launcher.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedEntry; @@ -47,7 +47,7 @@ public DirWatcher(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean dig private static void handleError(Throwable e) { LogHelper.error(e); - LauncherEngine.exitLauncher(-123); + ClientLauncherMethods.exitLauncher(-123); } private static Deque toPath(Iterable path) { diff --git a/Launcher/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java b/LauncherClient/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java similarity index 100% rename from Launcher/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java rename to LauncherClient/src/main/java/pro/gravit/launcher/utils/NativeJVMHalt.java diff --git a/LauncherCore/build.gradle b/LauncherCore/build.gradle index e8401182..86420ba1 100644 --- a/LauncherCore/build.gradle +++ b/LauncherCore/build.gradle @@ -37,6 +37,7 @@ java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compile from sourceSets.java11.output } archiveClassifier.set('clean') + manifest.attributes("Multi-Release": "true") } compileJava11Java { sourceCompatibility = 11 diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/AsyncDownloader.java b/LauncherCore/src/main/java/pro/gravit/launcher/AsyncDownloader.java deleted file mode 100644 index 2c495419..00000000 --- a/LauncherCore/src/main/java/pro/gravit/launcher/AsyncDownloader.java +++ /dev/null @@ -1,213 +0,0 @@ -package pro.gravit.launcher; - -import pro.gravit.utils.helper.IOHelper; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Path; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.Executor; - -public class AsyncDownloader { - public static final Callback IGNORE = (ignored) -> { - }; - @LauncherInject("launcher.certificatePinning") - private static boolean isCertificatePinning; - private static volatile SSLSocketFactory sslSocketFactory; - private static volatile SSLContext sslContext; - public final Callback callback; - public volatile boolean isClosed; - - public AsyncDownloader(Callback callback) { - this.callback = callback; - } - - public AsyncDownloader() { - callback = IGNORE; - } - - public static SSLSocketFactory makeSSLSocketFactory() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException { - if (sslSocketFactory != null) return sslSocketFactory; - SSLContext sslContext = makeSSLContext(); - sslSocketFactory = sslContext.getSocketFactory(); - return sslSocketFactory; - } - - public static SSLContext makeSSLContext() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException { - if (sslContext != null) return sslContext; - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, CertificatePinningTrustManager.getTrustManager().getTrustManagers(), new SecureRandom()); - return sslContext; - } - - public void downloadFile(URL url, Path target, long size) throws IOException { - if (isClosed) throw new IOException("Download interrupted"); - URLConnection connection = url.openConnection(); - if (isCertificatePinning) { - HttpsURLConnection connection1 = (HttpsURLConnection) connection; - try { - connection1.setSSLSocketFactory(makeSSLSocketFactory()); - } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | KeyManagementException e) { - throw new IOException(e); - } - } - try (InputStream input = connection.getInputStream()) { - transfer(input, target, size); - } - } - - public void downloadFile(URL url, Path target) throws IOException { - URLConnection connection = url.openConnection(); - if (isCertificatePinning) { - HttpsURLConnection connection1 = (HttpsURLConnection) connection; - try { - connection1.setSSLSocketFactory(makeSSLSocketFactory()); - } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | KeyManagementException e) { - throw new IOException(e); - } - } - try (InputStream input = connection.getInputStream()) { - IOHelper.transfer(input, target); - } - } - - public void downloadListInOneThread(List files, String baseURL, Path targetDir) throws URISyntaxException, IOException { - URI baseUri = new URI(baseURL); - String scheme = baseUri.getScheme(); - String host = baseUri.getHost(); - int port = baseUri.getPort(); - if (port != -1) - host = host + ":" + port; - String path = baseUri.getPath(); - for (AsyncDownloader.SizedFile currentFile : files) { - URL url = new URI(scheme, host, path + currentFile.urlPath, "", "").toURL(); - downloadFile(url, targetDir.resolve(currentFile.filePath), currentFile.size); - } - } - - public void downloadListInOneThreadSimple(List files, String baseURL, Path targetDir) throws IOException { - - for (AsyncDownloader.SizedFile currentFile : files) { - downloadFile(new URL(baseURL + currentFile.urlPath), targetDir.resolve(currentFile.filePath), currentFile.size); - } - } - - public List> sortFiles(List files, int threads) { - files.sort(Comparator.comparingLong((f) -> -f.size)); - List> result = new ArrayList<>(); - for (int i = 0; i < threads; ++i) result.add(new LinkedList<>()); - long[] sizes = new long[threads]; - Arrays.fill(sizes, 0); - for (SizedFile file : files) { - long min = Long.MAX_VALUE; - int minIndex = 0; - for (int i = 0; i < threads; ++i) - if (sizes[i] < min) { - min = sizes[i]; - minIndex = i; - } - result.get(minIndex).add(file); - sizes[minIndex] += file.size; - } - for (List list : result) { - Collections.shuffle(list); - } - return result; - } - - @SuppressWarnings("rawtypes") - public CompletableFuture[] runDownloadList(List> files, String baseURL, Path targetDir, Executor executor) { - int threads = files.size(); - CompletableFuture[] futures = new CompletableFuture[threads]; - for (int i = 0; i < threads; ++i) { - List currentTasks = files.get(i); - futures[i] = CompletableFuture.runAsync(() -> { - try { - downloadListInOneThread(currentTasks, baseURL, targetDir); - } catch (URISyntaxException | IOException e) { - throw new CompletionException(e); - } - }, executor); - } - return futures; - } - - @SuppressWarnings("rawtypes") - public CompletableFuture[] runDownloadListSimple(List> files, String baseURL, Path targetDir, Executor executor) { - int threads = files.size(); - CompletableFuture[] futures = new CompletableFuture[threads]; - for (int i = 0; i < threads; ++i) { - List currentTasks = files.get(i); - futures[i] = CompletableFuture.runAsync(() -> { - try { - downloadListInOneThreadSimple(currentTasks, baseURL, targetDir); - } catch (IOException e) { - throw new CompletionException(e); - } - }, executor); - } - return futures; - } - - public void transfer(InputStream input, Path file, long size) throws IOException { - try (OutputStream fileOutput = IOHelper.newOutput(file)) { - long downloaded = 0L; - - // Download with digest update - byte[] bytes = IOHelper.newBuffer(); - while (downloaded < size) { - if (isClosed) throw new IOException("Download interrupted"); - int remaining = (int) Math.min(size - downloaded, bytes.length); - int length = input.read(bytes, 0, remaining); - if (length < 0) - throw new EOFException(String.format("%d bytes remaining", size - downloaded)); - - // Update file - fileOutput.write(bytes, 0, length); - - // Update state - downloaded += length; - //totalDownloaded += length; - callback.update(length); - } - } - } - - @FunctionalInterface - public interface Callback { - void update(long diff); - } - - public static class SizedFile { - public final String urlPath, filePath; - public final long size; - - public SizedFile(String path, long size) { - this.urlPath = path; - this.filePath = path; - this.size = size; - } - - public SizedFile(String urlPath, String filePath, long size) { - this.urlPath = urlPath; - this.filePath = filePath; - this.size = size; - } - } -} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/HTTPRequest.java b/LauncherCore/src/main/java/pro/gravit/launcher/HTTPRequest.java deleted file mode 100644 index d33adae1..00000000 --- a/LauncherCore/src/main/java/pro/gravit/launcher/HTTPRequest.java +++ /dev/null @@ -1,57 +0,0 @@ -package pro.gravit.launcher; - -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import pro.gravit.utils.helper.LogHelper; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; - -public final class HTTPRequest { - private static final int TIMEOUT = 10000; - - private HTTPRequest() { - } - - 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); - if (request != null) connection.setDoOutput(true); - connection.setRequestMethod(method); - if (request != null) connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); - if (request != null) connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36"); - connection.setRequestProperty("Accept", "application/json"); - if (TIMEOUT > 0) - connection.setConnectTimeout(TIMEOUT); - 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(); - - if (200 <= statusCode && statusCode < 300) - reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8); - else - reader = new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8); - try { - return JsonParser.parseReader(reader); - } catch (Exception e) { - if (200 > statusCode || statusCode > 300) { - LogHelper.error("JsonRequest failed. Server response code %d", statusCode); - throw new IOException(e); - } - return null; - } - } -} diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Downloader.java b/LauncherCore/src/main/java/pro/gravit/utils/Downloader.java deleted file mode 100644 index 39cec8f0..00000000 --- a/LauncherCore/src/main/java/pro/gravit/utils/Downloader.java +++ /dev/null @@ -1,62 +0,0 @@ -package pro.gravit.utils; - -import pro.gravit.launcher.AsyncDownloader; -import pro.gravit.utils.helper.LogHelper; - -import java.nio.file.Path; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class Downloader { - private final CompletableFuture future; - private final AsyncDownloader asyncDownloader; - private Downloader(CompletableFuture future, AsyncDownloader downloader) { - this.future = future; - this.asyncDownloader = downloader; - } - - public static Downloader downloadList(List files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) { - final boolean closeExecutor; - LogHelper.info("Download with legacy mode"); - if (executor == null) { - executor = Executors.newWorkStealingPool(4); - closeExecutor = true; - } else { - closeExecutor = false; - } - AsyncDownloader asyncDownloader = new AsyncDownloader((diff) -> { - if (callback != null) { - callback.apply(diff); - } - }); - List> list = asyncDownloader.sortFiles(files, threads); - CompletableFuture future = CompletableFuture.allOf(asyncDownloader.runDownloadList(list, baseURL, targetDir, executor)); - - ExecutorService finalExecutor = executor; - return new Downloader(future.thenAccept(e -> { - if (closeExecutor) { - finalExecutor.shutdownNow(); - } - }), asyncDownloader); - } - - public CompletableFuture getFuture() { - return future; - } - - public void cancel() { - this.asyncDownloader.isClosed = true; - } - - public boolean isCanceled() { - return this.asyncDownloader.isClosed; - } - - public interface DownloadCallback { - void apply(long fullDiff); - - void onComplete(Path path); - } -} diff --git a/LauncherCore/src/main/java/pro/gravit/utils/HttpDownloader.java b/LauncherCore/src/main/java/pro/gravit/utils/HttpDownloader.java deleted file mode 100644 index 6a606f8d..00000000 --- a/LauncherCore/src/main/java/pro/gravit/utils/HttpDownloader.java +++ /dev/null @@ -1,76 +0,0 @@ -package pro.gravit.utils; - -import pro.gravit.utils.helper.IOHelper; -import pro.gravit.utils.helper.LogHelper; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -public final class HttpDownloader { - public static final int INTERVAL = 500; - public final AtomicInteger writed; - public final Thread thread; - private volatile String filename; - - public HttpDownloader(URL url, Path file) { - writed = new AtomicInteger(0); - filename = null; - thread = new Thread(() -> { - try { - filename = IOHelper.getFileName(file); - downloadFile(url, file, writed::set); - } catch (IOException e) { - e.printStackTrace(); - } - }); - thread.setDaemon(true); - thread.start(); - } - - 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[IOHelper.BUFFER_SIZE]; - int count; - long timestamp = System.currentTimeMillis(); - int writed_local = 0; - while ((count = in.read(data, 0, IOHelper.BUFFER_SIZE)) != -1) { - fout.write(data, 0, count); - writed_local += count; - if (System.currentTimeMillis() - timestamp > INTERVAL) { - chanheTrack.accept(writed_local); - LogHelper.debug("Downloaded %d", writed_local); - } - } - chanheTrack.accept(writed_local); - } - } - - public static void downloadZip(URL url, Path dir) throws IOException { - try (ZipInputStream input = IOHelper.newZipInput(url)) { - Files.createDirectory(dir); - for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) { - if (entry.isDirectory()) { - Files.createDirectory(dir.resolve(IOHelper.toPath(entry.getName()))); - continue; - } - // Unpack entry - String name = entry.getName(); - LogHelper.subInfo("Downloading file: '%s'", name); - IOHelper.transfer(input, dir.resolve(IOHelper.toPath(name))); - } - } - } - - public String getFilename() { - return filename; - } -} diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Version.java b/LauncherCore/src/main/java/pro/gravit/utils/Version.java index 9251cf19..1f1c5356 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/Version.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/Version.java @@ -5,8 +5,8 @@ public final class Version implements Comparable { public static final int MAJOR = 5; - public static final int MINOR = 4; - public static final int PATCH = 4; + public static final int MINOR = 5; + public static final int PATCH = 0; public static final int BUILD = 1; public static final Version.Type RELEASE = Type.STABLE; public final int major; 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 cf95e57e..e691aacb 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java @@ -123,7 +123,6 @@ public static Class firstClass(String... names) throws ClassNotFoundException public static void fullGC() { RUNTIME.gc(); - RUNTIME.runFinalization(); LogHelper.debug("Used heap: %d MiB", RUNTIME.totalMemory() - RUNTIME.freeMemory() >> 20); } 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 6a9ec45d..a4d1f58f 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/JavaHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/JavaHelper.java @@ -6,12 +6,23 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; +import java.util.*; public class JavaHelper { private static List javaVersionsCache; + public static final List javaFxModules; + + static { + List modules = new ArrayList<>(); + modules.add("javafx.base"); + modules.add("javafx.graphics"); + modules.add("javafx.fxml"); + modules.add("javafx.controls"); + modules.add("javafx.swing"); + modules.add("javafx.media"); + modules.add("javafx.web"); + javaFxModules = Collections.unmodifiableList(modules); + } public static Path tryGetOpenJFXPath(Path jvmDir) { String dirName = jvmDir.getFileName().toString(); @@ -187,30 +198,29 @@ public static class JavaVersion { public final int version; public final int build; public final JVMHelper.ARCH arch; + public final List modules; public boolean enabledJavaFX; - public JavaVersion(Path jvmDir, int version) { - this.jvmDir = jvmDir; - this.version = version; - this.build = 0; - this.arch = JVMHelper.ARCH_TYPE; - this.enabledJavaFX = true; - } - - public JavaVersion(Path jvmDir, int version, int build, boolean enabledJavaFX) { - this.jvmDir = jvmDir; - this.version = version; - this.build = build; - this.arch = JVMHelper.ARCH_TYPE; - this.enabledJavaFX = enabledJavaFX; - } - public JavaVersion(Path jvmDir, int version, int build, JVMHelper.ARCH arch, boolean enabledJavaFX) { this.jvmDir = jvmDir; this.version = version; this.build = build; this.arch = arch; this.enabledJavaFX = enabledJavaFX; + if(version > 8) { + this.modules = javaFxModules; + } else { + this.modules = Collections.unmodifiableList(new ArrayList<>()); + } + } + + public JavaVersion(Path jvmDir, int version, int build, JVMHelper.ARCH arch, List modules, boolean enabledJavaFX) { + this.jvmDir = jvmDir; + this.version = version; + this.build = build; + this.arch = arch; + this.modules = modules; + this.enabledJavaFX = enabledJavaFX; } public static JavaVersion getCurrentJavaVersion() { @@ -239,17 +249,28 @@ public static JavaVersion getByPath(Path jvmDir) { } Path releaseFile = jvmDir.resolve("release"); JavaVersionAndBuild versionAndBuild = null; + List modules = null; JVMHelper.ARCH arch = JVMHelper.ARCH_TYPE; if (IOHelper.isFile(releaseFile)) { try { Properties properties = new Properties(); properties.load(IOHelper.newReader(releaseFile)); - versionAndBuild = getJavaVersion(properties.getProperty("JAVA_VERSION").replaceAll("\"", "")); + String versionProperty = getProperty(properties, "JAVA_VERSION"); + if(versionProperty != null) { + versionAndBuild = getJavaVersion(versionProperty); + } try { - arch = JVMHelper.getArch(properties.getProperty("OS_ARCH").replaceAll("\"", "")); + String archProperty = getProperty(properties, "OS_ARCH"); + if(archProperty != null) { + arch = JVMHelper.getArch(archProperty); + } } catch (Throwable ignored) { arch = null; } + String modulesProperty = getProperty(properties, "MODULES"); + if(modulesProperty != null) { + modules = new ArrayList<>(Arrays.asList(modulesProperty.split(" "))); + } } catch (IOException ignored) { } @@ -261,13 +282,26 @@ public static JavaVersion getByPath(Path jvmDir) { if (versionAndBuild.version <= 8) { resultJavaVersion.enabledJavaFX = isExistExtJavaLibrary(jvmDir, "jfxrt"); } else { - resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir, "javafx.base") != null; - if (!resultJavaVersion.enabledJavaFX) - resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir.resolve("jre"), "javafx.base") != null; + if(modules != null) { + resultJavaVersion.enabledJavaFX = modules.contains("javafx.base"); + } + if(!resultJavaVersion.enabledJavaFX) { + resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir, "javafx.base") != null; + if (!resultJavaVersion.enabledJavaFX) + resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir.resolve("jre"), "javafx.base") != null; + } } return resultJavaVersion; } + private static String getProperty(Properties properties, String name) { + String prop = properties.getProperty(name); + if(prop == null) { + return null; + } + return prop.replaceAll("\"", ""); + } + public static boolean isExistExtJavaLibrary(Path jvmDir, String name) { Path jrePath = jvmDir.resolve("lib").resolve("ext").resolve(name.concat(".jar")); Path jrePathLin = jvmDir.resolve("lib").resolve(name.concat(".jar")); diff --git a/LauncherCore/src/main/java11/pro/gravit/launcher/HTTPRequest.java b/LauncherCore/src/main/java11/pro/gravit/launcher/HTTPRequest.java deleted file mode 100644 index eef69ae4..00000000 --- a/LauncherCore/src/main/java11/pro/gravit/launcher/HTTPRequest.java +++ /dev/null @@ -1,60 +0,0 @@ -package pro.gravit.launcher; - -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import pro.gravit.utils.helper.IOHelper; -import pro.gravit.utils.helper.LogHelper; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Duration; - -public final class HTTPRequest { - private static final int TIMEOUT = 10000; - - private HTTPRequest() { - } - - 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 { - HttpClient client = HttpClient.newBuilder() - .build(); - HttpRequest.BodyPublisher publisher; - if (request != null) { - publisher = HttpRequest.BodyPublishers.ofString(request.toString()); - } else { - publisher = HttpRequest.BodyPublishers.noBody(); - } - try { - HttpRequest request1 = HttpRequest.newBuilder() - .method(method, publisher) - .uri(url.toURI()) - .header("Content-Type", "application/json; charset=UTF-8") - .header("Accept", "application/json") - .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36") - .timeout(Duration.ofMillis(TIMEOUT)) - .build(); - HttpResponse response = client.send(request1, HttpResponse.BodyHandlers.ofInputStream()); - int statusCode = response.statusCode(); - try { - return JsonParser.parseReader(IOHelper.newReader(response.body())); - } catch (Exception e) { - if (200 > statusCode || statusCode > 300) { - LogHelper.error("JsonRequest failed. Server response code %d", statusCode); - throw new IOException(e); - } - return null; - } - } catch (URISyntaxException | InterruptedException e) { - throw new IOException(e); - } - } -} 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 ca8ff03a..d2779207 100644 --- a/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java +++ b/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java @@ -100,7 +100,6 @@ public static Class firstClass(String... names) throws ClassNotFoundException public static void fullGC() { RUNTIME.gc(); - RUNTIME.runFinalization(); LogHelper.debug("Used heap: %d MiB", RUNTIME.totalMemory() - RUNTIME.freeMemory() >> 20); } diff --git a/LauncherModernCore/build.gradle b/LauncherModernCore/build.gradle new file mode 100644 index 00000000..879f4a48 --- /dev/null +++ b/LauncherModernCore/build.gradle @@ -0,0 +1,72 @@ +sourceCompatibility = '17' +targetCompatibility = '17' + +dependencies { + api project(':LauncherCore') +} + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} +jar { + archiveClassifier.set('clean') + manifest.attributes("Multi-Release": "true") +} + +tasks.register('sourcesJar', Jar) { + from sourceSets.main.allJava + archiveClassifier.set('sources') +} + +tasks.register('javadocJar', Jar) { + from javadoc + archiveClassifier.set('javadoc') +} + +publishing { + publications { + launchermoderncore(MavenPublication) { + artifactId = 'launcher-modern-core' + artifact(jar) { + classifier "" + } + artifact sourcesJar + artifact javadocJar + pom { + name = 'GravitLauncher Core Utils with Java 17+' + description = 'GravitLauncher Core Utils' + url = 'https://gravitlauncher.com' + licenses { + license { + name = 'GNU General Public License, Version 3.0' + url = 'https://www.gnu.org/licenses/gpl-3.0.html' + } + } + developers { + developer { + id = 'gravita' + name = 'Gravita' + email = 'gravita@gravit.pro' + } + developer { + id = 'zaxar163' + name = 'Zaxar163' + email = 'zahar.vcherachny@yandex.ru' + } + } + scm { + connection = 'scm:git:https://github.com/GravitLauncher/Launcher.git' + developerConnection = 'scm:git:ssh://git@github.com:GravitLauncher/Launcher.git' + url = 'https://gravitlauncher.com/' + } + } + } + } +} + +signing { + sign publishing.publications.launchermoderncore +} diff --git a/LauncherCore/src/main/java11/pro/gravit/utils/Downloader.java b/LauncherModernCore/src/main/java/pro/gravit/launcher/modern/Downloader.java similarity index 62% rename from LauncherCore/src/main/java11/pro/gravit/utils/Downloader.java rename to LauncherModernCore/src/main/java/pro/gravit/launcher/modern/Downloader.java index daf1dc5e..6cecfc9e 100644 --- a/LauncherCore/src/main/java11/pro/gravit/utils/Downloader.java +++ b/LauncherModernCore/src/main/java/pro/gravit/launcher/modern/Downloader.java @@ -1,10 +1,13 @@ -package pro.gravit.utils; +package pro.gravit.launcher.modern; -import pro.gravit.launcher.AsyncDownloader; +import pro.gravit.launcher.CertificatePinningTrustManager; import pro.gravit.launcher.LauncherInject; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpClient; @@ -13,6 +16,11 @@ import java.nio.ByteBuffer; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; import java.util.Collections; import java.util.List; import java.util.Queue; @@ -26,6 +34,8 @@ public class Downloader { private static boolean isCertificatePinning; @LauncherInject("launcher.noHttp2") private static boolean isNoHttp2; + private static volatile SSLSocketFactory sslSocketFactory; + private static volatile SSLContext sslContext; protected final HttpClient client; protected final ExecutorService executor; protected final Queue tasks = new ConcurrentLinkedDeque<>(); @@ -35,7 +45,50 @@ protected Downloader(HttpClient client, ExecutorService executor) { this.executor = executor; } - public static Downloader downloadList(List files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception { + public static ThreadFactory getDaemonThreadFactory(String name) { + return (task) -> { + Thread thread = new Thread(task); + thread.setName(name); + thread.setDaemon(true); + return thread; + }; + } + + public static SSLSocketFactory makeSSLSocketFactory() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException { + if (sslSocketFactory != null) return sslSocketFactory; + SSLContext sslContext = makeSSLContext(); + sslSocketFactory = sslContext.getSocketFactory(); + return sslSocketFactory; + } + + public static SSLContext makeSSLContext() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException { + if (sslContext != null) return sslContext; + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, CertificatePinningTrustManager.getTrustManager().getTrustManagers(), new SecureRandom()); + return sslContext; + } + + public static Downloader downloadFile(URI uri, Path path, ExecutorService executor) { + boolean closeExecutor = false; + if (executor == null) { + executor = Executors.newSingleThreadExecutor(getDaemonThreadFactory("Downloader")); + closeExecutor = true; + } + Downloader downloader = newDownloader(executor); + downloader.future = downloader.downloadFile(uri, path); + if (closeExecutor) { + ExecutorService finalExecutor = executor; + downloader.future = downloader.future.thenAccept((e) -> { + finalExecutor.shutdownNow(); + }).exceptionallyCompose((ex) -> { + finalExecutor.shutdownNow(); + return CompletableFuture.failedFuture(ex); + }); + } + return downloader; + } + + public static Downloader downloadList(List files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception { boolean closeExecutor = false; LogHelper.info("Download with Java 11+ HttpClient"); if (executor == null) { @@ -46,7 +99,12 @@ public static Downloader downloadList(List files, Str downloader.future = downloader.downloadFiles(files, baseURL, targetDir, callback, executor, threads); if (closeExecutor) { ExecutorService finalExecutor = executor; - downloader.future = downloader.future.thenAccept(e -> finalExecutor.shutdownNow()); + downloader.future = downloader.future.thenAccept((e) -> { + finalExecutor.shutdownNow(); + }).exceptionallyCompose((ex) -> { + finalExecutor.shutdownNow(); + return CompletableFuture.failedFuture(ex); + }); } return downloader; } @@ -61,7 +119,7 @@ public static Downloader newDownloader(ExecutorService executor) { .executor(executor); if (isCertificatePinning) { try { - builder.sslContext(AsyncDownloader.makeSSLContext()); + builder.sslContext(makeSSLContext()); } catch (Exception e) { throw new SecurityException(e); } @@ -88,11 +146,28 @@ public CompletableFuture getFuture() { return future; } - public CompletableFuture downloadFiles(List files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception { + public CompletableFuture downloadFile(URI uri, Path path) { + try { + IOHelper.createParentDirs(path); + } catch (IOException e) { + return CompletableFuture.failedFuture(e); + } + return client.sendAsync(HttpRequest.newBuilder() + .GET() + .uri(uri) + .build(), HttpResponse.BodyHandlers.ofFile(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)).thenCompose((t) -> { + if(t.statusCode() < 200 || t.statusCode() >= 400) { + return CompletableFuture.failedFuture(new IOException(String.format("Failed to download %s: code %d", uri.toString(), t.statusCode()))); + } + return CompletableFuture.completedFuture(null); + }); + } + + public CompletableFuture downloadFiles(List files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception { // URI scheme - URI baseUri = new URI(baseURL); + URI baseUri = baseURL == null ? null : new URI(baseURL); Collections.shuffle(files); - Queue queue = new ConcurrentLinkedDeque<>(files); + Queue queue = new ConcurrentLinkedDeque<>(files); CompletableFuture future = new CompletableFuture<>(); AtomicInteger currentThreads = new AtomicInteger(threads); ConsumerObject consumerObject = new ConsumerObject(); @@ -100,7 +175,7 @@ public CompletableFuture downloadFiles(List fil if (callback != null && e != null) { callback.onComplete(e.body()); } - AsyncDownloader.SizedFile file = queue.poll(); + SizedFile file = queue.poll(); if (file == null) { if (currentThreads.decrementAndGet() == 0) future.complete(null); @@ -124,7 +199,7 @@ public CompletableFuture downloadFiles(List fil return future; } - protected DownloadTask sendAsync(AsyncDownloader.SizedFile file, URI baseUri, Path targetDir, DownloadCallback callback) throws Exception { + protected DownloadTask sendAsync(SizedFile file, URI baseUri, Path targetDir, DownloadCallback callback) throws Exception { IOHelper.createParentDirs(targetDir.resolve(file.filePath)); ProgressTrackingBodyHandler bodyHandler = makeBodyHandler(targetDir.resolve(file.filePath), callback); CompletableFuture> future = client.sendAsync(makeHttpRequest(baseUri, file.urlPath), bodyHandler); @@ -139,15 +214,21 @@ protected DownloadTask sendAsync(AsyncDownloader.SizedFile file, URI baseUri, Pa } protected HttpRequest makeHttpRequest(URI baseUri, String filePath) throws URISyntaxException { - String scheme = baseUri.getScheme(); - String host = baseUri.getHost(); - int port = baseUri.getPort(); - if (port != -1) - host = host + ":" + port; - String path = baseUri.getPath(); + URI uri; + if(baseUri != null) { + String scheme = baseUri.getScheme(); + String host = baseUri.getHost(); + int port = baseUri.getPort(); + if (port != -1) + host = host + ":" + port; + String path = baseUri.getPath(); + uri = new URI(scheme, host, path + filePath, "", ""); + } else { + uri = new URI(filePath); + } return HttpRequest.newBuilder() .GET() - .uri(new URI(scheme, host, path + filePath, "", "")) + .uri(uri) .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36") .build(); } @@ -262,4 +343,21 @@ public void cancel() { } } } + + public static class SizedFile { + public final String urlPath, filePath; + public final long size; + + public SizedFile(String path, long size) { + this.urlPath = path; + this.filePath = path; + this.size = size; + } + + public SizedFile(String urlPath, String filePath, long size) { + this.urlPath = urlPath; + this.filePath = filePath; + this.size = size; + } + } } diff --git a/LauncherStart/build.gradle b/LauncherStart/build.gradle new file mode 100644 index 00000000..bdc73a50 --- /dev/null +++ b/LauncherStart/build.gradle @@ -0,0 +1,80 @@ +apply plugin: 'org.openjfx.javafxplugin' + +String mainClassName = "pro.gravit.launcher.ClientLauncherWrapper" +String mainAgentName = "pro.gravit.launcher.LauncherAgent" + +repositories { + maven { + url "https://repo.spring.io/plugins-release/" + } +} +sourceCompatibility = '1.8' +targetCompatibility = '1.8' + +jar { + archiveClassifier.set('clean') + manifest.attributes("Main-Class": mainClassName, + "Premain-Class": mainAgentName, + "Multi-Release": "true") +} + +tasks.register('sourcesJar', Jar) { + from sourceSets.main.allJava + archiveClassifier.set('sources') +} + +tasks.register('javadocJar', Jar) { + from javadoc + archiveClassifier.set('javadoc') +} + +dependencies { + implementation project(':LauncherAPI') + implementation project(':LauncherClient') +} + +publishing { + publications { + launcherclientstart(MavenPublication) { + artifactId = 'launcher-client-start-api' + artifact(jar) { + classifier "" + } + artifact sourcesJar + artifact javadocJar + pom { + name = 'GravitLauncher Client API' + description = 'GravitLauncher Client Module API' + url = 'https://gravitlauncher.com' + licenses { + license { + name = 'GNU General Public License, Version 3.0' + url = 'https://www.gnu.org/licenses/gpl-3.0.html' + } + } + developers { + developer { + id = 'gravita' + name = 'Gravita' + email = 'gravita@gravit.pro' + } + developer { + id = 'zaxar163' + name = 'Zaxar163' + email = 'zahar.vcherachny@yandex.ru' + } + } + scm { + connection = 'scm:git:https://github.com/GravitLauncher/Launcher.git' + developerConnection = 'scm:git:ssh://git@github.com:GravitLauncher/Launcher.git' + url = 'https://gravitlauncher.com/' + } + } + } + } +} + + +signing { + sign publishing.publications.launcherclientstart +} diff --git a/Launcher/src/main/java/pro/gravit/launcher/ClientLauncherWrapper.java b/LauncherStart/src/main/java/pro/gravit/launcher/ClientLauncherWrapper.java similarity index 86% rename from Launcher/src/main/java/pro/gravit/launcher/ClientLauncherWrapper.java rename to LauncherStart/src/main/java/pro/gravit/launcher/ClientLauncherWrapper.java index 4e35838e..185bbb5f 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/ClientLauncherWrapper.java +++ b/LauncherStart/src/main/java/pro/gravit/launcher/ClientLauncherWrapper.java @@ -1,16 +1,15 @@ package pro.gravit.launcher; -import pro.gravit.launcher.client.ClientModuleManager; +import pro.gravit.launcher.client.RuntimeModuleManager; import pro.gravit.launcher.client.DirBridge; import pro.gravit.launcher.utils.DirWatcher; +import pro.gravit.utils.Version; import pro.gravit.utils.helper.*; +import javax.swing.*; import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class ClientLauncherWrapper { public static final String MAGIC_ARG = "-Djdk.attach.allowAttachSelf"; @@ -22,6 +21,16 @@ public class ClientLauncherWrapper { public static int launcherMemoryLimit; @LauncherInject("launcher.customJvmOptions") public static List customJvmOptions; + public static RuntimeModuleManager modulesManager; + + public static boolean contains(String[] array, String value) { + for(String s : array) { + if(s.equals(value)) { + return true; + } + } + return false; + } public static void main(String[] arguments) throws IOException, InterruptedException { LogHelper.printVersion("Launcher"); @@ -30,9 +39,8 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep JVMHelper.verifySystemProperties(Launcher.class, true); EnvHelper.checkDangerousParams(); LauncherConfig config = Launcher.getConfig(); - LauncherEngine.modulesManager = new ClientModuleManager(); - LauncherConfig.initModules(LauncherEngine.modulesManager); - + modulesManager = new RuntimeModuleManager(); + LauncherConfig.initModules(modulesManager); LogHelper.info("Launcher for project %s", config.projectName); if (config.environment.equals(LauncherConfig.LauncherEnvironment.PROD)) { if (System.getProperty(LogHelper.DEBUG_PROPERTY) != null) { @@ -45,6 +53,10 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep } else { LogHelper.info("If need debug output use -Dlauncher.debug=true"); LogHelper.info("If need stacktrace output use -Dlauncher.stacktrace=true"); + if(contains(arguments, "--debug")) { + LogHelper.setDebugEnabled(true); + LogHelper.setStacktraceEnabled(true); + } if (LogHelper.isDebugEnabled()) waitProcess = true; } LogHelper.info("Restart Launcher with JavaAgent..."); @@ -82,9 +94,16 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep context.javaVersion = JavaHelper.JavaVersion.getCurrentJavaVersion(); } + if(context.javaVersion.version < 17) { + String message = String.format("GravitLauncher v%s required Java 17 or higher", Version.getVersion()); + LogHelper.error(message); + JOptionPane.showMessageDialog(null, message, "GravitLauncher", JOptionPane.ERROR_MESSAGE); + System.exit(0); + } + context.executePath = IOHelper.resolveJavaBin(context.javaVersion.jvmDir); - String pathLauncher = IOHelper.getCodeSource(LauncherEngine.class).toString(); - context.mainClass = LauncherEngine.class.getName(); + String pathLauncher = IOHelper.getCodeSource(ClientLauncherWrapper.class).toString(); + context.mainClass = "pro.gravit.launcher.LauncherEngineWrapper"; context.memoryLimit = launcherMemoryLimit; context.classpath.add(pathLauncher); context.jvmProperties.put(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled())); @@ -98,13 +117,13 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep context.jvmModules.add("javafx.graphics"); context.jvmModules.add("javafx.fxml"); context.jvmModules.add("javafx.controls"); - context.jvmModules.add("javafx.swing"); context.jvmModules.add("javafx.media"); context.jvmModules.add("javafx.web"); context.args.add(MAGIC_ARG); context.args.add("-XX:+DisableAttachMechanism"); + context.clientArgs.addAll(Arrays.asList(arguments)); EnvHelper.addEnv(context.processBuilder); - LauncherEngine.modulesManager.callWrapper(context); + modulesManager.callWrapper(context); // --------- List args = new ArrayList<>(16); args.add(context.executePath.toAbsolutePath().toString()); diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientWrapperModule.java b/LauncherStart/src/main/java/pro/gravit/launcher/ClientWrapperModule.java similarity index 83% rename from Launcher/src/main/java/pro/gravit/launcher/client/ClientWrapperModule.java rename to LauncherStart/src/main/java/pro/gravit/launcher/ClientWrapperModule.java index 73e726d6..6c4feafb 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientWrapperModule.java +++ b/LauncherStart/src/main/java/pro/gravit/launcher/ClientWrapperModule.java @@ -1,4 +1,4 @@ -package pro.gravit.launcher.client; +package pro.gravit.launcher; import pro.gravit.launcher.ClientLauncherWrapper; diff --git a/LauncherStart/src/main/java/pro/gravit/launcher/client/RuntimeModuleManager.java b/LauncherStart/src/main/java/pro/gravit/launcher/client/RuntimeModuleManager.java new file mode 100644 index 00000000..c3f92075 --- /dev/null +++ b/LauncherStart/src/main/java/pro/gravit/launcher/client/RuntimeModuleManager.java @@ -0,0 +1,50 @@ +package pro.gravit.launcher.client; + +import pro.gravit.launcher.ClientLauncherWrapper; +import pro.gravit.launcher.ClientWrapperModule; +import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.LauncherTrustManager; +import pro.gravit.launcher.modules.LauncherModule; +import pro.gravit.launcher.modules.impl.SimpleModuleManager; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +public final class RuntimeModuleManager extends SimpleModuleManager { + public RuntimeModuleManager() { + super(null, null, Launcher.getConfig().trustManager); + } + + @Override + public void autoload() { + throw new UnsupportedOperationException(); + } + + @Override + public void autoload(Path dir) { + throw new UnsupportedOperationException(); + } + + @Override + 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; + } + + public void callWrapper(ClientLauncherWrapper.ClientLauncherWrapperContext context) { + for (LauncherModule module : modules) { + if (module instanceof ClientWrapperModule) { + ((ClientWrapperModule) module).wrapperPhase(context); + } + } + } +} 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 fdcfd42f..0e07b07d 100644 --- a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java @@ -128,6 +128,11 @@ public void run(String... args) throws Throwable { LogHelper.error(e); } }; + if(config.properties != null) { + for(Map.Entry e : config.properties.entrySet()) { + System.setProperty(e.getKey(), e.getValue()); + } + } Request.setRequestService(service); if (config.logFile != null) LogHelper.addOutput(IOHelper.newWriter(Paths.get(config.logFile), true)); { @@ -213,6 +218,7 @@ public Config getDefaultConfig() { newConfig.address = "ws://localhost:9274/api"; newConfig.classLoaderConfig = ClientProfile.ClassLoaderConfig.SYSTEM_ARGS; newConfig.env = LauncherConfig.LauncherEnvironment.STD; + newConfig.properties = new HashMap<>(); return newConfig; } @@ -231,13 +237,15 @@ public static final class Config { public String authId; public AuthRequestEvent.OAuthRequestEvent oauth; public long oauthExpireTime; - public Map extendedTokens; + public Map extendedTokens; public LauncherConfig.LauncherEnvironment env; public ModuleConf moduleConf = new ModuleConf(); public byte[] encodedServerRsaPublicKey; public byte[] encodedServerEcPublicKey; + + public Map properties; } 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 fdd1fa0d..9f2e24da 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 @@ -75,7 +75,7 @@ public void run() throws Exception { } System.out.println("Print server token:"); String checkServerToken = commands.commandHandler.readLine(); - wrapper.config.extendedTokens.put("checkServer", checkServerToken); + wrapper.config.extendedTokens.put("checkServer", new Request.ExtendedToken(checkServerToken, 0)); wrapper.updateLauncherConfig(); try { wrapper.restore(); diff --git a/build.gradle b/build.gradle index 9b320def..8ec0579d 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.4.4' +version = '5.5.0' apply from: 'props.gradle' diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4..7f93135c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c747538f..8838ba97 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca1..1aa94a42 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -201,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/modules b/modules index f6706567..5847a9b9 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit f6706567b4d02e802a3d285ca5d1fb0086b6799e +Subproject commit 5847a9b937039eb6402082a458ad0afac7163840 diff --git a/props.gradle b/props.gradle index df32b125..d8072da7 100644 --- a/props.gradle +++ b/props.gradle @@ -1,7 +1,7 @@ project.ext { - verAsm = '9.5' - verNetty = '4.1.94.Final' - verOshiCore = '6.4.4' + verAsm = '9.6' + verNetty = '4.1.99.Final' + verOshiCore = '6.4.6' verJunit = '5.9.3' verGuavaC = '30.1.1-jre' verJansi = '2.4.0' @@ -11,10 +11,9 @@ verGson = '2.10.1' verBcpkix = '1.70' verSlf4j = '1.7.36' - verLog4j = '2.19.0' - verMySQLConn = '8.0.33' + verLog4j = '2.20.0' + verMySQLConn = '8.1.0' verPostgreSQLConn = '42.6.0' - verProguard = '7.3.2' + verProguard = '7.4.0' verLaunch4j = '3.50' - verHibernate = '5.5.6.Final' } diff --git a/settings.gradle b/settings.gradle index 49181b91..9566cd8d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,11 @@ rootProject.name = 'GravitLauncher' include 'Launcher' +include 'LauncherModernCore' include 'LauncherCore' include 'LauncherAPI' +include 'LauncherClient' +include 'LauncherStart' include 'ServerWrapper' include 'LaunchServer' include 'modules'