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/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index b8e487e2b..9f4456159 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -1,19 +1,13 @@ 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 com.google.common.annotations.VisibleForTesting; 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.AuthMeColumns; 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; @@ -26,14 +20,10 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -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.getNullableLong; import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; @@ -41,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; @@ -54,7 +44,6 @@ public class MySQL implements DataSource { private int maxLifetime; private List columnOthers; private Columns col; - private AuthMeColumnsHandler columnsHandler; private MySqlExtension sqlExtension; private HikariDataSource ds; @@ -273,29 +262,6 @@ public class MySQL implements DataSource { } } - @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 PlayerAuth getAuth(String user) { String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;"; @@ -318,9 +284,7 @@ public class MySQL implements DataSource { @Override public boolean saveAuth(PlayerAuth auth) { - columnsHandler.insert(auth, - AuthMeColumns.NAME, AuthMeColumns.NICK_NAME, AuthMeColumns.PASSWORD, AuthMeColumns.SALT, - AuthMeColumns.EMAIL, AuthMeColumns.REGISTRATION_DATE, AuthMeColumns.REGISTRATION_IP); + super.saveAuth(auth); try (Connection con = getConnection()) { if (!columnOthers.isEmpty()) { @@ -342,23 +306,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) { - return columnsHandler.update(user, - with(AuthMeColumns.PASSWORD, password.getHash()) - .and(AuthMeColumns.SALT, password.getSalt()).build()); - } - - @Override - public boolean updateSession(PlayerAuth auth) { - return columnsHandler.update(auth, AuthMeColumns.LAST_IP, AuthMeColumns.LAST_LOGIN, AuthMeColumns.NICK_NAME); - } - @Override public Set getRecordsToPurge(long until) { Set list = new HashSet<>(); @@ -396,18 +343,6 @@ public class MySQL implements DataSource { return false; } - @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 boolean updateEmail(PlayerAuth auth) { - return columnsHandler.update(auth, AuthMeColumns.EMAIL); - } - @Override public void closeConnection() { if (ds != null && !ds.isClosed()) { @@ -415,21 +350,6 @@ public class MySQL implements DataSource { } } - @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 void purgeRecords(Collection toPurge) { String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; @@ -448,73 +368,6 @@ public class MySQL implements DataSource { return DataSourceType.MYSQL; } - @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 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 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(); - } - } - @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 5c78e0bbe..b2f639a37 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -1,15 +1,9 @@ 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 com.google.common.annotations.VisibleForTesting; import fr.xephi.authme.ConsoleLogger; 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 fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; @@ -23,14 +17,10 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -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.getNullableLong; import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; @@ -38,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; @@ -46,7 +36,6 @@ public class SQLite implements DataSource { private final String tableName; private final Columns col; private Connection con; - private AuthMeColumnsHandler columnsHandler; /** * Constructor for SQLite. @@ -71,6 +60,7 @@ public class SQLite implements DataSource { ConsoleLogger.logException("Error during SQLite initialization:", ex); throw ex; } + this.columnsHandler = AuthMeColumnsHandler.createForSqlite(con, settings); } @VisibleForTesting @@ -215,29 +205,6 @@ public class SQLite implements DataSource { } } - @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 PlayerAuth getAuth(String user) { String sql = "SELECT * FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"; @@ -254,30 +221,6 @@ public class SQLite implements DataSource { 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 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 updateSession(PlayerAuth auth) { - return columnsHandler.update(auth, AuthMeColumns.LAST_IP, AuthMeColumns.LAST_LOGIN, AuthMeColumns.NICK_NAME); - } - @Override public Set getRecordsToPurge(long until) { Set list = new HashSet<>(); @@ -325,18 +268,6 @@ public class SQLite implements DataSource { return false; } - @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 boolean updateEmail(PlayerAuth auth) { - return columnsHandler.update(auth, AuthMeColumns.EMAIL); - } - @Override public void closeConnection() { try { @@ -348,112 +279,11 @@ public class SQLite implements DataSource { } } - @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 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) { - 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 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(); - } - } - @Override public List getAllAuths() { List auths = new ArrayList<>(); diff --git a/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java b/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java index eb00d14e0..f02b5dc9b 100644 --- a/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/ClassesConsistencyTest.java @@ -5,6 +5,7 @@ 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; @@ -62,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 );