Merge branch 'release/5.1.3'

This commit is contained in:
Gravit 2020-04-04 20:54:44 +07:00
commit 45e3d0b18e
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
62 changed files with 602 additions and 1250 deletions

82
.github/workflows/push.yml vendored Normal file
View file

@ -0,0 +1,82 @@
name: push
on:
push:
create:
tags:
- v*
jobs:
launcher:
name: Launcher
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: recursive
- name: Cache Gradle
uses: actions/cache@v1
with:
path: ~/.gradle/caches
key: gravit-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}-launcher
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Create artifacts
run: |
mkdir -p artifacts/modules
cd LaunchServer/build/libs/
zip -r -9 ../../../artifacts/libraries.zip * -x "LaunchServer.jar" -x "LaunchServer-clean.jar"
cp LaunchServer.jar ../../../artifacts/LaunchServer.jar
cd ../../../ServerWrapper/build/libs
cp ServerWrapper.jar ../../../artifacts/ServerWrapper.jar
cd ../../../LauncherAuthlib/build/libs
cp LauncherAuthlib.jar ../../../artifacts/LauncherAuthlib.jar
cd ../../../
cp modules/*_module/build/libs/*.jar artifacts/modules
cp modules/*_swmodule/build/libs/*.jar artifacts/modules
cp modules/*_lmodule/build/libs/*.jar artifacts/modules
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: Launcher
path: artifacts
- name: Create release
id: create_release
uses: actions/create-release@v1
if: github.event_name == 'create'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: GravitLauncher ${{ github.ref }}
draft: false
prerelease: false
- name: Pack release
if: github.event_name == 'create'
run: |
cd artifacts/
zip -r -9 ../Release.zip *
- name: Upload release
if: github.event_name == 'create'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./Release.zip
asset_name: Release.zip
asset_content_type: application/zip

1
.gitignore vendored
View file

@ -109,3 +109,4 @@ cmd.bat
cmd.sh cmd.sh
## PVS Studio ## PVS Studio
.PVS-Studio/ .PVS-Studio/
project/target

View file

@ -1,90 +0,0 @@
image: gradle:jdk11
stages:
- build
- test
- deploy
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
before_script:
- apt-get -y update
- 'which zip || ( apt-get -y install zip )'
- 'which git || ( apt-get -y install git )'
- export GRADLE_USER_HOME=`pwd`/.gradle
- chmod +x gradlew
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - > /dev/null
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- git submodule sync
- mv modules modules_cache || true
- git submodule update --init --recursive --force
- cp -a modules_cache/* modules/ || true
build:
stage: build
script:
- gradle assemble
after_script:
- mkdir -p artifacts/modules
- cd LaunchServer/build/libs/
- zip -r -9 ../../../artifacts/libraries.zip * -x "LaunchServer.jar" -x "LaunchServer-clean.jar"
- cp LaunchServer.jar ../../../artifacts/LaunchServer.jar
- cd ../../../ServerWrapper/build/libs
- cp ServerWrapper.jar ../../../artifacts/ServerWrapper.jar
- cd ../../../LauncherAuthlib/build/libs
- cp LauncherAuthlib.jar ../../../artifacts/LauncherAuthlib.jar
- cd ../../../
- cp modules/*_module/build/libs/*.jar artifacts/modules
- cp modules/*_swmodule/build/libs/*.jar artifacts/modules
- cp modules/*_lmodule/build/libs/*.jar artifacts/modules
cache:
key: "$CI_COMMIT_REF_NAME"
paths:
- .gradle
- LaunchServer/build
- Launcher/build
- LauncherCore/build
- LauncherAPI/build
- LauncherAuthlib/build
- modules/*_*module/build
artifacts:
expire_in: 6 week
paths:
- artifacts
test:
stage: test
script:
- gradle check
cache:
key: "$CI_COMMIT_REF_NAME"
policy: pull
paths:
- .gradle
- LaunchServer/build
- Launcher/build
- LauncherCore/build
- LauncherAPI/build
- LauncherAuthlib/build
- modules/*_*module/build
deploy-demo:
stage: deploy
only: [dev]
script:
- gradle build
- eval $(ssh $SSH_USER@$SSH_HOST 'cd $SSH_DIR && cat deploy.sh')
cache:
key: "$CI_COMMIT_REF_NAME"
policy: pull
paths:
- .gradle
- LaunchServer/build
- Launcher/build
- LauncherCore/build
- LauncherAPI/build
- LauncherAuthlib/build
- modules/*_*module/build

2
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "modules"] [submodule "modules"]
path = modules path = modules
url = git@github.com:GravitLauncher/LauncherModules.git url = https://github.com/GravitLauncher/LauncherModules.git

View file

@ -1,22 +0,0 @@
language: java
dist: trusty
jdk:
- openjdk11
# Use https (public access) instead of git for git-submodules. This modifies only Travis-CI behavior!
# disable the default submodule logic
git:
submodules: false
# use sed to replace the SSH URL with the public URL, then init and update submodules
before_install:
- sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules
- git submodule update --init --recursive
# gradle
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
script:
- ./gradlew build

View file

@ -100,7 +100,7 @@ pack project(':LauncherAPI')
exclude group: 'org.slf4j' exclude group: 'org.slf4j'
} }
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + ':workdir-win32') { transitive = false } launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + ':workdir-win32') { transitive = false }
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + 'workdir-linux') { transitive = false } launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + ':workdir-linux64') { transitive = false }
compileOnlyA group: 'com.google.guava', name: 'guava', version: rootProject['verGuavaC'] compileOnlyA group: 'com.google.guava', name: 'guava', version: rootProject['verGuavaC']
// Do not update (laggy deps). // Do not update (laggy deps).

View file

@ -98,7 +98,6 @@ public void reload(ReloadType type) throws Exception {
LogHelper.debug("Init components"); LogHelper.debug("Init components");
config.components.forEach((k, v) -> { config.components.forEach((k, v) -> {
LogHelper.subDebug("Init component %s", k); LogHelper.subDebug("Init component %s", k);
registerObject("component.".concat(k), v);
v.init(this); v.init(this);
}); });
LogHelper.debug("Init components successful"); LogHelper.debug("Init components successful");

View file

@ -43,8 +43,8 @@ public synchronized Connection getConnection() throws SQLException {
PGSimpleDataSource postgresqlSource = new PGSimpleDataSource(); PGSimpleDataSource postgresqlSource = new PGSimpleDataSource();
// Set credentials // Set credentials
postgresqlSource.setServerName(address); postgresqlSource.setServerNames(new String[] {address}); //TODO support multinode PostgreSQL DB
postgresqlSource.setPortNumber(port); postgresqlSource.setPortNumbers(new int[] {port});
postgresqlSource.setUser(username); postgresqlSource.setUser(username);
postgresqlSource.setPassword(password); postgresqlSource.setPassword(password);
postgresqlSource.setDatabaseName(database); postgresqlSource.setDatabaseName(database);

View file

@ -21,6 +21,7 @@ public static class authResult {
String username; String username;
String error; String error;
long permissions; long permissions;
long flags;
} }
public static class authRequest { public static class authRequest {
@ -54,7 +55,7 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
authResult result = gson.fromJson(content, authResult.class); authResult result = gson.fromJson(content, authResult.class);
if (result.username != null) if (result.username != null)
return new AuthProviderResult(result.username, SecurityHelper.randomStringToken(), new ClientPermissions(result.permissions)); return new AuthProviderResult(result.username, SecurityHelper.randomStringToken(), new ClientPermissions(result.permissions, result.flags));
else if (result.error != null) else if (result.error != null)
return authError(result.error); return authError(result.error);
else else

View file

@ -20,6 +20,7 @@ public final class MySQLAuthProvider extends AuthProvider {
private String query; private String query;
private String message; private String message;
private String[] queryParams; private String[] queryParams;
private boolean flagsEnabled;
@Override @Override
public void init(LaunchServer srv) { public void init(LaunchServer srv) {
@ -41,7 +42,8 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
// Execute SQL query // Execute SQL query
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT); s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
try (ResultSet set = s.executeQuery()) { try (ResultSet set = s.executeQuery()) {
return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), new ClientPermissions(set.getLong(2))) : authError(message); return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), new ClientPermissions(
set.getLong(2), flagsEnabled ? set.getLong(3) : 0)) : authError(message);
} }
} }

View file

@ -19,6 +19,7 @@ public final class PostgreSQLAuthProvider extends AuthProvider {
private String query; private String query;
private String message; private String message;
private String[] queryParams; private String[] queryParams;
private boolean flagsEnabled;
@Override @Override
public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws SQLException, AuthException { public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws SQLException, AuthException {
@ -32,7 +33,8 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
// Execute SQL query // Execute SQL query
s.setQueryTimeout(PostgreSQLSourceConfig.TIMEOUT); s.setQueryTimeout(PostgreSQLSourceConfig.TIMEOUT);
try (ResultSet set = s.executeQuery()) { try (ResultSet set = s.executeQuery()) {
return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), new ClientPermissions(set.getLong(2))) : authError(message); return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), new ClientPermissions(
set.getLong(2), flagsEnabled ? set.getLong(3) : 0)) : authError(message);
} }
} }
} }

View file

@ -22,7 +22,7 @@ public RejectAuthProvider(String message) {
} }
private String message; private String message;
private ArrayList<String> whitelist; private ArrayList<String> whitelist = new ArrayList<>();
@Override @Override
public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws AuthException { public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws AuthException {
@ -46,11 +46,20 @@ public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>(); Map<String, Command> commands = new HashMap<>();
commands.put("message", new SubCommand() { commands.put("message", new SubCommand() {
@Override @Override
public void invoke(String... args) { public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
message = args[0]; message = args[0];
LogHelper.info("New reject message: %s", message); LogHelper.info("New reject message: %s", message);
} }
}); });
commands.put("whirelist.add", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
whitelist.add(args[0]);
LogHelper.info("%s added to whitelist", args[0]);
}
});
return commands; return commands;
} }
} }

View file

@ -19,6 +19,7 @@ public final class RequestAuthProvider extends AuthProvider {
private String url; private String url;
private transient Pattern pattern; private transient Pattern pattern;
private String response; private String response;
private boolean flagsEnabled;
@Override @Override
public void init(LaunchServer srv) { public void init(LaunchServer srv) {
@ -36,7 +37,8 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
// Match username // Match username
Matcher matcher = pattern.matcher(currentResponse); Matcher matcher = pattern.matcher(currentResponse);
return matcher.matches() && matcher.groupCount() >= 1 ? return matcher.matches() && matcher.groupCount() >= 1 ?
new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), new ClientPermissions(Long.parseLong(matcher.group("permission")))) : new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), new ClientPermissions(
Long.parseLong(matcher.group("permissions")), flagsEnabled ? Long.parseLong(matcher.group("flags")) : 0)) :
authError(currentResponse); authError(currentResponse);
} }

View file

@ -52,6 +52,7 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
updates.registerCommand("syncBinaries", new SyncBinariesCommand(server)); updates.registerCommand("syncBinaries", new SyncBinariesCommand(server));
updates.registerCommand("syncUpdates", new SyncUpdatesCommand(server)); updates.registerCommand("syncUpdates", new SyncUpdatesCommand(server));
updates.registerCommand("syncProfiles", new SyncProfilesCommand(server)); updates.registerCommand("syncProfiles", new SyncProfilesCommand(server));
updates.registerCommand("saveProfiles", new SaveProfilesCommand(server));
Category updatesCategory = new Category(updates, "updates", "Update and Sync Management"); Category updatesCategory = new Category(updates, "updates", "Update and Sync Management");
handler.registerCategory(updatesCategory); handler.registerCategory(updatesCategory);

View file

@ -0,0 +1,64 @@
package pro.gravit.launchserver.command.hash;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
public class SaveProfilesCommand extends Command {
public SaveProfilesCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[profile names...]";
}
@Override
public String getUsageDescription() {
return "load and save profile";
}
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
if(args.length > 0)
{
for(String profileName : args)
{
Path profilePath = server.profilesDir.resolve(profileName.concat(".json"));
if(!Files.exists(profilePath))
{
LogHelper.error("Profile %s not found", profilePath.toString());
return;
}
ClientProfile profile;
try(Reader reader = IOHelper.newReader(profilePath))
{
profile = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class);
}
saveProfile(profile, profilePath);
LogHelper.info("Profile %s save successful", profilePath.toString());
}
server.syncProfilesDir();
}
}
public static void saveProfile(ClientProfile profile, Path path) throws IOException
{
if(profile.getUUID() == null) profile.setUUID(UUID.randomUUID());
try(Writer w = IOHelper.newWriter(path))
{
Launcher.gsonManager.configGson.toJson(profile, w);
}
}
}

View file

@ -16,8 +16,6 @@
import java.util.Map; import java.util.Map;
public final class UnindexAssetCommand extends Command { public final class UnindexAssetCommand extends Command {
private static final JsonParser parser = new JsonParser();
public UnindexAssetCommand(LaunchServer server) { public UnindexAssetCommand(LaunchServer server) {
super(server); super(server);
} }
@ -51,7 +49,7 @@ public void invoke(String... args) throws Exception {
JsonObject objects; JsonObject objects;
LogHelper.subInfo("Reading asset index file: '%s'", indexFileName); LogHelper.subInfo("Reading asset index file: '%s'", indexFileName);
try (BufferedReader reader = IOHelper.newReader(IndexAssetCommand.resolveIndexFile(inputAssetDir, indexFileName))) { try (BufferedReader reader = IOHelper.newReader(IndexAssetCommand.resolveIndexFile(inputAssetDir, indexFileName))) {
objects = parser.parse(reader).getAsJsonObject().get("objects").getAsJsonObject(); objects = JsonParser.parseReader(reader).getAsJsonObject().get("objects").getAsJsonObject();
} }
// Restore objects // Restore objects

View file

@ -36,7 +36,7 @@ public void invoke(String... args) {
LogHelper.info("Client name %s | ip %s | connectUUID %s", client.username == null ? "null" : client.username, ip, frameHandler.getConnectUUID()); LogHelper.info("Client name %s | ip %s | connectUUID %s", client.username == null ? "null" : client.username, ip, frameHandler.getConnectUUID());
LogHelper.subInfo("Data: checkSign %s | auth_id %s", client.checkSign ? "true" : "false", LogHelper.subInfo("Data: checkSign %s | auth_id %s", client.checkSign ? "true" : "false",
client.auth_id); client.auth_id);
LogHelper.subInfo("Permissions: %s (long %d)", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.toLong()); LogHelper.subInfo("Permissions: %s (permissions %d | flags %d)", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.permissions, client.permissions == null ? 0 : client.permissions.flags);
} }
})); }));
} }

View file

@ -5,6 +5,7 @@
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherConfig; import pro.gravit.launcher.LauncherConfig;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.handler.MemoryAuthHandler; import pro.gravit.launchserver.auth.handler.MemoryAuthHandler;
import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.ProtectHandler;
@ -124,8 +125,10 @@ public void init(LaunchServer.ReloadType type) {
for (Map.Entry<String,AuthProviderPair> provider : auth.entrySet()) { for (Map.Entry<String,AuthProviderPair> provider : auth.entrySet()) {
provider.getValue().init(server, provider.getKey()); provider.getValue().init(server, provider.getKey());
} }
if (dao != null) if (dao != null) {
server.registerObject("dao", dao);
dao.init(server); dao.init(server);
}
if (protectHandler != null) { if (protectHandler != null) {
protectHandler.checkLaunchServerLicense(); protectHandler.checkLaunchServerLicense();
} }
@ -149,6 +152,7 @@ public void close(LaunchServer.ReloadType type) {
server.unregisterObject("auth.".concat(pair.name).concat(".provider"), pair.provider); server.unregisterObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
server.unregisterObject("auth.".concat(pair.name).concat(".handler"), pair.handler); server.unregisterObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
server.unregisterObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider); server.unregisterObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
pair.close();
} }
} }
if (type.equals(LaunchServer.ReloadType.FULL)) { if (type.equals(LaunchServer.ReloadType.FULL)) {
@ -166,10 +170,16 @@ public void close(LaunchServer.ReloadType type) {
} catch (Exception e) { } catch (Exception e) {
LogHelper.error(e); LogHelper.error(e);
} }
try { if(dao != null) {
for (AuthProviderPair p : auth.values()) p.close(); server.unregisterObject("dao", dao);
} catch (IOException e) { if(dao instanceof AutoCloseable)
LogHelper.error(e); {
try {
((AutoCloseable) dao).close();
} catch (Exception e) {
LogHelper.error(e);
}
}
} }
} }

View file

@ -12,7 +12,7 @@
import java.util.Arrays; import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
@Entity @Entity(name = "User")
@Table(name = "users") @Table(name = "users")
public class UserHibernateImpl implements User { public class UserHibernateImpl implements User {
@Id @Id
@ -29,6 +29,7 @@ public class UserHibernateImpl implements User {
public String serverID; public String serverID;
private String password_salt; private String password_salt;
public long permissions; public long permissions;
public long flags;
public void setPassword(String password) { public void setPassword(String password) {
password_salt = SecurityHelper.randomStringAESKey(); password_salt = SecurityHelper.randomStringAESKey();
@ -55,11 +56,12 @@ public boolean verifyPassword(String password) {
} }
public ClientPermissions getPermissions() { public ClientPermissions getPermissions() {
return new ClientPermissions(permissions); return new ClientPermissions(permissions, flags);
} }
public void setPermissions(ClientPermissions permissions) { public void setPermissions(ClientPermissions permissions) {
this.permissions = permissions.toLong(); this.permissions = permissions.permissions;
this.flags = permissions.flags;
} }
public String getAccessToken() { public String getAccessToken() {

View file

@ -2,14 +2,22 @@
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.dao.impl.UserHibernateImpl; import pro.gravit.launchserver.dao.impl.UserHibernateImpl;
import pro.gravit.launchserver.dao.impl.HibernateUserDAOImpl; import pro.gravit.launchserver.dao.impl.HibernateUserDAOImpl;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.LogHelper;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class HibernateDaoProvider extends DaoProvider { public class HibernateDaoProvider extends DaoProvider implements Reconfigurable, AutoCloseable {
public String driver; public String driver;
public String url; public String url;
public String username; public String username;
@ -42,4 +50,72 @@ public void init(LaunchServer server) {
else else
init.run(); init.run();
} }
@Override
public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>();
commands.put("getallusers", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
int count = 0;
for (User user : userDAO.findAll()) {
LogHelper.subInfo("[%s] UUID: %s", user.getUsername(), user.getUuid().toString());
count++;
}
LogHelper.info("Print %d users", count);
}
});
commands.put("getuser", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
User user = userDAO.findByUsername(args[0]);
if (user == null) {
LogHelper.error("User %s not found", args[0]);
return;
}
LogHelper.info("[%s] UUID: %s | permissions %s", user.getUsername(), user.getUuid().toString(), user.getPermissions() == null ? "null" : user.getPermissions().toString());
}
});
commands.put("givepermission", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 3);
User user = userDAO.findByUsername(args[0]);
if (user == null) {
LogHelper.error("User %s not found", args[0]);
return;
}
ClientPermissions permissions = user.getPermissions();
long perm = Long.parseLong(args[1]);
boolean value = Boolean.parseBoolean(args[2]);
permissions.setPermission(perm, value);
user.setPermissions(permissions);
userDAO.update(user);
}
});
commands.put("giveflag", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 3);
User user = userDAO.findByUsername(args[0]);
if (user == null) {
LogHelper.error("User %s not found", args[0]);
return;
}
ClientPermissions permissions = user.getPermissions();
long perm = Long.parseLong(args[1]);
boolean value = Boolean.parseBoolean(args[2]);
permissions.setFlag(perm, value);
user.setPermissions(permissions);
userDAO.update(user);
}
});
return commands;
}
@Override
public void close() throws Exception {
sessionFactory.close();
}
} }

View file

@ -1,6 +1,7 @@
package pro.gravit.launchserver.socket.response.admin; package pro.gravit.launchserver.socket.response.admin;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.events.request.LogEvent; import pro.gravit.launcher.events.request.LogEvent;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse; import pro.gravit.launchserver.socket.response.SimpleResponse;
@ -20,7 +21,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
sendError("Access denied"); sendError("Access denied");
return; return;
} }
if (!client.permissions.canAdmin) { if (!client.permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN)) {
sendError("Access denied"); sendError("Access denied");
return; return;
} }

View file

@ -1,6 +1,7 @@
package pro.gravit.launchserver.socket.response.admin; package pro.gravit.launchserver.socket.response.admin;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.events.request.ExecCommandRequestEvent; import pro.gravit.launcher.events.request.ExecCommandRequestEvent;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse; import pro.gravit.launchserver.socket.response.SimpleResponse;
@ -15,7 +16,7 @@ public String getType() {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) { public void execute(ChannelHandlerContext ctx, Client client) {
if (!client.isAuth || !client.permissions.canAdmin) { if (!client.isAuth || !client.permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN)) {
sendError("Access denied"); sendError("Access denied");
return; return;
} }

View file

@ -1,6 +1,7 @@
package pro.gravit.launchserver.socket.response.auth; package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.events.RequestEvent; import pro.gravit.launcher.events.RequestEvent;
import pro.gravit.launcher.events.request.ExitRequestEvent; import pro.gravit.launcher.events.request.ExitRequestEvent;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
@ -17,7 +18,7 @@ public String getType() {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) throws Exception { public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
if(username != null && ( !client.isAuth || client.permissions == null || !client.permissions.canAdmin )) if(username != null && ( !client.isAuth || client.permissions == null || !client.permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN) ))
{ {
sendError("Permissions denied"); sendError("Permissions denied");
return; return;

View file

@ -1,6 +1,7 @@
package pro.gravit.launchserver.socket.response.auth; package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launchserver.dao.User; import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.dao.impl.UserHibernateImpl; import pro.gravit.launchserver.dao.impl.UserHibernateImpl;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
@ -21,7 +22,7 @@ public class RegisterResponse extends SimpleResponse {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) throws Exception { public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
byte[] normalHash = registerHash(login, server.runtime.registerApiKey); byte[] normalHash = registerHash(login, server.runtime.registerApiKey);
if (!(client.isAuth && client.permissions.canAdmin) && !Arrays.equals(normalHash, verifyHash)) { if (!(client.isAuth && client.permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN)) && !Arrays.equals(normalHash, verifyHash)) {
sendError("Hash invalid"); sendError("Hash invalid");
return; return;
} }

View file

@ -1,6 +1,7 @@
package pro.gravit.launchserver.socket.response.auth; package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.events.request.SetPasswordRequestEvent; import pro.gravit.launcher.events.request.SetPasswordRequestEvent;
import pro.gravit.launchserver.dao.User; import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
@ -26,7 +27,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
sendError("You not authorized"); sendError("You not authorized");
return; return;
} }
if (username != null && !client.permissions.canAdmin) { if (username != null && !client.permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN)) {
sendError("You not admin"); sendError("You not admin");
return; return;
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher; package pro.gravit.launcher;
import pro.gravit.launcher.client.ClientLauncher;
import pro.gravit.launcher.client.ClientModuleManager; import pro.gravit.launcher.client.ClientModuleManager;
import pro.gravit.launcher.client.DirBridge; import pro.gravit.launcher.client.DirBridge;
import pro.gravit.launcher.utils.DirWatcher; import pro.gravit.launcher.utils.DirWatcher;
@ -72,10 +71,13 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep
tryAddModule(findPath, "javafx.graphics", builder); tryAddModule(findPath, "javafx.graphics", builder);
tryAddModule(findPath, "javafx.fxml", builder); tryAddModule(findPath, "javafx.fxml", builder);
tryAddModule(findPath, "javafx.controls", builder); tryAddModule(findPath, "javafx.controls", builder);
boolean useSwing = tryAddModule(findPath, "javafx.swing", builder);
String modulePath = builder.toString(); String modulePath = builder.toString();
if (!modulePath.isEmpty()) { if (!modulePath.isEmpty()) {
args.add("--add-modules"); args.add("--add-modules");
args.add("javafx.base,javafx.fxml,javafx.controls,jdk.unsupported"); String javaModules = "javafx.base,javafx.fxml,javafx.controls,jdk.unsupported";
if(useSwing) javaModules = javaModules.concat(",javafx.swing");
args.add(javaModules);
args.add("--module-path"); args.add("--module-path");
args.add(modulePath); args.add(modulePath);
} }

View file

@ -4,11 +4,13 @@
import pro.gravit.launcher.client.events.ClientEngineInitPhase; import pro.gravit.launcher.client.events.ClientEngineInitPhase;
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.guard.LauncherGuardInterface;
import pro.gravit.launcher.guard.LauncherGuardManager; import pro.gravit.launcher.guard.LauncherGuardManager;
import pro.gravit.launcher.guard.LauncherNoGuard;
import pro.gravit.launcher.guard.LauncherWrapperGuard;
import pro.gravit.launcher.gui.NoRuntimeProvider; import pro.gravit.launcher.gui.NoRuntimeProvider;
import pro.gravit.launcher.gui.RuntimeProvider; import pro.gravit.launcher.gui.RuntimeProvider;
import pro.gravit.launcher.managers.ClientGsonManager; import pro.gravit.launcher.managers.ClientGsonManager;
import pro.gravit.launcher.managers.ClientHookManager;
import pro.gravit.launcher.managers.ConsoleManager; import pro.gravit.launcher.managers.ConsoleManager;
import pro.gravit.launcher.modules.events.PreConfigPhase; import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
@ -40,6 +42,7 @@ public static X509Certificate[] getCertificates(Class<?> clazz) {
public static final AtomicBoolean IS_CLIENT = new AtomicBoolean(false); public static final AtomicBoolean IS_CLIENT = new AtomicBoolean(false);
public static ClientLauncherProcess.ClientParams clientParams; public static ClientLauncherProcess.ClientParams clientParams;
public static LauncherGuardInterface guard;
public static void checkClass(Class<?> clazz) throws SecurityException { public static void checkClass(Class<?> clazz) throws SecurityException {
LauncherTrustManager trustManager = Launcher.getConfig().trustManager; LauncherTrustManager trustManager = Launcher.getConfig().trustManager;
@ -146,11 +149,11 @@ private LauncherEngine() {
public void start(String... args) throws Throwable { public void start(String... args) throws Throwable {
//Launcher.modulesManager = new ClientModuleManager(this); //Launcher.modulesManager = new ClientModuleManager(this);
LauncherEngine.guard = tryGetStdGuard();
ClientPreGuiPhase event = new ClientPreGuiPhase(null); ClientPreGuiPhase event = new ClientPreGuiPhase(null);
LauncherEngine.modulesManager.invokeEvent(event); LauncherEngine.modulesManager.invokeEvent(event);
runtimeProvider = event.runtimeProvider; runtimeProvider = event.runtimeProvider;
if (runtimeProvider == null) runtimeProvider = new NoRuntimeProvider(); if (runtimeProvider == null) runtimeProvider = new NoRuntimeProvider();
ClientHookManager.initGuiHook.hook(runtimeProvider);
runtimeProvider.init(false); runtimeProvider.init(false);
//runtimeProvider.preLoad(); //runtimeProvider.preLoad();
if (Request.service == null) { if (Request.service == null) {
@ -186,6 +189,18 @@ public void start(String... args) throws Throwable {
runtimeProvider.run(args); runtimeProvider.run(args);
} }
public static LauncherGuardInterface tryGetStdGuard()
{
switch (Launcher.getConfig().guardType)
{
case "no":
return new LauncherNoGuard();
case "wrapper":
return new LauncherWrapperGuard();
}
return null;
}
public static LauncherEngine clientInstance() { public static LauncherEngine clientInstance() {
return new LauncherEngine(); return new LauncherEngine();
} }

View file

@ -12,10 +12,6 @@ public class AuthService {
public static ClientProfile profile; public static ClientProfile profile;
public static boolean isAdmin() { public static boolean isAdmin() {
return permissions.canAdmin; return permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN);
}
public static boolean isServer() {
return permissions.canServer;
} }
} }

View file

@ -1,685 +0,0 @@
package pro.gravit.launcher.client;
import pro.gravit.launcher.*;
import pro.gravit.launcher.api.AuthService;
import pro.gravit.launcher.api.ClientService;
import pro.gravit.launcher.client.events.ClientLaunchPhase;
import pro.gravit.launcher.client.events.ClientLauncherInitPhase;
import pro.gravit.launcher.client.events.ClientLauncherPostInitPhase;
import pro.gravit.launcher.guard.LauncherGuardManager;
import pro.gravit.launcher.hasher.FileNameMatcher;
import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.managers.ClientGsonManager;
import pro.gravit.launcher.managers.ClientHookManager;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.patches.FMLPatcher;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.auth.RestoreSessionRequest;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.stream.StreamObject;
import pro.gravit.launcher.utils.DirWatcher;
import pro.gravit.utils.Version;
import pro.gravit.utils.helper.*;
import pro.gravit.utils.helper.JVMHelper.OS;
import javax.swing.*;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.*;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class ClientLauncher {
public static int getClientJVMBits() {
return LauncherGuardManager.guard.getClientJVMBits();
}
private static final class ClassPathFileVisitor extends SimpleFileVisitor<Path> {
private final Stream.Builder<Path> result;
private ClassPathFileVisitor(Stream.Builder<Path> result) {
this.result = result;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (IOHelper.hasExtension(file, "jar") || IOHelper.hasExtension(file, "zip"))
result.accept(file);
return super.visitFile(file, attrs);
}
}
public static final class Params extends StreamObject {
// Client paths
public final Path assetDir;
public final Path clientDir;
// Client params
public final PlayerProfile pp;
public final String accessToken;
public final boolean autoEnter;
public final boolean fullScreen;
public final int ram;
public final int width;
public final int height;
public final long session;
public Params(byte[] launcherDigest, Path assetDir, Path clientDir, PlayerProfile pp, String accessToken,
boolean autoEnter, boolean fullScreen, int ram, int width, int height) {
// Client paths
this.assetDir = assetDir;
this.clientDir = clientDir;
// Client params
this.pp = pp;
this.accessToken = accessToken;
this.autoEnter = autoEnter;
this.fullScreen = fullScreen;
this.ram = ram;
this.width = width;
this.height = height;
this.session = Request.getSession();
}
public Params(HInput input) throws Exception {
session = input.readLong();
// Client paths
assetDir = IOHelper.toPath(input.readString(0));
clientDir = IOHelper.toPath(input.readString(0));
// Client params
pp = new PlayerProfile(input);
byte[] encryptedAccessToken = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
accessToken = new String(SecurityHelper.decrypt(Launcher.getConfig().secretKeyClient.getBytes(), encryptedAccessToken));
autoEnter = input.readBoolean();
fullScreen = input.readBoolean();
ram = input.readVarInt();
width = input.readVarInt();
height = input.readVarInt();
}
@Override
public void write(HOutput output) throws IOException {
output.writeLong(session);
// Client paths
output.writeString(assetDir.toString(), 0);
output.writeString(clientDir.toString(), 0);
pp.write(output);
try {
output.writeByteArray(SecurityHelper.encrypt(Launcher.getConfig().secretKeyClient.getBytes(), accessToken.getBytes()), SecurityHelper.CRYPTO_MAX_LENGTH);
} catch (Exception e) {
LogHelper.error(e);
}
output.writeBoolean(autoEnter);
output.writeBoolean(fullScreen);
output.writeVarInt(ram);
output.writeVarInt(width);
output.writeVarInt(height);
}
}
private static final String SOCKET_HOST = "127.0.0.1";
private static final int SOCKET_PORT = Launcher.getConfig().clientPort;
private static final String MAGICAL_INTEL_OPTION = "-XX:HeapDumpPath=ThisTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump";
private static Path JavaBinPath;
@SuppressWarnings("unused")
private static final Set<PosixFilePermission> BIN_POSIX_PERMISSIONS = Collections.unmodifiableSet(EnumSet.of(
PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE, // Owner
PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_EXECUTE, // Group
PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_EXECUTE // Others
));
// Constants
private static final Path NATIVES_DIR = IOHelper.toPath("natives");
private static final Path RESOURCEPACKS_DIR = IOHelper.toPath("resourcepacks");
private static ClientClassLoader classLoader;
public static class ClientUserProperties {
String[] skinURL;
String[] skinDigest;
String[] cloakURL;
String[] cloakDigest;
}
public static Path getJavaBinPath() {
return JavaBinPath;
}
private static void addClientArgs(Collection<String> args, ClientProfile profile, Params params) {
PlayerProfile pp = params.pp;
// Add version-dependent args
ClientProfile.Version version = profile.getVersion();
Collections.addAll(args, "--username", pp.username);
if (version.compareTo(ClientProfile.Version.MC172) >= 0) {
Collections.addAll(args, "--uuid", Launcher.toHash(pp.uuid));
Collections.addAll(args, "--accessToken", params.accessToken);
// Add 1.7.10+ args (user properties, asset index)
if (version.compareTo(ClientProfile.Version.MC1710) >= 0) {
// Add user properties
Collections.addAll(args, "--userType", "mojang");
ClientUserProperties properties = new ClientUserProperties();
if (pp.skin != null) {
properties.skinURL = new String[]{pp.skin.url};
properties.skinDigest = new String[]{SecurityHelper.toHex(pp.skin.digest)};
}
if (pp.cloak != null) {
properties.cloakURL = new String[]{pp.cloak.url};
properties.cloakDigest = new String[]{SecurityHelper.toHex(pp.cloak.digest)};
}
Collections.addAll(args, "--userProperties", Launcher.gsonManager.gson.toJson(properties));
// Add asset index
Collections.addAll(args, "--assetIndex", profile.getAssetIndex());
}
} else
Collections.addAll(args, "--session", params.accessToken);
// Add version and dirs args
Collections.addAll(args, "--version", profile.getVersion().name);
Collections.addAll(args, "--gameDir", params.clientDir.toString());
Collections.addAll(args, "--assetsDir", params.assetDir.toString());
Collections.addAll(args, "--resourcePackDir", params.clientDir.resolve(RESOURCEPACKS_DIR).toString());
if (version.compareTo(ClientProfile.Version.MC194) >= 0)
Collections.addAll(args, "--versionType", "Launcher v" + Version.getVersion().getVersionString());
// Add server args
if (params.autoEnter) {
Collections.addAll(args, "--server", profile.getServerAddress());
Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
}
profile.pushOptionalClientArgs(args);
// Add window size args
if (params.fullScreen)
Collections.addAll(args, "--fullscreen", Boolean.toString(true));
if (params.width > 0 && params.height > 0) {
Collections.addAll(args, "--width", Integer.toString(params.width));
Collections.addAll(args, "--height", Integer.toString(params.height));
}
}
public static void setJavaBinPath(Path javaBinPath) {
JavaBinPath = javaBinPath;
}
private static void addClientLegacyArgs(Collection<String> args, ClientProfile profile, Params params) {
args.add(params.pp.username);
args.add(params.accessToken);
// Add args for tweaker
Collections.addAll(args, "--version", profile.getVersion().name);
Collections.addAll(args, "--gameDir", params.clientDir.toString());
Collections.addAll(args, "--assetsDir", params.assetDir.toString());
}
public static void checkJVMBitsAndVersion() {
if (JVMHelper.JVM_BITS != JVMHelper.OS_BITS) {
String error = String.format("У Вас установлена Java %d, но Ваша система определена как %d. Установите Java правильной разрядности", JVMHelper.JVM_BITS, JVMHelper.OS_BITS);
LogHelper.error(error);
if (Launcher.getConfig().isWarningMissArchJava)
JOptionPane.showMessageDialog(null, error);
}
String jvmVersion = JVMHelper.RUNTIME_MXBEAN.getVmVersion();
LogHelper.info(jvmVersion);
if (jvmVersion.startsWith("10.") || jvmVersion.startsWith("9.") || jvmVersion.startsWith("11.")) {
String error = String.format("У Вас установлена Java %s. Для правильной работы необходима Java 8", JVMHelper.RUNTIME_MXBEAN.getVmVersion());
LogHelper.error(error);
if (Launcher.getConfig().isWarningMissArchJava)
JOptionPane.showMessageDialog(null, error);
}
}
public static boolean isLaunched() {
return Launcher.LAUNCHED.get();
}
private static void launch(ClientProfile profile, Params params) throws Throwable {
// Add client args
Collection<String> args = new LinkedList<>();
if (profile.getVersion().compareTo(ClientProfile.Version.MC164) >= 0)
addClientArgs(args, profile, params);
else {
addClientLegacyArgs(args, profile, params);
System.setProperty("minecraft.applet.TargetDirectory", params.clientDir.toString());
}
Collections.addAll(args, profile.getClientArgs());
List<String> copy = new ArrayList<>(args);
for (int i = 0, l = copy.size(); i < l; i++) {
String s = copy.get(i);
if (i + 1 < l && ("--accessToken".equals(s) || "--session".equals(s))) {
copy.set(i + 1, "censored");
}
}
LogHelper.debug("Args: " + copy);
// Resolve main class and method
Class<?> mainClass = classLoader.loadClass(profile.getMainClass());
for(URL u : classLoader.getURLs())
{
LogHelper.info("ClassLoader URL: %s", u.toString());
}
FMLPatcher.apply();
MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
Launcher.LAUNCHED.set(true);
JVMHelper.fullGC();
// Invoke main method
try {
mainMethod.invokeWithArguments((Object) args.toArray(new String[0]));
LogHelper.debug("Main exit successful");
} catch (Throwable e) {
LogHelper.error(e);
throw e;
} finally {
LauncherEngine.exitLauncher(0);
}
}
private static Process process = null;
private static boolean clientStarted = false;
private static Thread writeParamsThread;
public static void setWriteParamsThread(Thread writeParamsThread) {
ClientLauncher.writeParamsThread = writeParamsThread;
ClientLauncher.writeParamsThread.start();
}
public static Process getProcess() {
return process;
}
public static void setClientStarted() {
clientStarted = true;
}
public static PlayerProfile playerProfile;
public static Process launch(
HashedDir assetHDir, HashedDir clientHDir,
ClientProfile profile, Params params, boolean pipeOutput) throws Throwable {
LogHelper.debug("Writing ClientLauncher params");
ClientLauncherContext context = new ClientLauncherContext();
clientStarted = false;
container.write(new ParamContainer(params, profile, assetHDir, clientHDir));
checkJVMBitsAndVersion();
LogHelper.debug("Resolving JVM binary");
Path javaBin = LauncherGuardManager.getGuardJavaBinPath();
context.javaBin = javaBin;
context.clientProfile = profile;
context.playerProfile = params.pp;
context.args.add(javaBin.toString());
context.args.add(MAGICAL_INTEL_OPTION);
if (params.ram > 0) {
context.args.add("-Xms" + params.ram + 'M');
context.args.add("-Xmx" + params.ram + 'M');
}
context.args.add(JVMHelper.jvmProperty(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled())));
context.args.add(JVMHelper.jvmProperty(LogHelper.STACKTRACE_PROPERTY, Boolean.toString(LogHelper.isStacktraceEnabled())));
context.args.add(JVMHelper.jvmProperty(LogHelper.DEV_PROPERTY, Boolean.toString(LogHelper.isDevEnabled())));
context.args.add(JVMHelper.jvmProperty(LogHelper.NO_JANSI_PROPERTY, "true")); // Отключаем JAnsi для нормального вывода в DEBUG окно
JVMHelper.addSystemPropertyToArgs(context.args, DirBridge.CUSTOMDIR_PROPERTY);
JVMHelper.addSystemPropertyToArgs(context.args, DirBridge.USE_CUSTOMDIR_PROPERTY);
JVMHelper.addSystemPropertyToArgs(context.args, DirBridge.USE_OPTDIR_PROPERTY);
JVMHelper.addSystemPropertyToArgs(context.args, DirWatcher.IGN_OVERFLOW);
if (JVMHelper.OS_TYPE == OS.MUSTDIE) {
if (JVMHelper.OS_VERSION.startsWith("10.")) {
LogHelper.debug("MustDie 10 fix is applied");
context.args.add(JVMHelper.jvmProperty("os.name", "Windows 10"));
context.args.add(JVMHelper.jvmProperty("os.version", "10.0"));
}
}
// Add classpath and main class
context.pathLauncher = IOHelper.getCodeSource(ClientLauncher.class).toString();
context.args.add(ClientLauncherWrapper.MAGIC_ARG);
Collections.addAll(context.args, profile.getJvmArgs());
profile.pushOptionalJvmArgs(context.args);
context.args.add("-Djava.library.path=".concat(params.clientDir.resolve(NATIVES_DIR).toString())); // Add Native Path
//context.args.add("-javaagent:".concat(pathLauncher));
ClientHookManager.clientLaunchHook.hook(context);
LauncherGuardManager.guard.addCustomParams(context);
context.args.add(ClientLauncher.class.getName());
ClientHookManager.clientLaunchFinallyHook.hook(context);
// Print commandline debug message
LogHelper.debug("Commandline: " + context.args);
// Build client process
LogHelper.debug("Launching client instance");
ProcessBuilder builder = new ProcessBuilder(context.args);
context.builder = builder;
LauncherGuardManager.guard.addCustomEnv(context);
//else
//builder.environment().put("CLASSPATH", classPathString.toString());
EnvHelper.addEnv(builder);
builder.directory(params.clientDir.toFile());
builder.inheritIO();
if (pipeOutput) {
builder.redirectErrorStream(true);
builder.redirectOutput(Redirect.PIPE);
}
List<String> command = builder.command();
// Let's rock!
ClientHookManager.preStartHook.hook(context, builder);
process = builder.start();
if (builder.command() != command) {
LogHelper.error("Something strange cheating...");
System.exit(100);
clientStarted = false;
return null;
}
if (ClientHookManager.postStartHook.hook(context, builder)) return process;
if (!pipeOutput) {
for (int i = 0; i < 50; ++i) {
if (!process.isAlive()) {
int exitCode = process.exitValue();
LogHelper.error("Process exit code %d", exitCode);
if (writeParamsThread != null && writeParamsThread.isAlive()) writeParamsThread.interrupt();
break;
}
if (clientStarted) {
break;
}
Thread.sleep(200);
}
if (!clientStarted) {
LogHelper.error("Client did not start properly. Enable debug mode for more information");
}
}
clientStarted = false;
return process;
}
public static class ClientLaunchContext {
public final Params params;
public final ClientProfile profile;
public final HashedDir assetHDir, clientHDir;
public DirWatcher assetWatcher, clientWatcher;
public ClientLaunchContext(Params params, ClientProfile profile, HashedDir assetHDir, HashedDir clientHDir) {
this.params = params;
this.profile = profile;
this.assetHDir = assetHDir;
this.clientHDir = clientHDir;
}
}
public static void main(String... args) throws Throwable {
LauncherEngine.IS_CLIENT.set(true);
LauncherEngine engine = LauncherEngine.clientInstance();
LauncherEngine.checkClass(LauncherEngine.class);
LauncherEngine.checkClass(LauncherAgent.class);
LauncherEngine.checkClass(ClientLauncher.class);
LauncherEngine.modulesManager = new ClientModuleManager();
LauncherConfig.initModules(LauncherEngine.modulesManager); //INIT
LauncherEngine.modulesManager.initModules(null);
initGson(LauncherEngine.modulesManager);
LauncherEngine.verifyNoAgent();
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
JVMHelper.verifySystemProperties(ClientLauncher.class, true);
EnvHelper.checkDangerousParams();
JVMHelper.checkStackTrace(ClientLauncher.class);
LogHelper.printVersion("Client Launcher");
engine.readKeys();
LauncherGuardManager.initGuard(true);
LogHelper.debug("Reading ClientLauncher params");
ParamContainer p = container.read();
Params params = p.params;
ClientProfile profile = p.profile;
HashedDir assetHDir = p.assetHDir, clientHDir = p.clientHDir;
ClientLaunchContext context = new ClientLaunchContext(params, profile, assetHDir, clientHDir);
Launcher.profile = profile;
AuthService.profile = profile;
playerProfile = params.pp;
Request.setSession(params.session);
checkJVMBitsAndVersion();
LauncherEngine.modulesManager.invokeEvent(new ClientLauncherInitPhase(context));
// Verify ClientLauncher sign and classpath
LogHelper.debug("Verifying ClientLauncher sign and classpath");
URL[] classpath = resolveClassPath(params.clientDir, profile.getClassPath());
classLoader = new ClientClassLoader(classpath, ClassLoader.getSystemClassLoader());
profile.pushOptionalClassPath(cp -> {
LinkedList<Path> optionalClassPath = resolveClassPathList(params.clientDir, cp);
for (Path classpathURL : optionalClassPath) {
classLoader.addURL(classpathURL.normalize().toAbsolutePath().toUri().toURL());
}
});
Thread.currentThread().setContextClassLoader(classLoader);
classLoader.nativePath = params.clientDir.resolve(NATIVES_DIR).toString();
// Start client with WatchService monitoring
boolean digest = !profile.isUpdateFastCheck();
LogHelper.debug("Restore sessions");
RestoreSessionRequest request = new RestoreSessionRequest(Request.getSession());
request.request();
Request.service.reconnectCallback = () ->
{
LogHelper.debug("WebSocket connect closed. Try reconnect");
try {
Request.service.open();
LogHelper.debug("Connect to %s", Launcher.getConfig().address);
} catch (Exception e) {
LogHelper.error(e);
throw new RequestException(String.format("Connect error: %s", e.getMessage() != null ? e.getMessage() : "null"));
}
try {
RestoreSessionRequest request1 = new RestoreSessionRequest(Request.getSession());
request1.request();
} catch (Exception e) {
LogHelper.error(e);
}
};
AuthService.username = params.pp.username;
AuthService.uuid = params.pp.uuid;
ClientService.classLoader = classLoader;
ClientService.nativePath = classLoader.nativePath;
classLoader.addURL(IOHelper.getCodeSource(ClientLauncher.class).toUri().toURL());
//classForName(classLoader, "com.google.common.collect.ForwardingMultimap");
ClientService.baseURLs = classLoader.getURLs();
LogHelper.debug("Starting JVM and client WatchService");
FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher();
FileNameMatcher clientMatcher = profile.getClientUpdateMatcher();
try (DirWatcher assetWatcher = new DirWatcher(params.assetDir, assetHDir, assetMatcher, digest);
DirWatcher clientWatcher = new DirWatcher(params.clientDir, clientHDir, clientMatcher, digest)) {
// Verify current state of all dirs
//verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null, digest);
//for (OptionalFile s : Launcher.profile.getOptional()) {
// if (params.updateOptional.contains(s)) s.mark = true;
// else hdir.removeR(s.file);
//}
context.assetWatcher = assetWatcher;
context.clientWatcher = clientWatcher;
Launcher.profile.pushOptionalFile(clientHDir, false);
LauncherEngine.modulesManager.invokeEvent(new ClientLauncherPostInitPhase(context));
// Start WatchService, and only then client
CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
verifyHDir(params.assetDir, assetHDir, assetMatcher, digest);
verifyHDir(params.clientDir, clientHDir, clientMatcher, digest);
LauncherEngine.modulesManager.invokeEvent(new ClientLaunchPhase(context));
launch(profile, params);
}
}
public static void classForName(ClassLoader loader, String name)
{
try {
Class.forName(name, false, loader);
} catch (ClassNotFoundException ignored) {
}
}
private static URL[] resolveClassPath(Path clientDir, String... classPath) throws IOException {
return resolveClassPathStream(clientDir, classPath).map(IOHelper::toURL).toArray(URL[]::new);
}
private static LinkedList<Path> resolveClassPathList(Path clientDir, String... classPath) throws IOException {
return resolveClassPathStream(clientDir, classPath).collect(Collectors.toCollection(LinkedList::new));
}
private static Stream<Path> resolveClassPathStream(Path clientDir, String... classPath) throws IOException {
Stream.Builder<Path> builder = Stream.builder();
for (String classPathEntry : classPath) {
Path path = clientDir.resolve(IOHelper.toPath(classPathEntry.replace(IOHelper.CROSS_SEPARATOR, IOHelper.PLATFORM_SEPARATOR)));
if (IOHelper.isDir(path)) { // Recursive walking and adding
IOHelper.walk(path, new ClassPathFileVisitor(builder), false);
continue;
}
builder.accept(path);
}
return builder.build();
}
private static void initGson(ClientModuleManager moduleManager) {
Launcher.gsonManager = new ClientGsonManager(moduleManager);
Launcher.gsonManager.initGson();
}
public static void setProfile(ClientProfile profile) {
Launcher.profile = profile;
LogHelper.debug("New Profile name: %s", profile.getTitle());
}
public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest) throws IOException {
//if (matcher != null)
// matcher = matcher.verifyOnly();
// Hash directory and compare (ignore update-only matcher entries, it will break offline-mode)
HashedDir currentHDir = new HashedDir(dir, matcher, true, digest);
HashedDir.Diff diff = hdir.diff(currentHDir, matcher);
if (!diff.isSame()) {
/*AtomicBoolean isFoundFile = new AtomicBoolean(false);
diff.extra.walk(File.separator, (e,k,v) -> {
if(v.getType().equals(HashedEntry.Type.FILE)) { LogHelper.error("Extra file %s", e); isFoundFile.set(true); }
else LogHelper.error("Extra %s", e);
});
diff.mismatch.walk(File.separator, (e,k,v) -> {
if(v.getType().equals(HashedEntry.Type.FILE)) { LogHelper.error("Mismatch file %s", e); isFoundFile.set(true); }
else LogHelper.error("Mismatch %s", e);
});
if(isFoundFile.get())*/
throw new SecurityException(String.format("Forbidden modification: '%s'", IOHelper.getFileName(dir)));
}
}
private ClientLauncher() {
}
public interface ParamsAPI {
ParamContainer read() throws Exception;
void write(ParamContainer p) throws Exception;
}
public static ParamsAPI container = new ParamsAPI() {
@Override
public ParamContainer read() throws Exception {
ParamContainer p;
try (Socket socket = IOHelper.newSocket()) {
socket.connect(new InetSocketAddress(SOCKET_HOST, SOCKET_PORT));
try (HInput input = new HInput(socket.getInputStream())) {
p = new ParamContainer(input);
}
}
return p;
}
@Override
public void write(ParamContainer p) throws Exception {
setWriteParamsThread(CommonHelper.newThread("Client params writter", true, () ->
{
try {
try (ServerSocket socket = new ServerSocket()) {
socket.setReuseAddress(true);
socket.setSoTimeout(30000);
socket.bind(new InetSocketAddress(SOCKET_HOST, SOCKET_PORT));
Socket client = socket.accept();
if (process == null) {
LogHelper.error("Process is null");
return;
}
if (!process.isAlive()) {
LogHelper.error("Process is not alive");
JOptionPane.showMessageDialog(null, "Client Process crashed", "Launcher", JOptionPane.ERROR_MESSAGE);
return;
}
try (HOutput output = new HOutput(client.getOutputStream())) {
p.write(output);
}
clientStarted = true;
}
} catch (IOException e) {
LogHelper.error(e);
}
}));
}
};
public static class ParamContainer extends StreamObject {
public ParamContainer(HInput input) throws Exception {
params = new Params(input);
profile = Launcher.gsonManager.gson.fromJson(input.readString(0), ClientProfile.class);
assetHDir = new HashedDir(input);
clientHDir = new HashedDir(input);
ClientHookManager.paramsInputHook.hook(input);
}
public ParamContainer() {
}
public ParamContainer(Params params, ClientProfile profile, HashedDir assetHDir, HashedDir clientHDir) {
this.params = params;
this.profile = profile;
this.assetHDir = assetHDir;
this.clientHDir = clientHDir;
}
public Params params;
public ClientProfile profile;
public HashedDir assetHDir, clientHDir;
@Override
public void write(HOutput output) throws IOException {
params.write(output);
output.writeString(Launcher.gsonManager.gson.toJson(profile), 0);
assetHDir.write(output);
clientHDir.write(output);
ClientHookManager.paramsOutputHook.hook(output);
}
}
}

