Compare commits

...

16 commits

Author SHA1 Message Date
Gravita
98eee95fc8
[ANY] 5.5.7 lts 2024-07-21 20:11:57 +07:00
Gravita
85938d4d38
[FIX] Backport: OptionalView fixDependencies 2024-07-21 20:10:58 +07:00
Gravita
c76e451210
[FIX] Backport: Downloader truncate file 2024-07-21 19:50:51 +07:00
Gravita
a53b18ae68 [ANY] Update modules 2024-05-30 22:36:32 +07:00
Gravita
5f04ea7ccc [ANY] Update dependencies 2024-05-30 22:36:12 +07:00
Gravita
505eb347de [FIX] Compile fix 2024-05-12 00:56:03 +07:00
Gravita
ced13d2cb4 [FIX] Backport "Strict profile access, update gradle" 2024-04-10 17:20:16 +07:00
Gravita
a02a5b6af3 [ANY] 5.5.6 stable 2024-03-14 18:14:03 +07:00
microwin7
31dc4052c8 [FIX] Sort files in installAuthlib 2024-03-09 14:24:12 +03:00
microwin7
5abadb0d8a [FEATURE] Sort jar files, before patching in installAuthlib 2024-03-09 00:39:33 +03:00
Gravita
d422a6ea0a [ANY] v5.5.5 2024-03-01 15:24:20 +07:00
microwin7
65ee7540ce [ANY] Update modules 2024-02-24 22:11:16 +03:00
microwin7
ce45844b7f [FIX] Encrypted ClientParams test for java 8 2024-02-24 05:10:57 +03:00
Gravita
b15500f6fa [FEATURE] Use encrypted ClientParams 2024-02-24 05:02:42 +03:00
Gravit
683be84cef
Merge pull request #701 from microwin7/support/5.5.x
[FEATURE]  Handle non 2XX codes in Downloader
2024-02-16 00:44:46 +07:00
Gravita
6ef0d49e72 [FEATURE] Handle non 2XX codes in Downloader 2024-02-14 21:57:04 +03:00
20 changed files with 117 additions and 163 deletions

View file

