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