View file

@ -1,19 +0,0 @@
package pro.gravit.launcher.client;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launcher.profiles.PlayerProfile;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
public class ClientLauncherContext {
public Path javaBin;
public final List<String> args = new LinkedList<>();
public String pathLauncher;
public ProcessBuilder builder;
public Process process;
public ClientProfile clientProfile;
public PlayerProfile playerProfile;
public ClientLauncher.Params params;
}

View file

@ -6,9 +6,7 @@
import pro.gravit.launcher.LauncherEngine; import pro.gravit.launcher.LauncherEngine;
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.client.events.ClientLaunchPhase; import pro.gravit.launcher.client.events.client.*;
import pro.gravit.launcher.client.events.ClientLauncherInitPhase;
import pro.gravit.launcher.client.events.ClientLauncherPostInitPhase;
import pro.gravit.launcher.guard.LauncherGuardManager; 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;
@ -34,7 +32,6 @@
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.security.spec.InvalidKeySpecException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -59,6 +56,10 @@ private static ClientLauncherProcess.ClientParams readParams(SocketAddress addre
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
LauncherEngine.IS_CLIENT.set(true); LauncherEngine.IS_CLIENT.set(true);
LauncherEngine engine = LauncherEngine.clientInstance(); LauncherEngine engine = LauncherEngine.clientInstance();
JVMHelper.verifySystemProperties(ClientLauncherEntryPoint.class, true);
EnvHelper.checkDangerousParams();
JVMHelper.checkStackTrace(ClientLauncherEntryPoint.class);
LogHelper.printVersion("Client Launcher");
LauncherEngine.checkClass(LauncherEngine.class); LauncherEngine.checkClass(LauncherEngine.class);
LauncherEngine.checkClass(LauncherAgent.class); LauncherEngine.checkClass(LauncherAgent.class);
LauncherEngine.checkClass(ClientLauncherEntryPoint.class); LauncherEngine.checkClass(ClientLauncherEntryPoint.class);
@ -68,10 +69,6 @@ public static void main(String[] args) throws Throwable {
initGson(LauncherEngine.modulesManager); initGson(LauncherEngine.modulesManager);
LauncherEngine.verifyNoAgent(); LauncherEngine.verifyNoAgent();
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase()); LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
JVMHelper.verifySystemProperties(ClientLauncherEntryPoint.class, true);
EnvHelper.checkDangerousParams();
JVMHelper.checkStackTrace(ClientLauncherEntryPoint.class);
LogHelper.printVersion("Client Launcher");
engine.readKeys(); engine.readKeys();
LauncherGuardManager.initGuard(true); LauncherGuardManager.initGuard(true);
LogHelper.debug("Reading ClientLauncher params"); LogHelper.debug("Reading ClientLauncher params");
@ -82,7 +79,7 @@ public static void main(String[] args) throws Throwable {
LauncherEngine.clientParams = params; LauncherEngine.clientParams = params;
Request.setSession(params.session); Request.setSession(params.session);
checkJVMBitsAndVersion(); checkJVMBitsAndVersion();
LauncherEngine.modulesManager.invokeEvent(new ClientLauncherInitPhase(null)); LauncherEngine.modulesManager.invokeEvent(new ClientProcessInitPhase(engine, params));
Path clientDir = Paths.get(params.clientDir); Path clientDir = Paths.get(params.clientDir);
Path assetDir = Paths.get(params.assetDir); Path assetDir = Paths.get(params.assetDir);
@ -98,6 +95,7 @@ public static void main(String[] args) throws Throwable {
classLoader = new ClientClassLoader(classpath.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); classLoader = new ClientClassLoader(classpath.toArray(new URL[0]), ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(classLoader); Thread.currentThread().setContextClassLoader(classLoader);
classLoader.nativePath = clientDir.resolve("natives").toString(); classLoader.nativePath = clientDir.resolve("natives").toString();
LauncherEngine.modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(engine, classLoader, profile));
// Start client with WatchService monitoring // Start client with WatchService monitoring
boolean digest = !profile.isUpdateFastCheck(); boolean digest = !profile.isUpdateFastCheck();
LogHelper.debug("Restore sessions"); LogHelper.debug("Restore sessions");
@ -127,6 +125,7 @@ public static void main(String[] args) throws Throwable {
classLoader.addURL(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL()); classLoader.addURL(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL());
//classForName(classLoader, "com.google.common.collect.ForwardingMultimap"); //classForName(classLoader, "com.google.common.collect.ForwardingMultimap");
ClientService.baseURLs = classLoader.getURLs(); ClientService.baseURLs = classLoader.getURLs();
LauncherEngine.modulesManager.invokeEvent(new ClientProcessReadyEvent(engine, params));
LogHelper.debug("Starting JVM and client WatchService"); LogHelper.debug("Starting JVM and client WatchService");
FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher(); FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher();
FileNameMatcher clientMatcher = profile.getClientUpdateMatcher(); FileNameMatcher clientMatcher = profile.getClientUpdateMatcher();
@ -144,6 +143,7 @@ public static void main(String[] args) throws Throwable {
CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start(); CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
verifyHDir(assetDir, params.assetHDir, assetMatcher, digest); verifyHDir(assetDir, params.assetHDir, assetMatcher, digest);
verifyHDir(clientDir, params.clientHDir, clientMatcher, digest); verifyHDir(clientDir, params.clientHDir, clientMatcher, digest);
LauncherEngine.modulesManager.invokeEvent(new ClientProcessLaunchEvent(engine, params));
launch(profile, params); launch(profile, params);
} }
} }
@ -244,6 +244,7 @@ private static void launch(ClientProfile profile, ClientLauncherProcess.ClientPa
LogHelper.info("ClassLoader URL: %s", u.toString()); LogHelper.info("ClassLoader URL: %s", u.toString());
} }
FMLPatcher.apply(); FMLPatcher.apply();
LauncherEngine.modulesManager.invokeEvent(new ClientProcessPreInvokeMainClassEvent(params, profile, args));
MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity(); MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
Launcher.LAUNCHED.set(true); Launcher.LAUNCHED.set(true);
JVMHelper.fullGC(); JVMHelper.fullGC();

