diff --git a/LaunchServer/LaunchServer.iml b/LaunchServer/LaunchServer.iml
index f54725d..d63758e 100644
--- a/LaunchServer/LaunchServer.iml
+++ b/LaunchServer/LaunchServer.iml
@@ -36,8 +36,24 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -78,5 +94,7 @@
+
+
\ No newline at end of file
diff --git a/LaunchServer/source/auth/MariaDBSourceConfig.java b/LaunchServer/source/auth/MariaDBSourceConfig.java
new file mode 100644
index 0000000..f63f347
--- /dev/null
+++ b/LaunchServer/source/auth/MariaDBSourceConfig.java
@@ -0,0 +1,129 @@
+package launchserver.auth;
+
+import org.mariadb.jdbc.MariaDbDataSource;
+import com.zaxxer.hikari.HikariDataSource;
+import launcher.LauncherAPI;
+import launcher.helper.LogHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.ConfigObject;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.IntegerConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public final class MariaDBSourceConfig extends ConfigObject implements AutoCloseable, SQLSourceConfig
+{
+ @LauncherAPI
+ public static final int TIMEOUT = VerifyHelper.verifyInt(
+ Integer.parseInt(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.parseInt(System.getProperty("launcher.mysql.maxPoolSize", Integer.toString(3))),
+ VerifyHelper.POSITIVE, "launcher.mysql.maxPoolSize can't be <= 0");
+
+ // Instance
+ private final String poolName;
+
+ // Config
+ private final String address;
+ private final int port;
+ private final String username;
+ private final String password;
+ private final String database;
+
+ // Cache
+ private DataSource source;
+ private boolean hikari;
+
+ @LauncherAPI
+ public MariaDBSourceConfig(String poolName, BlockConfigEntry block)
+ {
+ super(block);
+ this.poolName = poolName;
+ address = VerifyHelper.verify(block.getEntryValue("address", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL address can't be empty");
+ port = VerifyHelper.verifyInt(block.getEntryValue("port", IntegerConfigEntry.class),
+ VerifyHelper.range(0, 65535), "Illegal MySQL port");
+ username = VerifyHelper.verify(block.getEntryValue("username", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL username can't be empty");
+ password = block.getEntryValue("password", StringConfigEntry.class);
+ database = VerifyHelper.verify(block.getEntryValue("database", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL database can't be empty");
+
+ // Password shouldn't be verified
+ }
+
+ @Override
+ public synchronized void close()
+ {
+ if (hikari)
+ { // Shutdown hikari pool
+ ((HikariDataSource) source).close();
+ }
+ }
+
+ @LauncherAPI
+ public synchronized Connection getConnection() throws SQLException
+ {
+ if (source == null)
+ { // New data source
+ MariaDbDataSource mariaDbSource = new MariaDbDataSource();
+
+ // Нету такого функционала у конектора MariaDB, попробуем так
+ //mariaDbSource.setCharacterEncoding("UTF-8");
+ //mariaDbSource.setUseSSL(false);
+
+ // Prep statements cache
+ //mariaDbSource.setPrepStmtCacheSize(250);
+ //mariaDbSource.setPrepStmtCacheSqlLimit(2048);
+ //mariaDbSource.setCachePrepStmts(true);
+ //mariaDbSource.setUseServerPrepStmts(true);
+
+ // General optimizations
+ //mariaDbSource.setCacheServerConfiguration(true);
+ //mariaDbSource.setUseLocalSessionState(true);
+ //mariaDbSource.setRewriteBatchedStatements(true);
+ //mariaDbSource.setMaintainTimeStats(false);
+ //mariaDbSource.setUseUnbufferedInput(false);
+ //mariaDbSource.setUseReadAheadInput(false);
+ //mariaDbSource.setTcpNoDelay(true);
+
+ // Set credentials
+ mariaDbSource.setServerName(address);
+ mariaDbSource.setPortNumber(port);
+ mariaDbSource.setUser(username);
+ mariaDbSource.setPassword(password);
+ mariaDbSource.setDatabaseName(database);
+
+ // Try using HikariCP
+ source = mariaDbSource;
+ try
+ {
+ Class.forName("com.zaxxer.hikari.HikariDataSource");
+ hikari = true; // Used for shutdown. Not instanceof because of possible classpath error
+
+ // Set HikariCP pool
+ HikariDataSource hikariSource = new HikariDataSource();
+ hikariSource.setDataSource(source);
+
+ // Set pool settings
+ hikariSource.setPoolName(poolName);
+ hikariSource.setMinimumIdle(0);
+ hikariSource.setMaximumPoolSize(MAX_POOL_SIZE);
+ hikariSource.setIdleTimeout(TIMEOUT * 1000L);
+
+ // Replace source with hds
+ source = hikariSource;
+ LogHelper.info("HikariCP pooling enabled for '%s'", poolName);
+ }
+ catch (ClassNotFoundException ignored)
+ {
+ LogHelper.warning("HikariCP isn't in classpath for '%s'", poolName);
+ }
+ }
+ return source.getConnection();
+ }
+}
diff --git a/LaunchServer/source/auth/MySQL8SourceConfig.java b/LaunchServer/source/auth/MySQL8SourceConfig.java
new file mode 100644
index 0000000..2d830f6
--- /dev/null
+++ b/LaunchServer/source/auth/MySQL8SourceConfig.java
@@ -0,0 +1,127 @@
+package launchserver.auth;
+
+import com.mysql.cj.jdbc.MysqlDataSource;
+import com.zaxxer.hikari.HikariDataSource;
+import launcher.LauncherAPI;
+import launcher.helper.LogHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.ConfigObject;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.IntegerConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public final class MySQL8SourceConfig extends ConfigObject implements AutoCloseable, SQLSourceConfig
+{
+ @LauncherAPI
+ public static final int TIMEOUT = VerifyHelper.verifyInt(
+ Integer.parseInt(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.parseInt(System.getProperty("launcher.mysql.maxPoolSize", Integer.toString(3))),
+ VerifyHelper.POSITIVE, "launcher.mysql.maxPoolSize can't be <= 0");
+
+ // Instance
+ private final String poolName;
+
+ // Config
+ private final String address;
+ private final int port;
+ private final String username;
+ private final String password;
+ private final String database;
+
+ // Cache
+ private DataSource source;
+ private boolean hikari;
+
+ @LauncherAPI
+ public MySQL8SourceConfig(String poolName, BlockConfigEntry block)
+ {
+ super(block);
+ this.poolName = poolName;
+ address = VerifyHelper.verify(block.getEntryValue("address", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL address can't be empty");
+ port = VerifyHelper.verifyInt(block.getEntryValue("port", IntegerConfigEntry.class),
+ VerifyHelper.range(0, 65535), "Illegal MySQL port");
+ username = VerifyHelper.verify(block.getEntryValue("username", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL username can't be empty");
+ password = block.getEntryValue("password", StringConfigEntry.class);
+ database = VerifyHelper.verify(block.getEntryValue("database", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL database can't be empty");
+
+ // Password shouldn't be verified
+ }
+
+ @Override
+ public synchronized void close()
+ {
+ if (hikari)
+ { // Shutdown hikari pool
+ ((HikariDataSource) source).close();
+ }
+ }
+
+ @LauncherAPI
+ public synchronized Connection getConnection() throws SQLException
+ {
+ if (source == null)
+ { // New data source
+ MysqlDataSource mysqlSource = new MysqlDataSource();
+ mysqlSource.setCharacterEncoding("UTF-8");
+ mysqlSource.setUseSSL(false);
+
+ // Prep statements cache
+ mysqlSource.setPrepStmtCacheSize(250);
+ mysqlSource.setPrepStmtCacheSqlLimit(2048);
+ mysqlSource.setCachePrepStmts(true);
+ mysqlSource.setUseServerPrepStmts(true);
+
+ // General optimizations
+ mysqlSource.setCacheServerConfiguration(true);
+ mysqlSource.setUseLocalSessionState(true);
+ mysqlSource.setRewriteBatchedStatements(true);
+ mysqlSource.setMaintainTimeStats(false);
+ mysqlSource.setUseUnbufferedInput(false);
+ mysqlSource.setUseReadAheadInput(false);
+ mysqlSource.setTcpNoDelay(true);
+
+ // Set credentials
+ mysqlSource.setServerName(address);
+ mysqlSource.setPortNumber(port);
+ mysqlSource.setUser(username);
+ mysqlSource.setPassword(password);
+ mysqlSource.setDatabaseName(database);
+
+ // Try using HikariCP
+ source = mysqlSource;
+ try
+ {
+ Class.forName("com.zaxxer.hikari.HikariDataSource");
+ hikari = true; // Used for shutdown. Not instanceof because of possible classpath error
+
+ // Set HikariCP pool
+ HikariDataSource hikariSource = new HikariDataSource();
+ hikariSource.setDataSource(source);
+
+ // Set pool settings
+ hikariSource.setPoolName(poolName);
+ hikariSource.setMinimumIdle(0);
+ hikariSource.setMaximumPoolSize(MAX_POOL_SIZE);
+ hikariSource.setIdleTimeout(TIMEOUT * 1000L);
+
+ // Replace source with hds
+ source = hikariSource;
+ LogHelper.info("HikariCP pooling enabled for '%s'", poolName);
+ }
+ catch (ClassNotFoundException ignored)
+ {
+ LogHelper.warning("HikariCP isn't in classpath for '%s'", poolName);
+ }
+ }
+ return source.getConnection();
+ }
+}
diff --git a/LaunchServer/source/auth/handler/AuthHandler.java b/LaunchServer/source/auth/handler/AuthHandler.java
index f578748..e1de616 100644
--- a/LaunchServer/source/auth/handler/AuthHandler.java
+++ b/LaunchServer/source/auth/handler/AuthHandler.java
@@ -26,6 +26,8 @@
registerHandler("binaryFile", BinaryFileAuthHandler::new);
registerHandler("textFile", TextFileAuthHandler::new);
registerHandler("mysql", MySQLAuthHandler::new);
+ registerHandler("mysql-8", MySQL8AuthHandler::new);
+ registerHandler("mariadb", MariaDBAuthHandler::new);
registerHandler("postgresql", PostgreSQLAuthHandler::new);
registerHandler("json", JsonAuthHandler::new);
}
diff --git a/LaunchServer/source/auth/handler/MariaDBAuthHandler.java b/LaunchServer/source/auth/handler/MariaDBAuthHandler.java
new file mode 100644
index 0000000..9a33ed1
--- /dev/null
+++ b/LaunchServer/source/auth/handler/MariaDBAuthHandler.java
@@ -0,0 +1,155 @@
+package launchserver.auth.handler;
+
+import launcher.helper.LogHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.BooleanConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+import launchserver.auth.MariaDBSourceConfig;
+
+import java.io.IOException;
+import java.sql.*;
+import java.util.UUID;
+
+public final class MariaDBAuthHandler extends CachedAuthHandler
+{
+ private final MariaDBSourceConfig mariaDBHolder;
+ private final String uuidColumn;
+ private final String usernameColumn;
+ private final String accessTokenColumn;
+ private final String serverIDColumn;
+
+ // Prepared SQL queries
+ private final String queryByUUIDSQL;
+ private final String queryByUsernameSQL;
+ private final String updateAuthSQL;
+ private final String updateServerIDSQL;
+
+ MariaDBAuthHandler(BlockConfigEntry block)
+ {
+ super(block);
+ mariaDBHolder = new MariaDBSourceConfig("authHandlerPool", block);
+
+ // Read query params
+ String table = VerifyHelper.verifyIDName(
+ block.getEntryValue("table", StringConfigEntry.class));
+ uuidColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("uuidColumn", StringConfigEntry.class));
+ usernameColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("usernameColumn", StringConfigEntry.class));
+ accessTokenColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("accessTokenColumn", StringConfigEntry.class));
+ serverIDColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("serverIDColumn", StringConfigEntry.class));
+
+ // Prepare SQL queries
+ queryByUUIDSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, uuidColumn);
+ queryByUsernameSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, usernameColumn);
+ updateAuthSQL = String.format("UPDATE %s SET %s=?, %s=?, %s=NULL WHERE %s=? LIMIT 1",
+ table, usernameColumn, accessTokenColumn, serverIDColumn, uuidColumn);
+ updateServerIDSQL = String.format("UPDATE %s SET %s=? WHERE %s=? LIMIT 1",
+ table, serverIDColumn, uuidColumn);
+
+ // Fetch all entries
+ if (block.getEntryValue("fetchAll", BooleanConfigEntry.class))
+ {
+ LogHelper.info("Fetching all AuthHandler entries");
+ String query = String.format("SELECT %s, %s, %s, %s FROM %s",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table);
+ try (Connection c = mariaDBHolder.getConnection(); Statement statement = c.createStatement();
+ ResultSet set = statement.executeQuery(query))
+ {
+ for (Entry entry = constructEntry(set); entry != null; entry = constructEntry(set))
+ {
+ addEntry(entry);
+ }
+ }
+ catch (SQLException e)
+ {
+ LogHelper.error(e);
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ mariaDBHolder.close();
+ }
+
+ @Override
+ protected Entry fetchEntry(String username) throws IOException
+ {
+ return query(queryByUsernameSQL, username);
+ }
+
+ @Override
+ protected Entry fetchEntry(UUID uuid) throws IOException
+ {
+ return query(queryByUUIDSQL, uuid.toString());
+ }
+
+ @Override
+ protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException
+ {
+ try (Connection c = mariaDBHolder.getConnection(); PreparedStatement s = c.prepareStatement(updateAuthSQL))
+ {
+ s.setString(1, username); // Username case
+ s.setString(2, accessToken);
+ s.setString(3, uuid.toString());
+
+ // Execute update
+ s.setQueryTimeout(MariaDBSourceConfig.TIMEOUT);
+ return s.executeUpdate() > 0;
+ }
+ catch (SQLException e)
+ {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ protected boolean updateServerID(UUID uuid, String serverID) throws IOException
+ {
+ try (Connection c = mariaDBHolder.getConnection(); PreparedStatement s = c.prepareStatement(updateServerIDSQL))
+ {
+ s.setString(1, serverID);
+ s.setString(2, uuid.toString());
+
+ // Execute update
+ s.setQueryTimeout(MariaDBSourceConfig.TIMEOUT);
+ return s.executeUpdate() > 0;
+ }
+ catch (SQLException e)
+ {
+ throw new IOException(e);
+ }
+ }
+
+ private Entry constructEntry(ResultSet set) throws SQLException
+ {
+ return set.next() ? new Entry(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
+ set.getString(accessTokenColumn), set.getString(serverIDColumn)) : null;
+ }
+
+ private Entry query(String sql, String value) throws IOException
+ {
+ try (Connection c = mariaDBHolder.getConnection(); PreparedStatement s = c.prepareStatement(sql))
+ {
+ s.setString(1, value);
+
+ // Execute query
+ s.setQueryTimeout(MariaDBSourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery())
+ {
+ return constructEntry(set);
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new IOException(e);
+ }
+ }
+}
diff --git a/LaunchServer/source/auth/handler/MySQL8AuthHandler.java b/LaunchServer/source/auth/handler/MySQL8AuthHandler.java
new file mode 100644
index 0000000..4a376c7
--- /dev/null
+++ b/LaunchServer/source/auth/handler/MySQL8AuthHandler.java
@@ -0,0 +1,155 @@
+package launchserver.auth.handler;
+
+import launcher.helper.LogHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.BooleanConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+import launchserver.auth.MySQL8SourceConfig;
+
+import java.io.IOException;
+import java.sql.*;
+import java.util.UUID;
+
+public final class MySQL8AuthHandler extends CachedAuthHandler
+{
+ private final MySQL8SourceConfig mySQL8Holder;
+ private final String uuidColumn;
+ private final String usernameColumn;
+ private final String accessTokenColumn;
+ private final String serverIDColumn;
+
+ // Prepared SQL queries
+ private final String queryByUUIDSQL;
+ private final String queryByUsernameSQL;
+ private final String updateAuthSQL;
+ private final String updateServerIDSQL;
+
+ MySQL8AuthHandler(BlockConfigEntry block)
+ {
+ super(block);
+ mySQL8Holder = new MySQL8SourceConfig("authHandlerPool", block);
+
+ // Read query params
+ String table = VerifyHelper.verifyIDName(
+ block.getEntryValue("table", StringConfigEntry.class));
+ uuidColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("uuidColumn", StringConfigEntry.class));
+ usernameColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("usernameColumn", StringConfigEntry.class));
+ accessTokenColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("accessTokenColumn", StringConfigEntry.class));
+ serverIDColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("serverIDColumn", StringConfigEntry.class));
+
+ // Prepare SQL queries
+ queryByUUIDSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, uuidColumn);
+ queryByUsernameSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, usernameColumn);
+ updateAuthSQL = String.format("UPDATE %s SET %s=?, %s=?, %s=NULL WHERE %s=? LIMIT 1",
+ table, usernameColumn, accessTokenColumn, serverIDColumn, uuidColumn);
+ updateServerIDSQL = String.format("UPDATE %s SET %s=? WHERE %s=? LIMIT 1",
+ table, serverIDColumn, uuidColumn);
+
+ // Fetch all entries
+ if (block.getEntryValue("fetchAll", BooleanConfigEntry.class))
+ {
+ LogHelper.info("Fetching all AuthHandler entries");
+ String query = String.format("SELECT %s, %s, %s, %s FROM %s",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table);
+ try (Connection c = mySQL8Holder.getConnection(); Statement statement = c.createStatement();
+ ResultSet set = statement.executeQuery(query))
+ {
+ for (Entry entry = constructEntry(set); entry != null; entry = constructEntry(set))
+ {
+ addEntry(entry);
+ }
+ }
+ catch (SQLException e)
+ {
+ LogHelper.error(e);
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ mySQL8Holder.close();
+ }
+
+ @Override
+ protected Entry fetchEntry(String username) throws IOException
+ {
+ return query(queryByUsernameSQL, username);
+ }
+
+ @Override
+ protected Entry fetchEntry(UUID uuid) throws IOException
+ {
+ return query(queryByUUIDSQL, uuid.toString());
+ }
+
+ @Override
+ protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException
+ {
+ try (Connection c = mySQL8Holder.getConnection(); PreparedStatement s = c.prepareStatement(updateAuthSQL))
+ {
+ s.setString(1, username); // Username case
+ s.setString(2, accessToken);
+ s.setString(3, uuid.toString());
+
+ // Execute update
+ s.setQueryTimeout(MySQL8SourceConfig.TIMEOUT);
+ return s.executeUpdate() > 0;
+ }
+ catch (SQLException e)
+ {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ protected boolean updateServerID(UUID uuid, String serverID) throws IOException
+ {
+ try (Connection c = mySQL8Holder.getConnection(); PreparedStatement s = c.prepareStatement(updateServerIDSQL))
+ {
+ s.setString(1, serverID);
+ s.setString(2, uuid.toString());
+
+ // Execute update
+ s.setQueryTimeout(MySQL8SourceConfig.TIMEOUT);
+ return s.executeUpdate() > 0;
+ }
+ catch (SQLException e)
+ {
+ throw new IOException(e);
+ }
+ }
+
+ private Entry constructEntry(ResultSet set) throws SQLException
+ {
+ return set.next() ? new Entry(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
+ set.getString(accessTokenColumn), set.getString(serverIDColumn)) : null;
+ }
+
+ private Entry query(String sql, String value) throws IOException
+ {
+ try (Connection c = mySQL8Holder.getConnection(); PreparedStatement s = c.prepareStatement(sql))
+ {
+ s.setString(1, value);
+
+ // Execute query
+ s.setQueryTimeout(MySQL8SourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery())
+ {
+ return constructEntry(set);
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new IOException(e);
+ }
+ }
+}
diff --git a/LaunchServer/source/auth/provider/AuthProvider.java b/LaunchServer/source/auth/provider/AuthProvider.java
index d51023f..89c0ea9 100644
--- a/LaunchServer/source/auth/provider/AuthProvider.java
+++ b/LaunchServer/source/auth/provider/AuthProvider.java
@@ -26,6 +26,10 @@
registerProvider("mojang", MojangAuthProvider::new);
registerProvider("mysql", MySQLAuthProvider::new);
registerProvider("mysql-bcrypt", MySQLBcryptAuthProvider::new);
+ registerProvider("mysql-8", MySQL8AuthProvider::new);
+ registerProvider("mysql-8-bcrypt", MySQL8BcryptAuthProvider::new);
+ registerProvider("mariadb", MariaDBAuthProvider::new);
+ registerProvider("mariadb-bcrypt", MariaDBBcryptAuthProvider::new);
registerProvider("request", RequestAuthProvider::new);
registerProvider("postgresql", PostgreSQLAuthProvider::new);
registerProvider("json", JsonAuthProvider::new);
diff --git a/LaunchServer/source/auth/provider/MariaDBAuthProvider.java b/LaunchServer/source/auth/provider/MariaDBAuthProvider.java
new file mode 100644
index 0000000..f74b5bf
--- /dev/null
+++ b/LaunchServer/source/auth/provider/MariaDBAuthProvider.java
@@ -0,0 +1,60 @@
+package launchserver.auth.provider;
+
+import launcher.helper.CommonHelper;
+import launcher.helper.SecurityHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.ListConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+import launchserver.auth.AuthException;
+import launchserver.auth.MariaDBSourceConfig;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public final class MariaDBAuthProvider extends AuthProvider
+{
+ private final MariaDBSourceConfig mySQLHolder;
+ private final String query;
+ private final String[] queryParams;
+
+ MariaDBAuthProvider(BlockConfigEntry block)
+ {
+ super(block);
+ mySQLHolder = new MariaDBSourceConfig("authProviderPool", block);
+
+ // Read query
+ query = VerifyHelper.verify(block.getEntryValue("query", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL query can't be empty");
+ queryParams = block.getEntry("queryParams", ListConfigEntry.class).
+ stream(StringConfigEntry.class).toArray(String[]::new);
+ }
+
+ @Override
+ public AuthProviderResult auth(String login, String password, String ip) throws SQLException, AuthException
+ {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(query))
+ {
+ String[] replaceParams = {"login", login, "password", password, "ip", ip};
+ for (int i = 0; i < queryParams.length; i++)
+ {
+ s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams));
+ }
+
+ // Execute SQL query
+ s.setQueryTimeout(MariaDBSourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery())
+ {
+ return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken()) : authError("Incorrect username or password");
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ // Do nothing
+ }
+}
diff --git a/LaunchServer/source/auth/provider/MariaDBBcryptAuthProvider.java b/LaunchServer/source/auth/provider/MariaDBBcryptAuthProvider.java
new file mode 100644
index 0000000..5185e64
--- /dev/null
+++ b/LaunchServer/source/auth/provider/MariaDBBcryptAuthProvider.java
@@ -0,0 +1,60 @@
+package launchserver.auth.provider;
+
+import launcher.helper.CommonHelper;
+import launcher.helper.SecurityHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.ListConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+import launchserver.auth.AuthException;
+import launchserver.auth.MariaDBSourceConfig;
+import org.mindrot.jbcrypt.BCrypt;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public final class MariaDBBcryptAuthProvider extends AuthProvider
+{
+ private final MariaDBSourceConfig mySQLHolder;
+ private final String query;
+ private final String[] queryParams;
+
+ MariaDBBcryptAuthProvider(BlockConfigEntry block)
+ {
+ super(block);
+ mySQLHolder = new MariaDBSourceConfig("authProviderPool", block);
+
+ query = VerifyHelper.verify(block.getEntryValue("query", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL query can't be empty");
+ queryParams = block.getEntry("queryParams", ListConfigEntry.class).
+ stream(StringConfigEntry.class).toArray(String[]::new);
+ }
+
+ @Override
+ public AuthProviderResult auth(String login, String password, String ip) throws SQLException, AuthException
+ {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(query))
+ {
+ String[] replaceParams = {"login", login, "password", password, "ip", ip};
+ for (int i = 0; i < queryParams.length; i++)
+ {
+ s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams));
+ }
+
+ // Execute SQL query
+ s.setQueryTimeout(MariaDBSourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery())
+ {
+ return set.next() ? BCrypt.checkpw(password, "$2a" + set.getString(1).substring(3)) ? new AuthProviderResult(set.getString(2), SecurityHelper.randomStringToken()) : authError("Incorrect username or password") : authError("Incorrect username or password");
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ mySQLHolder.close();
+ }
+}
diff --git a/LaunchServer/source/auth/provider/MySQL8AuthProvider.java b/LaunchServer/source/auth/provider/MySQL8AuthProvider.java
new file mode 100644
index 0000000..899ad4c
--- /dev/null
+++ b/LaunchServer/source/auth/provider/MySQL8AuthProvider.java
@@ -0,0 +1,60 @@
+package launchserver.auth.provider;
+
+import launcher.helper.CommonHelper;
+import launcher.helper.SecurityHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.ListConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+import launchserver.auth.AuthException;
+import launchserver.auth.MySQL8SourceConfig;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public final class MySQL8AuthProvider extends AuthProvider
+{
+ private final MySQL8SourceConfig mySQLHolder;
+ private final String query;
+ private final String[] queryParams;
+
+ MySQL8AuthProvider(BlockConfigEntry block)
+ {
+ super(block);
+ mySQLHolder = new MySQL8SourceConfig("authProviderPool", block);
+
+ // Read query
+ query = VerifyHelper.verify(block.getEntryValue("query", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL query can't be empty");
+ queryParams = block.getEntry("queryParams", ListConfigEntry.class).
+ stream(StringConfigEntry.class).toArray(String[]::new);
+ }
+
+ @Override
+ public AuthProviderResult auth(String login, String password, String ip) throws SQLException, AuthException
+ {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(query))
+ {
+ String[] replaceParams = {"login", login, "password", password, "ip", ip};
+ for (int i = 0; i < queryParams.length; i++)
+ {
+ s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams));
+ }
+
+ // Execute SQL query
+ s.setQueryTimeout(MySQL8SourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery())
+ {
+ return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken()) : authError("Incorrect username or password");
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ // Do nothing
+ }
+}
diff --git a/LaunchServer/source/auth/provider/MySQL8BcryptAuthProvider.java b/LaunchServer/source/auth/provider/MySQL8BcryptAuthProvider.java
new file mode 100644
index 0000000..a6f6ecd
--- /dev/null
+++ b/LaunchServer/source/auth/provider/MySQL8BcryptAuthProvider.java
@@ -0,0 +1,60 @@
+package launchserver.auth.provider;
+
+import launcher.helper.CommonHelper;
+import launcher.helper.SecurityHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.config.entry.BlockConfigEntry;
+import launcher.serialize.config.entry.ListConfigEntry;
+import launcher.serialize.config.entry.StringConfigEntry;
+import launchserver.auth.AuthException;
+import launchserver.auth.MySQL8SourceConfig;
+import org.mindrot.jbcrypt.BCrypt;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public final class MySQL8BcryptAuthProvider extends AuthProvider
+{
+ private final MySQL8SourceConfig mySQLHolder;
+ private final String query;
+ private final String[] queryParams;
+
+ MySQL8BcryptAuthProvider(BlockConfigEntry block)
+ {
+ super(block);
+ mySQLHolder = new MySQL8SourceConfig("authProviderPool", block);
+
+ query = VerifyHelper.verify(block.getEntryValue("query", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL query can't be empty");
+ queryParams = block.getEntry("queryParams", ListConfigEntry.class).
+ stream(StringConfigEntry.class).toArray(String[]::new);
+ }
+
+ @Override
+ public AuthProviderResult auth(String login, String password, String ip) throws SQLException, AuthException
+ {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(query))
+ {
+ String[] replaceParams = {"login", login, "password", password, "ip", ip};
+ for (int i = 0; i < queryParams.length; i++)
+ {
+ s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams));
+ }
+
+ // Execute SQL query
+ s.setQueryTimeout(MySQL8SourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery())
+ {
+ return set.next() ? BCrypt.checkpw(password, "$2a" + set.getString(1).substring(3)) ? new AuthProviderResult(set.getString(2), SecurityHelper.randomStringToken()) : authError("Incorrect username or password") : authError("Incorrect username or password");
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ mySQLHolder.close();
+ }
+}
diff --git a/build/libraries/mariadb.jar b/build/libraries/mariadb.jar
new file mode 100644
index 0000000..4845a5b
--- /dev/null
+++ b/build/libraries/mariadb.jar
Binary files differ
diff --git a/build/libraries/mysql-8.jar b/build/libraries/mysql-8.jar
new file mode 100644
index 0000000..c3b5f70
--- /dev/null
+++ b/build/libraries/mysql-8.jar
Binary files differ