diff --git a/pom.xml b/pom.xml index 3c19ea9a3..0cd2db1d5 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ jenkins - http://ci.codemc.org/job/AuthMeReloaded/ + http://ci.codemc.org/job/AuthMe/job/AuthMeReloaded/ @@ -258,6 +258,10 @@ ch.jalu.configme fr.xephi.authme.libs.ch.jalu.configme + + ch.jalu.datasourcecolumns + fr.xephi.authme.libs.ch.jalu.datasourcecolumns + com.zaxxer.hikari fr.xephi.authme.libs.com.zaxxer.hikari @@ -399,7 +403,7 @@ com.google.guava guava - 24.0-jre + 24.1-jre true @@ -799,6 +803,13 @@ + + ch.jalu + datasourcecolumns + 0.1-SNAPSHOT + true + + @@ -819,7 +830,7 @@ org.mockito mockito-core test - 2.15.0 + 2.16.0 hamcrest-core diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java index a7f327a10..b66914387 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java @@ -1,8 +1,8 @@ package fr.xephi.authme.command.executable.authme; +import ch.jalu.datasourcecolumns.data.DataSourceValue; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.service.CommonService; import org.bukkit.command.CommandSender; @@ -25,8 +25,8 @@ public class GetEmailCommand implements ExecutableCommand { public void executeCommand(CommandSender sender, List arguments) { String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - DataSourceResult email = dataSource.getEmail(playerName); - if (email.playerExists()) { + DataSourceValue email = dataSource.getEmail(playerName); + if (email.rowExists()) { sender.sendMessage("[AuthMe] " + playerName + "'s email: " + email.getValue()); } else { commonService.send(sender, MessageKey.UNKNOWN_USER); diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java index f3580d326..02bd4a213 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java @@ -1,8 +1,8 @@ package fr.xephi.authme.command.executable.authme.debug; +import ch.jalu.datasourcecolumns.data.DataSourceValue; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.mail.SendMailSsl; import fr.xephi.authme.permission.DebugSectionPermissions; import fr.xephi.authme.permission.PermissionNode; @@ -82,8 +82,8 @@ class TestEmailSender implements DebugSection { */ private String getEmail(CommandSender sender, List arguments) { if (arguments.isEmpty()) { - DataSourceResult emailResult = dataSource.getEmail(sender.getName()); - if (!emailResult.playerExists()) { + DataSourceValue emailResult = dataSource.getEmail(sender.getName()); + if (!emailResult.rowExists()) { sender.sendMessage(ChatColor.RED + "Please provide an email address, " + "e.g. /authme debug mail test@example.com"); return null; diff --git a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java index 339980a34..0a3a96945 100644 --- a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java @@ -1,10 +1,10 @@ package fr.xephi.authme.command.executable.email; +import ch.jalu.datasourcecolumns.data.DataSourceValue; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.mail.EmailService; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.service.BukkitService; @@ -58,8 +58,8 @@ public class RecoverEmailCommand extends PlayerCommand { return; } - DataSourceResult emailResult = dataSource.getEmail(playerName); - if (!emailResult.playerExists()) { + DataSourceValue emailResult = dataSource.getEmail(playerName); + if (!emailResult.rowExists()) { commonService.send(player, MessageKey.USAGE_REGISTER); return; } diff --git a/src/main/java/fr/xephi/authme/data/VerificationCodeManager.java b/src/main/java/fr/xephi/authme/data/VerificationCodeManager.java index a6ba75c6e..c5c2d7257 100644 --- a/src/main/java/fr/xephi/authme/data/VerificationCodeManager.java +++ b/src/main/java/fr/xephi/authme/data/VerificationCodeManager.java @@ -1,7 +1,7 @@ package fr.xephi.authme.data; +import ch.jalu.datasourcecolumns.data.DataSourceValue; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.initialization.HasCleanup; import fr.xephi.authme.initialization.SettingsDependent; import fr.xephi.authme.mail.EmailService; @@ -103,8 +103,8 @@ public class VerificationCodeManager implements SettingsDependent, HasCleanup { */ public boolean hasEmail(String name) { boolean result = false; - DataSourceResult emailResult = dataSource.getEmail(name); - if (emailResult.playerExists()) { + DataSourceValue emailResult = dataSource.getEmail(name); + if (emailResult.rowExists()) { final String email = emailResult.getValue(); if (!Utils.isEmailEmpty(email)) { result = true; @@ -130,8 +130,8 @@ public class VerificationCodeManager implements SettingsDependent, HasCleanup { * @param name the name of the player to generate a code for */ private void generateCode(String name) { - DataSourceResult emailResult = dataSource.getEmail(name); - if (emailResult.playerExists()) { + DataSourceValue emailResult = dataSource.getEmail(name); + if (emailResult.rowExists()) { final String email = emailResult.getValue(); if (!Utils.isEmailEmpty(email)) { String code = RandomStringUtils.generateNum(6); // 6 digits code diff --git a/src/main/java/fr/xephi/authme/datasource/AbstractSqlDataSource.java b/src/main/java/fr/xephi/authme/datasource/AbstractSqlDataSource.java new file mode 100644 index 000000000..0c40c479d --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/AbstractSqlDataSource.java @@ -0,0 +1,169 @@ +package fr.xephi.authme.datasource; + +import ch.jalu.datasourcecolumns.data.DataSourceValue; +import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; +import ch.jalu.datasourcecolumns.data.DataSourceValues; +import ch.jalu.datasourcecolumns.predicate.AlwaysTruePredicate; +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.columnshandler.AuthMeColumns; +import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; +import fr.xephi.authme.security.crypts.HashedPassword; + +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; + +import static ch.jalu.datasourcecolumns.data.UpdateValues.with; +import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eq; +import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eqIgnoreCase; +import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; + +/** + * Common type for SQL-based data sources. Classes implementing this + * must ensure that {@link #columnsHandler} is initialized on creation. + */ +public abstract class AbstractSqlDataSource implements DataSource { + + protected AuthMeColumnsHandler columnsHandler; + + @Override + public boolean isAuthAvailable(String user) { + try { + return columnsHandler.retrieve(user, AuthMeColumns.NAME).rowExists(); + } catch (SQLException e) { + logSqlException(e); + return false; + } + } + + @Override + public HashedPassword getPassword(String user) { + try { + DataSourceValues values = columnsHandler.retrieve(user, AuthMeColumns.PASSWORD, AuthMeColumns.SALT); + if (values.rowExists()) { + return new HashedPassword(values.get(AuthMeColumns.PASSWORD), values.get(AuthMeColumns.SALT)); + } + } catch (SQLException e) { + logSqlException(e); + } + return null; + } + + @Override + public boolean saveAuth(PlayerAuth auth) { + return columnsHandler.insert(auth, + AuthMeColumns.NAME, AuthMeColumns.NICK_NAME, AuthMeColumns.PASSWORD, AuthMeColumns.SALT, + AuthMeColumns.EMAIL, AuthMeColumns.REGISTRATION_DATE, AuthMeColumns.REGISTRATION_IP); + } + + @Override + public boolean hasSession(String user) { + try { + DataSourceValue result = columnsHandler.retrieve(user, AuthMeColumns.HAS_SESSION); + return result.rowExists() && Integer.valueOf(1).equals(result.getValue()); + } catch (SQLException e) { + logSqlException(e); + return false; + } + } + + @Override + public boolean updateSession(PlayerAuth auth) { + return columnsHandler.update(auth, AuthMeColumns.LAST_IP, AuthMeColumns.LAST_LOGIN, AuthMeColumns.NICK_NAME); + } + + @Override + public boolean updatePassword(PlayerAuth auth) { + return updatePassword(auth.getNickname(), auth.getPassword()); + } + + @Override + public boolean updatePassword(String user, HashedPassword password) { + return columnsHandler.update(user, + with(AuthMeColumns.PASSWORD, password.getHash()) + .and(AuthMeColumns.SALT, password.getSalt()).build()); + } + + @Override + public boolean updateQuitLoc(PlayerAuth auth) { + return columnsHandler.update(auth, + AuthMeColumns.LOCATION_X, AuthMeColumns.LOCATION_Y, AuthMeColumns.LOCATION_Z, + AuthMeColumns.LOCATION_WORLD, AuthMeColumns.LOCATION_YAW, AuthMeColumns.LOCATION_PITCH); + } + + @Override + public List getAllAuthsByIp(String ip) { + try { + return columnsHandler.retrieve(eq(AuthMeColumns.LAST_IP, ip), AuthMeColumns.NAME); + } catch (SQLException e) { + logSqlException(e); + return Collections.emptyList(); + } + } + + @Override + public int countAuthsByEmail(String email) { + return columnsHandler.count(eqIgnoreCase(AuthMeColumns.EMAIL, email)); + } + + @Override + public boolean updateEmail(PlayerAuth auth) { + return columnsHandler.update(auth, AuthMeColumns.EMAIL); + } + + @Override + public boolean isLogged(String user) { + try { + DataSourceValue result = columnsHandler.retrieve(user, AuthMeColumns.IS_LOGGED); + return result.rowExists() && Integer.valueOf(1).equals(result.getValue()); + } catch (SQLException e) { + logSqlException(e); + return false; + } + } + + @Override + public void setLogged(String user) { + columnsHandler.update(user, AuthMeColumns.IS_LOGGED, 1); + } + + @Override + public void setUnlogged(String user) { + columnsHandler.update(user, AuthMeColumns.IS_LOGGED, 0); + } + + @Override + public void grantSession(String user) { + columnsHandler.update(user, AuthMeColumns.HAS_SESSION, 1); + } + + @Override + public void revokeSession(String user) { + columnsHandler.update(user, AuthMeColumns.HAS_SESSION, 0); + } + + @Override + public void purgeLogged() { + columnsHandler.update(eq(AuthMeColumns.IS_LOGGED, 1), AuthMeColumns.IS_LOGGED, 0); + } + + @Override + public int getAccountsRegistered() { + return columnsHandler.count(new AlwaysTruePredicate<>()); + } + + @Override + public boolean updateRealName(String user, String realName) { + return columnsHandler.update(user, AuthMeColumns.NICK_NAME, realName); + } + + @Override + public DataSourceValue getEmail(String user) { + try { + return columnsHandler.retrieve(user, AuthMeColumns.EMAIL); + } catch (SQLException e) { + logSqlException(e); + return DataSourceValueImpl.unknownRow(); + } + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 0926def86..165560b1e 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -1,5 +1,7 @@ package fr.xephi.authme.datasource; +import ch.jalu.datasourcecolumns.data.DataSourceValue; +import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -244,10 +246,10 @@ public class CacheDataSource implements DataSource { } @Override - public DataSourceResult getEmail(String user) { + public DataSourceValue getEmail(String user) { return cachedAuths.getUnchecked(user) - .map(auth -> DataSourceResult.of(auth.getEmail())) - .orElse(DataSourceResult.unknownPlayer()); + .map(auth -> DataSourceValueImpl.of(auth.getEmail())) + .orElse(DataSourceValueImpl.unknownRow()); } @Override diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index b6e09fff9..6ce28852f 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -1,5 +1,6 @@ package fr.xephi.authme.datasource; +import ch.jalu.datasourcecolumns.data.DataSourceValue; import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.security.crypts.HashedPassword; @@ -216,7 +217,7 @@ public interface DataSource extends Reloadable { * @param user the user to retrieve an email for * @return the email saved for the user, or null if user or email is not present */ - DataSourceResult getEmail(String user); + DataSourceValue getEmail(String user); /** * Return all players of the database. diff --git a/src/main/java/fr/xephi/authme/datasource/DataSourceResult.java b/src/main/java/fr/xephi/authme/datasource/DataSourceResult.java deleted file mode 100644 index c005874e2..000000000 --- a/src/main/java/fr/xephi/authme/datasource/DataSourceResult.java +++ /dev/null @@ -1,53 +0,0 @@ -package fr.xephi.authme.datasource; - -/** - * Wraps a value and allows to specify whether a value is missing or the player is not registered. - */ -public final class DataSourceResult { - - /** Instance used when a player does not exist. */ - private static final DataSourceResult UNKNOWN_PLAYER = new DataSourceResult<>(null); - private final T value; - - private DataSourceResult(T value) { - this.value = value; - } - - /** - * Returns a {@link DataSourceResult} for the given value. - * - * @param value the value to wrap - * @param the value's type - * @return DataSourceResult object for the given value - */ - public static DataSourceResult of(T value) { - return new DataSourceResult<>(value); - } - - /** - * Returns a {@link DataSourceResult} specifying that the player does not exist. - * - * @param the value type - * @return data source result for unknown player - */ - public static DataSourceResult unknownPlayer() { - return UNKNOWN_PLAYER; - } - - /** - * @return whether the player of the associated value exists - */ - public boolean playerExists() { - return this != UNKNOWN_PLAYER; - } - - /** - * Returns the value. It is {@code null} if the player is unknown. It is also {@code null} - * if the player exists but does not have the value defined. - * - * @return the value, or null - */ - public T getValue() { - return value; - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index f70b0376f..ab9bf85c1 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -1,5 +1,6 @@ package fr.xephi.authme.datasource; +import ch.jalu.datasourcecolumns.data.DataSourceValue; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.security.crypts.HashedPassword; @@ -366,7 +367,7 @@ public class FlatFile implements DataSource { } @Override - public DataSourceResult getEmail(String user) { + public DataSourceValue getEmail(String user) { throw new UnsupportedOperationException("Flat file no longer supported"); } diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 35998330a..3bb187ff1 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -5,13 +5,12 @@ import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension; import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; -import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.util.StringUtils; import java.sql.Connection; import java.sql.DatabaseMetaData; @@ -32,7 +31,7 @@ import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; * MySQL data source. */ @SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore -public class MySQL implements DataSource { +public class MySQL extends AbstractSqlDataSource { private boolean useSsl; private String host; @@ -99,6 +98,7 @@ public class MySQL implements DataSource { this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS); this.col = new Columns(settings); + this.columnsHandler = AuthMeColumnsHandler.createForMySql(this::getConnection, settings); this.sqlExtension = extensionsFactory.buildExtension(col); this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); this.maxLifetime = settings.getProperty(DatabaseSettings.MYSQL_CONNECTION_MAX_LIFETIME); @@ -267,40 +267,6 @@ public class MySQL implements DataSource { } } - @Override - public boolean isAuthAvailable(String user) { - String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase()); - try (ResultSet rs = pst.executeQuery()) { - return rs.next(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public HashedPassword getPassword(String user) { - boolean useSalt = !col.SALT.isEmpty(); - String sql = "SELECT " + col.PASSWORD - + (useSalt ? ", " + col.SALT : "") - + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase()); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return new HashedPassword(rs.getString(col.PASSWORD), - useSalt ? rs.getString(col.SALT) : null); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return null; - } - @Override public PlayerAuth getAuth(String user) { String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;"; @@ -323,33 +289,9 @@ public class MySQL implements DataSource { @Override public boolean saveAuth(PlayerAuth auth) { + super.saveAuth(auth); + try (Connection con = getConnection()) { - // TODO ljacqu 20171104: Replace with generic columns util to clean this up - boolean useSalt = !col.SALT.isEmpty() || !StringUtils.isEmpty(auth.getPassword().getSalt()); - boolean hasEmail = auth.getEmail() != null; - String emailPlaceholder = hasEmail ? "?" : "DEFAULT"; - - String sql = "INSERT INTO " + tableName + "(" - + col.NAME + "," + col.PASSWORD + "," + col.REAL_NAME - + "," + col.EMAIL + "," + col.REGISTRATION_DATE + "," + col.REGISTRATION_IP - + (useSalt ? "," + col.SALT : "") - + ") VALUES (?,?,?," + emailPlaceholder + ",?,?" + (useSalt ? ",?" : "") + ");"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - int index = 1; - pst.setString(index++, auth.getNickname()); - pst.setString(index++, auth.getPassword().getHash()); - pst.setString(index++, auth.getRealName()); - if (hasEmail) { - pst.setString(index++, auth.getEmail()); - } - pst.setObject(index++, auth.getRegistrationDate()); - pst.setString(index++, auth.getRegistrationIp()); - if (useSalt) { - pst.setString(index++, auth.getPassword().getSalt()); - } - pst.executeUpdate(); - } - if (!columnOthers.isEmpty()) { for (String column : columnOthers) { try (PreparedStatement pst = con.prepareStatement( @@ -369,59 +311,6 @@ public class MySQL implements DataSource { return false; } - @Override - public boolean updatePassword(PlayerAuth auth) { - return updatePassword(auth.getNickname(), auth.getPassword()); - } - - @Override - public boolean updatePassword(String user, HashedPassword password) { - user = user.toLowerCase(); - try (Connection con = getConnection()) { - boolean useSalt = !col.SALT.isEmpty(); - if (useSalt) { - String sql = String.format("UPDATE %s SET %s = ?, %s = ? WHERE %s = ?;", - tableName, col.PASSWORD, col.SALT, col.NAME); - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, password.getHash()); - pst.setString(2, password.getSalt()); - pst.setString(3, user); - pst.executeUpdate(); - } - } else { - String sql = String.format("UPDATE %s SET %s = ? WHERE %s = ?;", - tableName, col.PASSWORD, col.NAME); - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, password.getHash()); - pst.setString(2, user); - pst.executeUpdate(); - } - } - sqlExtension.changePassword(user, password, con); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public boolean updateSession(PlayerAuth auth) { - String sql = "UPDATE " + tableName + " SET " - + col.LAST_IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, auth.getLastIp()); - pst.setObject(2, auth.getLastLogin()); - pst.setString(3, auth.getRealName()); - pst.setString(4, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - @Override public Set getRecordsToPurge(long until) { Set list = new HashSet<>(); @@ -459,42 +348,6 @@ public class MySQL implements DataSource { return false; } - @Override - public boolean updateQuitLoc(PlayerAuth auth) { - String sql = "UPDATE " + tableName - + " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " - + col.LASTLOC_WORLD + "=?, " + col.LASTLOC_YAW + "=?, " + col.LASTLOC_PITCH + "=?" - + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setDouble(1, auth.getQuitLocX()); - pst.setDouble(2, auth.getQuitLocY()); - pst.setDouble(3, auth.getQuitLocZ()); - pst.setString(4, auth.getWorld()); - pst.setFloat(5, auth.getYaw()); - pst.setFloat(6, auth.getPitch()); - pst.setString(7, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public boolean updateEmail(PlayerAuth auth) { - String sql = "UPDATE " + tableName + " SET " + col.EMAIL + " =? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, auth.getEmail()); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - @Override public void closeConnection() { if (ds != null && !ds.isClosed()) { @@ -502,39 +355,6 @@ public class MySQL implements DataSource { } } - @Override - public List getAllAuthsByIp(String ip) { - List result = new ArrayList<>(); - String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_IP + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, ip); - try (ResultSet rs = pst.executeQuery()) { - while (rs.next()) { - result.add(rs.getString(col.NAME)); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return result; - } - - @Override - public int countAuthsByEmail(String email) { - String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, email); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(1); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return 0; - } - @Override public void purgeRecords(Collection toPurge) { String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; @@ -553,140 +373,6 @@ public class MySQL implements DataSource { return DataSourceType.MYSQL; } - @Override - public boolean isLogged(String user) { - String sql = "SELECT " + col.IS_LOGGED + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - return rs.next() && (rs.getInt(col.IS_LOGGED) == 1); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void setLogged(String user) { - String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 1); - pst.setString(2, user.toLowerCase()); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public void setUnlogged(String user) { - String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 0); - pst.setString(2, user.toLowerCase()); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public boolean hasSession(String user) { - String sql = "SELECT " + col.HAS_SESSION + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase()); - try (ResultSet rs = pst.executeQuery()) { - return rs.next() && (rs.getInt(col.HAS_SESSION) == 1); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void grantSession(String user) { - String sql = "UPDATE " + tableName + " SET " + col.HAS_SESSION + "=? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 1); - pst.setString(2, user.toLowerCase()); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public void revokeSession(String user) { - String sql = "UPDATE " + tableName + " SET " + col.HAS_SESSION + "=? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 0); - pst.setString(2, user.toLowerCase()); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public void purgeLogged() { - String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.IS_LOGGED + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 0); - pst.setInt(2, 1); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public int getAccountsRegistered() { - int result = 0; - String sql = "SELECT COUNT(*) FROM " + tableName; - try (Connection con = getConnection(); - Statement st = con.createStatement(); - ResultSet rs = st.executeQuery(sql)) { - if (rs.next()) { - result = rs.getInt(1); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return result; - } - - @Override - public boolean updateRealName(String user, String realName) { - String sql = "UPDATE " + tableName + " SET " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, realName); - pst.setString(2, user); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public DataSourceResult getEmail(String user) { - String sql = "SELECT " + col.EMAIL + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return DataSourceResult.of(rs.getString(1)); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return DataSourceResult.unknownPlayer(); - } - @Override public List getAllAuths() { List auths = new ArrayList<>(); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index 2978a93f8..ff72a8018 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -3,10 +3,9 @@ package fr.xephi.authme.datasource; import com.google.common.annotations.VisibleForTesting; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.util.StringUtils; import java.io.File; import java.sql.Connection; @@ -29,7 +28,7 @@ import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; * SQLite data source. */ @SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore -public class SQLite implements DataSource { +public class SQLite extends AbstractSqlDataSource { private final Settings settings; private final File dataFolder; @@ -71,6 +70,7 @@ public class SQLite implements DataSource { this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); this.col = new Columns(settings); this.con = connection; + this.columnsHandler = AuthMeColumnsHandler.createForSqlite(con, settings); } /** @@ -85,6 +85,7 @@ public class SQLite implements DataSource { ConsoleLogger.debug("SQLite driver loaded"); this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); + this.columnsHandler = AuthMeColumnsHandler.createForSqlite(con, settings); } /** @@ -209,40 +210,6 @@ public class SQLite implements DataSource { } } - @Override - public boolean isAuthAvailable(String user) { - String sql = "SELECT 1 FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - return rs.next(); - } - } catch (SQLException ex) { - ConsoleLogger.warning(ex.getMessage()); - return false; - } - } - - @Override - public HashedPassword getPassword(String user) { - boolean useSalt = !col.SALT.isEmpty(); - String sql = "SELECT " + col.PASSWORD - + (useSalt ? ", " + col.SALT : "") - + " FROM " + tableName + " WHERE " + col.NAME + "=?"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return new HashedPassword(rs.getString(col.PASSWORD), - useSalt ? rs.getString(col.SALT) : null); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return null; - } - @Override public PlayerAuth getAuth(String user) { String sql = "SELECT * FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"; @@ -259,95 +226,6 @@ public class SQLite implements DataSource { return null; } - @Override - public boolean saveAuth(PlayerAuth auth) { - PreparedStatement pst = null; - try { - HashedPassword password = auth.getPassword(); - if (col.SALT.isEmpty()) { - if (!StringUtils.isEmpty(auth.getPassword().getSalt())) { - ConsoleLogger.warning("Warning! Detected hashed password with separate salt but the salt column " - + "is not set in the config!"); - } - - pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD - + "," + col.REAL_NAME + "," + col.EMAIL - + "," + col.REGISTRATION_DATE + "," + col.REGISTRATION_IP - + ") VALUES (?,?,?,?,?,?);"); - pst.setString(1, auth.getNickname()); - pst.setString(2, password.getHash()); - pst.setString(3, auth.getRealName()); - pst.setString(4, auth.getEmail()); - pst.setLong(5, auth.getRegistrationDate()); - pst.setString(6, auth.getRegistrationIp()); - pst.executeUpdate(); - } else { - pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD - + "," + col.REAL_NAME + "," + col.EMAIL - + "," + col.REGISTRATION_DATE + "," + col.REGISTRATION_IP + "," + col.SALT - + ") VALUES (?,?,?,?,?,?,?);"); - pst.setString(1, auth.getNickname()); - pst.setString(2, password.getHash()); - pst.setString(3, auth.getRealName()); - pst.setString(4, auth.getEmail()); - pst.setLong(5, auth.getRegistrationDate()); - pst.setString(6, auth.getRegistrationIp()); - pst.setString(7, password.getSalt()); - pst.executeUpdate(); - } - } catch (SQLException ex) { - logSqlException(ex); - } finally { - close(pst); - } - return true; - } - - @Override - public boolean updatePassword(PlayerAuth auth) { - return updatePassword(auth.getNickname(), auth.getPassword()); - } - - @Override - public boolean updatePassword(String user, HashedPassword password) { - user = user.toLowerCase(); - boolean useSalt = !col.SALT.isEmpty(); - String sql = "UPDATE " + tableName + " SET " + col.PASSWORD + " = ?" - + (useSalt ? ", " + col.SALT + " = ?" : "") - + " WHERE " + col.NAME + " = ?"; - try (PreparedStatement pst = con.prepareStatement(sql)){ - pst.setString(1, password.getHash()); - if (useSalt) { - pst.setString(2, password.getSalt()); - pst.setString(3, user); - } else { - pst.setString(2, user); - } - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public boolean updateSession(PlayerAuth auth) { - String sql = "UPDATE " + tableName + " SET " + col.LAST_IP + "=?, " + col.LAST_LOGIN + "=?, " - + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)){ - pst.setString(1, auth.getLastIp()); - pst.setObject(2, auth.getLastLogin()); - pst.setString(3, auth.getRealName()); - pst.setString(4, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - @Override public Set getRecordsToPurge(long until) { Set list = new HashSet<>(); @@ -395,42 +273,6 @@ public class SQLite implements DataSource { return false; } - @Override - public boolean updateQuitLoc(PlayerAuth auth) { - String sql = "UPDATE " + tableName + " SET " - + col.LASTLOC_X + "=?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " - + col.LASTLOC_WORLD + "=?, " + col.LASTLOC_YAW + "=?, " + col.LASTLOC_PITCH + "=? " - + "WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setDouble(1, auth.getQuitLocX()); - pst.setDouble(2, auth.getQuitLocY()); - pst.setDouble(3, auth.getQuitLocZ()); - pst.setString(4, auth.getWorld()); - pst.setFloat(5, auth.getYaw()); - pst.setFloat(6, auth.getPitch()); - pst.setString(7, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public boolean updateEmail(PlayerAuth auth) { - String sql = "UPDATE " + tableName + " SET " + col.EMAIL + "=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, auth.getEmail()); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - @Override public void closeConnection() { try { @@ -442,180 +284,11 @@ public class SQLite implements DataSource { } } - @Override - public List getAllAuthsByIp(String ip) { - List countIp = new ArrayList<>(); - String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_IP + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, ip); - try (ResultSet rs = pst.executeQuery()) { - while (rs.next()) { - countIp.add(rs.getString(col.NAME)); - } - return countIp; - } - } catch (SQLException ex) { - logSqlException(ex); - } - return new ArrayList<>(); - } - - @Override - public int countAuthsByEmail(String email) { - String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE " + col.EMAIL + " = ? COLLATE NOCASE;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, email); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(1); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return 0; - } - @Override public DataSourceType getType() { return DataSourceType.SQLITE; } - @Override - public boolean isLogged(String user) { - String sql = "SELECT " + col.IS_LOGGED + " FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(col.IS_LOGGED) == 1; - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void setLogged(String user) { - String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE LOWER(" + col.NAME + ")=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 1); - pst.setString(2, user); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public void setUnlogged(String user) { - String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE LOWER(" + col.NAME + ")=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 0); - pst.setString(2, user); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public boolean hasSession(String user) { - String sql = "SELECT " + col.HAS_SESSION + " FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase()); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(col.HAS_SESSION) == 1; - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void grantSession(String user) { - String sql = "UPDATE " + tableName + " SET " + col.HAS_SESSION + "=? WHERE LOWER(" + col.NAME + ")=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 1); - pst.setString(2, user.toLowerCase()); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public void revokeSession(String user) { - String sql = "UPDATE " + tableName + " SET " + col.HAS_SESSION + "=? WHERE LOWER(" + col.NAME + ")=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 0); - pst.setString(2, user.toLowerCase()); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public void purgeLogged() { - String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.IS_LOGGED + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, 0); - pst.setInt(2, 1); - pst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public int getAccountsRegistered() { - String sql = "SELECT COUNT(*) FROM " + tableName + ";"; - try (PreparedStatement pst = con.prepareStatement(sql); ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(1); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return 0; - } - - @Override - public boolean updateRealName(String user, String realName) { - String sql = "UPDATE " + tableName + " SET " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, realName); - pst.setString(2, user); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public DataSourceResult getEmail(String user) { - String sql = "SELECT " + col.EMAIL + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return DataSourceResult.of(rs.getString(1)); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return DataSourceResult.unknownPlayer(); - } - @Override public List getAllAuths() { List auths = new ArrayList<>(); @@ -716,16 +389,6 @@ public class SQLite implements DataSource { + currentTimestamp + ", to all " + updatedRows + " rows"); } - private static void close(Statement st) { - if (st != null) { - try { - st.close(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - } - private static void close(Connection con) { if (con != null) { try { diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java new file mode 100644 index 000000000..5c235095f --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java @@ -0,0 +1,82 @@ +package fr.xephi.authme.datasource.columnshandler; + +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.settings.properties.DatabaseSettings; + +import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.ColumnOptions.DEFAULT_FOR_NULL; +import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.ColumnOptions.OPTIONAL; +import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createDouble; +import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createFloat; +import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createInteger; +import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createLong; +import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createString; + +/** + * Contains column definitions for the AuthMe table. + */ +public final class AuthMeColumns { + + public static final PlayerAuthColumn NAME = createString( + DatabaseSettings.MYSQL_COL_NAME, PlayerAuth::getNickname); + + public static final PlayerAuthColumn NICK_NAME = createString( + DatabaseSettings.MYSQL_COL_REALNAME, PlayerAuth::getRealName); + + public static final PlayerAuthColumn PASSWORD = createString( + DatabaseSettings.MYSQL_COL_PASSWORD, auth -> auth.getPassword().getHash()); + + public static final PlayerAuthColumn SALT = createString( + DatabaseSettings.MYSQL_COL_SALT, auth -> auth.getPassword().getSalt(), OPTIONAL); + + public static final PlayerAuthColumn EMAIL = createString( + DatabaseSettings.MYSQL_COL_EMAIL, PlayerAuth::getEmail, DEFAULT_FOR_NULL); + + public static final PlayerAuthColumn LAST_IP = createString( + DatabaseSettings.MYSQL_COL_LAST_IP, PlayerAuth::getLastIp); + + public static final PlayerAuthColumn GROUP_ID = createInteger( + DatabaseSettings.MYSQL_COL_GROUP, PlayerAuth::getGroupId, OPTIONAL); + + public static final PlayerAuthColumn LAST_LOGIN = createLong( + DatabaseSettings.MYSQL_COL_LASTLOGIN, PlayerAuth::getLastLogin); + + public static final PlayerAuthColumn REGISTRATION_IP = createString( + DatabaseSettings.MYSQL_COL_REGISTER_IP, PlayerAuth::getRegistrationIp); + + public static final PlayerAuthColumn REGISTRATION_DATE = createLong( + DatabaseSettings.MYSQL_COL_REGISTER_DATE, PlayerAuth::getRegistrationDate); + + // -------- + // Location columns + // -------- + public static final PlayerAuthColumn LOCATION_X = createDouble( + DatabaseSettings.MYSQL_COL_LASTLOC_X, PlayerAuth::getQuitLocX); + + public static final PlayerAuthColumn LOCATION_Y = createDouble( + DatabaseSettings.MYSQL_COL_LASTLOC_Y, PlayerAuth::getQuitLocY); + + public static final PlayerAuthColumn LOCATION_Z = createDouble( + DatabaseSettings.MYSQL_COL_LASTLOC_Z, PlayerAuth::getQuitLocZ); + + public static final PlayerAuthColumn LOCATION_WORLD = createString( + DatabaseSettings.MYSQL_COL_LASTLOC_WORLD, PlayerAuth::getWorld); + + public static final PlayerAuthColumn LOCATION_YAW = createFloat( + DatabaseSettings.MYSQL_COL_LASTLOC_YAW, PlayerAuth::getYaw); + + public static final PlayerAuthColumn LOCATION_PITCH = createFloat( + DatabaseSettings.MYSQL_COL_LASTLOC_PITCH, PlayerAuth::getPitch); + + // -------- + // Columns not on PlayerAuth + // -------- + public static final DataSourceColumn IS_LOGGED = createInteger( + DatabaseSettings.MYSQL_COL_ISLOGGED); + + public static final DataSourceColumn HAS_SESSION = createInteger( + DatabaseSettings.MYSQL_COL_HASSESSION); + + + private AuthMeColumns() { + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsFactory.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsFactory.java new file mode 100644 index 000000000..3400f76cd --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsFactory.java @@ -0,0 +1,83 @@ +package fr.xephi.authme.datasource.columnshandler; + +import ch.jalu.configme.properties.Property; +import ch.jalu.datasourcecolumns.ColumnType; +import ch.jalu.datasourcecolumns.StandardTypes; +import fr.xephi.authme.data.auth.PlayerAuth; + +import java.util.function.Function; + +/** + * Util class for initializing {@link DataSourceColumn} objects. + */ +final class AuthMeColumnsFactory { + + private AuthMeColumnsFactory() { + } + + static DataSourceColumn createInteger(Property nameProperty, + ColumnOptions... options) { + return new DataSourceColumn<>(StandardTypes.INTEGER, nameProperty, + isOptional(options), hasDefaultForNull(options)); + } + + static PlayerAuthColumn createInteger(Property nameProperty, + Function playerAuthGetter, + ColumnOptions... options) { + return createInternal(StandardTypes.INTEGER, nameProperty, playerAuthGetter, options); + } + + static PlayerAuthColumn createLong(Property nameProperty, + Function playerAuthGetter, + ColumnOptions... options) { + return createInternal(StandardTypes.LONG, nameProperty, playerAuthGetter, options); + } + + static PlayerAuthColumn createString(Property nameProperty, + Function playerAuthGetter, + ColumnOptions... options) { + return createInternal(StandardTypes.STRING, nameProperty, playerAuthGetter, options); + } + + static PlayerAuthColumn createDouble(Property nameProperty, + Function playerAuthGetter, + ColumnOptions... options) { + return createInternal(StandardTypes.DOUBLE, nameProperty, playerAuthGetter, options); + } + + static PlayerAuthColumn createFloat(Property nameProperty, + Function playerAuthGetter, + ColumnOptions... options) { + return createInternal(StandardTypes.FLOAT, nameProperty, playerAuthGetter, options); + } + + private static PlayerAuthColumn createInternal(ColumnType type, Property nameProperty, + Function authGetter, + ColumnOptions... options) { + return new PlayerAuthColumn<>(type, nameProperty, isOptional(options), hasDefaultForNull(options), authGetter); + } + + private static boolean isOptional(ColumnOptions[] options) { + return containsInArray(ColumnOptions.OPTIONAL, options); + } + + private static boolean hasDefaultForNull(ColumnOptions[] options) { + return containsInArray(ColumnOptions.DEFAULT_FOR_NULL, options); + } + + private static boolean containsInArray(ColumnOptions needle, ColumnOptions[] haystack) { + for (ColumnOptions option : haystack) { + if (option == needle) { + return true; + } + } + return false; + } + + enum ColumnOptions { + + OPTIONAL, + + DEFAULT_FOR_NULL + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java new file mode 100644 index 000000000..bb0d80b77 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java @@ -0,0 +1,205 @@ +package fr.xephi.authme.datasource.columnshandler; + +import ch.jalu.datasourcecolumns.data.DataSourceValue; +import ch.jalu.datasourcecolumns.data.DataSourceValues; +import ch.jalu.datasourcecolumns.data.UpdateValues; +import ch.jalu.datasourcecolumns.predicate.Predicate; +import ch.jalu.datasourcecolumns.sqlimplementation.PredicateSqlGenerator; +import ch.jalu.datasourcecolumns.sqlimplementation.PreparedStatementGenerator; +import ch.jalu.datasourcecolumns.sqlimplementation.ResultSetValueRetriever; +import ch.jalu.datasourcecolumns.sqlimplementation.SqlColumnsHandler; +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.DatabaseSettings; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; + +/** + * Wrapper of {@link SqlColumnsHandler} for the AuthMe data table. + * Wraps exceptions and provides better support for operations based on a {@link PlayerAuth} object. + */ +public final class AuthMeColumnsHandler { + + private final SqlColumnsHandler internalHandler; + + private AuthMeColumnsHandler(SqlColumnsHandler internalHandler) { + this.internalHandler = internalHandler; + } + + /** + * Creates a column handler for SQLite. + * + * @param connection the connection to the database + * @param settings plugin settings + * @return created column handler + */ + public static AuthMeColumnsHandler createForSqlite(Connection connection, Settings settings) { + ColumnContext columnContext = new ColumnContext(settings, false); + String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); + String nameColumn = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME); + + SqlColumnsHandler sqlColHandler = new SqlColumnsHandler<>( + PreparedStatementGenerator.fromConnection(connection), columnContext, tableName, nameColumn, + new ResultSetValueRetriever<>(columnContext), new PredicateSqlGenerator<>(columnContext, true)); + return new AuthMeColumnsHandler(sqlColHandler); + } + + /** + * Creates a column handler for MySQL. + * + * @param connectionSupplier supplier of connections from the connection pool + * @param settings plugin settings + * @return created column handler + */ + public static AuthMeColumnsHandler createForMySql(ConnectionSupplier connectionSupplier, Settings settings) { + ColumnContext columnContext = new ColumnContext(settings, true); + String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); + String nameColumn = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME); + + SqlColumnsHandler sqlColHandler = new SqlColumnsHandler<>( + new MySqlPreparedStatementGenerator(connectionSupplier), columnContext, tableName, nameColumn, + new ResultSetValueRetriever<>(columnContext), new PredicateSqlGenerator<>(columnContext)); + return new AuthMeColumnsHandler(sqlColHandler); + } + + /** + * Changes a column from a specific row to the given value. + * + * @param name name of the account to modify + * @param column the column to modify + * @param value the value to set the column to + * @param the column type + * @return true upon success, false otherwise + */ + public boolean update(String name, DataSourceColumn column, T value) { + try { + return internalHandler.update(name, column, value); + } catch (SQLException e) { + logSqlException(e); + return false; + } + } + + /** + * Updates a row to have the values as retrieved from the PlayerAuth object. + * + * @param auth the player auth object to modify and to get values from + * @param columns the columns to update in the row + * @return true upon success, false otherwise + */ + public boolean update(PlayerAuth auth, PlayerAuthColumn... columns) { + try { + return internalHandler.update(auth.getNickname(), auth, columns); + } catch (SQLException e) { + logSqlException(e); + return false; + } + } + + /** + * Updates a row to have the given values. + * + * @param name the name of the account to modify + * @param updateValues the values to set on the row + * @return true upon success, false otherwise + */ + public boolean update(String name, UpdateValues updateValues) { + try { + return internalHandler.update(name.toLowerCase(), updateValues); + } catch (SQLException e) { + logSqlException(e); + return false; + } + } + + /** + * Sets the given value to the provided column for all rows which match the predicate. + * + * @param predicate the predicate to filter rows by + * @param column the column to modify on the matched rows + * @param value the new value to set + * @param the column type + * @return number of modified rows + */ + public int update(Predicate predicate, DataSourceColumn column, T value) { + try { + return internalHandler.update(predicate, column, value); + } catch (SQLException e) { + logSqlException(e); + return 0; + } + } + + /** + * Retrieves the given column from a given row. + * + * @param name the account name to look up + * @param column the column whose value should be retrieved + * @param the column type + * @return the result of the lookup + * @throws SQLException . + */ + public DataSourceValue retrieve(String name, DataSourceColumn column) throws SQLException { + return internalHandler.retrieve(name.toLowerCase(), column); + } + + /** + * Retrieves multiple values from a given row. + * + * @param name the account name to look up + * @param columns the columns to retrieve + * @return map-like object with the requested values + * @throws SQLException . + */ + public DataSourceValues retrieve(String name, DataSourceColumn... columns) throws SQLException { + return internalHandler.retrieve(name.toLowerCase(), columns); + } + + /** + * Retrieves a column's value for all rows that satisfy the given predicate. + * + * @param predicate the predicate to fulfill + * @param column the column to retrieve from the matching rows + * @param the column's value type + * @return the values of the matching rows + * @throws SQLException . + */ + public List retrieve(Predicate predicate, DataSourceColumn column) throws SQLException { + return internalHandler.retrieve(predicate, column); + } + + /** + * Inserts the given values into a new row, as taken from the player auth. + * + * @param auth the player auth to get values from + * @param columns the columns to insert + * @return true upon success, false otherwise + */ + public boolean insert(PlayerAuth auth, PlayerAuthColumn... columns) { + try { + return internalHandler.insert(auth, columns); + } catch (SQLException e) { + logSqlException(e); + return false; + } + } + + /** + * Returns the number of rows that match the provided predicate. + * + * @param predicate the predicate to test the rows for + * @return number of rows fulfilling the predicate + */ + public int count(Predicate predicate) { + try { + return internalHandler.count(predicate); + } catch (SQLException e) { + logSqlException(e); + return 0; + } + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/ColumnContext.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/ColumnContext.java new file mode 100644 index 000000000..554266a05 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/ColumnContext.java @@ -0,0 +1,35 @@ +package fr.xephi.authme.datasource.columnshandler; + +import fr.xephi.authme.settings.Settings; + +import java.util.HashMap; +import java.util.Map; + +/** + * Context for resolving the properties of {@link AuthMeColumns} entries. + */ +public class ColumnContext { + + private final Settings settings; + private final Map, String> columnNames = new HashMap<>(); + private final boolean hasDefaultSupport; + + /** + * Constructor. + * + * @param settings plugin settings + * @param hasDefaultSupport whether or not the underlying database has support for the {@code DEFAULT} keyword + */ + public ColumnContext(Settings settings, boolean hasDefaultSupport) { + this.settings = settings; + this.hasDefaultSupport = hasDefaultSupport; + } + + public String getName(DataSourceColumn column) { + return columnNames.computeIfAbsent(column, k -> settings.getProperty(k.getNameProperty())); + } + + public boolean hasDefaultSupport() { + return hasDefaultSupport; + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/ConnectionSupplier.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/ConnectionSupplier.java new file mode 100644 index 000000000..77fbe8f3a --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/ConnectionSupplier.java @@ -0,0 +1,20 @@ +package fr.xephi.authme.datasource.columnshandler; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Supplier of connections to a database. + */ +@FunctionalInterface +public interface ConnectionSupplier { + + /** + * Returns a connection to the database. + * + * @return the connection + * @throws SQLException . + */ + Connection get() throws SQLException; + +} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/DataSourceColumn.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/DataSourceColumn.java new file mode 100644 index 000000000..4b7fa4ca7 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/DataSourceColumn.java @@ -0,0 +1,57 @@ +package fr.xephi.authme.datasource.columnshandler; + +import ch.jalu.configme.properties.Property; +import ch.jalu.datasourcecolumns.Column; +import ch.jalu.datasourcecolumns.ColumnType; + +/** + * Basic {@link Column} implementation for AuthMe. + * + * @param column type + */ +public class DataSourceColumn implements Column { + + private final ColumnType columnType; + private final Property nameProperty; + private final boolean isOptional; + private final boolean useDefaultForNull; + + /** + * Constructor. + * + * @param type type of the column + * @param nameProperty property defining the column name + * @param isOptional whether or not the column can be skipped (if name is configured to empty string) + * @param useDefaultForNull whether SQL DEFAULT should be used for null values (if supported by the database) + */ + DataSourceColumn(ColumnType type, Property nameProperty, boolean isOptional, boolean useDefaultForNull) { + this.columnType = type; + this.nameProperty = nameProperty; + this.isOptional = isOptional; + this.useDefaultForNull = useDefaultForNull; + } + + public Property getNameProperty() { + return nameProperty; + } + + @Override + public String resolveName(ColumnContext columnContext) { + return columnContext.getName(this); + } + + @Override + public ColumnType getType() { + return columnType; + } + + @Override + public boolean isColumnUsed(ColumnContext columnContext) { + return !isOptional || !resolveName(columnContext).isEmpty(); + } + + @Override + public boolean useDefaultForNullValue(ColumnContext columnContext) { + return useDefaultForNull && columnContext.hasDefaultSupport(); + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/MySqlPreparedStatementGenerator.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/MySqlPreparedStatementGenerator.java new file mode 100644 index 000000000..c20357ae4 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/MySqlPreparedStatementGenerator.java @@ -0,0 +1,44 @@ +package fr.xephi.authme.datasource.columnshandler; + +import ch.jalu.datasourcecolumns.sqlimplementation.PreparedStatementGenerator; +import ch.jalu.datasourcecolumns.sqlimplementation.PreparedStatementResult; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * Implementation of {@link PreparedStatementGenerator} for MySQL which ensures that the connection + * taken from the connection pool is also closed after the prepared statement has been executed. + */ +class MySqlPreparedStatementGenerator implements PreparedStatementGenerator { + + private final ConnectionSupplier connectionSupplier; + + MySqlPreparedStatementGenerator(ConnectionSupplier connectionSupplier) { + this.connectionSupplier = connectionSupplier; + } + + @Override + public PreparedStatementResult create(String sql) throws SQLException { + Connection connection = connectionSupplier.get(); + return new MySqlPreparedStatementResult(connection, connection.prepareStatement(sql)); + } + + /** Prepared statement result which also closes the associated connection. */ + private static final class MySqlPreparedStatementResult extends PreparedStatementResult { + + private final Connection connection; + + MySqlPreparedStatementResult(Connection connection, PreparedStatement preparedStatement) { + super(preparedStatement); + this.connection = connection; + } + + @Override + public void close() throws SQLException { + super.close(); + connection.close(); + } + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/PlayerAuthColumn.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/PlayerAuthColumn.java new file mode 100644 index 000000000..43d022b13 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/PlayerAuthColumn.java @@ -0,0 +1,32 @@ +package fr.xephi.authme.datasource.columnshandler; + +import ch.jalu.configme.properties.Property; +import ch.jalu.datasourcecolumns.ColumnType; +import ch.jalu.datasourcecolumns.DependentColumn; +import fr.xephi.authme.data.auth.PlayerAuth; + +import java.util.function.Function; + +/** + * Implementation for columns which can also be retrieved from a {@link PlayerAuth} object. + * + * @param column type + */ +public class PlayerAuthColumn extends DataSourceColumn implements DependentColumn { + + private final Function playerAuthGetter; + + /* + * Constructor. See parent class for details. + */ + PlayerAuthColumn(ColumnType type, Property nameProperty, boolean isOptional, boolean useDefaultForNull, + Function playerAuthGetter) { + super(type, nameProperty, isOptional, useDefaultForNull); + this.playerAuthGetter = playerAuthGetter; + } + + @Override + public T getValueFromDependent(PlayerAuth auth) { + return playerAuthGetter.apply(auth); + } +} diff --git a/src/main/resources/messages/messages_pl.yml b/src/main/resources/messages/messages_pl.yml index 4d9061dfd..cc512acc3 100644 --- a/src/main/resources/messages/messages_pl.yml +++ b/src/main/resources/messages/messages_pl.yml @@ -79,7 +79,7 @@ on_join_validation: country_banned: '&4Ten kraj jest zbanowany na tym serwerze' not_owner_error: '&cNie jesteś właścicielem tego konta, wybierz inny nick!' invalid_name_case: '&cPowinieneś dołączyć do serwera z nicku %valid, a nie %invalid.' - # TODO quick_command: 'You used a command too fast! Please, join the server again and wait more before using any command.' + quick_command: '&cUżyłeś komendy zbyt szybko! Ponownie dołącz do serwera i poczekaj chwilę, zanim użyjesz dowolnej komendy.' # Email email: diff --git a/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java b/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java index 267f7d7cb..f02b5dc9b 100644 --- a/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java @@ -5,7 +5,10 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import fr.xephi.authme.data.captcha.CaptchaCodeStorage; +import fr.xephi.authme.datasource.AbstractSqlDataSource; import fr.xephi.authme.datasource.Columns; +import fr.xephi.authme.datasource.columnshandler.DataSourceColumn; +import fr.xephi.authme.datasource.columnshandler.PlayerAuthColumn; import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension; import fr.xephi.authme.initialization.HasCleanup; import fr.xephi.authme.process.register.executors.RegistrationMethod; @@ -52,7 +55,7 @@ public class ClassesConsistencyTest { int.class, long.class, float.class, String.class, File.class, Enum.class, collectionsUnmodifiableList(), Charset.class, /* AuthMe */ - Property.class, RegistrationMethod.class, + Property.class, RegistrationMethod.class, DataSourceColumn.class, PlayerAuthColumn.class, /* Guava */ ImmutableMap.class, ImmutableList.class); @@ -60,6 +63,7 @@ public class ClassesConsistencyTest { private static final Set> CLASSES_EXCLUDED_FROM_VISIBILITY_TEST = ImmutableSet.of( Whirlpool.class, // not our implementation, so we don't touch it MySqlExtension.class, // has immutable protected fields used by all children + AbstractSqlDataSource.class, // protected members for inheritance Columns.class // uses non-static String constants, which is safe ); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java index 07c92d13c..dc3fda40e 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java @@ -1,7 +1,7 @@ package fr.xephi.authme.command.executable.authme; +import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.service.CommonService; import org.bukkit.command.CommandSender; @@ -38,7 +38,7 @@ public class GetEmailCommandTest { public void shouldReportUnknownUser() { // given String user = "myTestUser"; - given(dataSource.getEmail(user)).willReturn(DataSourceResult.unknownPlayer()); + given(dataSource.getEmail(user)).willReturn(DataSourceValueImpl.unknownRow()); CommandSender sender = mock(CommandSender.class); // when @@ -53,7 +53,7 @@ public class GetEmailCommandTest { // given String user = "userToView"; String email = "user.email@example.org"; - given(dataSource.getEmail(user)).willReturn(DataSourceResult.of(email)); + given(dataSource.getEmail(user)).willReturn(DataSourceValueImpl.of(email)); CommandSender sender = mock(CommandSender.class); // when diff --git a/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java index 416649e05..5842ec300 100644 --- a/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java @@ -1,12 +1,12 @@ package fr.xephi.authme.command.executable.email; +import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; import ch.jalu.injector.testing.BeforeInjecting; import ch.jalu.injector.testing.DelayedInjectionRunner; import ch.jalu.injector.testing.InjectDelayed; import fr.xephi.authme.TestHelper; import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.mail.EmailService; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.security.PasswordSecurity; @@ -118,7 +118,7 @@ public class RecoverEmailCommandTest { given(sender.getName()).willReturn(name); given(emailService.hasAllInformation()).willReturn(true); given(playerCache.isAuthenticated(name)).willReturn(false); - given(dataSource.getEmail(name)).willReturn(DataSourceResult.unknownPlayer()); + given(dataSource.getEmail(name)).willReturn(DataSourceValueImpl.unknownRow()); // when command.executeCommand(sender, Collections.singletonList("someone@example.com")); @@ -138,7 +138,7 @@ public class RecoverEmailCommandTest { given(sender.getName()).willReturn(name); given(emailService.hasAllInformation()).willReturn(true); given(playerCache.isAuthenticated(name)).willReturn(false); - given(dataSource.getEmail(name)).willReturn(DataSourceResult.of(DEFAULT_EMAIL)); + given(dataSource.getEmail(name)).willReturn(DataSourceValueImpl.of(DEFAULT_EMAIL)); // when command.executeCommand(sender, Collections.singletonList(DEFAULT_EMAIL)); @@ -158,7 +158,7 @@ public class RecoverEmailCommandTest { given(sender.getName()).willReturn(name); given(emailService.hasAllInformation()).willReturn(true); given(playerCache.isAuthenticated(name)).willReturn(false); - given(dataSource.getEmail(name)).willReturn(DataSourceResult.of("raptor@example.org")); + given(dataSource.getEmail(name)).willReturn(DataSourceValueImpl.of("raptor@example.org")); // when command.executeCommand(sender, Collections.singletonList("wrong-email@example.com")); @@ -180,7 +180,7 @@ public class RecoverEmailCommandTest { given(emailService.sendRecoveryCode(anyString(), anyString(), anyString())).willReturn(true); given(playerCache.isAuthenticated(name)).willReturn(false); String email = "v@example.com"; - given(dataSource.getEmail(name)).willReturn(DataSourceResult.of(email)); + given(dataSource.getEmail(name)).willReturn(DataSourceValueImpl.of(email)); String code = "a94f37"; given(recoveryCodeService.isRecoveryCodeNeeded()).willReturn(true); given(recoveryCodeService.generateCode(name)).willReturn(code); @@ -205,7 +205,7 @@ public class RecoverEmailCommandTest { given(emailService.sendPasswordMail(anyString(), anyString(), anyString())).willReturn(true); given(playerCache.isAuthenticated(name)).willReturn(false); String email = "vulture@example.com"; - given(dataSource.getEmail(name)).willReturn(DataSourceResult.of(email)); + given(dataSource.getEmail(name)).willReturn(DataSourceValueImpl.of(email)); given(recoveryCodeService.isRecoveryCodeNeeded()).willReturn(false); setBukkitServiceToRunTaskAsynchronously(bukkitService); diff --git a/src/test/java/fr/xephi/authme/data/VerificationCodeManagerTest.java b/src/test/java/fr/xephi/authme/data/VerificationCodeManagerTest.java index b99d6a373..732b1ad70 100644 --- a/src/test/java/fr/xephi/authme/data/VerificationCodeManagerTest.java +++ b/src/test/java/fr/xephi/authme/data/VerificationCodeManagerTest.java @@ -1,7 +1,7 @@ package fr.xephi.authme.data; +import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.mail.EmailService; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerPermission; @@ -51,7 +51,7 @@ public class VerificationCodeManagerTest { // given String name1 = "ILoveTests"; Player player1 = mockPlayerWithName(name1); - given(dataSource.getEmail(name1)).willReturn(DataSourceResult.of("ilovetests@test.com")); + given(dataSource.getEmail(name1)).willReturn(DataSourceValueImpl.of("ilovetests@test.com")); given(permissionsManager.hasPermission(player1, PlayerPermission.VERIFICATION_CODE)).willReturn(true); String name2 = "StillLovingTests"; Player player2 = mockPlayerWithName(name2); @@ -106,7 +106,7 @@ public class VerificationCodeManagerTest { // given String player = "ILoveTests"; String email = "ilovetests@test.com"; - given(dataSource.getEmail(player)).willReturn(DataSourceResult.of(email)); + given(dataSource.getEmail(player)).willReturn(DataSourceValueImpl.of(email)); VerificationCodeManager codeManager1 = createCodeManager(); VerificationCodeManager codeManager2 = createCodeManager(); codeManager2.codeExistOrGenerateNew(player); @@ -125,7 +125,7 @@ public class VerificationCodeManagerTest { // given String player = "ILoveTests"; String email = "ilovetests@test.com"; - given(dataSource.getEmail(player)).willReturn(DataSourceResult.of(email)); + given(dataSource.getEmail(player)).willReturn(DataSourceValueImpl.of(email)); VerificationCodeManager codeManager1 = createCodeManager(); VerificationCodeManager codeManager2 = createCodeManager(); codeManager2.codeExistOrGenerateNew(player); @@ -145,7 +145,7 @@ public class VerificationCodeManagerTest { String player = "ILoveTests"; String code = "193458"; String email = "ilovetests@test.com"; - given(dataSource.getEmail(player)).willReturn(DataSourceResult.of(email)); + given(dataSource.getEmail(player)).willReturn(DataSourceValueImpl.of(email)); VerificationCodeManager codeManager1 = createCodeManager(); VerificationCodeManager codeManager2 = createCodeManager(); codeManager1.codeExistOrGenerateNew(player); diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java index 0e8094825..58fd59c08 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java @@ -1,5 +1,7 @@ package fr.xephi.authme.datasource; +import ch.jalu.datasourcecolumns.data.DataSourceValue; +import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; import com.google.common.collect.Lists; import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.security.crypts.HashedPassword; @@ -61,7 +63,7 @@ public abstract class AbstractDataSourceIntegrationTest { // when HashedPassword bobbyPassword = dataSource.getPassword("bobby"); HashedPassword invalidPassword = dataSource.getPassword("doesNotExist"); - HashedPassword userPassword = dataSource.getPassword("user"); + HashedPassword userPassword = dataSource.getPassword("User"); // then assertThat(bobbyPassword, equalToHash("$SHA$11aa0706173d7272$dbba966")); @@ -162,7 +164,8 @@ public abstract class AbstractDataSourceIntegrationTest { boolean response2 = dataSource.updatePassword("non-existent-name", new HashedPassword("sd")); // then - assertThat(response1 && response2, equalTo(true)); + assertThat(response1, equalTo(true)); + assertThat(response2, equalTo(false)); // no record modified assertThat(dataSource.getPassword("user"), equalToHash(newHash)); } @@ -177,7 +180,8 @@ public abstract class AbstractDataSourceIntegrationTest { boolean response2 = dataSource.updatePassword("non-existent-name", new HashedPassword("asdfasdf", "a1f34ec")); // then - assertThat(response1 && response2, equalTo(true)); + assertThat(response1, equalTo(true)); + assertThat(response2, equalTo(false)); // no record modified assertThat(dataSource.getPassword("user"), equalToHash("new_hash")); } @@ -193,7 +197,8 @@ public abstract class AbstractDataSourceIntegrationTest { boolean response2 = dataSource.updatePassword(invalidAuth); // then - assertThat(response1 && response2, equalTo(true)); + assertThat(response1, equalTo(true)); + assertThat(response2, equalTo(false)); // no record modified assertThat(dataSource.getPassword("bobby"), equalToHash("tt", "cc")); } @@ -275,7 +280,8 @@ public abstract class AbstractDataSourceIntegrationTest { boolean response2 = dataSource.updateEmail(invalidAuth); // then - assertThat(response1 && response2, equalTo(true)); + assertThat(response1, equalTo(true)); + assertThat(response2, equalTo(false)); // no record modified assertThat(dataSource.getAllAuths(), hasItem(hasAuthBasicData("user", "user", email, "34.56.78.90"))); } @@ -330,7 +336,8 @@ public abstract class AbstractDataSourceIntegrationTest { boolean response2 = dataSource.updateRealName("notExists", "NOTEXISTS"); // then - assertThat(response1 && response2, equalTo(true)); + assertThat(response1, equalTo(true)); + assertThat(response2, equalTo(false)); // no record modified assertThat(dataSource.getAuth("bobby"), hasAuthBasicData("bobby", "BOBBY", null, "123.45.67.89")); } @@ -417,12 +424,12 @@ public abstract class AbstractDataSourceIntegrationTest { DataSource dataSource = getDataSource(); // when - DataSourceResult email1 = dataSource.getEmail(user1); - DataSourceResult email2 = dataSource.getEmail(user2); + DataSourceValue email1 = dataSource.getEmail(user1); + DataSourceValue email2 = dataSource.getEmail(user2); // then assertThat(email1.getValue(), equalTo("user@example.org")); - assertThat(email2, is(DataSourceResult.unknownPlayer())); + assertThat(email2, is(DataSourceValueImpl.unknownRow())); } @Test diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java index eab6a4cc4..027608230 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -55,7 +55,9 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { HikariConfig config = new HikariConfig(); config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); config.setConnectionTestQuery("VALUES 1"); - config.addDataSourceProperty("URL", "jdbc:h2:mem:test"); + // Note "ignorecase=true": H2 does not support `COLLATE NOCASE` for case-insensitive equals queries. + // MySQL is by default case-insensitive so this is OK to make as an assumption. + config.addDataSourceProperty("URL", "jdbc:h2:mem:test;ignorecase=true"); config.addDataSourceProperty("user", "sa"); config.addDataSourceProperty("password", "sa"); HikariDataSource ds = new HikariDataSource(config);