@ -29,12 +29,12 @@ public void init(LaunchServer server) {
@Override @Override
public boolean canGetProfile(ClientProfile profile, Client client) { public boolean canGetProfile(ClientProfile profile, Client client) {
return !profile.isLimited() || isWhitelisted("launchserver.profile.%s.show", profile, client); return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.show", profile, client);
} }
@Override @Override
public boolean canChangeProfile(ClientProfile profile, Client client) { public boolean canChangeProfile(ClientProfile profile, Client client) {
return !profile.isLimited() || isWhitelisted("launchserver.profile.%s.enter", profile, client); return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.enter", profile, client);
} }
@Override @Override

View file

@ -30,7 +30,6 @@
import pro.gravit.launchserver.socket.response.secure.SecurityReportResponse; import pro.gravit.launchserver.socket.response.secure.SecurityReportResponse;
import pro.gravit.launchserver.socket.response.secure.VerifySecureLevelKeyResponse; import pro.gravit.launchserver.socket.response.secure.VerifySecureLevelKeyResponse;
import pro.gravit.launchserver.socket.response.update.LauncherResponse; import pro.gravit.launchserver.socket.response.update.LauncherResponse;
import pro.gravit.launchserver.socket.response.update.UpdateListResponse;
import pro.gravit.launchserver.socket.response.update.UpdateResponse; import pro.gravit.launchserver.socket.response.update.UpdateResponse;
import pro.gravit.utils.BiHookSet; import pro.gravit.utils.BiHookSet;
import pro.gravit.utils.HookSet; import pro.gravit.utils.HookSet;
@ -64,7 +63,6 @@ public static void registerResponses() {
providers.register("joinServer", JoinServerResponse.class); providers.register("joinServer", JoinServerResponse.class);
providers.register("profiles", ProfilesResponse.class); providers.register("profiles", ProfilesResponse.class);
providers.register("launcher", LauncherResponse.class); providers.register("launcher", LauncherResponse.class);
providers.register("updateList", UpdateListResponse.class);
providers.register("setProfile", SetProfileResponse.class); providers.register("setProfile", SetProfileResponse.class);
providers.register("update", UpdateResponse.class); providers.register("update", UpdateResponse.class);
providers.register("batchProfileByUsername", BatchProfileByUsername.class); providers.register("batchProfileByUsername", BatchProfileByUsername.class);

View file

@ -1,27 +0,0 @@
package pro.gravit.launchserver.socket.response.update;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.UpdateListRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import java.util.HashSet;
public class UpdateListResponse extends SimpleResponse {
@Override
public String getType() {
return "updateList";
}
@Override
public void execute(ChannelHandlerContext ctx, Client client) {
if (!client.isAuth) {
sendError("Access denied");
return;
}
HashSet<String> set = server.updatesManager.getUpdatesList();
sendResult(new UpdateListRequestEvent(set));
}
}

View file

@ -17,6 +17,7 @@
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.utils.helper.*; import pro.gravit.utils.helper.*;
import javax.crypto.CipherOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -28,7 +29,6 @@
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class ClientLauncherProcess { public class ClientLauncherProcess {
public final List<String> pre = new LinkedList<>(); public final List<String> pre = new LinkedList<>();
public final ClientParams params = new ClientParams(); public final ClientParams params = new ClientParams();
public final List<String> jvmArgs = new LinkedList<>(); public final List<String> jvmArgs = new LinkedList<>();
@ -75,6 +75,7 @@ public ClientLauncherProcess(Path clientDir, Path assetDir, JavaHelper.JavaVersi
this.params.clientDir = this.workDir.toString(); this.params.clientDir = this.workDir.toString();
this.params.resourcePackDir = resourcePackDir.toAbsolutePath().toString(); this.params.resourcePackDir = resourcePackDir.toAbsolutePath().toString();
this.params.assetDir = assetDir.toAbsolutePath().toString(); this.params.assetDir = assetDir.toAbsolutePath().toString();
this.params.timestamp = System.currentTimeMillis();
Path nativesPath; Path nativesPath;
if(profile.hasFlag(ClientProfile.CompatibilityFlags.LEGACY_NATIVES_DIR)) { if(profile.hasFlag(ClientProfile.CompatibilityFlags.LEGACY_NATIVES_DIR)) {
nativesPath = workDir.resolve("natives"); nativesPath = workDir.resolve("natives");
@ -222,7 +223,7 @@ public void runWriteParams(SocketAddress address) throws IOException {
waitWriteParams.notifyAll(); waitWriteParams.notifyAll();
} }
Socket socket = serverSocket.accept(); Socket socket = serverSocket.accept();
try (HOutput output = new HOutput(socket.getOutputStream())) { try (HOutput output = new HOutput(new CipherOutputStream(socket.getOutputStream(), SecurityHelper.newAESEncryptCipher(SecurityHelper.fromHex(Launcher.getConfig().secretKeyClient))))) {
byte[] serializedMainParams = IOHelper.encode(Launcher.gsonManager.gson.toJson(params)); byte[] serializedMainParams = IOHelper.encode(Launcher.gsonManager.gson.toJson(params));
output.writeByteArray(serializedMainParams, 0); output.writeByteArray(serializedMainParams, 0);
params.clientHDir.write(output); params.clientHDir.write(output);
@ -233,6 +234,8 @@ public void runWriteParams(SocketAddress address) throws IOException {
output.writeBoolean(true); output.writeBoolean(true);
params.javaHDir.write(output); params.javaHDir.write(output);
} }
} catch (Exception e) {
throw new IOException(e);
} }
} }
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderParamsWrittedEvent(this)); LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderParamsWrittedEvent(this));

View file

@ -1,24 +0,0 @@
package pro.gravit.launcher.events.request;
import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.RequestEvent;
import java.util.HashSet;
import java.util.UUID;
public class UpdateListRequestEvent extends RequestEvent {
@SuppressWarnings("unused")
private static final UUID uuid = UUID.fromString("5fa836ae-6b61-401c-96ac-d8396f07ec6b");
@LauncherNetworkAPI
public final HashSet<String> dirs;
public UpdateListRequestEvent(HashSet<String> dirs) {
this.dirs = dirs;
}
@Override
public String getType() {
return "updateList";
}
}

View file

@ -88,7 +88,7 @@ public Set<OptionalAction> getEnabledActions() {
public void fixDependencies() { public void fixDependencies() {
Set<OptionalFile> disabled = all.stream().filter(t -> !isEnabled(t)).collect(Collectors.toSet()); Set<OptionalFile> disabled = all.stream().filter(t -> !isEnabled(t)).collect(Collectors.toSet());
for (OptionalFile file : disabled) { for (OptionalFile file : disabled) {
if (file.group != null && Arrays.stream(file.group).noneMatch(this::isEnabled)) { if (file.group != null && file.group.length > 0 && Arrays.stream(file.group).noneMatch(this::isEnabled)) {
enable(file.group[0], false, null); enable(file.group[0], false, null);
} }
} }

View file

@ -1,13 +0,0 @@
package pro.gravit.launcher.request.update;
import pro.gravit.launcher.events.request.UpdateListRequestEvent;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.websockets.WebSocketRequest;
public final class UpdateListRequest extends Request<UpdateListRequestEvent> implements WebSocketRequest {
@Override
public String getType() {
return "updateList";
}
}

View file

@ -94,7 +94,6 @@ public void registerResults() {
results.register("batchProfileByUsername", BatchProfileByUsernameRequestEvent.class); results.register("batchProfileByUsername", BatchProfileByUsernameRequestEvent.class);
results.register("profiles", ProfilesRequestEvent.class); results.register("profiles", ProfilesRequestEvent.class);
results.register("setProfile", SetProfileRequestEvent.class); results.register("setProfile", SetProfileRequestEvent.class);
results.register("updateList", UpdateListRequestEvent.class);
results.register("error", ErrorRequestEvent.class); results.register("error", ErrorRequestEvent.class);
results.register("update", UpdateRequestEvent.class); results.register("update", UpdateRequestEvent.class);
results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class); results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class);

View file

@ -23,6 +23,7 @@
import pro.gravit.utils.helper.*; import pro.gravit.utils.helper.*;
import pro.gravit.utils.launch.*; import pro.gravit.utils.launch.*;
import javax.crypto.CipherInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
@ -49,7 +50,7 @@ public class ClientLauncherEntryPoint {
private static ClientParams readParams(SocketAddress address) throws IOException { private static ClientParams readParams(SocketAddress address) throws IOException {
try (Socket socket = IOHelper.newSocket()) { try (Socket socket = IOHelper.newSocket()) {
socket.connect(address); socket.connect(address);
try (HInput input = new HInput(socket.getInputStream())) { try (HInput input = new HInput(new CipherInputStream(socket.getInputStream(), SecurityHelper.newAESDecryptCipher(SecurityHelper.fromHex(Launcher.getConfig().secretKeyClient))))) {
byte[] serialized = input.readByteArray(0); byte[] serialized = input.readByteArray(0);
ClientParams params = Launcher.gsonManager.gson.fromJson(IOHelper.decode(serialized), ClientParams.class); ClientParams params = Launcher.gsonManager.gson.fromJson(IOHelper.decode(serialized), ClientParams.class);
params.clientHDir = new HashedDir(input); params.clientHDir = new HashedDir(input);
@ -87,6 +88,11 @@ private static void realMain(String[] args) throws Throwable {
if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) { if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) {
ClientLauncherMethods.verifyNoAgent(); ClientLauncherMethods.verifyNoAgent();
} }
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
LogHelper.error("Timestamp failed. Exit");
ClientLauncherMethods.exitLauncher(-662);
return;
}
ClientProfile profile = params.profile; ClientProfile profile = params.profile;
Launcher.profile = profile; Launcher.profile = profile;
AuthService.profile = profile; AuthService.profile = profile;

View file

@ -14,6 +14,7 @@
import java.util.*; import java.util.*;
public class ClientParams { public class ClientParams {
public long timestamp;
public String assetDir; public String assetDir;
public String clientDir; public String clientDir;

View file

@ -6,9 +6,9 @@ public final class Version implements Comparable<Version> {
public static final int MAJOR = 5; public static final int MAJOR = 5;
public static final int MINOR = 5; public static final int MINOR = 5;
public static final int PATCH = 4; public static final int PATCH = 7;
public static final int BUILD = 1; public static final int BUILD = 1;
public static final Version.Type RELEASE = Type.STABLE; public static final Version.Type RELEASE = Type.LTS;
public final int major; public final int major;
public final int minor; public final int minor;
public final int patch; public final int patch;

View file

@ -33,20 +33,15 @@ public final class SecurityHelper {
public static final String RSA_ALGO = "RSA"; public static final String RSA_ALGO = "RSA";
public static final String RSA_SIGN_ALGO = "SHA256withRSA"; public static final String RSA_SIGN_ALGO = "SHA256withRSA";
public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding"; public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding";
public static final String AES_CIPHER_ALGO = "AES/ECB/PKCS5Padding";
// Algorithm size constants // Algorithm size constants
public static final int AES_KEY_LENGTH = 8; public static final int AES_KEY_LENGTH = 16;
public static final int TOKEN_STRING_LENGTH = TOKEN_LENGTH << 1; public static final int TOKEN_STRING_LENGTH = TOKEN_LENGTH << 1;
public static final int RSA_KEY_LENGTH_BITS = 2048; public static final int RSA_KEY_LENGTH_BITS = 2048;
public static final int RSA_KEY_LENGTH = RSA_KEY_LENGTH_BITS / Byte.SIZE; public static final int RSA_KEY_LENGTH = RSA_KEY_LENGTH_BITS / Byte.SIZE;
public static final int CRYPTO_MAX_LENGTH = 2048; public static final int CRYPTO_MAX_LENGTH = 2048;
public static final String HEX = "0123456789abcdef"; public static final String HEX = "0123456789abcdef";
// Certificate constants
public static final byte[] NUMBERS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
public static final SecureRandom secureRandom = new SecureRandom();
// Random generator constants
private static final char[] VOWELS = {'e', 'u', 'i', 'o', 'a'};
private static final char[] CONS = {'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'k', 'l', 'c', 'v', 'b', 'n', 'm'};
private SecurityHelper() { private SecurityHelper() {
} }
@ -189,6 +184,16 @@ private static Cipher newRSACipher(int mode, RSAKey key) {
return cipher; return cipher;
} }
private static Cipher newAESCipher(int mode, byte[] key) {
Cipher cipher = newCipher(AES_CIPHER_ALGO);
try {
cipher.init(mode, new SecretKeySpec(key, "AES"));
} catch (InvalidKeyException e) {
throw new InternalError(e);
}
return cipher;
}
private static KeyFactory newECDSAKeyFactory() { private static KeyFactory newECDSAKeyFactory() {
try { try {
return KeyFactory.getInstance(EC_ALGO); return KeyFactory.getInstance(EC_ALGO);
@ -313,70 +318,6 @@ public static byte[] randomAESKey(Random random) {
return randomBytes(random, AES_KEY_LENGTH); return randomBytes(random, AES_KEY_LENGTH);
} }
public static String randomUsername() {
return randomUsername(newRandom());
}
public static String randomUsername(Random random) {
int usernameLength = 3 + random.nextInt(7); // 3-9
// Choose prefix
String prefix;
int prefixType = random.nextInt(7);
if (usernameLength >= 5 && prefixType == 6) { // (6) 2-char
prefix = random.nextBoolean() ? "Mr" : "Dr";
usernameLength -= 2;
} else if (usernameLength >= 6 && prefixType == 5) { // (5) 3-char
prefix = "Mrs";
usernameLength -= 3;
} else
prefix = "";
// Choose suffix
String suffix;
int suffixType = random.nextInt(7); // 0-6, 7 values
if (usernameLength >= 5 && suffixType == 6) { // (6) 10-99
suffix = String.valueOf(10 + random.nextInt(90));
usernameLength -= 2;
} else if (usernameLength >= 7 && suffixType == 5) { // (5) 1990-2015
suffix = String.valueOf(1990 + random.nextInt(26));
usernameLength -= 4;
} else
suffix = "";
// Choose name
int consRepeat = 0;
boolean consPrev = random.nextBoolean();
char[] chars = new char[usernameLength];
for (int i = 0; i < chars.length; i++) {
if (i > 1 && consPrev && random.nextInt(10) == 0) { // Doubled
chars[i] = chars[i - 1];
continue;
}
// Choose next char
if (consRepeat < 1 && random.nextInt() == 5)
consRepeat++;
else {
consRepeat = 0;
consPrev ^= true;
}
// Choose char
char[] alphabet = consPrev ? CONS : VOWELS;
chars[i] = alphabet[random.nextInt(alphabet.length)];
}
// Make first letter uppercase
if (!prefix.isEmpty() || random.nextBoolean())
chars[0] = Character.toUpperCase(chars[0]);
// Return chosen name (and verify for sure)
return VerifyHelper.verifyUsername(prefix + new String(chars) + suffix);
}
public static byte[] sign(byte[] bytes, ECPrivateKey privateKey) { public static byte[] sign(byte[] bytes, ECPrivateKey privateKey) {
Signature signature = newECSignSignature(privateKey); Signature signature = newECSignSignature(privateKey);
try { try {
@ -484,6 +425,22 @@ public static Cipher newRSAEncryptCipher(RSAPublicKey publicKey) {
} }
} }
public static Cipher newAESDecryptCipher(byte[] key) {
try {
return newAESCipher(Cipher.DECRYPT_MODE, key);
} catch (SecurityException e) {
throw new InternalError(e);
}
}
public static Cipher newAESEncryptCipher(byte[] key) {
try {
return newAESCipher(Cipher.ENCRYPT_MODE, key);
} catch (SecurityException e) {
throw new InternalError(e);
}
}
//AES //AES
public static byte[] encrypt(String seed, byte[] cleartext) throws Exception { public static byte[] encrypt(String seed, byte[] cleartext) throws Exception {
byte[] rawKey = getAESKey(IOHelper.encode(seed)); byte[] rawKey = getAESKey(IOHelper.encode(seed));

View file

@ -0,0 +1,47 @@
package pro.gravit.launcher;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.SecurityHelper;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class SecurityHelperTests {
@Test
public void aesLegacyTest() throws Exception {
byte[] bytes = SecurityHelper.randomBytes(24);
byte[] seed = SecurityHelper.randomBytes(32);
byte[] encrypted = SecurityHelper.encrypt(seed, bytes);
byte[] decrypted = SecurityHelper.decrypt(seed, encrypted);
Assertions.assertArrayEquals(bytes, decrypted);
}
@Test
public void aesStreamTest() throws Exception {
byte[] bytes = SecurityHelper.randomBytes(128);
byte[] seed = SecurityHelper.randomAESKey();
byte[] encrypted;
ByteArrayOutputStream s = new ByteArrayOutputStream();
try (OutputStream o = new CipherOutputStream(s, SecurityHelper.newAESEncryptCipher(seed))) {
try (ByteArrayInputStream i = new ByteArrayInputStream(bytes)) {
IOHelper.transfer(i, o);
}
}
encrypted = s.toByteArray();
byte[] decrypted;
try (InputStream i = new CipherInputStream(new ByteArrayInputStream(encrypted), SecurityHelper.newAESDecryptCipher(seed))) {
try (ByteArrayOutputStream s2 = new ByteArrayOutputStream()) {
IOHelper.transfer(i, s2);
decrypted = s2.toByteArray();
}
}
Assertions.assertArrayEquals(bytes, decrypted);
}
}

View file

@ -183,7 +183,13 @@ public CompletableFuture<Void> downloadFiles(List<SizedFile> files, String baseU
} }
try { try {
DownloadTask task = sendAsync(file, baseUri, targetDir, callback); DownloadTask task = sendAsync(file, baseUri, targetDir, callback);
task.completableFuture.thenAccept(consumerObject.next).exceptionally(ec -> { task.completableFuture.thenCompose((res) -> {
if(res.statusCode() < 200 || res.statusCode() >= 300) {
return CompletableFuture.failedFuture(new IOException(String.format("Failed to download %s: code %d",
file.urlPath != null ? file.urlPath /* TODO: baseUri */ : file.filePath, res.statusCode())));
}
return CompletableFuture.completedFuture(res);
}).thenAccept(consumerObject.next).exceptionally(ec -> {
future.completeExceptionally(ec); future.completeExceptionally(ec);
return null; return null;
}); });
@ -234,7 +240,7 @@ protected HttpRequest makeHttpRequest(URI baseUri, String filePath) throws URISy
} }
protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadCallback callback) { protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadCallback callback) {
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE), callback); return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING), callback);
} }
public interface DownloadCallback { public interface DownloadCallback {

View file

@ -15,6 +15,7 @@
public class InstallAuthlib { public class InstallAuthlib {
private static final Map<String, LibrariesHashFileModifier> modifierMap; private static final Map<String, LibrariesHashFileModifier> modifierMap;
private static final String tempLaunchAuthLibName = "authlib.jar";
static { static {
modifierMap = new HashMap<>(); modifierMap = new HashMap<>();
modifierMap.put("META-INF/libraries.list", new LibrariesLstModifier()); modifierMap.put("META-INF/libraries.list", new LibrariesLstModifier());
@ -26,30 +27,30 @@ public void run(String... args) throws Exception {
boolean deleteAuthlibAfterInstall = false; boolean deleteAuthlibAfterInstall = false;
InstallAuthlibContext context = new InstallAuthlibContext(); InstallAuthlibContext context = new InstallAuthlibContext();
if(args[0].startsWith("http://") || args[0].startsWith("https://")) { if(args[0].startsWith("http://") || args[0].startsWith("https://")) {
Path tempAuthlib = Paths.get("authlib.jar"); Path tempAuthlib = Paths.get(tempLaunchAuthLibName);
LogHelper.info("Download %s to %s", args[0], tempAuthlib); LogHelper.info("Download %s to %s", args[0], tempAuthlib);
try(InputStream input = IOHelper.newInput(new URL(args[0]))) { try(InputStream input = IOHelper.newInput(new URL(args[0]))) {
IOHelper.transfer(input, tempAuthlib); IOHelper.transfer(input, tempAuthlib);
} }
context.pathToAuthlib = tempAuthlib; context.pathToAuthlib = tempAuthlib.toAbsolutePath();
deleteAuthlibAfterInstall = true; deleteAuthlibAfterInstall = true;
} else { } else {
context.pathToAuthlib = Paths.get(args[0]); context.pathToAuthlib = Paths.get(args[0]).toAbsolutePath();
} }
if(Files.notExists(context.pathToAuthlib)) { if(Files.notExists(context.pathToAuthlib)) {
throw new FileNotFoundException(context.pathToAuthlib.toString()); throw new FileNotFoundException(context.pathToAuthlib.toString());
} }
context.workdir = IOHelper.WORKING_DIR;
LogHelper.info("Search .jar files in %s", context.workdir.toAbsolutePath()); LogHelper.info("Search .jar files in %s", context.workdir.toAbsolutePath());
IOHelper.walk(context.workdir, new SimpleFileVisitor<Path>() { IOHelper.walk(context.workdir, new SimpleFileVisitor<Path>() {
@Override @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if(file.getFileName().toString().endsWith(".jar")) { if (file.getFileName().toString().endsWith(".jar") && !file.equals(context.pathToAuthlib)) {
context.files.add(file); context.files.add(file);
} }
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
}, true); }, true);
context.files.sort(Comparator.comparingInt((Path path) -> - path.getNameCount()));
LogHelper.info("Search authlib in %d files", context.files.size()); LogHelper.info("Search authlib in %d files", context.files.size());
for(Path path : context.files) { for(Path path : context.files) {
boolean foundAuthlib = false; boolean foundAuthlib = false;

View file

@ -5,7 +5,7 @@
id 'org.openjfx.javafxplugin' version '0.0.10' apply false id 'org.openjfx.javafxplugin' version '0.0.10' apply false
} }
group = 'pro.gravit.launcher' group = 'pro.gravit.launcher'
version = '5.5.4' version = '5.5.6'
apply from: 'props.gradle' apply from: 'props.gradle'

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

@ -1 +1 @@
Subproject commit 7581b6c01470a5ec32ac67170635d10f6f589b0a Subproject commit f02bbbc20de0cbbf45f82b2dc5e2efcb1d846d44

View file

@ -1,8 +1,8 @@
project.ext { project.ext {
verAsm = '9.6' verAsm = '9.7'
verNetty = '4.1.99.Final' verNetty = '4.1.110.Final'
verOshiCore = '6.4.11' verOshiCore = '6.6.1'
verJunit = '5.9.3' verJunit = '5.10.2'
verGuavaC = '30.1.1-jre' verGuavaC = '30.1.1-jre'
verJansi = '2.4.1' verJansi = '2.4.1'
verJline = '3.25.0' verJline = '3.25.0'
@ -12,8 +12,8 @@
verBcpkix = '1.70' verBcpkix = '1.70'
verSlf4j = '1.7.36' verSlf4j = '1.7.36'
verLog4j = '2.20.0' verLog4j = '2.20.0'
verMySQLConn = '8.3.0' verMySQLConn = '8.4.0'
verPostgreSQLConn = '42.7.1' verPostgreSQLConn = '42.7.3'
verProguard = '7.4.1' verProguard = '7.5.0'
verLaunch4j = '3.50' verLaunch4j = '3.50'
} }