View file

@ -1,7 +1,12 @@
package pro.gravit.launcher.client; package pro.gravit.launcher.client;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.guard.LauncherGuardManager; import pro.gravit.launcher.LauncherEngine;
import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.client.events.client.ClientProcessBuilderCreateEvent;
import pro.gravit.launcher.client.events.client.ClientProcessBuilderLaunchedEvent;
import pro.gravit.launcher.client.events.client.ClientProcessBuilderParamsWrittedEvent;
import pro.gravit.launcher.client.events.client.ClientProcessBuilderPreLaunchEvent;
import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launcher.profiles.PlayerProfile; import pro.gravit.launcher.profiles.PlayerProfile;
@ -10,10 +15,7 @@
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
import pro.gravit.utils.helper.*; import pro.gravit.utils.helper.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress; import java.net.SocketAddress;
@ -24,9 +26,9 @@
public class ClientLauncherProcess { public class ClientLauncherProcess {
private transient Process process; private transient Process process;
private final transient Boolean[] waitWriteParams = new Boolean[] {false}; private final transient Boolean[] waitWriteParams = new Boolean[] {false};
public final Path executeFile; public Path executeFile;
public final Path workDir; public Path workDir;
public final Path javaDir; public Path javaDir;
public final ClientParams params = new ClientParams(); public final ClientParams params = new ClientParams();
public final List<String> jvmArgs = new LinkedList<>(); public final List<String> jvmArgs = new LinkedList<>();
public final List<String> systemClientArgs = new LinkedList<>(); public final List<String> systemClientArgs = new LinkedList<>();
@ -42,18 +44,24 @@ public ClientLauncherProcess(Path executeFile, Path workDir, Path javaDir, Strin
this.mainClass = mainClass; this.mainClass = mainClass;
} }
public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir,
ClientProfile profile, PlayerProfile playerProfile, String accessToken,
HashedDir clientHDir, HashedDir assetHDir, HashedDir jvmHDir) {
this(clientDir, assetDir, javaDir, clientDir.resolve("resourcepacks"), profile, playerProfile, 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, clientDir.resolve("resourcepacks"), profile, playerProfile, accessToken, clientHDir, assetHDir, jvmHDir); this(clientDir, assetDir, Paths.get(System.getProperty("java.home")), clientDir.resolve("resourcepacks"), profile, playerProfile, accessToken, clientHDir, assetHDir, jvmHDir);
} }
public ClientLauncherProcess(Path clientDir, Path assetDir, Path resourcePackDir, public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, Path resourcePackDir,
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.executeFile = LauncherGuardManager.getGuardJavaBinPath();
this.workDir = clientDir.toAbsolutePath(); this.workDir = clientDir.toAbsolutePath();
this.javaDir = Paths.get(System.getProperty("java.home")); this.javaDir = javaDir;
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();
@ -78,6 +86,7 @@ private void applyClientProfile()
this.jvmArgs.add("-Xmx" + params.ram + 'M'); this.jvmArgs.add("-Xmx" + params.ram + 'M');
} }
this.params.session = Request.getSession(); this.params.session = Request.getSession();
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderCreateEvent(this));
} }
@ -128,6 +137,18 @@ public void addClientArgs(Collection<String> args)
} }
public static class ClientUserProperties {
@LauncherNetworkAPI
public String[] skinURL;
@LauncherNetworkAPI
public String[] skinDigest;
@LauncherNetworkAPI
public String[] cloakURL;
@LauncherNetworkAPI
public String[] cloakDigest;
}
public void addClientLegacyArgs(Collection<String> args) { public void addClientLegacyArgs(Collection<String> args) {
args.add(playerProfile.username); args.add(playerProfile.username);
args.add(accessToken); args.add(accessToken);
@ -151,7 +172,7 @@ private void addModernClientArgs(Collection<String> args) {
if (version.compareTo(ClientProfile.Version.MC1710) >= 0) { if (version.compareTo(ClientProfile.Version.MC1710) >= 0) {
// Add user properties // Add user properties
Collections.addAll(args, "--userType", "mojang"); Collections.addAll(args, "--userType", "mojang");
ClientLauncher.ClientUserProperties properties = new ClientLauncher.ClientUserProperties(); ClientUserProperties properties = new ClientUserProperties();
if (playerProfile.skin != null) { if (playerProfile.skin != null) {
properties.skinURL = new String[]{playerProfile.skin.url}; properties.skinURL = new String[]{playerProfile.skin.url};
properties.skinDigest = new String[]{SecurityHelper.toHex(playerProfile.skin.digest)}; properties.skinDigest = new String[]{SecurityHelper.toHex(playerProfile.skin.digest)};
@ -193,6 +214,8 @@ private void addModernClientArgs(Collection<String> args) {
} }
public void start(boolean pipeOutput) throws IOException, InterruptedException { public void start(boolean pipeOutput) throws IOException, InterruptedException {
if(isStarted) throw new IllegalStateException("Process already started"); if(isStarted) throw new IllegalStateException("Process already started");
if(LauncherEngine.guard != null) LauncherEngine.guard.applyGuardParams(this);
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderPreLaunchEvent(this));
List<String> processArgs = new LinkedList<>(); List<String> processArgs = new LinkedList<>();
processArgs.add(executeFile.toString()); processArgs.add(executeFile.toString());
processArgs.addAll(jvmArgs); processArgs.addAll(jvmArgs);
@ -212,6 +235,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().putAll(systemEnv); processBuilder.environment().putAll(systemEnv);
processBuilder.directory(workDir.toFile()); processBuilder.directory(workDir.toFile());
processBuilder.inheritIO(); processBuilder.inheritIO();
@ -220,6 +244,7 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException {
processBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE); processBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE);
} }
process = processBuilder.start(); process = processBuilder.start();
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderLaunchedEvent(this));
isStarted = true; isStarted = true;
} }
public void runWriteParams(SocketAddress address) throws IOException public void runWriteParams(SocketAddress address) throws IOException
@ -242,6 +267,7 @@ public void runWriteParams(SocketAddress address) throws IOException
params.javaHDir.write(output); params.javaHDir.write(output);
} }
} }
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderParamsWrittedEvent(this));
} }
public Process getProcess() { public Process getProcess() {

View file

@ -20,7 +20,6 @@
import java.util.regex.Pattern; import java.util.regex.Pattern;
public final class ServerPinger { public final class ServerPinger {
private final JsonParser parser = new JsonParser();
public static final class Result { public static final class Result {
@ -184,7 +183,7 @@ private Result modernPing(HInput input, HOutput output) throws IOException {
} }
// Parse JSON response // Parse JSON response
JsonObject object = parser.parse(response).getAsJsonObject(); JsonObject object = JsonParser.parseString(response).getAsJsonObject();
JsonObject playersObject = object.get("players").getAsJsonObject(); JsonObject playersObject = object.get("players").getAsJsonObject();
int online = playersObject.get("online").getAsInt(); int online = playersObject.get("online").getAsInt();
int max = playersObject.get("max").getAsInt(); int max = playersObject.get("max").getAsInt();

View file

@ -1,12 +0,0 @@
package pro.gravit.launcher.client.events;
import pro.gravit.launcher.client.ClientLauncher;
import pro.gravit.launcher.modules.LauncherModule;
public class ClientLaunchPhase extends LauncherModule.Event {
public final ClientLauncher.ClientLaunchContext context;
public ClientLaunchPhase(ClientLauncher.ClientLaunchContext context) {
this.context = context;
}
}

View file

@ -1,12 +0,0 @@
package pro.gravit.launcher.client.events;
import pro.gravit.launcher.client.ClientLauncher;
import pro.gravit.launcher.modules.events.InitPhase;
public class ClientLauncherInitPhase extends InitPhase {
public final ClientLauncher.ClientLaunchContext context;
public ClientLauncherInitPhase(ClientLauncher.ClientLaunchContext context) {
this.context = context;
}
}

View file

@ -1,12 +0,0 @@
package pro.gravit.launcher.client.events;
import pro.gravit.launcher.client.ClientLauncher;
import pro.gravit.launcher.modules.events.PostInitPhase;
public class ClientLauncherPostInitPhase extends PostInitPhase {
public final ClientLauncher.ClientLaunchContext context;
public ClientLauncherPostInitPhase(ClientLauncher.ClientLaunchContext context) {
this.context = context;
}
}

View file

@ -0,0 +1,12 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.LauncherModule;
public class ClientProcessBuilderCreateEvent extends LauncherModule.Event {
public final ClientLauncherProcess processBuilder;
public ClientProcessBuilderCreateEvent(ClientLauncherProcess processBuilder) {
this.processBuilder = processBuilder;
}
}

View file

@ -0,0 +1,12 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.LauncherModule;
public class ClientProcessBuilderLaunchedEvent extends LauncherModule.Event {
public final ClientLauncherProcess processBuilder;
public ClientProcessBuilderLaunchedEvent(ClientLauncherProcess processBuilder) {
this.processBuilder = processBuilder;
}
}

View file

@ -0,0 +1,12 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.LauncherModule;
public class ClientProcessBuilderParamsWrittedEvent extends LauncherModule.Event {
public final ClientLauncherProcess process;
public ClientProcessBuilderParamsWrittedEvent(ClientLauncherProcess process) {
this.process = process;
}
}

View file

@ -0,0 +1,12 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.LauncherModule;
public class ClientProcessBuilderPreLaunchEvent extends LauncherModule.Event {
public final ClientLauncherProcess processBuilder;
public ClientProcessBuilderPreLaunchEvent(ClientLauncherProcess processBuilder) {
this.processBuilder = processBuilder;
}
}

View file

@ -0,0 +1,17 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.LauncherEngine;
import pro.gravit.launcher.modules.LauncherModule;
import pro.gravit.launcher.profiles.ClientProfile;
public class ClientProcessClassLoaderEvent extends LauncherModule.Event {
public final LauncherEngine clientInstance;
public final ClassLoader clientClassLoader;
public final ClientProfile profile;
public ClientProcessClassLoaderEvent(LauncherEngine clientInstance, ClassLoader clientClassLoader, ClientProfile profile) {
this.clientInstance = clientInstance;
this.clientClassLoader = clientClassLoader;
this.profile = profile;
}
}

View file

@ -0,0 +1,15 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.LauncherEngine;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.events.InitPhase;
public class ClientProcessInitPhase extends InitPhase {
public final LauncherEngine clientInstance;
public final ClientLauncherProcess.ClientParams params;
public ClientProcessInitPhase(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) {
this.clientInstance = clientInstance;
this.params = params;
}
}

View file

@ -0,0 +1,15 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.LauncherEngine;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.LauncherModule;
public class ClientProcessLaunchEvent extends LauncherModule.Event {
public final LauncherEngine clientInstance;
public final ClientLauncherProcess.ClientParams params;
public ClientProcessLaunchEvent(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) {
this.clientInstance = clientInstance;
this.params = params;
}
}

View file

@ -0,0 +1,19 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.LauncherModule;
import pro.gravit.launcher.profiles.ClientProfile;
import java.util.Collection;
public class ClientProcessPreInvokeMainClassEvent extends LauncherModule.Event {
public final ClientLauncherProcess.ClientParams params;
public final ClientProfile profile;
public final Collection<String> args;
public ClientProcessPreInvokeMainClassEvent(ClientLauncherProcess.ClientParams params, ClientProfile profile, Collection<String> args) {
this.params = params;
this.profile = profile;
this.args = args;
}
}

View file

@ -0,0 +1,16 @@
package pro.gravit.launcher.client.events.client;
import pro.gravit.launcher.LauncherEngine;
import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.modules.events.PostInitPhase;
import pro.gravit.launcher.profiles.ClientProfile;
public class ClientProcessReadyEvent extends PostInitPhase {
public final LauncherEngine clientInstance;
public final ClientLauncherProcess.ClientParams params;
public ClientProcessReadyEvent(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) {
this.clientInstance = clientInstance;
this.params = params;
}
}

View file

@ -1,21 +1,9 @@
package pro.gravit.launcher.guard; package pro.gravit.launcher.guard;
import pro.gravit.launcher.client.ClientLauncherContext; import pro.gravit.launcher.client.ClientLauncherProcess;
import java.nio.file.Path;
public interface LauncherGuardInterface { public interface LauncherGuardInterface {
String getName(); String getName();
Path getJavaBinPath(); void applyGuardParams(ClientLauncherProcess process);
int getClientJVMBits();
void init(boolean clientInstance);
void addCustomParams(ClientLauncherContext context);
void addCustomEnv(ClientLauncherContext context);
void setProtectToken(String token);
} }

View file

@ -9,31 +9,5 @@ public class LauncherGuardManager {
public static LauncherGuardInterface guard; public static LauncherGuardInterface guard;
public static void initGuard(boolean clientInstance) { public static void initGuard(boolean clientInstance) {
if(guard == null)
{
LauncherConfig config = Launcher.getConfig();
switch (config.guardType) {
case "stdguard": {
guard = new LauncherStdGuard();
break;
}
case "wrapper": {
guard = new LauncherWrapperGuard();
break;
}
case "java": {
guard = new LauncherJavaGuard();
break;
}
default: {
guard = new LauncherNoGuard();
}
}
}
guard.init(clientInstance);
}
public static Path getGuardJavaBinPath() {
return guard.getJavaBinPath();
} }
} }

View file

@ -1,51 +0,0 @@
package pro.gravit.launcher.guard;
import pro.gravit.launcher.client.ClientLauncher;
import pro.gravit.launcher.client.ClientLauncherContext;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
public class LauncherJavaGuard implements LauncherGuardInterface {
@Override
public String getName() {
return "java";
}
@Override
public Path getJavaBinPath() {
if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE)
return IOHelper.resolveJavaBin(ClientLauncher.getJavaBinPath());
else
return IOHelper.resolveJavaBin(Paths.get(System.getProperty("java.home")));
}
@Override
public int getClientJVMBits() {
return JVMHelper.OS_BITS;
}
@Override
public void init(boolean clientInstance) {
}
@Override
public void addCustomParams(ClientLauncherContext context) {
Collections.addAll(context.args, "-cp");
Collections.addAll(context.args, context.pathLauncher);
}
@Override
public void addCustomEnv(ClientLauncherContext context) {
}
@Override
public void setProtectToken(String token) {
//Skip
}
}

View file

@ -1,13 +1,6 @@
package pro.gravit.launcher.guard; package pro.gravit.launcher.guard;
import pro.gravit.launcher.client.ClientLauncherContext; import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
public class LauncherNoGuard implements LauncherGuardInterface { public class LauncherNoGuard implements LauncherGuardInterface {
@Override @Override
@ -16,33 +9,7 @@ public String getName() {
} }
@Override @Override
public Path getJavaBinPath() { public void applyGuardParams(ClientLauncherProcess process) {
return IOHelper.resolveJavaBin(Paths.get(System.getProperty("java.home"))); //IGNORED
}
@Override
public int getClientJVMBits() {
return JVMHelper.JVM_BITS;
}
@Override
public void init(boolean clientInstance) {
LogHelper.warning("Using noGuard interface");
}
@Override
public void addCustomParams(ClientLauncherContext context) {
Collections.addAll(context.args, "-cp");
Collections.addAll(context.args, context.pathLauncher);
}
@Override
public void addCustomEnv(ClientLauncherContext context) {
}
@Override
public void setProtectToken(String token) {
//Skip
} }
} }

View file

@ -1,85 +0,0 @@
package pro.gravit.launcher.guard;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherConfig;
import pro.gravit.launcher.client.ClientLauncher;
import pro.gravit.launcher.client.ClientLauncherContext;
import pro.gravit.launcher.client.DirBridge;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.UnpackHelper;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Map;
//Стандартный интерфейс для всех AntiInject
public class LauncherStdGuard implements LauncherGuardInterface {
public String protectToken;
public Path javaBinPath;
@Override
public String getName() {
return "stdguard";
}
@Override
public Path getJavaBinPath() {
if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) {
javaBinPath = ClientLauncher.getJavaBinPath();
String projectName = Launcher.getConfig().projectName;
String wrapperUnpackName = (javaBinPath == null ? JVMHelper.JVM_BITS : JVMHelper.OS_BITS) == 64 ? projectName.concat("64.exe") : projectName.concat("32.exe");
return DirBridge.getGuardDir().resolve(wrapperUnpackName);
} else
return IOHelper.resolveJavaBin(Paths.get(System.getProperty("java.home")));
}
@Override
public int getClientJVMBits() {
//При использовании GravitGuard без своей джавы
//Если при запуске лаунчера используется 32 бит джава, а ОС 64бит
//То в окне настроек будет отображаться >1.б доступной памяти
//Однако при выставлении >1.б JVM x32 работать откажеться
return JVMHelper.OS_BITS;
}
@Override
public void init(boolean clientInstance) {
try {
String projectName = Launcher.getConfig().projectName;
UnpackHelper.unpack(Launcher.getResourceURL("wrapper64.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("64.exe")));
UnpackHelper.unpack(Launcher.getResourceURL("AntiInject64.dll", "guard"), DirBridge.getGuardDir().resolve("AntiInject64.dll"));
UnpackHelper.unpack(Launcher.getResourceURL("wrapper32.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("32.exe")));
UnpackHelper.unpack(Launcher.getResourceURL("AntiInject32.dll", "guard"), DirBridge.getGuardDir().resolve("AntiInject32.dll"));
} catch (IOException e) {
throw new SecurityException(e);
}
}
@Override
public void addCustomParams(ClientLauncherContext context) {
Collections.addAll(context.args, "-Djava.class.path=".concat(context.pathLauncher));
}
@Override
public void addCustomEnv(ClientLauncherContext context) {
Map<String, String> env = context.builder.environment();
if (javaBinPath == null)
env.put("JAVA_HOME", System.getProperty("java.home"));
else
env.put("JAVA_HOME", javaBinPath.toAbsolutePath().toString());
LauncherConfig config = Launcher.getConfig();
env.put("GUARD_USERNAME", context.playerProfile.username);
env.put("GUARD_PROJECTNAME", config.projectName);
if (protectToken != null)
env.put("GUARD_TOKEN", protectToken);
}
@Override
public void setProtectToken(String token) {
protectToken = token;
}
}

View file

@ -1,45 +1,30 @@
package pro.gravit.launcher.guard; package pro.gravit.launcher.guard;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherConfig; import pro.gravit.launcher.client.ClientLauncherProcess;
import pro.gravit.launcher.client.ClientLauncherContext;
import pro.gravit.launcher.client.DirBridge; import pro.gravit.launcher.client.DirBridge;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.UnpackHelper; import pro.gravit.utils.helper.UnpackHelper;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Map;
public class LauncherWrapperGuard implements LauncherGuardInterface { public class LauncherWrapperGuard implements LauncherGuardInterface {
public String protectToken;
@Override @Override
public String getName() { public String getName() {
return "wrapper"; return "wrapper";
} }
@Override @Override
public Path getJavaBinPath() { public void applyGuardParams(ClientLauncherProcess process) {
if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) { if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) {
String projectName = Launcher.getConfig().projectName; String projectName = Launcher.getConfig().projectName;
String wrapperUnpackName = JVMHelper.JVM_BITS == 64 ? projectName.concat("64.exe") : projectName.concat("32.exe"); String wrapperUnpackName = JVMHelper.JVM_BITS == 64 ? projectName.concat("64.exe") : projectName.concat("32.exe");
return DirBridge.getGuardDir().resolve(wrapperUnpackName); process.executeFile = DirBridge.getGuardDir().resolve(wrapperUnpackName);
} else }
return IOHelper.resolveJavaBin(Paths.get(System.getProperty("java.home")));
} }
@Override public LauncherWrapperGuard() {
public int getClientJVMBits() {
return JVMHelper.JVM_BITS;
}
@Override
public void init(boolean clientInstance) {
try { try {
String wrapperName = JVMHelper.JVM_BITS == 64 ? "wrapper64.exe" : "wrapper32.exe"; String wrapperName = JVMHelper.JVM_BITS == 64 ? "wrapper64.exe" : "wrapper32.exe";
String projectName = Launcher.getConfig().projectName; String projectName = Launcher.getConfig().projectName;
@ -51,25 +36,4 @@ public void init(boolean clientInstance) {
throw new SecurityException(e); throw new SecurityException(e);
} }
} }
@Override
public void addCustomParams(ClientLauncherContext context) {
Collections.addAll(context.args, "-Djava.class.path=".concat(context.pathLauncher));
}
@Override
public void addCustomEnv(ClientLauncherContext context) {
Map<String, String> env = context.builder.environment();
env.put("JAVA_HOME", System.getProperty("java.home"));
LauncherConfig config = Launcher.getConfig();
env.put("GUARD_USERNAME", context.playerProfile.username);
env.put("GUARD_PROJECTNAME", config.projectName);
if (protectToken != null)
env.put("GUARD_TOKEN", protectToken);
}
@Override
public void setProtectToken(String token) {
protectToken = token;
}
} }

View file

@ -1,20 +0,0 @@
package pro.gravit.launcher.managers;
import pro.gravit.launcher.client.ClientLauncherContext;
import pro.gravit.launcher.gui.RuntimeProvider;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.utils.BiHookSet;
import pro.gravit.utils.HookSet;
public class ClientHookManager {
public static final HookSet<RuntimeProvider> initGuiHook = new HookSet<>();
public static final HookSet<HInput> paramsInputHook = new HookSet<>();
public static final HookSet<HOutput> paramsOutputHook = new HookSet<>();
public static final HookSet<ClientLauncherContext> clientLaunchHook = new HookSet<>();
public static final HookSet<ClientLauncherContext> clientLaunchFinallyHook = new HookSet<>();
public static final BiHookSet<ClientLauncherContext, ProcessBuilder> preStartHook = new BiHookSet<>();
public static final BiHookSet<ClientLauncherContext, ProcessBuilder> postStartHook = new BiHookSet<>();
}

View file

@ -8,73 +8,104 @@
public class ClientPermissions { public class ClientPermissions {
public static final ClientPermissions DEFAULT = new ClientPermissions(); public static final ClientPermissions DEFAULT = new ClientPermissions();
@LauncherNetworkAPI public long permissions;
public boolean canAdmin; public long flags;
@LauncherNetworkAPI public enum PermissionConsts
public boolean canServer; {
@LauncherNetworkAPI ADMIN(0x01),
public final boolean canUSR1; MANAGEMENT(0x02);
@LauncherNetworkAPI public final long mask;
public final boolean canUSR2;
@LauncherNetworkAPI PermissionConsts(long mask) {
public final boolean canUSR3; this.mask = mask;
@LauncherNetworkAPI }
public boolean canBot; }
public enum FlagConsts
{
SYSTEM(0x01),
BANNED(0x02),
UNTRUSTED(0x04),
HIDDEN(0x08);
public final long mask;
FlagConsts(long mask) {
this.mask = mask;
}
}
public ClientPermissions(HInput input) throws IOException { public ClientPermissions(HInput input) throws IOException {
this(input.readLong()); this(input.readLong());
} }
public ClientPermissions() { public ClientPermissions() {
canAdmin = false;
canServer = false;
canUSR1 = false;
canUSR2 = false;
canUSR3 = false;
canBot = false;
} }
public ClientPermissions(long data) { public ClientPermissions(long permissions) {
canAdmin = (data & (1)) != 0; this.permissions = permissions;
canServer = (data & (1 << 1)) != 0;
canUSR1 = (data & (1 << 2)) != 0;
canUSR2 = (data & (1 << 3)) != 0;
canUSR3 = (data & (1 << 4)) != 0;
canBot = (data & (1 << 5)) != 0;
} }
public ClientPermissions(long permissions, long flags) {
this.permissions = permissions;
this.flags = flags;
}
public long toLong() { public long toLong() {
long result = 0; return permissions;
result |= !canAdmin ? 0 : 1;
result |= !canServer ? 0 : (1 << 1);
result |= !canUSR1 ? 0 : (1 << 2);
result |= !canUSR2 ? 0 : (1 << 3);
result |= !canUSR3 ? 0 : (1 << 4);
result |= !canBot ? 0 : (1 << 5);
return result;
} }
public static ClientPermissions getSuperuserAccount() { public static ClientPermissions getSuperuserAccount() {
ClientPermissions perm = new ClientPermissions(); ClientPermissions perm = new ClientPermissions();
perm.canServer = true;
perm.canAdmin = true;
return perm; return perm;
} }
@Deprecated
public void write(HOutput output) throws IOException { public void write(HOutput output) throws IOException {
output.writeLong(toLong()); output.writeLong(toLong());
} }
//Read methods
public final boolean isPermission(PermissionConsts con)
{
return (permissions & con.mask) != 0;
}
public final boolean isPermission(long mask)
{
return (permissions & mask) != 0;
}
public final boolean isFlag(FlagConsts con)
{
return (flags & con.mask) != 0;
}
public final boolean isFlag(long mask)
{
return (flags & mask) != 0;
}
//Write methods
public final void setPermission(PermissionConsts con, boolean value)
{
if(value) this.permissions |= con.mask;
else this.permissions &= ~con.mask;
}
public final void setPermission(long mask, boolean value)
{
if(value) this.permissions |= mask;
else this.permissions &= ~mask;
}
public final void setFlag(FlagConsts con, boolean value)
{
if(value) this.flags |= con.mask;
else this.flags &= ~con.mask;
}
public final void setFlag(long mask, boolean value)
{
if(value) this.flags |= mask;
else this.flags &= ~mask;
}
@Override @Override
public String toString() { public String toString() {
return new StringJoiner(", ", ClientPermissions.class.getSimpleName() + "[", "]") return String.format("permissions %d | flags %d", permissions, flags);
.add("canAdmin=" + canAdmin)
.add("canServer=" + canServer)
.add("canUSR1=" + canUSR1)
.add("canUSR2=" + canUSR2)
.add("canUSR3=" + canUSR3)
.add("canBot=" + canBot)
.toString();
} }
} }

View file

@ -5,6 +5,7 @@
import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.profiles.optional.OptionalDepend; import pro.gravit.launcher.profiles.optional.OptionalDepend;
import pro.gravit.launcher.profiles.optional.OptionalFile; import pro.gravit.launcher.profiles.optional.OptionalFile;
import pro.gravit.launcher.profiles.optional.OptionalTrigger;
import pro.gravit.launcher.profiles.optional.OptionalType; import pro.gravit.launcher.profiles.optional.OptionalType;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.VerifyHelper; import pro.gravit.utils.helper.VerifyHelper;
@ -444,6 +445,16 @@ public void verify() {
if (s == null) if (s == null)
throw new IllegalArgumentException(String.format("Found null entry in updateOptional.%s.dependenciesFile", f.name)); throw new IllegalArgumentException(String.format("Found null entry in updateOptional.%s.dependenciesFile", f.name));
} }
if(f.triggers != null)
{
for(OptionalTrigger trigger : f.triggers)
{
if(trigger == null)
throw new IllegalArgumentException(String.format("Found null entry in updateOptional.%s.triggers", f.name));
if(trigger.type == null)
throw new IllegalArgumentException(String.format("trigger.type must not be null in updateOptional.%s.triggers", f.name));
}
}
} }
} }

View file

@ -25,6 +25,10 @@ public void registerEventHandler(EventHandler handler)
{ {
eventHandlers.add(handler); eventHandlers.add(handler);
} }
public void unregisterEventHandler(EventHandler handler)
{
eventHandlers.remove(handler);
}
public<T extends WebSocketEvent> void processEventHandlers(T event) public<T extends WebSocketEvent> void processEventHandlers(T event)
{ {
for(EventHandler handler : eventHandlers) for(EventHandler handler : eventHandlers)

View file

@ -28,7 +28,6 @@
import java.util.UUID; import java.util.UUID;
public class YggdrasilMinecraftSessionService extends BaseMinecraftSessionService { public class YggdrasilMinecraftSessionService extends BaseMinecraftSessionService {
public static final JsonParser JSON_PARSER = new JsonParser();
public static final boolean NO_TEXTURES = Boolean.parseBoolean("launcher.com.mojang.authlib.noTextures"); public static final boolean NO_TEXTURES = Boolean.parseBoolean("launcher.com.mojang.authlib.noTextures");
public static void fillTextureProperties(GameProfile profile, PlayerProfile pp) { public static void fillTextureProperties(GameProfile profile, PlayerProfile pp) {
@ -62,7 +61,7 @@ private static void getTexturesMojang(Map<MinecraftProfileTexture.Type, Minecraf
JsonObject texturesJSON; JsonObject texturesJSON;
try { try {
byte[] decoded = Base64.getDecoder().decode(texturesBase64); byte[] decoded = Base64.getDecoder().decode(texturesBase64);
texturesJSON = JSON_PARSER.parse(new String(decoded, IOHelper.UNICODE_CHARSET)).getAsJsonObject().getAsJsonObject("textures"); texturesJSON = JsonParser.parseString(new String(decoded, IOHelper.UNICODE_CHARSET)).getAsJsonObject().getAsJsonObject("textures");
} catch (Exception ignored) { } catch (Exception ignored) {
LogHelper.error("Could not decode textures payload, Username: '%s', UUID: '%s'", profile.getName(), profile.getUUID()); LogHelper.error("Could not decode textures payload, Username: '%s', UUID: '%s'", profile.getName(), profile.getUUID());
return; return;

View file

@ -13,7 +13,6 @@
public final class HTTPRequest { public final class HTTPRequest {
private static final int TIMEOUT = 10000; private static final int TIMEOUT = 10000;
private static final JsonParser parser = new JsonParser();
public static JsonElement jsonRequest(JsonElement request, URL url) throws IOException { public static JsonElement jsonRequest(JsonElement request, URL url) throws IOException {
return jsonRequest(request, "POST", url); return jsonRequest(request, "POST", url);
@ -42,7 +41,7 @@ public static JsonElement jsonRequest(JsonElement request, String method, URL ur
else else
reader = new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8); reader = new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8);
try { try {
return parser.parse(reader); return JsonParser.parseReader(reader);
} catch (Exception e) { } catch (Exception e) {
if (200 > statusCode || statusCode > 300) { if (200 > statusCode || statusCode > 300) {
LogHelper.error("JsonRequest failed. Server response code %d", statusCode); LogHelper.error("JsonRequest failed. Server response code %d", statusCode);

View file

@ -15,9 +15,9 @@ public final class Version {
public final Type release; public final Type release;
public static final int MAJOR = 5; public static final int MAJOR = 5;
public static final int MINOR = 1; public static final int MINOR = 1;
public static final int PATCH = 2; public static final int PATCH = 3;
public static final int BUILD = 1; public static final int BUILD = 1;
public static final Version.Type RELEASE = Type.BETA; public static final Version.Type RELEASE = Type.STABLE;
public Version(int major, int minor, int patch) { public Version(int major, int minor, int patch) {

View file

@ -259,7 +259,7 @@ public static final class Config {
public String login; public String login;
public String[] args; public String[] args;
public String password; public String password;
public final String auth_id = ""; public String auth_id = "";
public LauncherConfig.LauncherEnvironment env; public LauncherConfig.LauncherEnvironment env;
} }

View file

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

@ -1 +1 @@
Subproject commit 2edb2c7259d5a7dba3fa82c503f88a8a0e171840 Subproject commit 07e4380ad52c4ef08378b8eb2202d8a1bd3639a2

View file

@ -1,18 +1,18 @@
project.ext { project.ext {
verAsm = '7.2' verAsm = '7.3.1'
verNetty = '4.1.43.Final' verNetty = '4.1.48.Final'
verOshiCore = '3.13.0' verOshiCore = '4.5.2'
verJunit = '5.6.0' verJunit = '5.6.1'
verGuavaC = '26.0-jre' verGuavaC = '28.2-jre'
verJansi = '1.18' verJansi = '1.18'
verJline = '3.11.0' verJline = '3.14.0'
verBcprov = '1.46' verBcprov = '1.46'
verGson = '2.8.5' verGson = '2.8.6'
verBcpkix = '1.61' verBcpkix = '1.61'
verSlf4j = '1.7.25' verSlf4j = '1.7.25'
verMySQLConn = '8.0.16' verMySQLConn = '8.0.19'
verPostgreSQLConn = '42.2.6' verPostgreSQLConn = '42.2.11'
verProguard = '6.2.0' verProguard = '6.2.2'
verLaunch4j = '3.12' verLaunch4j = '3.12'
verHibernate = '5.4.9.Final' verHibernate = '5.4.12.Final'
} }