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