mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-02-22 19:49:46 +03:00
[FEATURE] Backport MariaDB auth provider
This commit is contained in:
parent
fb4e31117a
commit
cc931d0b17
5 changed files with 455 additions and 0 deletions
|
@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
verSlf4j = '1.7.36'
|
||||
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