mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-23 00:51:01 +03:00
Merge with dev
This commit is contained in:
commit
c90a13af71
37 changed files with 760 additions and 247 deletions
|
@ -70,6 +70,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
/**
|
/**
|
||||||
* The path to the folder with updates/webroot
|
* The path to the folder with updates/webroot
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final Path updatesDir;
|
public final Path updatesDir;
|
||||||
|
|
||||||
// Constant paths
|
// Constant paths
|
||||||
|
@ -359,9 +360,7 @@ public void run() {
|
||||||
syncProfilesDir();
|
syncProfilesDir();
|
||||||
|
|
||||||
// Sync updates dir
|
// Sync updates dir
|
||||||
if (!IOHelper.isDir(updatesDir))
|
config.updatesProvider.syncInitially();
|
||||||
Files.createDirectory(updatesDir);
|
|
||||||
updatesManager.readUpdatesDir();
|
|
||||||
|
|
||||||
|
|
||||||
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||||
|
@ -180,6 +181,7 @@ public static void registerAll() {
|
||||||
OptionalTrigger.registerProviders();
|
OptionalTrigger.registerProviders();
|
||||||
MixProvider.registerProviders();
|
MixProvider.registerProviders();
|
||||||
ProfileProvider.registerProviders();
|
ProfileProvider.registerProviders();
|
||||||
|
UpdatesProvider.registerProviders();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printExperimentalBranch() {
|
private static void printExperimentalBranch() {
|
||||||
|
|
|
@ -9,15 +9,22 @@
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class HikariSQLSourceConfig implements SQLSourceConfig {
|
public class HikariSQLSourceConfig implements SQLSourceConfig {
|
||||||
private transient HikariDataSource dataSource;
|
private transient volatile HikariDataSource dataSource;
|
||||||
private String dsClass;
|
private String dsClass;
|
||||||
private Properties dsProps;
|
private Properties dsProps;
|
||||||
private String driverClass;
|
private String driverClass;
|
||||||
private String jdbcUrl;
|
private String jdbcUrl;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
private boolean initializeAtStart;
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
|
if(initializeAtStart) {
|
||||||
|
initializeConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeConnection() {
|
||||||
if (dataSource != null) {
|
if (dataSource != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +41,11 @@ public void init() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Connection getConnection() throws SQLException {
|
public Connection getConnection() throws SQLException {
|
||||||
|
if(dataSource == null && !initializeAtStart) {
|
||||||
|
synchronized (this) {
|
||||||
|
initializeConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
return dataSource.getConnection();
|
return dataSource.getConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -295,7 +295,9 @@ private SQLUser queryUser(String sql, String value) throws SQLException {
|
||||||
user = constructUser(set);
|
user = constructUser(set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.permissions = requestPermissions(user.uuid.toString());
|
if(user != null) {
|
||||||
|
user.permissions = requestPermissions(user.uuid.toString());
|
||||||
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ public SQLSourceConfig getSQLConfig() {
|
||||||
@Override
|
@Override
|
||||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
public void init(LaunchServer server, AuthProviderPair pair) {
|
||||||
super.init(server, pair);
|
super.init(server, pair);
|
||||||
|
logger.warn("Method 'mysql' deprecated and may be removed in future release. Please use new 'sql' method: https://gravitlauncher.com/auth");
|
||||||
String userInfoCols = makeUserCols();
|
String userInfoCols = makeUserCols();
|
||||||
String hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
|
String hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
|
||||||
if (sqlFindHardwareByPublicKey == null)
|
if (sqlFindHardwareByPublicKey == null)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package pro.gravit.launchserver.auth.core;
|
package pro.gravit.launchserver.auth.core;
|
||||||
|
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
import pro.gravit.launchserver.auth.PostgreSQLSourceConfig;
|
import pro.gravit.launchserver.auth.PostgreSQLSourceConfig;
|
||||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
||||||
|
|
||||||
|
@ -10,4 +12,10 @@ public class PostgresSQLCoreProvider extends AbstractSQLCoreProvider {
|
||||||
public SQLSourceConfig getSQLConfig() {
|
public SQLSourceConfig getSQLConfig() {
|
||||||
return postgresSQLHolder;
|
return postgresSQLHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LaunchServer server, AuthProviderPair pair) {
|
||||||
|
super.init(server, pair);
|
||||||
|
logger.warn("Method 'postgresql' deprecated and may be removed in future release. Please use new 'sql' method: https://gravitlauncher.com/auth");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
package pro.gravit.launchserver.auth.core;
|
package pro.gravit.launchserver.auth.core;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
|
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
|
||||||
|
import pro.gravit.launchserver.auth.MySQLSourceConfig;
|
||||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
||||||
|
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||||
|
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportExtendedCheckServer;
|
||||||
|
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
|
||||||
|
import pro.gravit.launchserver.auth.core.interfaces.session.UserSessionSupportHardware;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
public class SQLCoreProvider extends AbstractSQLCoreProvider {
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SQLCoreProvider extends AbstractSQLCoreProvider implements AuthSupportHardware, AuthSupportExtendedCheckServer {
|
||||||
public HikariSQLSourceConfig holder;
|
public HikariSQLSourceConfig holder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -14,14 +30,364 @@ public void close() {
|
||||||
holder.close();
|
holder.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
|
||||||
holder.init();
|
|
||||||
super.init(server, pair);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SQLSourceConfig getSQLConfig() {
|
public SQLSourceConfig getSQLConfig() {
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String hardwareIdColumn;
|
||||||
|
public String tableHWID = "hwids";
|
||||||
|
public String tableHWIDLog = "hwidLog";
|
||||||
|
public double criticalCompareLevel = 1.0;
|
||||||
|
private transient String sqlFindHardwareByPublicKey;
|
||||||
|
private transient String sqlFindHardwareByData;
|
||||||
|
private transient String sqlFindHardwareById;
|
||||||
|
private transient String sqlCreateHardware;
|
||||||
|
private transient String sqlCreateHWIDLog;
|
||||||
|
private transient String sqlUpdateHardwarePublicKey;
|
||||||
|
private transient String sqlUpdateHardwareBanned;
|
||||||
|
private transient String sqlUpdateUsers;
|
||||||
|
private transient String sqlUsersByHwidId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LaunchServer server, AuthProviderPair pair) {
|
||||||
|
holder.init();
|
||||||
|
super.init(server, pair);
|
||||||
|
String userInfoCols = makeUserCols();
|
||||||
|
String hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
|
||||||
|
if (sqlFindHardwareByPublicKey == null)
|
||||||
|
sqlFindHardwareByPublicKey = "SELECT %s FROM %s WHERE publicKey = ?".formatted(hardwareInfoCols, tableHWID);
|
||||||
|
if (sqlFindHardwareById == null)
|
||||||
|
sqlFindHardwareById = "SELECT %s FROM %s WHERE id = ?".formatted(hardwareInfoCols, tableHWID);
|
||||||
|
if (sqlUsersByHwidId == null)
|
||||||
|
sqlUsersByHwidId = "SELECT %s FROM %s WHERE %s = ?".formatted(userInfoCols, table, hardwareIdColumn);
|
||||||
|
if (sqlFindHardwareByData == null)
|
||||||
|
sqlFindHardwareByData = "SELECT %s FROM %s".formatted(hardwareInfoCols, tableHWID);
|
||||||
|
if (sqlCreateHardware == null)
|
||||||
|
sqlCreateHardware = "INSERT INTO %s (publickey, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, graphicCard, battery, banned) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '0')".formatted(tableHWID);
|
||||||
|
if (sqlCreateHWIDLog == null)
|
||||||
|
sqlCreateHWIDLog = "INSERT INTO %s (hwidId, newPublicKey) VALUES (?, ?)".formatted(tableHWIDLog);
|
||||||
|
if (sqlUpdateHardwarePublicKey == null)
|
||||||
|
sqlUpdateHardwarePublicKey = "UPDATE %s SET publicKey = ? WHERE id = ?".formatted(tableHWID);
|
||||||
|
sqlUpdateHardwareBanned = "UPDATE %s SET banned = ? WHERE id = ?".formatted(tableHWID);
|
||||||
|
sqlUpdateUsers = "UPDATE %s SET %s = ? WHERE %s = ?".formatted(table, hardwareIdColumn, uuidColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String makeUserCols() {
|
||||||
|
return super.makeUserCols().concat(", ").concat(hardwareIdColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLUser constructUser(ResultSet set) throws SQLException {
|
||||||
|
return set.next() ? new SQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
||||||
|
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), set.getLong(hardwareIdColumn)) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLUserHardware fetchHardwareInfo(ResultSet set) throws SQLException, IOException {
|
||||||
|
HardwareReportRequest.HardwareInfo hardwareInfo = new HardwareReportRequest.HardwareInfo();
|
||||||
|
hardwareInfo.hwDiskId = set.getString("hwDiskId");
|
||||||
|
hardwareInfo.baseboardSerialNumber = set.getString("baseboardSerialNumber");
|
||||||
|
byte[] displayId = set.getBytes("displayId");
|
||||||
|
hardwareInfo.displayId = displayId == null ? null : displayId;
|
||||||
|
hardwareInfo.bitness = set.getInt("bitness");
|
||||||
|
hardwareInfo.totalMemory = set.getLong("totalMemory");
|
||||||
|
hardwareInfo.logicalProcessors = set.getInt("logicalProcessors");
|
||||||
|
hardwareInfo.physicalProcessors = set.getInt("physicalProcessors");
|
||||||
|
hardwareInfo.processorMaxFreq = set.getLong("processorMaxFreq");
|
||||||
|
hardwareInfo.battery = set.getBoolean("battery");
|
||||||
|
hardwareInfo.graphicCard = set.getString("graphicCard");
|
||||||
|
byte[] publicKey = set.getBytes("publicKey");
|
||||||
|
long id = set.getLong("id");
|
||||||
|
boolean banned = set.getBoolean("banned");
|
||||||
|
return new SQLUserHardware(hardwareInfo, publicKey, id, banned);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUserHardwareId(Connection connection, UUID uuid, long hwidId) throws SQLException {
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlUpdateUsers);
|
||||||
|
s.setLong(1, hwidId);
|
||||||
|
s.setString(2, uuid.toString());
|
||||||
|
s.executeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserHardware getHardwareInfoByPublicKey(byte[] publicKey) {
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlFindHardwareByPublicKey);
|
||||||
|
s.setBytes(1, publicKey);
|
||||||
|
try (ResultSet set = s.executeQuery()) {
|
||||||
|
if (set.next()) {
|
||||||
|
connection.commit();
|
||||||
|
return fetchHardwareInfo(set);
|
||||||
|
} else {
|
||||||
|
connection.commit();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException | IOException throwables) {
|
||||||
|
logger.error("SQL Error", throwables);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserHardware getHardwareInfoByData(HardwareReportRequest.HardwareInfo info) {
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlFindHardwareByData);
|
||||||
|
try (ResultSet set = s.executeQuery()) {
|
||||||
|
while (set.next()) {
|
||||||
|
SQLUserHardware hw = fetchHardwareInfo(set);
|
||||||
|
AuthSupportHardware.HardwareInfoCompareResult result = compareHardwareInfo(hw.getHardwareInfo(), info);
|
||||||
|
if (result.compareLevel > criticalCompareLevel) {
|
||||||
|
connection.commit();
|
||||||
|
return hw;
|
||||||
|
} else {
|
||||||
|
connection.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException | IOException throwables) {
|
||||||
|
logger.error("SQL Error", throwables);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserHardware getHardwareInfoById(String id) {
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlFindHardwareById);
|
||||||
|
s.setLong(1, Long.parseLong(id));
|
||||||
|
try (ResultSet set = s.executeQuery()) {
|
||||||
|
if (set.next()) {
|
||||||
|
connection.commit();
|
||||||
|
return fetchHardwareInfo(set);
|
||||||
|
} else {
|
||||||
|
connection.commit();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException | IOException throwables) {
|
||||||
|
logger.error("SQL Error", throwables);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey) {
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlCreateHardware, Statement.RETURN_GENERATED_KEYS);
|
||||||
|
s.setBytes(1, publicKey);
|
||||||
|
s.setString(2, hardwareInfo.hwDiskId);
|
||||||
|
s.setString(3, hardwareInfo.baseboardSerialNumber);
|
||||||
|
s.setBytes(4, hardwareInfo.displayId == null ? null : hardwareInfo.displayId);
|
||||||
|
s.setInt(5, hardwareInfo.bitness);
|
||||||
|
s.setLong(6, hardwareInfo.totalMemory);
|
||||||
|
s.setInt(7, hardwareInfo.logicalProcessors);
|
||||||
|
s.setInt(8, hardwareInfo.physicalProcessors);
|
||||||
|
s.setLong(9, hardwareInfo.processorMaxFreq);
|
||||||
|
s.setString(10, hardwareInfo.graphicCard);
|
||||||
|
s.setBoolean(11, hardwareInfo.battery);
|
||||||
|
s.executeUpdate();
|
||||||
|
try (ResultSet generatedKeys = s.getGeneratedKeys()) {
|
||||||
|
if (generatedKeys.next()) {
|
||||||
|
//writeHwidLog(connection, generatedKeys.getLong(1), publicKey);
|
||||||
|
long id = generatedKeys.getLong(1);
|
||||||
|
connection.commit();
|
||||||
|
return new SQLUserHardware(hardwareInfo, publicKey, id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connection.commit();
|
||||||
|
return null;
|
||||||
|
} catch (SQLException throwables) {
|
||||||
|
logger.error("SQL Error", throwables);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectUserAndHardware(UserSession userSession, UserHardware hardware) {
|
||||||
|
AbstractSQLCoreProvider.SQLUserSession SQLUserSession = (AbstractSQLCoreProvider.SQLUserSession) userSession;
|
||||||
|
SQLUser SQLUser = (SQLUser) SQLUserSession.getUser();
|
||||||
|
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
||||||
|
if (SQLUser.hwidId == SQLUserHardware.id) return;
|
||||||
|
SQLUser.hwidId = SQLUserHardware.id;
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
setUserHardwareId(connection, SQLUser.getUUID(), SQLUserHardware.id);
|
||||||
|
} catch (SQLException throwables) {
|
||||||
|
logger.error("SQL Error", throwables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey) {
|
||||||
|
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
||||||
|
SQLUserHardware.publicKey = publicKey;
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwarePublicKey);
|
||||||
|
s.setBytes(1, publicKey);
|
||||||
|
s.setLong(2, SQLUserHardware.id);
|
||||||
|
s.executeUpdate();
|
||||||
|
connection.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.error("SQL error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<User> getUsersByHardwareInfo(UserHardware hardware) {
|
||||||
|
List<User> users = new LinkedList<>();
|
||||||
|
try (Connection c = holder.getConnection()) {
|
||||||
|
c.setAutoCommit(false);
|
||||||
|
PreparedStatement s = c.prepareStatement(sqlUsersByHwidId);
|
||||||
|
s.setLong(1, Long.parseLong(hardware.getId()));
|
||||||
|
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
||||||
|
try (ResultSet set = s.executeQuery()) {
|
||||||
|
while (!set.isLast()) {
|
||||||
|
users.add(constructUser(set));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.error("SQL error", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void banHardware(UserHardware hardware) {
|
||||||
|
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
||||||
|
SQLUserHardware.banned = true;
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwareBanned);
|
||||||
|
s.setBoolean(1, true);
|
||||||
|
s.setLong(2, SQLUserHardware.id);
|
||||||
|
s.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.error("SQL Error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unbanHardware(UserHardware hardware) {
|
||||||
|
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
||||||
|
SQLUserHardware.banned = false;
|
||||||
|
try (Connection connection = holder.getConnection()) {
|
||||||
|
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwareBanned);
|
||||||
|
s.setBoolean(1, false);
|
||||||
|
s.setLong(2, SQLUserHardware.id);
|
||||||
|
s.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.error("SQL error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbstractSQLCoreProvider.SQLUserSession createSession(AbstractSQLCoreProvider.SQLUser user) {
|
||||||
|
return new SQLUserSession(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserSession extendedCheckServer(Client client, String username, String serverID) throws IOException {
|
||||||
|
AbstractSQLCoreProvider.SQLUser user = (AbstractSQLCoreProvider.SQLUser) getUserByUsername(username);
|
||||||
|
if (user == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (user.getUsername().equals(username) && user.getServerId().equals(serverID)) {
|
||||||
|
return createSession(user);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SQLUserSession extends AbstractSQLCoreProvider.SQLUserSession implements UserSessionSupportHardware {
|
||||||
|
private transient SQLUser SQLUser;
|
||||||
|
protected transient SQLUserHardware hardware;
|
||||||
|
|
||||||
|
public SQLUserSession(AbstractSQLCoreProvider.SQLUser user) {
|
||||||
|
super(user);
|
||||||
|
SQLUser = (SQLUser) user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHardwareId() {
|
||||||
|
return SQLUser.hwidId == 0 ? null : String.valueOf(SQLUser.hwidId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserHardware getHardware() {
|
||||||
|
if(hardware == null) {
|
||||||
|
hardware = (SQLUserHardware) getHardwareInfoById(String.valueOf(SQLUser.hwidId));
|
||||||
|
}
|
||||||
|
return hardware;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SQLUserHardware implements UserHardware {
|
||||||
|
private final HardwareReportRequest.HardwareInfo hardwareInfo;
|
||||||
|
private final long id;
|
||||||
|
private byte[] publicKey;
|
||||||
|
private boolean banned;
|
||||||
|
|
||||||
|
public SQLUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, long id, boolean banned) {
|
||||||
|
this.hardwareInfo = hardwareInfo;
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.id = id;
|
||||||
|
this.banned = banned;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HardwareReportRequest.HardwareInfo getHardwareInfo() {
|
||||||
|
return hardwareInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getPublicKey() {
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return String.valueOf(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBanned() {
|
||||||
|
return banned;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SQLUserHardware{" +
|
||||||
|
"hardwareInfo=" + hardwareInfo +
|
||||||
|
", publicKey=" + (publicKey == null ? null : new String(Base64.getEncoder().encode(publicKey))) +
|
||||||
|
", id=" + id +
|
||||||
|
", banned=" + banned +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SQLUser extends AbstractSQLCoreProvider.SQLUser {
|
||||||
|
protected long hwidId;
|
||||||
|
|
||||||
|
public SQLUser(UUID uuid, String username, String accessToken, String serverId, String password, long hwidId) {
|
||||||
|
super(uuid, username, accessToken, serverId, password);
|
||||||
|
this.hwidId = hwidId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SQLUser{" +
|
||||||
|
"uuid=" + uuid +
|
||||||
|
", username='" + username + '\'' +
|
||||||
|
", permissions=" + permissions +
|
||||||
|
", hwidId=" + hwidId +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,7 @@ public void addProfile(ClientProfile profile) throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(target == null) {
|
if(target == null) {
|
||||||
target = IOHelper.resolveIncremental(profilesDirPath,
|
target = profilesDirPath.resolve(profile.getTitle()+".json");
|
||||||
profile.getTitle(), "json");
|
|
||||||
oldProfile = profilesMap.get(target);
|
oldProfile = profilesMap.get(target);
|
||||||
if(oldProfile != null && !oldProfile.getUUID().equals(profile.getUUID())) {
|
if(oldProfile != null && !oldProfile.getUUID().equals(profile.getUUID())) {
|
||||||
throw new FileAlreadyExistsException(target.toString());
|
throw new FileAlreadyExistsException(target.toString());
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
package pro.gravit.launchserver.auth.updates;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||||
|
import pro.gravit.launcher.core.serialize.HInput;
|
||||||
|
import pro.gravit.launcher.core.serialize.HOutput;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.DirectoryStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class LocalUpdatesProvider extends UpdatesProvider {
|
||||||
|
private final transient Logger logger = LogManager.getLogger();
|
||||||
|
public String cacheFile = ".updates-cache";
|
||||||
|
public String updatesDir = "updates";
|
||||||
|
public boolean cacheUpdates = true;
|
||||||
|
private volatile transient Map<String, HashedDir> updatesDirMap;
|
||||||
|
|
||||||
|
private void writeCache(Path file) throws IOException {
|
||||||
|
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
||||||
|
output.writeLength(updatesDirMap.size(), 0);
|
||||||
|
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
||||||
|
output.writeString(entry.getKey(), 0);
|
||||||
|
entry.getValue().write(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readCache(Path file) throws IOException {
|
||||||
|
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
||||||
|
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
||||||
|
int size = input.readLength(0);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
String name = input.readString(0);
|
||||||
|
HashedDir dir = new HashedDir(input);
|
||||||
|
updatesDirMap.put(name, dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
||||||
|
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readUpdatesFromCache() throws IOException {
|
||||||
|
readCache(Path.of(cacheFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readUpdatesDir() throws IOException {
|
||||||
|
var cacheFilePath = Path.of(cacheFile);
|
||||||
|
if (cacheUpdates) {
|
||||||
|
if (Files.exists(cacheFilePath)) {
|
||||||
|
try {
|
||||||
|
readCache(cacheFilePath);
|
||||||
|
return;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("Read updates cache failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sync(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LaunchServer server) {
|
||||||
|
super.init(server);
|
||||||
|
try {
|
||||||
|
if (!IOHelper.isDir(Path.of(updatesDir)))
|
||||||
|
Files.createDirectory(Path.of(updatesDir));
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Updates not synced", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncInitially() throws IOException {
|
||||||
|
readUpdatesDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sync(Collection<String> dirs) throws IOException {
|
||||||
|
logger.info("Syncing updates dir");
|
||||||
|
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
||||||
|
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(Path.of(updatesDir))) {
|
||||||
|
for (final Path updateDir : dirStream) {
|
||||||
|
if (Files.isHidden(updateDir))
|
||||||
|
continue; // Skip hidden
|
||||||
|
|
||||||
|
// Resolve name and verify is dir
|
||||||
|
String name = IOHelper.getFileName(updateDir);
|
||||||
|
if (!IOHelper.isDir(updateDir)) {
|
||||||
|
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
||||||
|
logger.warn("Not update dir: '{}'", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add from previous map (it's guaranteed to be non-null)
|
||||||
|
if (dirs != null && !dirs.contains(name)) {
|
||||||
|
HashedDir hdir = updatesDirMap.get(name);
|
||||||
|
if (hdir != null) {
|
||||||
|
newUpdatesDirMap.put(name, hdir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync and sign update dir
|
||||||
|
logger.info("Syncing '{}' update dir", name);
|
||||||
|
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
||||||
|
newUpdatesDirMap.put(name, updateHDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
||||||
|
if (cacheUpdates) {
|
||||||
|
try {
|
||||||
|
writeCache(Path.of(cacheFile));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("Write updates cache failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedDir getUpdatesDir(String updateName) {
|
||||||
|
return updatesDirMap.get(updateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path resolveUpdateName(String updateName) {
|
||||||
|
if(updateName == null) {
|
||||||
|
return Path.of(updatesDir);
|
||||||
|
}
|
||||||
|
return Path.of(updatesDir).resolve(updateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException {
|
||||||
|
var path = resolveUpdateName(updateName);
|
||||||
|
for(var e : files.entrySet()) {
|
||||||
|
var target = path.resolve(e.getKey());
|
||||||
|
var source = e.getValue();
|
||||||
|
IOHelper.createParentDirs(target);
|
||||||
|
if(deleteAfterUpload) {
|
||||||
|
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} else {
|
||||||
|
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Path> download(String updateName, List<String> files) {
|
||||||
|
var path = resolveUpdateName(updateName);
|
||||||
|
Map<String, Path> map = new HashMap<>();
|
||||||
|
for(var e : files) {
|
||||||
|
map.put(e, path.resolve(e));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String updateName, List<String> files) throws IOException {
|
||||||
|
var path = resolveUpdateName(updateName);
|
||||||
|
for(var e : files) {
|
||||||
|
var target = path.resolve(e);
|
||||||
|
Files.delete(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String updateName) throws IOException {
|
||||||
|
var path = resolveUpdateName(updateName);
|
||||||
|
IOHelper.deleteDir(path, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(String updateName) throws IOException {
|
||||||
|
var path = resolveUpdateName(updateName);
|
||||||
|
Files.createDirectories(path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package pro.gravit.launchserver.auth.updates;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.utils.ProviderMap;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public abstract class UpdatesProvider {
|
||||||
|
public static final ProviderMap<UpdatesProvider> providers = new ProviderMap<>("UpdatesProvider");
|
||||||
|
private static boolean registredProviders = false;
|
||||||
|
protected transient LaunchServer server;
|
||||||
|
|
||||||
|
public static void registerProviders() {
|
||||||
|
if (!registredProviders) {
|
||||||
|
providers.register("local", LocalUpdatesProvider.class);
|
||||||
|
registredProviders = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(LaunchServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sync() throws IOException {
|
||||||
|
sync(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void syncInitially() throws IOException;
|
||||||
|
|
||||||
|
public abstract void sync(Collection<String> updateNames) throws IOException;
|
||||||
|
|
||||||
|
public abstract HashedDir getUpdatesDir(String updateName);
|
||||||
|
|
||||||
|
public abstract void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException;
|
||||||
|
|
||||||
|
public abstract Map<String, Path> download(String updateName, List<String> files);
|
||||||
|
|
||||||
|
public abstract void delete(String updateName, List<String> files) throws IOException;
|
||||||
|
|
||||||
|
public abstract void delete(String updateName) throws IOException;
|
||||||
|
|
||||||
|
public abstract void create(String updateName) throws IOException;
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,11 +14,11 @@
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class BinaryPipeline {
|
public abstract class BinaryPipeline {
|
||||||
public final List<LauncherBuildTask> tasks = new ArrayList<>();
|
public final List<LauncherBuildTask> tasks = new ArrayList<>();
|
||||||
public final Path buildDir;
|
public final Path buildDir;
|
||||||
public final String nameFormat;
|
public final String nameFormat;
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
protected transient final Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
public BinaryPipeline(Path buildDir, String nameFormat) {
|
public BinaryPipeline(Path buildDir, String nameFormat) {
|
||||||
this.buildDir = buildDir;
|
this.buildDir = buildDir;
|
||||||
|
@ -80,27 +80,6 @@ public Optional<LauncherBuildTask> getTaskBefore(Predicate<LauncherBuildTask> pr
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void build(Path target, boolean deleteTempFiles) throws IOException {
|
|
||||||
logger.info("Building launcher binary file");
|
|
||||||
Path thisPath = null;
|
|
||||||
long time_start = System.currentTimeMillis();
|
|
||||||
long time_this = time_start;
|
|
||||||
for (LauncherBuildTask task : tasks) {
|
|
||||||
logger.info("Task {}", task.getName());
|
|
||||||
Path oldPath = thisPath;
|
|
||||||
thisPath = task.process(oldPath);
|
|
||||||
long time_task_end = System.currentTimeMillis();
|
|
||||||
long time_task = time_task_end - time_this;
|
|
||||||
time_this = time_task_end;
|
|
||||||
logger.info("Task {} processed from {} millis", task.getName(), time_task);
|
|
||||||
}
|
|
||||||
long time_end = System.currentTimeMillis();
|
|
||||||
if (deleteTempFiles) IOHelper.move(thisPath, target);
|
|
||||||
else IOHelper.copy(thisPath, target);
|
|
||||||
IOHelper.deleteDir(buildDir, false);
|
|
||||||
logger.info("Build successful from {} millis", time_end - time_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String nextName(String taskName) {
|
public String nextName(String taskName) {
|
||||||
return nameFormat.formatted(taskName);
|
return nameFormat.formatted(taskName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package pro.gravit.launchserver.binary;
|
package pro.gravit.launchserver.binary;
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class LauncherBinary extends BinaryPipeline {
|
public abstract class LauncherBinary extends BinaryPipeline {
|
||||||
public final LaunchServer server;
|
public final LaunchServer server;
|
||||||
|
@ -19,11 +22,27 @@ protected LauncherBinary(LaunchServer server, Path binaryFile, String nameFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Path resolve(LaunchServer server, String ext) {
|
public static Path resolve(LaunchServer server, String ext) {
|
||||||
return server.config.copyBinaries ? server.updatesDir.resolve(server.config.binaryName + ext) : server.dir.resolve(server.config.binaryName + ext);
|
return Path.of(server.config.binaryName + ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void build() throws IOException {
|
public void build() throws IOException {
|
||||||
build(syncBinaryFile, server.config.launcher.deleteTempFiles);
|
logger.info("Building launcher binary file");
|
||||||
|
Path thisPath = null;
|
||||||
|
long time_start = System.currentTimeMillis();
|
||||||
|
long time_this = time_start;
|
||||||
|
for (LauncherBuildTask task : tasks) {
|
||||||
|
logger.info("Task {}", task.getName());
|
||||||
|
Path oldPath = thisPath;
|
||||||
|
thisPath = task.process(oldPath);
|
||||||
|
long time_task_end = System.currentTimeMillis();
|
||||||
|
long time_task = time_task_end - time_this;
|
||||||
|
time_this = time_task_end;
|
||||||
|
logger.info("Task {} processed from {} millis", task.getName(), time_task);
|
||||||
|
}
|
||||||
|
long time_end = System.currentTimeMillis();
|
||||||
|
server.config.updatesProvider.upload(null, Map.of(syncBinaryFile.toString(), thisPath), true);
|
||||||
|
IOHelper.deleteDir(buildDir, false);
|
||||||
|
logger.info("Build successful from {} millis", time_end - time_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean exists() {
|
public final boolean exists() {
|
||||||
|
@ -38,9 +57,13 @@ public void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean sync() throws IOException {
|
public final boolean sync() throws IOException {
|
||||||
boolean exists = exists();
|
try {
|
||||||
digest = exists ? SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(syncBinaryFile)) : null;
|
var target = syncBinaryFile.toString();
|
||||||
|
var path = server.config.updatesProvider.download(null, List.of(target)).get(target);
|
||||||
return exists;
|
digest = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(path));
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,7 @@
|
||||||
import pro.gravit.utils.helper.UnpackHelper;
|
import pro.gravit.utils.helper.UnpackHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.*;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.SimpleFileVisitor;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -40,7 +37,7 @@ public Path process(Path inputFile) throws IOException {
|
||||||
if(Files.isDirectory(server.launcherLibrariesCompile)) {
|
if(Files.isDirectory(server.launcherLibrariesCompile)) {
|
||||||
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
||||||
}
|
}
|
||||||
try(Stream<Path> stream = Files.walk(server.launcherPack).filter((e) -> {
|
try(Stream<Path> stream = Files.walk(server.launcherPack, FileVisitOption.FOLLOW_LINKS).filter((e) -> {
|
||||||
try {
|
try {
|
||||||
return !Files.isDirectory(e) && !Files.isHidden(e);
|
return !Files.isDirectory(e) && !Files.isHidden(e);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
|
|
@ -40,14 +40,13 @@ public void invoke(String... args) throws Exception {
|
||||||
logger.error("Profile {} not found", args[0]);
|
logger.error("Profile {} not found", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var clientDir = server.updatesDir.resolve(profile.getDir()).toAbsolutePath();
|
logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", profile.getDir());
|
||||||
logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", clientDir);
|
|
||||||
if(!showApplyDialog("Continue?")) {
|
if(!showApplyDialog("Continue?")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID());
|
logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID());
|
||||||
server.config.profileProvider.deleteProfile(profile);
|
server.config.profileProvider.deleteProfile(profile);
|
||||||
logger.info("Delete {}", clientDir);
|
logger.info("Delete {}", profile.getDir());
|
||||||
IOHelper.deleteDir(clientDir, true);
|
server.config.updatesProvider.delete(profile.getDir());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||||
|
import pro.gravit.launchserver.auth.updates.LocalUpdatesProvider;
|
||||||
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.components.ProGuardComponent;
|
import pro.gravit.launchserver.components.ProGuardComponent;
|
||||||
|
@ -32,13 +34,13 @@ public final class LaunchServerConfig {
|
||||||
public String[] mirrors;
|
public String[] mirrors;
|
||||||
public String binaryName;
|
public String binaryName;
|
||||||
public boolean copyBinaries = true;
|
public boolean copyBinaries = true;
|
||||||
public boolean cacheUpdates = true;
|
|
||||||
public LauncherConfig.LauncherEnvironment env;
|
public LauncherConfig.LauncherEnvironment env;
|
||||||
public Map<String, AuthProviderPair> auth;
|
public Map<String, AuthProviderPair> auth;
|
||||||
// Handlers & Providers
|
// Handlers & Providers
|
||||||
public ProtectHandler protectHandler;
|
public ProtectHandler protectHandler;
|
||||||
public Map<String, Component> components;
|
public Map<String, Component> components;
|
||||||
public ProfileProvider profileProvider = new LocalProfileProvider();
|
public ProfileProvider profileProvider = new LocalProfileProvider();
|
||||||
|
public UpdatesProvider updatesProvider = new LocalUpdatesProvider();
|
||||||
public NettyConfig netty;
|
public NettyConfig netty;
|
||||||
public LauncherConf launcher;
|
public LauncherConf launcher;
|
||||||
public JarSignerConf sign;
|
public JarSignerConf sign;
|
||||||
|
@ -174,6 +176,10 @@ public void init(LaunchServer.ReloadType type) {
|
||||||
server.registerObject("profileProvider", profileProvider);
|
server.registerObject("profileProvider", profileProvider);
|
||||||
profileProvider.init(server);
|
profileProvider.init(server);
|
||||||
}
|
}
|
||||||
|
if(updatesProvider != null) {
|
||||||
|
server.registerObject("updatesProvider", updatesProvider);
|
||||||
|
updatesProvider.init(server);
|
||||||
|
}
|
||||||
if (components != null) {
|
if (components != null) {
|
||||||
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
||||||
}
|
}
|
||||||
|
@ -218,6 +224,10 @@ public void close(LaunchServer.ReloadType type) {
|
||||||
server.unregisterObject("profileProvider", profileProvider);
|
server.unregisterObject("profileProvider", profileProvider);
|
||||||
profileProvider.close();
|
profileProvider.close();
|
||||||
}
|
}
|
||||||
|
if(updatesProvider != null) {
|
||||||
|
server.unregisterObject("updatesProvider", updatesProvider);
|
||||||
|
updatesProvider.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class JarSignerConf {
|
public static class JarSignerConf {
|
||||||
|
|
|
@ -197,9 +197,6 @@ public static String getMainClassByVersion(ClientProfile.Version version, MakePr
|
||||||
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) == 0) {
|
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) == 0) {
|
||||||
return "com.gtnewhorizons.retrofuturabootstrap.Main";
|
return "com.gtnewhorizons.retrofuturabootstrap.Main";
|
||||||
}
|
}
|
||||||
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) == 0) {
|
|
||||||
return "top.outlands.foundation.boot.Foundation"; // Cleanroom
|
|
||||||
}
|
|
||||||
if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) {
|
if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) {
|
||||||
return "net.minecraft.launchwrapper.Launch";
|
return "net.minecraft.launchwrapper.Launch";
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||||
import pro.gravit.launchserver.socket.WebSocketService;
|
import pro.gravit.launchserver.socket.WebSocketService;
|
||||||
|
@ -48,6 +49,7 @@ public void registerAdapters(GsonBuilder builder) {
|
||||||
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
||||||
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
||||||
builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers));
|
builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers));
|
||||||
|
builder.registerTypeAdapter(UpdatesProvider.class, new UniversalJsonAdapter<>(UpdatesProvider.providers));
|
||||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,112 +18,38 @@
|
||||||
|
|
||||||
public class UpdatesManager {
|
public class UpdatesManager {
|
||||||
private final LaunchServer server;
|
private final LaunchServer server;
|
||||||
private final Logger logger = LogManager.getLogger();
|
|
||||||
private final Path cacheFile;
|
|
||||||
private volatile Map<String, HashedDir> updatesDirMap;
|
|
||||||
|
|
||||||
public UpdatesManager(LaunchServer server) {
|
public UpdatesManager(LaunchServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.cacheFile = server.dir.resolve(".updates-cache");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeCache(Path file) throws IOException {
|
|
||||||
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
|
||||||
output.writeLength(updatesDirMap.size(), 0);
|
|
||||||
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
|
||||||
output.writeString(entry.getKey(), 0);
|
|
||||||
entry.getValue().write(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readCache(Path file) throws IOException {
|
|
||||||
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
|
||||||
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
|
||||||
int size = input.readLength(0);
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
String name = input.readString(0);
|
|
||||||
HashedDir dir = new HashedDir(input);
|
|
||||||
updatesDirMap.put(name, dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
|
||||||
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void readUpdatesFromCache() throws IOException {
|
public void readUpdatesFromCache() throws IOException {
|
||||||
readCache(cacheFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void readUpdatesDir() throws IOException {
|
public void readUpdatesDir() throws IOException {
|
||||||
if (server.config.cacheUpdates) {
|
|
||||||
if (Files.exists(cacheFile)) {
|
|
||||||
try {
|
|
||||||
readCache(cacheFile);
|
|
||||||
return;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("Read updates cache failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
syncUpdatesDir(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
||||||
logger.info("Syncing updates dir");
|
server.config.updatesProvider.sync(dirs);
|
||||||
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
|
||||||
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(server.updatesDir)) {
|
|
||||||
for (final Path updateDir : dirStream) {
|
|
||||||
if (Files.isHidden(updateDir))
|
|
||||||
continue; // Skip hidden
|
|
||||||
|
|
||||||
// Resolve name and verify is dir
|
|
||||||
String name = IOHelper.getFileName(updateDir);
|
|
||||||
if (!IOHelper.isDir(updateDir)) {
|
|
||||||
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
|
||||||
logger.warn("Not update dir: '{}'", name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add from previous map (it's guaranteed to be non-null)
|
|
||||||
if (dirs != null && !dirs.contains(name)) {
|
|
||||||
HashedDir hdir = updatesDirMap.get(name);
|
|
||||||
if (hdir != null) {
|
|
||||||
newUpdatesDirMap.put(name, hdir);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync and sign update dir
|
|
||||||
logger.info("Syncing '{}' update dir", name);
|
|
||||||
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
|
||||||
newUpdatesDirMap.put(name, updateHDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
|
||||||
if (server.config.cacheUpdates) {
|
|
||||||
try {
|
|
||||||
writeCache(cacheFile);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("Write updates cache failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public HashSet<String> getUpdatesList() {
|
public HashSet<String> getUpdatesList() {
|
||||||
HashSet<String> set = new HashSet<>();
|
return new HashSet<>();
|
||||||
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet())
|
|
||||||
set.add(entry.getKey());
|
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public HashedDir getUpdate(String name) {
|
public HashedDir getUpdate(String name) {
|
||||||
return updatesDirMap.get(name);
|
return server.config.updatesProvider.getUpdatesDir(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void addUpdate(String name, HashedDir dir) {
|
public void addUpdate(String name, HashedDir dir) {
|
||||||
updatesDirMap.put(name, dir);
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ProfilesResponse extends SimpleResponse {
|
public class ProfilesResponse extends SimpleResponse {
|
||||||
|
@Deprecated
|
||||||
public static List<ClientProfile> getListVisibleProfiles(LaunchServer server, Client client) {
|
public static List<ClientProfile> getListVisibleProfiles(LaunchServer server, Client client) {
|
||||||
List<ClientProfile> profileList;
|
List<ClientProfile> profileList;
|
||||||
Set<ClientProfile> serverProfiles = server.getProfiles();
|
Set<ClientProfile> serverProfiles = server.getProfiles();
|
||||||
|
@ -40,6 +41,6 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
sendError("Access denied");
|
sendError("Access denied");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendResult(new ProfilesRequestEvent(getListVisibleProfiles(server, client)));
|
sendResult(new ProfilesRequestEvent(server.config.profileProvider.getProfiles(client)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
client.checkSign = true;
|
client.checkSign = true;
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||||
} else {
|
} else {
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, null, 0));
|
||||||
}
|
}
|
||||||
} else if (launcher_type == 2) //EXE
|
} else if (launcher_type == 2) //EXE
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
client.checkSign = true;
|
client.checkSign = true;
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||||
} else {
|
} else {
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, null, 0));
|
||||||
}
|
}
|
||||||
} else sendError("Request launcher type error");
|
} else sendError("Request launcher type error");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
apply plugin: 'com.github.johnrengelman.shadow'
|
apply plugin: 'com.github.johnrengelman.shadow'
|
||||||
|
|
||||||
String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper"
|
String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper"
|
||||||
String mainAgentName = "pro.gravit.launcher.runtime.LauncherAgent"
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -20,7 +19,6 @@
|
||||||
jar {
|
jar {
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Main-Class": mainClassName,
|
manifest.attributes("Main-Class": mainClassName,
|
||||||
"Premain-Class": mainAgentName,
|
|
||||||
"Multi-Release": "true",
|
"Multi-Release": "true",
|
||||||
"Automatic-Module-Name": "GravitLauncher")
|
"Automatic-Module-Name": "GravitLauncher")
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,6 @@ public static void main(String... args) throws Throwable {
|
||||||
LogHelper.printLicense("Launcher");
|
LogHelper.printLicense("Launcher");
|
||||||
LauncherEngine.checkClass(LauncherEngineWrapper.class);
|
LauncherEngine.checkClass(LauncherEngineWrapper.class);
|
||||||
LauncherEngine.checkClass(LauncherEngine.class);
|
LauncherEngine.checkClass(LauncherEngine.class);
|
||||||
LauncherEngine.checkClass(LauncherAgent.class);
|
|
||||||
LauncherEngine.checkClass(ClientLauncherEntryPoint.class);
|
LauncherEngine.checkClass(ClientLauncherEntryPoint.class);
|
||||||
LauncherEngine.modulesManager = new RuntimeModuleManager();
|
LauncherEngine.modulesManager = new RuntimeModuleManager();
|
||||||
LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule());
|
LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule());
|
||||||
|
|
|
@ -142,9 +142,7 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException {
|
||||||
}
|
}
|
||||||
//ADD CLASSPATH
|
//ADD CLASSPATH
|
||||||
processArgs.add(JVMHelper.jvmProperty("java.library.path", this.params.nativesDir));
|
processArgs.add(JVMHelper.jvmProperty("java.library.path", this.params.nativesDir));
|
||||||
if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.AGENT) {
|
if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
||||||
processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString()));
|
|
||||||
} else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
|
||||||
Set<Path> ignorePath = new HashSet<>();
|
Set<Path> ignorePath = new HashSet<>();
|
||||||
var moduleConf = params.profile.getModuleConf();
|
var moduleConf = params.profile.getModuleConf();
|
||||||
if(moduleConf != null) {
|
if(moduleConf != null) {
|
||||||
|
@ -159,6 +157,24 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException {
|
||||||
processArgs.add("--add-modules");
|
processArgs.add("--add-modules");
|
||||||
processArgs.add(String.join(",", moduleConf.modules));
|
processArgs.add(String.join(",", moduleConf.modules));
|
||||||
}
|
}
|
||||||
|
if(moduleConf.exports != null && !moduleConf.exports.isEmpty()) {
|
||||||
|
for(var e : moduleConf.exports.entrySet()) {
|
||||||
|
processArgs.add("--add-exports");
|
||||||
|
processArgs.add(String.format("%s=%s", e.getKey(), e.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(moduleConf.opens != null && !moduleConf.opens.isEmpty()) {
|
||||||
|
for(var e : moduleConf.opens.entrySet()) {
|
||||||
|
processArgs.add("--add-opens");
|
||||||
|
processArgs.add(String.format("%s=%s", e.getKey(), e.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(moduleConf.reads != null && !moduleConf.reads.isEmpty()) {
|
||||||
|
for(var e : moduleConf.reads.entrySet()) {
|
||||||
|
processArgs.add("--add-reads");
|
||||||
|
processArgs.add(String.format("%s=%s", e.getKey(), e.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(ignorePath, workDir, params.actions, params.profile)
|
systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(ignorePath, workDir, params.actions, params.profile)
|
||||||
.map(Path::toString)
|
.map(Path::toString)
|
||||||
|
|
|
@ -141,7 +141,6 @@ public void cancel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tasks.clear();
|
tasks.clear();
|
||||||
executor.shutdownNow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCanceled() {
|
public boolean isCanceled() {
|
||||||
|
|
|
@ -414,7 +414,7 @@ public List<CompatibilityFlags> getFlags() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ClassLoaderConfig {
|
public enum ClassLoaderConfig {
|
||||||
AGENT, LAUNCHER, MODULE, SYSTEM_ARGS
|
LAUNCHER, MODULE, SYSTEM_ARGS
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CompatibilityFlags {
|
public enum CompatibilityFlags {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
apply plugin: 'org.openjfx.javafxplugin'
|
apply plugin: 'org.openjfx.javafxplugin'
|
||||||
|
|
||||||
String mainClassName = "pro.gravit.launcher.ClientLauncherWrapper"
|
String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper"
|
||||||
String mainAgentName = "pro.gravit.launcher.LauncherAgent"
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -14,7 +13,6 @@
|
||||||
jar {
|
jar {
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Main-Class": mainClassName,
|
manifest.attributes("Main-Class": mainClassName,
|
||||||
"Premain-Class": mainAgentName,
|
|
||||||
"Multi-Release": "true")
|
"Multi-Release": "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,11 +86,9 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
modulesManager.invokeEvent(new PreConfigPhase());
|
modulesManager.invokeEvent(new PreConfigPhase());
|
||||||
LogHelper.debug("Reading ClientLauncher params");
|
LogHelper.debug("Reading ClientLauncher params");
|
||||||
ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort));
|
ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort));
|
||||||
if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) {
|
ClientLauncherMethods.verifyNoAgent();
|
||||||
ClientLauncherMethods.verifyNoAgent();
|
|
||||||
}
|
|
||||||
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
|
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
|
||||||
LogHelper.error("Timestamp failed. Exit");
|
LogHelper.error("Timestamp failed: current %d | params %d | diff %d", System.currentTimeMillis(), params.timestamp, System.currentTimeMillis() - params.timestamp);
|
||||||
ClientLauncherMethods.exitLauncher(-662);
|
ClientLauncherMethods.exitLauncher(-662);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +158,7 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
System.load(Paths.get(params.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString());
|
System.load(Paths.get(params.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
|
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER || classLoaderConfig == ClientProfile.ClassLoaderConfig.MODULE) {
|
||||||
if(JVMHelper.JVM_VERSION <= 11) {
|
if(JVMHelper.JVM_VERSION <= 11) {
|
||||||
launch = new LegacyLaunch();
|
launch = new LegacyLaunch();
|
||||||
} else {
|
} else {
|
||||||
|
@ -170,20 +168,12 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)));
|
System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)));
|
||||||
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, classLoaderControl, profile));
|
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, classLoaderControl, profile));
|
||||||
ClientService.baseURLs = classLoaderControl.getURLs();
|
ClientService.baseURLs = classLoaderControl.getURLs();
|
||||||
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.AGENT) {
|
|
||||||
launch = new BasicLaunch(LauncherAgent.inst);
|
|
||||||
classpathURLs.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL());
|
|
||||||
classLoaderControl = launch.init(classpath, params.nativesDir, options);
|
|
||||||
for (URL url : classpathURLs) {
|
|
||||||
LauncherAgent.addJVMClassPath(Paths.get(url.toURI()));
|
|
||||||
}
|
|
||||||
ClientService.instrumentation = LauncherAgent.inst;
|
|
||||||
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, null, profile));
|
|
||||||
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
|
||||||
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
||||||
launch = new BasicLaunch();
|
launch = new BasicLaunch();
|
||||||
classLoaderControl = launch.init(classpath, params.nativesDir, options);
|
classLoaderControl = launch.init(classpath, params.nativesDir, options);
|
||||||
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException(String.format("Unknown classLoaderConfig %s", classLoaderConfig));
|
||||||
}
|
}
|
||||||
if(profile.hasFlag(ClientProfile.CompatibilityFlags.CLASS_CONTROL_API)) {
|
if(profile.hasFlag(ClientProfile.CompatibilityFlags.CLASS_CONTROL_API)) {
|
||||||
ClientService.classLoaderControl = classLoaderControl;
|
ClientService.classLoaderControl = classLoaderControl;
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
package pro.gravit.launcher.client;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.client.utils.NativeJVMHalt;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
|
|
||||||
|
|
||||||
public final class LauncherAgent {
|
|
||||||
public static Instrumentation inst;
|
|
||||||
private static boolean isAgentStarted = false;
|
|
||||||
|
|
||||||
public static void addJVMClassPath(String path) throws IOException {
|
|
||||||
LogHelper.debug("Launcher Agent addJVMClassPath");
|
|
||||||
inst.appendToSystemClassLoaderSearch(new JarFile(new File(path)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addJVMClassPath(Path path) throws IOException {
|
|
||||||
LogHelper.debug("Launcher Agent addJVMClassPath");
|
|
||||||
inst.appendToSystemClassLoaderSearch(new JarFile(path.toFile()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void premain(String agentArgument, Instrumentation instrumentation) {
|
|
||||||
System.out.println("Launcher Agent");
|
|
||||||
checkAgentStacktrace();
|
|
||||||
inst = instrumentation;
|
|
||||||
NativeJVMHalt.initFunc();
|
|
||||||
isAgentStarted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkAgentStacktrace() {
|
|
||||||
RuntimeException ex = new SecurityException("Error check agent stacktrace");
|
|
||||||
boolean isFoundNative = false;
|
|
||||||
boolean foundPreMain = false;
|
|
||||||
for (StackTraceElement e : ex.getStackTrace()) {
|
|
||||||
if (e.isNativeMethod()) {
|
|
||||||
if (!isFoundNative) isFoundNative = true;
|
|
||||||
else throw ex;
|
|
||||||
}
|
|
||||||
if (e.getMethodName().equals("premain")) {
|
|
||||||
if (!foundPreMain) foundPreMain = true;
|
|
||||||
else throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isFoundNative || !foundPreMain) throw ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isStarted() {
|
|
||||||
return isAgentStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAgentStarted() {
|
|
||||||
return isAgentStarted;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -123,6 +123,9 @@ protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findLibrary(String name) {
|
public String findLibrary(String name) {
|
||||||
|
if(nativePath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,9 @@ protected Class<?> findClass(String moduleName, String name) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findLibrary(String name) {
|
public String findLibrary(String name) {
|
||||||
|
if(nativePath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
id 'org.openjfx.javafxplugin' version '0.1.0' apply false
|
id 'org.openjfx.javafxplugin' version '0.1.0' apply false
|
||||||
}
|
}
|
||||||
group = 'pro.gravit.launcher'
|
group = 'pro.gravit.launcher'
|
||||||
version = '5.7.0-SNAPSHOT'
|
version = '5.6.8'
|
||||||
|
|
||||||
apply from: 'props.gradle'
|
apply from: 'props.gradle'
|
||||||
|
|
||||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
7
gradlew
vendored
7
gradlew
vendored
|
@ -15,6 +15,8 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
|
@ -55,7 +57,7 @@
|
||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
@ -84,7 +86,8 @@ done
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
|
2
gradlew.bat
vendored
2
gradlew.bat
vendored
|
@ -13,6 +13,8 @@
|
||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit c5087d40c9dd5b065fccedeac21afb967a25e112
|
Subproject commit 0d8cef927b1fda3097dc88c3adcffc4d0e33dd69
|
24
props.gradle
24
props.gradle
|
@ -1,18 +1,18 @@
|
||||||
project.ext {
|
project.ext {
|
||||||
verAsm = '9.7'
|
verAsm = '9.7.1'
|
||||||
verNetty = '4.1.111.Final'
|
verNetty = '4.1.114.Final'
|
||||||
verOshiCore = '6.6.1'
|
verOshiCore = '6.6.5'
|
||||||
verJunit = '5.10.2'
|
verJunit = '5.11.2'
|
||||||
verJansi = '2.4.1'
|
verJansi = '2.4.1'
|
||||||
verJline = '3.26.1'
|
verJline = '3.26.3'
|
||||||
verJwt = '0.12.5'
|
verJwt = '0.12.6'
|
||||||
verGson = '2.11.0'
|
verGson = '2.11.0'
|
||||||
verBcpkix = '1.78.1'
|
verBcpkix = '1.78.1'
|
||||||
verSlf4j = '2.0.13'
|
verSlf4j = '2.0.16'
|
||||||
verLog4j = '2.23.1'
|
verLog4j = '2.24.1'
|
||||||
verMySQLConn = '9.0.0'
|
verMySQLConn = '9.0.0'
|
||||||
verMariaDBConn = '3.4.0'
|
verMariaDBConn = '3.4.1'
|
||||||
verPostgreSQLConn = '42.7.3'
|
verPostgreSQLConn = '42.7.4'
|
||||||
verH2Conn = '2.2.224'
|
verH2Conn = '2.3.232'
|
||||||
verProguard = '7.5.0'
|
verProguard = '7.6.0'
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue