mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-03-31 21:44:04 +03:00
Compare commits
26 commits
Author | SHA1 | Date | |
---|---|---|---|
|
c90fd717df | ||
|
14c7de0fde | ||
|
d06bceecf3 | ||
|
cc931d0b17 | ||
|
fb4e31117a | ||
|
cdf33cebc5 | ||
|
91d707b844 | ||
|
2adfa63891 | ||
|
1463df0bf8 | ||
|
5a2d0d8e84 | ||
|
98eee95fc8 | ||
|
85938d4d38 | ||
|
c76e451210 | ||
|
a53b18ae68 | ||
|
5f04ea7ccc | ||
|
505eb347de | ||
|
ced13d2cb4 | ||
|
a02a5b6af3 | ||
|
31dc4052c8 | ||
|
5abadb0d8a | ||
|
d422a6ea0a | ||
|
65ee7540ce | ||
|
ce45844b7f | ||
|
b15500f6fa | ||
|
683be84cef | ||
|
6ef0d49e72 |
28 changed files with 599 additions and 185 deletions
11
.github/workflows/push.yml
vendored
11
.github/workflows/push.yml
vendored
|
@ -6,20 +6,21 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: gravit-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}-launcher
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 21
|
||||
distribution: temurin
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
@ -40,7 +41,7 @@ jobs:
|
|||
cp modules/*_lmodule/build/libs/*.jar artifacts/modules || true
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Launcher
|
||||
path: artifacts
|
||||
|
@ -61,7 +62,7 @@ jobs:
|
|||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.event.ref, 'refs/tags')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
@ -87,6 +87,7 @@ pack project(':LauncherModernCore')
|
|||
bundle group: 'io.netty', name: 'netty-all', version: rootProject['verNetty']
|
||||
bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
||||
bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
|
||||
bundle group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: rootProject['verMariaDBConn']
|
||||
bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn']
|
||||
bundle group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard']
|
||||
bundle group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j']
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package pro.gravit.launchserver.auth;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.mariadb.jdbc.MariaDbDataSource;
|
||||
import pro.gravit.utils.helper.VerifyHelper;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
|
||||
public final class MariaDBSourceConfig implements AutoCloseable, SQLSourceConfig {
|
||||
|
||||
public static final int TIMEOUT = VerifyHelper.verifyInt(
|
||||
Integer.parseUnsignedInt(System.getProperty("launcher.mysql.idleTimeout", Integer.toString(5000))),
|
||||
VerifyHelper.POSITIVE, "launcher.mysql.idleTimeout can't be <= 5000");
|
||||
private static final int MAX_POOL_SIZE = VerifyHelper.verifyInt(
|
||||
Integer.parseUnsignedInt(System.getProperty("launcher.mysql.maxPoolSize", Integer.toString(3))),
|
||||
VerifyHelper.POSITIVE, "launcher.mysql.maxPoolSize can't be <= 0");
|
||||
|
||||
// Instance
|
||||
private transient final String poolName;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
||||
// Config
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
private long hikariMaxLifetime = MINUTES.toMillis(30);
|
||||
private boolean useHikari;
|
||||
|
||||
// Cache
|
||||
private transient DataSource source;
|
||||
private transient boolean hikari;
|
||||
|
||||
|
||||
public MariaDBSourceConfig(String poolName) {
|
||||
this.poolName = poolName;
|
||||
}
|
||||
|
||||
public MariaDBSourceConfig(String poolName, String url, String username, String password) {
|
||||
this.poolName = poolName;
|
||||
this.url = url;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public MariaDBSourceConfig(String poolName, DataSource source, boolean hikari) {
|
||||
this.poolName = poolName;
|
||||
this.source = source;
|
||||
this.hikari = hikari;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
if (hikari)
|
||||
((HikariDataSource) source).close();
|
||||
}
|
||||
|
||||
|
||||
public synchronized Connection getConnection() throws SQLException {
|
||||
if (source == null) { // New data source
|
||||
MariaDbDataSource mariaDbDataSource = new MariaDbDataSource();
|
||||
mariaDbDataSource.setUser(username);
|
||||
mariaDbDataSource.setPassword(password);
|
||||
mariaDbDataSource.setUrl(url);
|
||||
hikari = false;
|
||||
// Try using HikariCP
|
||||
source = mariaDbDataSource;
|
||||
if (useHikari) {
|
||||
try {
|
||||
Class.forName("com.zaxxer.hikari.HikariDataSource");
|
||||
hikari = true; // Used for shutdown. Not instanceof because of possible classpath error
|
||||
HikariConfig hikariConfig = new HikariConfig();
|
||||
hikariConfig.setDataSource(mariaDbDataSource);
|
||||
hikariConfig.setPoolName(poolName);
|
||||
hikariConfig.setMinimumIdle(1);
|
||||
hikariConfig.setMaximumPoolSize(MAX_POOL_SIZE);
|
||||
hikariConfig.setConnectionTestQuery("SELECT 1");
|
||||
hikariConfig.setConnectionTimeout(1000);
|
||||
hikariConfig.setLeakDetectionThreshold(2000);
|
||||
hikariConfig.setMaxLifetime(hikariMaxLifetime);
|
||||
// Set HikariCP pool
|
||||
// Replace source with hds
|
||||
source = new HikariDataSource(hikariConfig);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
logger.debug("HikariCP isn't in classpath for '{}'", poolName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return source.getConnection();
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@ public static void registerProviders() {
|
|||
if (!registredProviders) {
|
||||
providers.register("reject", RejectAuthCoreProvider.class);
|
||||
providers.register("mysql", MySQLCoreProvider.class);
|
||||
providers.register("mariadb", MariaDBCoreProvider.class);
|
||||
providers.register("postgresql", PostgresSQLCoreProvider.class);
|
||||
providers.register("memory", MemoryAuthCoreProvider.class);
|
||||
providers.register("merge", MergeAuthCoreProvider.class);
|
||||
|
|
|
@ -0,0 +1,354 @@
|
|||
package pro.gravit.launchserver.auth.core;
|
||||
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.MariaDBSourceConfig;
|
||||
import pro.gravit.launchserver.auth.MySQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.session.UserSessionSupportHardware;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
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 MariaDBCoreProvider extends AbstractSQLCoreProvider implements AuthSupportHardware {
|
||||
public MariaDBSourceConfig mariaDBHolder;
|
||||
|
||||
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 SQLSourceConfig getSQLConfig() {
|
||||
return mariaDBHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
super.init(server);
|
||||
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 MariaDBUser constructUser(ResultSet set) throws SQLException {
|
||||
return set.next() ? new MariaDBUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
||||
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), requestPermissions(set.getString(uuidColumn)), set.getLong(hardwareIdColumn)) : null;
|
||||
}
|
||||
|
||||
private MariaDBUserHardware fetchHardwareInfo(ResultSet set) throws SQLException, IOException {
|
||||
HardwareReportRequest.HardwareInfo hardwareInfo = new HardwareReportRequest.HardwareInfo();
|
||||
hardwareInfo.hwDiskId = set.getString("hwDiskId");
|
||||
hardwareInfo.baseboardSerialNumber = set.getString("baseboardSerialNumber");
|
||||
Blob displayId = set.getBlob("displayId");
|
||||
hardwareInfo.displayId = displayId == null ? null : IOHelper.read(displayId.getBinaryStream());
|
||||
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");
|
||||
Blob publicKey = set.getBlob("publicKey");
|
||||
long id = set.getLong("id");
|
||||
boolean banned = set.getBoolean("banned");
|
||||
return new MariaDBUserHardware(hardwareInfo, publicKey == null ? null : IOHelper.read(publicKey.getBinaryStream()), 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 = mariaDBHolder.getConnection()) {
|
||||
PreparedStatement s = connection.prepareStatement(sqlFindHardwareByPublicKey);
|
||||
s.setBlob(1, new ByteArrayInputStream(publicKey));
|
||||
try (ResultSet set = s.executeQuery()) {
|
||||
if (set.next()) {
|
||||
return fetchHardwareInfo(set);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (SQLException | IOException throwables) {
|
||||
logger.error("SQL Error", throwables);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware getHardwareInfoByData(HardwareReportRequest.HardwareInfo info) {
|
||||
try (Connection connection = mariaDBHolder.getConnection()) {
|
||||
PreparedStatement s = connection.prepareStatement(sqlFindHardwareByData);
|
||||
try (ResultSet set = s.executeQuery()) {
|
||||
while (set.next()) {
|
||||
MariaDBUserHardware hw = fetchHardwareInfo(set);
|
||||
HardwareInfoCompareResult result = compareHardwareInfo(hw.getHardwareInfo(), info);
|
||||
if (result.compareLevel > criticalCompareLevel) {
|
||||
return hw;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException | IOException throwables) {
|
||||
logger.error("SQL Error", throwables);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware getHardwareInfoById(String id) {
|
||||
try (Connection connection = mariaDBHolder.getConnection()) {
|
||||
PreparedStatement s = connection.prepareStatement(sqlFindHardwareById);
|
||||
s.setLong(1, Long.parseLong(id));
|
||||
try (ResultSet set = s.executeQuery()) {
|
||||
if (set.next()) {
|
||||
return fetchHardwareInfo(set);
|
||||
} else {
|
||||
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 = mariaDBHolder.getConnection()) {
|
||||
PreparedStatement s = connection.prepareStatement(sqlCreateHardware, Statement.RETURN_GENERATED_KEYS);
|
||||
s.setBlob(1, new ByteArrayInputStream(publicKey));
|
||||
s.setString(2, hardwareInfo.hwDiskId);
|
||||
s.setString(3, hardwareInfo.baseboardSerialNumber);
|
||||
s.setBlob(4, hardwareInfo.displayId == null ? null : new ByteArrayInputStream(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);
|
||||
return new MariaDBUserHardware(hardwareInfo, publicKey, id, false);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (SQLException throwables) {
|
||||
logger.error("SQL Error", throwables);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectUserAndHardware(UserSession userSession, UserHardware hardware) {
|
||||
SQLUserSession mySQLUserSession = (SQLUserSession) userSession;
|
||||
MariaDBUser mariaDBUser = (MariaDBUser) mySQLUserSession.getUser();
|
||||
MariaDBUserHardware mariaDBUserHardware = (MariaDBUserHardware) hardware;
|
||||
if (mariaDBUser.hwidId == mariaDBUserHardware.id) return;
|
||||
mariaDBUser.hwidId = mariaDBUserHardware.id;
|
||||
try (Connection connection = mariaDBHolder.getConnection()) {
|
||||
setUserHardwareId(connection, mariaDBUser.getUUID(), mariaDBUserHardware.id);
|
||||
} catch (SQLException throwables) {
|
||||
logger.error("SQL Error", throwables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey) {
|
||||
MariaDBUserHardware mariaDBUserHardware = (MariaDBUserHardware) hardware;
|
||||
mariaDBUserHardware.publicKey = publicKey;
|
||||
try (Connection connection = mariaDBHolder.getConnection()) {
|
||||
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwarePublicKey);
|
||||
s.setBlob(1, new ByteArrayInputStream(publicKey));
|
||||
s.setLong(2, mariaDBUserHardware.id);
|
||||
s.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
logger.error("SQL error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<User> getUsersByHardwareInfo(UserHardware hardware) {
|
||||
List<User> users = new LinkedList<>();
|
||||
try (Connection c = mariaDBHolder.getConnection()) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("SQL error", e);
|
||||
return null;
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void banHardware(UserHardware hardware) {
|
||||
MariaDBUserHardware mariaDBUserHardware = (MariaDBUserHardware) hardware;
|
||||
mariaDBUserHardware.banned = true;
|
||||
try (Connection connection = mariaDBHolder.getConnection()) {
|
||||
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwareBanned);
|
||||
s.setBoolean(1, true);
|
||||
s.setLong(2, mariaDBUserHardware.id);
|
||||
s.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
logger.error("SQL Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbanHardware(UserHardware hardware) {
|
||||
MariaDBUserHardware mariaDBUserHardware = (MariaDBUserHardware) hardware;
|
||||
mariaDBUserHardware.banned = false;
|
||||
try (Connection connection = mariaDBHolder.getConnection()) {
|
||||
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwareBanned);
|
||||
s.setBoolean(1, false);
|
||||
s.setLong(2, mariaDBUserHardware.id);
|
||||
s.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
logger.error("SQL error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLUserSession createSession(SQLUser user) {
|
||||
return new MariaDBUserSession(user);
|
||||
}
|
||||
|
||||
public class MariaDBUserSession extends SQLUserSession implements UserSessionSupportHardware {
|
||||
private transient MariaDBUser mariaDBUser;
|
||||
protected transient MariaDBUserHardware hardware;
|
||||
|
||||
public MariaDBUserSession(SQLUser user) {
|
||||
super(user);
|
||||
mariaDBUser = (MariaDBUser) user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHardwareId() {
|
||||
return mariaDBUser.hwidId == 0 ? null : String.valueOf(mariaDBUser.hwidId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware getHardware() {
|
||||
if(hardware == null) {
|
||||
hardware = (MariaDBUserHardware) getHardwareInfoById(String.valueOf(mariaDBUser.hwidId));
|
||||
}
|
||||
return hardware;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MariaDBUserHardware implements UserHardware {
|
||||
private final HardwareReportRequest.HardwareInfo hardwareInfo;
|
||||
private final long id;
|
||||
private byte[] publicKey;
|
||||
private boolean banned;
|
||||
|
||||
public MariaDBUserHardware(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 "MySQLUserHardware{" +
|
||||
"hardwareInfo=" + hardwareInfo +
|
||||
", publicKey=" + (publicKey == null ? null : new String(Base64.getEncoder().encode(publicKey))) +
|
||||
", id=" + id +
|
||||
", banned=" + banned +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public class MariaDBUser extends SQLUser {
|
||||
protected long hwidId;
|
||||
|
||||
public MariaDBUser(UUID uuid, String username, String accessToken, String serverId, String password, ClientPermissions permissions, long hwidId) {
|
||||
super(uuid, username, accessToken, serverId, password, permissions);
|
||||
this.hwidId = hwidId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MySQLUser{" +
|
||||
"uuid=" + uuid +
|
||||
", username='" + username + '\'' +
|
||||
", permissions=" + permissions +
|
||||
", hwidId=" + hwidId +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,12 +29,12 @@ public void init(LaunchServer server) {
|
|||
|
||||
@Override
|
||||
public boolean canGetProfile(ClientProfile profile, Client client) {
|
||||
return !profile.isLimited() || isWhitelisted("launchserver.profile.%s.show", profile, client);
|
||||
return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.show", profile, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChangeProfile(ClientProfile profile, Client client) {
|
||||
return !profile.isLimited() || isWhitelisted("launchserver.profile.%s.enter", profile, client);
|
||||
return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.enter", profile, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
import pro.gravit.launchserver.socket.response.secure.SecurityReportResponse;
|
||||
import pro.gravit.launchserver.socket.response.secure.VerifySecureLevelKeyResponse;
|
||||
import pro.gravit.launchserver.socket.response.update.LauncherResponse;
|
||||
import pro.gravit.launchserver.socket.response.update.UpdateListResponse;
|
||||
import pro.gravit.launchserver.socket.response.update.UpdateResponse;
|
||||
import pro.gravit.utils.BiHookSet;
|
||||
import pro.gravit.utils.HookSet;
|
||||
|
@ -64,7 +63,6 @@ public static void registerResponses() {
|
|||
providers.register("joinServer", JoinServerResponse.class);
|
||||
providers.register("profiles", ProfilesResponse.class);
|
||||
providers.register("launcher", LauncherResponse.class);
|
||||
providers.register("updateList", UpdateListResponse.class);
|
||||
providers.register("setProfile", SetProfileResponse.class);
|
||||
providers.register("update", UpdateResponse.class);
|
||||
providers.register("batchProfileByUsername", BatchProfileByUsername.class);
|
||||
|
|
|
@ -52,7 +52,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
|||
client.checkSign = true;
|
||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||
} 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
|
||||
{
|
||||
|
@ -62,7 +62,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
|||
client.checkSign = true;
|
||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||
} 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");
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package pro.gravit.launchserver.socket.response.update;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import pro.gravit.launcher.events.request.UpdateListRequestEvent;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class UpdateListResponse extends SimpleResponse {
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "updateList";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
||||
if (!client.isAuth) {
|
||||
sendError("Access denied");
|
||||
return;
|
||||
}
|
||||
HashSet<String> set = server.updatesManager.getUpdatesList();
|
||||
sendResult(new UpdateListRequestEvent(set));
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
import pro.gravit.launcher.serialize.HOutput;
|
||||
import pro.gravit.utils.helper.*;
|
||||
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
|
@ -28,7 +29,6 @@
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
public class ClientLauncherProcess {
|
||||
|
||||
public final List<String> pre = new LinkedList<>();
|
||||
public final ClientParams params = new ClientParams();
|
||||
public final List<String> jvmArgs = new LinkedList<>();
|
||||
|
@ -75,6 +75,7 @@ public ClientLauncherProcess(Path clientDir, Path assetDir, JavaHelper.JavaVersi
|
|||
this.params.clientDir = this.workDir.toString();
|
||||
this.params.resourcePackDir = resourcePackDir.toAbsolutePath().toString();
|
||||
this.params.assetDir = assetDir.toAbsolutePath().toString();
|
||||
this.params.timestamp = System.currentTimeMillis();
|
||||
Path nativesPath;
|
||||
if(profile.hasFlag(ClientProfile.CompatibilityFlags.LEGACY_NATIVES_DIR)) {
|
||||
nativesPath = workDir.resolve("natives");
|
||||
|
@ -222,7 +223,7 @@ public void runWriteParams(SocketAddress address) throws IOException {
|
|||
waitWriteParams.notifyAll();
|
||||
}
|
||||
Socket socket = serverSocket.accept();
|
||||
try (HOutput output = new HOutput(socket.getOutputStream())) {
|
||||
try (HOutput output = new HOutput(new CipherOutputStream(socket.getOutputStream(), SecurityHelper.newAESEncryptCipher(SecurityHelper.fromHex(Launcher.getConfig().secretKeyClient))))) {
|
||||
byte[] serializedMainParams = IOHelper.encode(Launcher.gsonManager.gson.toJson(params));
|
||||
output.writeByteArray(serializedMainParams, 0);
|
||||
params.clientHDir.write(output);
|
||||
|
@ -233,6 +234,8 @@ public void runWriteParams(SocketAddress address) throws IOException {
|
|||
output.writeBoolean(true);
|
||||
params.javaHDir.write(output);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderParamsWrittedEvent(this));
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package pro.gravit.launcher.events.request;
|
||||
|
||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||
import pro.gravit.launcher.events.RequestEvent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class UpdateListRequestEvent extends RequestEvent {
|
||||
@SuppressWarnings("unused")
|
||||
private static final UUID uuid = UUID.fromString("5fa836ae-6b61-401c-96ac-d8396f07ec6b");
|
||||
@LauncherNetworkAPI
|
||||
public final HashSet<String> dirs;
|
||||
|
||||
public UpdateListRequestEvent(HashSet<String> dirs) {
|
||||
this.dirs = dirs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "updateList";
|
||||
}
|
||||
}
|
|
@ -88,7 +88,7 @@ public Set<OptionalAction> getEnabledActions() {
|
|||
public void fixDependencies() {
|
||||
Set<OptionalFile> disabled = all.stream().filter(t -> !isEnabled(t)).collect(Collectors.toSet());
|
||||
for (OptionalFile file : disabled) {
|
||||
if (file.group != null && Arrays.stream(file.group).noneMatch(this::isEnabled)) {
|
||||
if (file.group != null && file.group.length > 0 && Arrays.stream(file.group).noneMatch(this::isEnabled)) {
|
||||
enable(file.group[0], false, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package pro.gravit.launcher.request.update;
|
||||
|
||||
import pro.gravit.launcher.events.request.UpdateListRequestEvent;
|
||||
import pro.gravit.launcher.request.Request;
|
||||
import pro.gravit.launcher.request.websockets.WebSocketRequest;
|
||||
|
||||
public final class UpdateListRequest extends Request<UpdateListRequestEvent> implements WebSocketRequest {
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "updateList";
|
||||
}
|
||||
}
|
|
@ -94,7 +94,6 @@ public void registerResults() {
|
|||
results.register("batchProfileByUsername", BatchProfileByUsernameRequestEvent.class);
|
||||
results.register("profiles", ProfilesRequestEvent.class);
|
||||
results.register("setProfile", SetProfileRequestEvent.class);
|
||||
results.register("updateList", UpdateListRequestEvent.class);
|
||||
results.register("error", ErrorRequestEvent.class);
|
||||
results.register("update", UpdateRequestEvent.class);
|
||||
results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
import pro.gravit.utils.helper.*;
|
||||
import pro.gravit.utils.launch.*;
|
||||
|
||||
import javax.crypto.CipherInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
@ -49,7 +50,7 @@ public class ClientLauncherEntryPoint {
|
|||
private static ClientParams readParams(SocketAddress address) throws IOException {
|
||||
try (Socket socket = IOHelper.newSocket()) {
|
||||
socket.connect(address);
|
||||
try (HInput input = new HInput(socket.getInputStream())) {
|
||||
try (HInput input = new HInput(new CipherInputStream(socket.getInputStream(), SecurityHelper.newAESDecryptCipher(SecurityHelper.fromHex(Launcher.getConfig().secretKeyClient))))) {
|
||||
byte[] serialized = input.readByteArray(0);
|
||||
ClientParams params = Launcher.gsonManager.gson.fromJson(IOHelper.decode(serialized), ClientParams.class);
|
||||
params.clientHDir = new HashedDir(input);
|
||||
|
@ -87,6 +88,11 @@ private static void realMain(String[] args) throws Throwable {
|
|||
if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) {
|
||||
ClientLauncherMethods.verifyNoAgent();
|
||||
}
|
||||
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
|
||||
LogHelper.error("Timestamp failed. Exit");
|
||||
ClientLauncherMethods.exitLauncher(-662);
|
||||
return;
|
||||
}
|
||||
ClientProfile profile = params.profile;
|
||||
Launcher.profile = profile;
|
||||
AuthService.profile = profile;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
import java.util.*;
|
||||
|
||||
public class ClientParams {
|
||||
public long timestamp;
|
||||
public String assetDir;
|
||||
|
||||
public String clientDir;
|
||||
|
|
|
@ -6,9 +6,9 @@ public final class Version implements Comparable<Version> {
|
|||
|
||||
public static final int MAJOR = 5;
|
||||
public static final int MINOR = 5;
|
||||
public static final int PATCH = 4;
|
||||
public static final int PATCH = 8;
|
||||
public static final int BUILD = 1;
|
||||
public static final Version.Type RELEASE = Type.STABLE;
|
||||
public static final Version.Type RELEASE = Type.LTS;
|
||||
public final int major;
|
||||
public final int minor;
|
||||
public final int patch;
|
||||
|
|
|
@ -33,20 +33,15 @@ public final class SecurityHelper {
|
|||
public static final String RSA_ALGO = "RSA";
|
||||
public static final String RSA_SIGN_ALGO = "SHA256withRSA";
|
||||
public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding";
|
||||
public static final String AES_CIPHER_ALGO = "AES/ECB/PKCS5Padding";
|
||||
|
||||
// Algorithm size constants
|
||||
public static final int AES_KEY_LENGTH = 8;
|
||||
public static final int AES_KEY_LENGTH = 16;
|
||||
public static final int TOKEN_STRING_LENGTH = TOKEN_LENGTH << 1;
|
||||
public static final int RSA_KEY_LENGTH_BITS = 2048;
|
||||
public static final int RSA_KEY_LENGTH = RSA_KEY_LENGTH_BITS / Byte.SIZE;
|
||||
public static final int CRYPTO_MAX_LENGTH = 2048;
|
||||
public static final String HEX = "0123456789abcdef";
|
||||
// Certificate constants
|
||||
public static final byte[] NUMBERS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
public static final SecureRandom secureRandom = new SecureRandom();
|
||||
// Random generator constants
|
||||
private static final char[] VOWELS = {'e', 'u', 'i', 'o', 'a'};
|
||||
private static final char[] CONS = {'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'k', 'l', 'c', 'v', 'b', 'n', 'm'};
|
||||
|
||||
private SecurityHelper() {
|
||||
}
|
||||
|
@ -189,6 +184,16 @@ private static Cipher newRSACipher(int mode, RSAKey key) {
|
|||
return cipher;
|
||||
}
|
||||
|
||||
private static Cipher newAESCipher(int mode, byte[] key) {
|
||||
Cipher cipher = newCipher(AES_CIPHER_ALGO);
|
||||
try {
|
||||
cipher.init(mode, new SecretKeySpec(key, "AES"));
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
return cipher;
|
||||
}
|
||||
|
||||
private static KeyFactory newECDSAKeyFactory() {
|
||||
try {
|
||||
return KeyFactory.getInstance(EC_ALGO);
|
||||
|
@ -313,70 +318,6 @@ public static byte[] randomAESKey(Random random) {
|
|||
return randomBytes(random, AES_KEY_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
public static String randomUsername() {
|
||||
return randomUsername(newRandom());
|
||||
}
|
||||
|
||||
|
||||
public static String randomUsername(Random random) {
|
||||
int usernameLength = 3 + random.nextInt(7); // 3-9
|
||||
|
||||
// Choose prefix
|
||||
String prefix;
|
||||
int prefixType = random.nextInt(7);
|
||||
if (usernameLength >= 5 && prefixType == 6) { // (6) 2-char
|
||||
prefix = random.nextBoolean() ? "Mr" : "Dr";
|
||||
usernameLength -= 2;
|
||||
} else if (usernameLength >= 6 && prefixType == 5) { // (5) 3-char
|
||||
prefix = "Mrs";
|
||||
usernameLength -= 3;
|
||||
} else
|
||||
prefix = "";
|
||||
|
||||
// Choose suffix
|
||||
String suffix;
|
||||
int suffixType = random.nextInt(7); // 0-6, 7 values
|
||||
if (usernameLength >= 5 && suffixType == 6) { // (6) 10-99
|
||||
suffix = String.valueOf(10 + random.nextInt(90));
|
||||
usernameLength -= 2;
|
||||
} else if (usernameLength >= 7 && suffixType == 5) { // (5) 1990-2015
|
||||
suffix = String.valueOf(1990 + random.nextInt(26));
|
||||
usernameLength -= 4;
|
||||
} else
|
||||
suffix = "";
|
||||
|
||||
// Choose name
|
||||
int consRepeat = 0;
|
||||
boolean consPrev = random.nextBoolean();
|
||||
char[] chars = new char[usernameLength];
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
if (i > 1 && consPrev && random.nextInt(10) == 0) { // Doubled
|
||||
chars[i] = chars[i - 1];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Choose next char
|
||||
if (consRepeat < 1 && random.nextInt() == 5)
|
||||
consRepeat++;
|
||||
else {
|
||||
consRepeat = 0;
|
||||
consPrev ^= true;
|
||||
}
|
||||
|
||||
// Choose char
|
||||
char[] alphabet = consPrev ? CONS : VOWELS;
|
||||
chars[i] = alphabet[random.nextInt(alphabet.length)];
|
||||
}
|
||||
|
||||
// Make first letter uppercase
|
||||
if (!prefix.isEmpty() || random.nextBoolean())
|
||||
chars[0] = Character.toUpperCase(chars[0]);
|
||||
|
||||
// Return chosen name (and verify for sure)
|
||||
return VerifyHelper.verifyUsername(prefix + new String(chars) + suffix);
|
||||
}
|
||||
|
||||
public static byte[] sign(byte[] bytes, ECPrivateKey privateKey) {
|
||||
Signature signature = newECSignSignature(privateKey);
|
||||
try {
|
||||
|
@ -484,6 +425,22 @@ public static Cipher newRSAEncryptCipher(RSAPublicKey publicKey) {
|
|||
}
|
||||
}
|
||||
|
||||
public static Cipher newAESDecryptCipher(byte[] key) {
|
||||
try {
|
||||
return newAESCipher(Cipher.DECRYPT_MODE, key);
|
||||
} catch (SecurityException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Cipher newAESEncryptCipher(byte[] key) {
|
||||
try {
|
||||
return newAESCipher(Cipher.ENCRYPT_MODE, key);
|
||||
} catch (SecurityException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
//AES
|
||||
public static byte[] encrypt(String seed, byte[] cleartext) throws Exception {
|
||||
byte[] rawKey = getAESKey(IOHelper.encode(seed));
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package pro.gravit.launcher;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
import javax.crypto.CipherInputStream;
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class SecurityHelperTests {
|
||||
@Test
|
||||
public void aesLegacyTest() throws Exception {
|
||||
byte[] bytes = SecurityHelper.randomBytes(24);
|
||||
byte[] seed = SecurityHelper.randomBytes(32);
|
||||
byte[] encrypted = SecurityHelper.encrypt(seed, bytes);
|
||||
byte[] decrypted = SecurityHelper.decrypt(seed, encrypted);
|
||||
Assertions.assertArrayEquals(bytes, decrypted);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void aesStreamTest() throws Exception {
|
||||
byte[] bytes = SecurityHelper.randomBytes(128);
|
||||
byte[] seed = SecurityHelper.randomAESKey();
|
||||
byte[] encrypted;
|
||||
ByteArrayOutputStream s = new ByteArrayOutputStream();
|
||||
try (OutputStream o = new CipherOutputStream(s, SecurityHelper.newAESEncryptCipher(seed))) {
|
||||
try (ByteArrayInputStream i = new ByteArrayInputStream(bytes)) {
|
||||
IOHelper.transfer(i, o);
|
||||
}
|
||||
}
|
||||
encrypted = s.toByteArray();
|
||||
byte[] decrypted;
|
||||
try (InputStream i = new CipherInputStream(new ByteArrayInputStream(encrypted), SecurityHelper.newAESDecryptCipher(seed))) {
|
||||
try (ByteArrayOutputStream s2 = new ByteArrayOutputStream()) {
|
||||
IOHelper.transfer(i, s2);
|
||||
decrypted = s2.toByteArray();
|
||||
}
|
||||
}
|
||||
Assertions.assertArrayEquals(bytes, decrypted);
|
||||
}
|
||||
}
|
|
@ -183,7 +183,13 @@ public CompletableFuture<Void> downloadFiles(List<SizedFile> files, String baseU
|
|||
}
|
||||
try {
|
||||
DownloadTask task = sendAsync(file, baseUri, targetDir, callback);
|
||||
task.completableFuture.thenAccept(consumerObject.next).exceptionally(ec -> {
|
||||
task.completableFuture.thenCompose((res) -> {
|
||||
if(res.statusCode() < 200 || res.statusCode() >= 300) {
|
||||
return CompletableFuture.failedFuture(new IOException(String.format("Failed to download %s: code %d",
|
||||
file.urlPath != null ? file.urlPath /* TODO: baseUri */ : file.filePath, res.statusCode())));
|
||||
}
|
||||
return CompletableFuture.completedFuture(res);
|
||||
}).thenAccept(consumerObject.next).exceptionally(ec -> {
|
||||
future.completeExceptionally(ec);
|
||||
return null;
|
||||
});
|
||||
|
@ -234,7 +240,7 @@ protected HttpRequest makeHttpRequest(URI baseUri, String filePath) throws URISy
|
|||
}
|
||||
|
||||
protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadCallback callback) {
|
||||
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE), callback);
|
||||
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING), callback);
|
||||
}
|
||||
|
||||
public interface DownloadCallback {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
public class InstallAuthlib {
|
||||
private static final Map<String, LibrariesHashFileModifier> modifierMap;
|
||||
private static final String tempLaunchAuthLibName = "authlib.jar";
|
||||
static {
|
||||
modifierMap = new HashMap<>();
|
||||
modifierMap.put("META-INF/libraries.list", new LibrariesLstModifier());
|
||||
|
@ -26,30 +27,30 @@ public void run(String... args) throws Exception {
|
|||
boolean deleteAuthlibAfterInstall = false;
|
||||
InstallAuthlibContext context = new InstallAuthlibContext();
|
||||
if(args[0].startsWith("http://") || args[0].startsWith("https://")) {
|
||||
Path tempAuthlib = Paths.get("authlib.jar");
|
||||
Path tempAuthlib = Paths.get(tempLaunchAuthLibName);
|
||||
LogHelper.info("Download %s to %s", args[0], tempAuthlib);
|
||||
try(InputStream input = IOHelper.newInput(new URL(args[0]))) {
|
||||
IOHelper.transfer(input, tempAuthlib);
|
||||
}
|
||||
context.pathToAuthlib = tempAuthlib;
|
||||
context.pathToAuthlib = tempAuthlib.toAbsolutePath();
|
||||
deleteAuthlibAfterInstall = true;
|
||||
} else {
|
||||
context.pathToAuthlib = Paths.get(args[0]);
|
||||
context.pathToAuthlib = Paths.get(args[0]).toAbsolutePath();
|
||||
}
|
||||
if(Files.notExists(context.pathToAuthlib)) {
|
||||
throw new FileNotFoundException(context.pathToAuthlib.toString());
|
||||
}
|
||||
context.workdir = IOHelper.WORKING_DIR;
|
||||
LogHelper.info("Search .jar files in %s", context.workdir.toAbsolutePath());
|
||||
IOHelper.walk(context.workdir, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
if(file.getFileName().toString().endsWith(".jar")) {
|
||||
if (file.getFileName().toString().endsWith(".jar") && !file.equals(context.pathToAuthlib)) {
|
||||
context.files.add(file);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}, true);
|
||||
context.files.sort(Comparator.comparingInt((Path path) -> - path.getNameCount()));
|
||||
LogHelper.info("Search authlib in %d files", context.files.size());
|
||||
for(Path path : context.files) {
|
||||
boolean foundAuthlib = false;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
id 'org.openjfx.javafxplugin' version '0.0.10' apply false
|
||||
}
|
||||
group = 'pro.gravit.launcher'
|
||||
version = '5.5.4'
|
||||
version = '5.5.8'
|
||||
|
||||
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
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
6
gradlew
vendored
6
gradlew
vendored
|
@ -15,6 +15,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
|
@ -55,7 +57,7 @@
|
|||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (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.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
@ -84,7 +86,7 @@ done
|
|||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# 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\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
|
22
gradlew.bat
vendored
22
gradlew.bat
vendored
|
@ -13,6 +13,8 @@
|
|||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
|
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
|||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
|||
Subproject commit 7581b6c01470a5ec32ac67170635d10f6f589b0a
|
||||
Subproject commit b2e476e5bb61c445937ec77078cd7597933847df
|
21
props.gradle
21
props.gradle
|
@ -1,19 +1,20 @@
|
|||
project.ext {
|
||||
verAsm = '9.6'
|
||||
verNetty = '4.1.99.Final'
|
||||
verOshiCore = '6.4.11'
|
||||
verJunit = '5.9.3'
|
||||
verAsm = '9.7.1'
|
||||
verNetty = '4.1.118.Final'
|
||||
verOshiCore = '6.6.6'
|
||||
verJunit = '5.11.4'
|
||||
verGuavaC = '30.1.1-jre'
|
||||
verJansi = '2.4.1'
|
||||
verJline = '3.25.0'
|
||||
verJline = '3.29.0'
|
||||
verJwt = '0.11.5'
|
||||
verBcprov = '1.70'
|
||||
verGson = '2.10.1'
|
||||
verGson = '2.12.1'
|
||||
verBcpkix = '1.70'
|
||||
verSlf4j = '1.7.36'
|
||||
verLog4j = '2.20.0'
|
||||
verMySQLConn = '8.3.0'
|
||||
verPostgreSQLConn = '42.7.1'
|
||||
verProguard = '7.4.1'
|
||||
verLog4j = '2.24.3'
|
||||
verMySQLConn = '9.2.0'
|
||||
verMariaDBConn = '3.5.1'
|
||||
verPostgreSQLConn = '42.7.5'
|
||||
verProguard = '7.6.1'
|
||||
verLaunch4j = '3.50'
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue