From c12e24d0f8d3582e11550c9d334118db4db707bf Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 21 Aug 2015 23:35:44 +0200 Subject: [PATCH 001/115] Added stacktraces to find out what's the problem -_- --- src/main/java/fr/xephi/authme/cache/backup/FileCache.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java index 2a4b09eb6..08eecab97 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java @@ -505,8 +505,10 @@ public class FileCache { else armours[i] = item; } } catch (final RuntimeException e) { + e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); } catch (final Exception e) { + e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); } finally { if (reader != null) @@ -515,9 +517,11 @@ public class FileCache { return new DataFileCache(inv, armours, group, op, flying); } } catch (RuntimeException e) { + e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); return null; } catch (Exception e) { + e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); return null; } From 217c217d13031f56f3ada74fcc508de4bcbd0ab3 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 22 Aug 2015 16:34:06 +0200 Subject: [PATCH 002/115] Stuff --- pom.xml | 2 +- .../xephi/authme/cache/backup/FileCache.java | 4 ++++ .../java/fr/xephi/authme/datasource/MySQL.java | 18 ++++++++++++------ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 2eab19595..c5f2e8f62 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ com.zaxxer HikariCP - 2.4.0 + 2.4.1 compile diff --git a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java index 08eecab97..f06b63f03 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java @@ -505,9 +505,11 @@ public class FileCache { else armours[i] = item; } } catch (final RuntimeException e) { + //verbose e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); } catch (final Exception e) { + //verbose e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); } finally { @@ -517,10 +519,12 @@ public class FileCache { return new DataFileCache(inv, armours, group, op, flying); } } catch (RuntimeException e) { + // Verbose e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); return null; } catch (Exception e) { + // Verbose e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); return null; diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 45c9c651f..b6cfd5a66 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -113,16 +113,19 @@ public class MySQL implements DataSource { throws ClassNotFoundException, SQLException, TimeoutException, NumberFormatException, PoolInitializationException { HikariConfig config = new HikariConfig(); + config.setPoolName("AuthMeMYSQLPool"); + config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); config.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); config.setUsername(this.username); config.setPassword(this.password); - config.setPoolName("AuthMeMYSQLPool"); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); config.addDataSourceProperty("autoReconnect", true); - config.setMaxLifetime(12000); - config.setInitializationFailFast(false); + config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable + config.setMaxLifetime(12000); // 12 Sec + config.setIdleTimeout(120000); // 2 Min + config.setMaximumPoolSize(50); // 50 Connections (including idle connections) ds = new HikariDataSource(config); ConsoleLogger.info("Connection pool ready"); } @@ -907,6 +910,8 @@ public class MySQL implements DataSource { if (ds != null) ds.close(); HikariConfig config = new HikariConfig(); + config.setPoolName("AuthMeMYSQLPool"); + config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); config.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); config.setUsername(this.username); config.setPassword(this.password); @@ -914,9 +919,10 @@ public class MySQL implements DataSource { config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); config.addDataSourceProperty("autoReconnect", true); - config.setInitializationFailFast(false); - config.setMaxLifetime(12000); - config.setPoolName("AuthMeMYSQLPool"); + config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable + config.setMaxLifetime(12000); // 12 Sec + config.setIdleTimeout(120000); // 2 Min + config.setMaximumPoolSize(50); // 50 Connections (including idle connections) ds = new HikariDataSource(config); if (!reload) ConsoleLogger.info("ConnectionPool was unavailable... Reconnected!"); From 568784a8e19566ea4c2f91600a6e9cab59a85794 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 26 Aug 2015 22:52:23 +0100 Subject: [PATCH 003/115] test new mysql (not working yet) --- .../fr/xephi/authme/datasource/MySQL.java | 270 ++++++++---------- 1 file changed, 117 insertions(+), 153 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index ac11a6022..61cf015db 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -8,7 +8,6 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeoutException; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; @@ -45,7 +44,7 @@ public class MySQL implements DataSource { private HikariDataSource ds; private String columnRealName; - public MySQL() { + public MySQL() throws ClassNotFoundException, SQLException, PoolInitializationException { this.host = Settings.getMySQLHost; this.port = Settings.getMySQLPort; this.username = Settings.getMySQLUsername; @@ -67,76 +66,112 @@ public class MySQL implements DataSource { this.columnID = Settings.getMySQLColumnId; this.columnLogged = Settings.getMySQLColumnLogged; this.columnRealName = Settings.getMySQLColumnRealName; + + // Set the connection arguments (and check if connection is ok) try { - this.connect(); - this.setup(); - } catch (ClassNotFoundException e) { - ConsoleLogger.showError(e.getMessage()); + this.setConnectionArguments(); + } catch (ClassNotFoundException ne) { + ConsoleLogger.showError(ne.getMessage()); + ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer! SHUTDOWN..."); + this.close(); if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use MySQL... Please input correct MySQL informations ! SHUTDOWN..."); AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + throw new ClassNotFoundException(ne.getMessage()); + } catch (IllegalArgumentException ae) { // This means that there are problems with the hikaricp pool arguments! + ConsoleLogger.showError(ae.getMessage()); + ConsoleLogger.showError("Invalid database arguments! Please check your configuration!"); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + this.close(); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + throw new IllegalArgumentException(ae); + } catch (PoolInitializationException ie) { // Can't initialize the connection pool! + ConsoleLogger.showError(ie.getMessage()); + ConsoleLogger.showError("Can't connect to the MySql database! Please check your configuration!"); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + this.close(); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + throw new PoolInitializationException(ie); + } + + // Initialize the database + try { + this.setupConnection(); } catch (SQLException e) { ConsoleLogger.showError(e.getMessage()); + ConsoleLogger.showError("Can't initialize the MySQL database... Please check your database settings in the config.yml file! SHUTDOWN..."); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + this.close(); if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use MySQL... Please input correct MySQL informations ! SHUTDOWN..."); AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; - } catch (TimeoutException e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use MySQL... Please input correct MySQL informations ! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) + } else { AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; - } catch (PoolInitializationException e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use MySQL... Please input correct MySQL informations ! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); } - if (!Settings.isStopEnabled) - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; + throw new SQLException(e); } } - private synchronized void connect() - throws ClassNotFoundException, SQLException, TimeoutException, - NumberFormatException, PoolInitializationException { - HikariConfig config = new HikariConfig(); + private synchronized void setConnectionArguments() + throws ClassNotFoundException, IllegalArgumentException { + HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeMYSQLPool"); - config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); - config.setDriverClassName("com.mysql.jdbc.Driver"); + config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); config.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); config.setUsername(this.username); config.setPassword(this.password); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); - config.addDataSourceProperty("autoReconnect", true); + config.addDataSourceProperty("autoReconnect", false); config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable - config.setMaxLifetime(12000); // 12 Sec - config.setIdleTimeout(120000); // 2 Min + config.setMaxLifetime(60000); // 60 Sec + config.setIdleTimeout(45000); // 45 Sec config.setMaximumPoolSize(50); // 50 Connections (including idle connections) ds = new HikariDataSource(config); - ConsoleLogger.info("Connection pool ready"); + ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); } - private synchronized void setup() throws SQLException { + private synchronized void reloadArguments() + throws ClassNotFoundException, IllegalArgumentException { + if (ds != null){ + ds.close(); + } + setConnectionArguments(); + ConsoleLogger.info("Hikari ConnectionPool arguments reloaded!"); + } + + private synchronized Connection getConnection() { + Connection con = null; + while(con == null){ + try { + con = ds.getConnection(); + } catch (SQLException ce) { + return null; + } + } + return con; + } + + private synchronized void setupConnection() throws SQLException { Connection con = null; Statement st = null; ResultSet rs = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); st = con.createStatement(); st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" + columnID + " INTEGER AUTO_INCREMENT," + columnName + " VARCHAR(255) NOT NULL UNIQUE," + columnPassword + " VARCHAR(255) NOT NULL," + columnIp + " VARCHAR(40) NOT NULL DEFAULT '127.0.0.1'," + columnLastLogin + " BIGINT NOT NULL DEFAULT '" + System.currentTimeMillis() + "'," + lastlocX + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocY + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocZ + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocWorld + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," + columnEmail + " VARCHAR(255) DEFAULT 'your@email.com'," + columnLogged + " SMALLINT NOT NULL DEFAULT '0'," + "CONSTRAINT table_const_prim PRIMARY KEY (" + columnID + "));"); rs = con.getMetaData().getColumns(null, null, tableName, columnPassword); @@ -188,6 +223,7 @@ public class MySQL implements DataSource { close(st); close(con); } + ConsoleLogger.info("MySQL Setup finished"); } @Override @@ -196,7 +232,7 @@ public class MySQL implements DataSource { PreparedStatement pst = null; ResultSet rs = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + columnName + ")=LOWER(?);"); pst.setString(1, user); rs = pst.executeQuery(); @@ -220,7 +256,7 @@ public class MySQL implements DataSource { PlayerAuth pAuth = null; int id = -1; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + columnName + ")=LOWER(?);"); pst.setString(1, user); rs = pst.executeQuery(); @@ -267,7 +303,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); if ((columnSalt == null || columnSalt.isEmpty()) || (auth.getSalt() == null || auth.getSalt().isEmpty())) { pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnRealName + ") VALUES (?,?,?,?,?);"); pst.setString(1, auth.getNickname()); @@ -476,7 +512,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnPassword + "=? WHERE LOWER(" + columnName + ")=?;"); pst.setString(1, auth.getHash()); pst.setString(2, auth.getNickname()); @@ -521,7 +557,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnIp + "=?, " + columnLastLogin + "=?, " + columnRealName + "=? WHERE LOWER(" + columnName + ")=?;"); pst.setString(1, auth.getIp()); pst.setLong(2, auth.getLastLogin()); @@ -543,7 +579,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + columnLastLogin + " list = new ArrayList(); try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLastLogin + " countIp = new ArrayList(); try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); pst.setString(1, auth.getIp()); rs = pst.executeQuery(); @@ -798,7 +834,7 @@ public class MySQL implements DataSource { ResultSet rs = null; List countIp = new ArrayList(); try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); pst.setString(1, ip); rs = pst.executeQuery(); @@ -823,7 +859,7 @@ public class MySQL implements DataSource { ResultSet rs = null; List countEmail = new ArrayList(); try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnEmail + "=?;"); pst.setString(1, email); rs = pst.executeQuery(); @@ -847,7 +883,7 @@ public class MySQL implements DataSource { PreparedStatement pst = null; try { for (String name : banned) { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE LOWER(" + columnName + ")=?;"); pst.setString(1, name); pst.executeUpdate(); @@ -860,78 +896,6 @@ public class MySQL implements DataSource { } } - private synchronized Connection makeSureConnectionIsReady() { - Connection con = null; - try { - con = ds.getConnection(); - } catch (Exception te) { - try { - con = null; - reconnect(false); - } catch (Exception e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't reconnect to MySQL database... Please check your MySQL informations ! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - } catch (AssertionError ae) { - // Make sure assertionerror is caused by the connectionpoolmanager, - // else re-throw it - if (!ae.getMessage().equalsIgnoreCase("AuthMeDatabaseError")) - throw new AssertionError(ae.getMessage()); - try { - con = null; - reconnect(false); - } catch (Exception e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't reconnect to MySQL database... Please check your MySQL informations ! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - } - while (con == null) - try { - con = ds.getConnection(); - } catch (Exception e) { - try { - reconnect(false); - con = ds.getConnection(); - } catch (Exception ex) { - } - } - return con; - } - - private synchronized void reconnect(boolean reload) - throws ClassNotFoundException, SQLException, TimeoutException, - PoolInitializationException { - if (ds != null) - ds.close(); - HikariConfig config = new HikariConfig(); - config.setPoolName("AuthMeMYSQLPool"); - config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); - config.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); - config.setUsername(this.username); - config.setPassword(this.password); - config.addDataSourceProperty("cachePrepStmts", "true"); - config.addDataSourceProperty("prepStmtCacheSize", "250"); - config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); - config.addDataSourceProperty("autoReconnect", true); - config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable - config.setMaxLifetime(12000); // 12 Sec - config.setIdleTimeout(120000); // 2 Min - config.setMaximumPoolSize(50); // 50 Connections (including idle connections) - ds = new HikariDataSource(config); - if (!reload) - ConsoleLogger.info("ConnectionPool was unavailable... Reconnected!"); - } - @Override public DataSourceType getType() { return DataSourceType.MYSQL; @@ -943,7 +907,7 @@ public class MySQL implements DataSource { PreparedStatement pst = null; ResultSet rs = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + columnName + ")=?;"); pst.setString(1, user); rs = pst.executeQuery(); @@ -965,7 +929,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnLogged + "=? WHERE LOWER(" + columnName + ")=?;"); pst.setInt(1, 1); pst.setString(2, user); @@ -986,7 +950,7 @@ public class MySQL implements DataSource { PreparedStatement pst = null; if (user != null) try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnLogged + "=? WHERE LOWER(" + columnName + ")=?;"); pst.setInt(1, 0); pst.setString(2, user); @@ -1006,7 +970,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnLogged + "=? WHERE " + columnLogged + "=?;"); pst.setInt(1, 0); pst.setInt(2, 1); @@ -1028,7 +992,7 @@ public class MySQL implements DataSource { PreparedStatement pst = null; ResultSet rs = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT COUNT(*) FROM " + tableName + ";"); rs = pst.executeQuery(); if (rs != null && rs.next()) { @@ -1049,7 +1013,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnName + "=? WHERE LOWER(" + columnName + ")=?;"); pst.setString(1, newone); pst.setString(2, oldone); @@ -1071,7 +1035,7 @@ public class MySQL implements DataSource { PreparedStatement pst = null; ResultSet rs = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + ";"); rs = pst.executeQuery(); while (rs.next()) { @@ -1122,7 +1086,7 @@ public class MySQL implements DataSource { PreparedStatement pst = null; ResultSet rs = null; try { - con = makeSureConnectionIsReady(); + con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); rs = pst.executeQuery(); while (rs.next()) { From 7c9298f096c31b20f370c07c8eac76f3775acca7 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 27 Aug 2015 00:21:53 +0100 Subject: [PATCH 004/115] More unstuble stuff! (Now it compiles) --- src/main/java/fr/xephi/authme/AuthMe.java | 17 +- .../xephi/authme/commands/AdminCommand.java | 36 +- .../authme/datasource/SQLite_HIKARI.java | 342 ++++++++++-------- .../xephi/authme/modules/ModuleManager.java | 6 +- 4 files changed, 248 insertions(+), 153 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 7ed3dd9f4..131991dcf 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -10,6 +10,7 @@ import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLConnection; +import java.sql.SQLException; import java.util.Calendar; import java.util.Collection; import java.util.Date; @@ -34,6 +35,7 @@ import org.mcstats.Metrics; import com.earth2me.essentials.Essentials; import com.maxmind.geoip.LookupService; import com.onarandombox.MultiverseCore.MultiverseCore; +import com.zaxxer.hikari.pool.PoolInitializationException; import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; @@ -214,7 +216,18 @@ public class AuthMe extends JavaPlugin { else ConsoleLogger.showError("Error while performing the backup!"); } - setupDatabase(); + try { + setupDatabase(); + } catch (ClassNotFoundException nfe) { + ConsoleLogger.showError("Fatal error occurred! Authme initialization ABORTED!"); + return; + } catch (SQLException sqle) { + ConsoleLogger.showError("Fatal error occurred! Authme initialization ABORTED!"); + return; + } catch (PoolInitializationException pie) { + ConsoleLogger.showError("Fatal error occurred! Authme initialization ABORTED!"); + return; + } dataManager = new DataManager(this); @@ -800,7 +813,7 @@ public class AuthMe extends JavaPlugin { return realIP; } - public void setupDatabase() { + public void setupDatabase() throws ClassNotFoundException, PoolInitializationException, SQLException { /* * Backend MYSQL - FILE - SQLITE */ diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 28f4519b9..25e77322d 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.security.NoSuchAlgorithmException; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -22,6 +23,8 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; +import com.zaxxer.hikari.pool.PoolInitializationException; + import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; @@ -143,7 +146,38 @@ public class AdminCommand implements CommandExecutor { Settings.reloadConfigOptions(newConfig); m.reloadMessages(); plugin.database.close(); - plugin.setupDatabase(); + + try { + plugin.setupDatabase(); + } catch (ClassNotFoundException nfe) { + ConsoleLogger.showError("Fatal error occurred! Authme instance ABORTED!"); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + return false; + } catch (SQLException sqle) { + ConsoleLogger.showError("Fatal error occurred! Authme instance ABORTED!"); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + return false; + } catch (PoolInitializationException pie) { + ConsoleLogger.showError("Fatal error occurred! Authme instance ABORTED!"); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + return false; + } + m.send(sender, "reload"); } else if (args[0].equalsIgnoreCase("lastlogin")) { if (args.length != 2) { diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java index 6f1350e31..767a5da7d 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java @@ -1,6 +1,5 @@ package fr.xephi.authme.datasource; -import java.io.EOFException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -8,10 +7,10 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; -import java.util.Properties; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; +import com.zaxxer.hikari.pool.PoolInitializationException; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; @@ -38,7 +37,7 @@ public class SQLite_HIKARI implements DataSource { private String columnLogged; private String columnRealName; - public SQLite_HIKARI() { + public SQLite_HIKARI() throws ClassNotFoundException, SQLException, PoolInitializationException { this.database = Settings.getMySQLDatabase; this.tableName = Settings.getMySQLTablename; this.columnName = Settings.getMySQLColumnName; @@ -56,65 +55,127 @@ public class SQLite_HIKARI implements DataSource { this.columnLogged = Settings.getMySQLColumnLogged; this.columnRealName = Settings.getMySQLColumnRealName; + // Set the connection arguments (and check if connection is ok) try { - this.connect(); - this.setup(); - } catch (ClassNotFoundException e) { - ConsoleLogger.showError(e.getMessage()); + this.setConnectionArguments(); + } catch (ClassNotFoundException ne) { + ConsoleLogger.showError(ne.getMessage()); + ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer! SHUTDOWN..."); + this.close(); if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use SQLITE... ! SHUTDOWN..."); AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + throw new ClassNotFoundException(ne.getMessage()); + } catch (IllegalArgumentException ae) { // This means that there are problems with the hikaricp pool arguments! + ConsoleLogger.showError(ae.getMessage()); + ConsoleLogger.showError("Invalid database arguments! Please check your configuration!"); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + this.close(); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + throw new IllegalArgumentException(ae); + } catch (PoolInitializationException ie) { // Can't initialize the connection pool! + ConsoleLogger.showError(ie.getMessage()); + ConsoleLogger.showError("Can't connect to the SQLite database! Please check your configuration!"); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + this.close(); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + throw new PoolInitializationException(ie); + } + + // Initialize the database + try { + this.setupConnection(); } catch (SQLException e) { ConsoleLogger.showError(e.getMessage()); + ConsoleLogger.showError("Can't initialize the MySQL database... Please check your database settings in the config.yml file! SHUTDOWN..."); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + this.close(); if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use SQLITE... ! SHUTDOWN..."); AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; - } catch (EOFException e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use SQLITE... ! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) + } else { AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; + } + throw new SQLException(e); } } - private Connection getConnection() throws SQLException, EOFException { - return this.ds.getConnection(); + @Override + public DataSourceType getType() { + return DataSourceType.SQLITE; } - private synchronized void connect() - throws ClassNotFoundException, SQLException, EOFException { - /* - * Class.forName("org.sqlite.JDBC"); ConsoleLogger.info( - * "SQLite driver loaded"); this.con = - * DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database - * + ".db"); - */ - Properties props = new Properties(); - props.setProperty("dataSourceClassName", "org.sqlite.SQLiteDataSource"); - HikariConfig config = new HikariConfig(props); - config.setPoolName("AuthMeSQLiteLPool"); + private synchronized void setConnectionArguments() + throws ClassNotFoundException, IllegalArgumentException { + HikariConfig config = new HikariConfig(); + config.setPoolName("AuthMeSQLitePool"); + config.setDataSourceClassName("org.sqlite.SQLiteDataSource"); + config.setJdbcUrl("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); + config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable + config.setConnectionTestQuery("SELECT 1"); + config.setMaxLifetime(60000); // 60 Sec + config.setIdleTimeout(45000); // 45 Sec + config.setMaximumPoolSize(50); // 50 Connections (including idle connections) ds = new HikariDataSource(config); - ConsoleLogger.info("Connection pool ready"); + ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); } - private synchronized void setup() throws SQLException, EOFException { + private synchronized Connection getRawConnection() { + Connection con = null; + while(con == null){ + try { + con = ds.getConnection(); + } catch (SQLException ce) { + return null; + } + } + return con; + } + + private synchronized Connection getConnection() { + Connection con; + con = getRawConnection(); + if(con == null){ + ds.close(); + ConsoleLogger.showError("Database connection is LOST! SHUTDOWN..."); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + } + return con; + } + + private synchronized void setupConnection() throws SQLException { Connection con = null; Statement st = null; ResultSet rs = null; try { - con = getConnection(); + con = getRawConnection(); + if(con == null){ + ds.close(); + if (Settings.isStopEnabled) { + ConsoleLogger.showError("Can't connect to the SQLite database... Please check your database settings in the config.yml file! SHUTDOWN..."); + AuthMe.getInstance().getServer().shutdown(); + } else { + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } + return; + } st = con.createStatement(); st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" + columnID + " INTEGER AUTO_INCREMENT," + columnName + " VARCHAR(255) NOT NULL UNIQUE," + columnPassword + " VARCHAR(255) NOT NULL," + columnIp + " VARCHAR(40) NOT NULL," + columnLastLogin + " BIGINT," + lastlocX + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocY + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocZ + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocWorld + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," + columnEmail + " VARCHAR(255) DEFAULT 'your@email.com'," + "CONSTRAINT table_const_prim PRIMARY KEY (" + columnID + "));"); rs = con.getMetaData().getColumns(null, null, tableName, columnPassword); @@ -166,14 +227,6 @@ public class SQLite_HIKARI implements DataSource { ConsoleLogger.info("SQLite Setup finished"); } - private void close(Connection con) { - try { - if (con != null) - con.close(); - } catch (Exception e) { - } - } - @Override public synchronized boolean isAuthAvailable(String user) { Connection con = null; @@ -185,7 +238,7 @@ public class SQLite_HIKARI implements DataSource { pst.setString(1, user); rs = pst.executeQuery(); return rs.next(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -218,7 +271,7 @@ public class SQLite_HIKARI implements DataSource { } else { return null; } - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return null; } finally { @@ -230,8 +283,8 @@ public class SQLite_HIKARI implements DataSource { @Override public synchronized boolean saveAuth(PlayerAuth auth) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); if (columnSalt.isEmpty() && auth.getSalt().isEmpty()) { @@ -252,7 +305,7 @@ public class SQLite_HIKARI implements DataSource { pst.setString(6, auth.getRealName()); pst.executeUpdate(); } - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -272,7 +325,7 @@ public class SQLite_HIKARI implements DataSource { pst.setString(1, auth.getHash()); pst.setString(2, auth.getNickname()); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -294,7 +347,7 @@ public class SQLite_HIKARI implements DataSource { pst.setString(3, auth.getRealName()); pst.setString(4, auth.getNickname()); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -313,7 +366,7 @@ public class SQLite_HIKARI implements DataSource { pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + columnLastLogin + "(); } finally { @@ -349,14 +402,14 @@ public class SQLite_HIKARI implements DataSource { @Override public synchronized boolean removeAuth(String user) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + columnName + "=?;"); pst.setString(1, user); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -368,8 +421,8 @@ public class SQLite_HIKARI implements DataSource { @Override public boolean updateQuitLoc(PlayerAuth auth) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + lastlocX + "=?, " + lastlocY + "=?, " + lastlocZ + "=?, " + lastlocWorld + "=? WHERE " + columnName + "=?;"); @@ -379,7 +432,7 @@ public class SQLite_HIKARI implements DataSource { pst.setString(4, auth.getWorld()); pst.setString(5, auth.getNickname()); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -391,9 +444,9 @@ public class SQLite_HIKARI implements DataSource { @Override public int getIps(String ip) { + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; int countIp = 0; try { con = getConnection(); @@ -404,7 +457,7 @@ public class SQLite_HIKARI implements DataSource { countIp++; } return countIp; - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return 0; } finally { @@ -416,15 +469,15 @@ public class SQLite_HIKARI implements DataSource { @Override public boolean updateEmail(PlayerAuth auth) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnEmail + "=? WHERE " + columnName + "=?;"); pst.setString(1, auth.getEmail()); pst.setString(2, auth.getNickname()); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -447,7 +500,7 @@ public class SQLite_HIKARI implements DataSource { pst.setString(1, auth.getSalt()); pst.setString(2, auth.getNickname()); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -457,56 +510,11 @@ public class SQLite_HIKARI implements DataSource { return true; } - @Override - public synchronized void close() { - try { - if (ds != null) - ds.close(); - } catch (Exception e) { - } - } - - @Override - public void reload() { - try { - connect(); - setup(); - } catch (Exception e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't reconnect to SQLite database... SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - } - - private void close(Statement st) { - if (st != null) { - try { - st.close(); - } catch (SQLException ex) { - ConsoleLogger.showError(ex.getMessage()); - } - } - } - - private void close(ResultSet rs) { - if (rs != null) { - try { - rs.close(); - } catch (SQLException ex) { - ConsoleLogger.showError(ex.getMessage()); - } - } - } - @Override public List getAllAuthsByName(PlayerAuth auth) { + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; List countIp = new ArrayList(); try { con = getConnection(); @@ -517,11 +525,11 @@ public class SQLite_HIKARI implements DataSource { countIp.add(rs.getString(columnName)); } return countIp; - } catch (NullPointerException ex) { - return new ArrayList(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return new ArrayList(); + } catch (NullPointerException npe) { + return new ArrayList(); } finally { close(rs); close(pst); @@ -531,9 +539,9 @@ public class SQLite_HIKARI implements DataSource { @Override public List getAllAuthsByIp(String ip) { + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; List countIp = new ArrayList(); try { con = getConnection(); @@ -544,11 +552,11 @@ public class SQLite_HIKARI implements DataSource { countIp.add(rs.getString(columnName)); } return countIp; - } catch (NullPointerException ex) { - return new ArrayList(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return new ArrayList(); + } catch (NullPointerException npe) { + return new ArrayList(); } finally { close(rs); close(pst); @@ -558,9 +566,9 @@ public class SQLite_HIKARI implements DataSource { @Override public List getAllAuthsByEmail(String email) { + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; List countEmail = new ArrayList(); try { con = getConnection(); @@ -571,11 +579,11 @@ public class SQLite_HIKARI implements DataSource { countEmail.add(rs.getString(columnName)); } return countEmail; - } catch (NullPointerException ex) { - return new ArrayList(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return new ArrayList(); + } catch (NullPointerException npe) { + return new ArrayList(); } finally { close(rs); close(pst); @@ -585,8 +593,8 @@ public class SQLite_HIKARI implements DataSource { @Override public void purgeBanned(List banned) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); for (String name : banned) { @@ -594,7 +602,7 @@ public class SQLite_HIKARI implements DataSource { pst.setString(1, name); pst.executeUpdate(); } - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); } finally { close(pst); @@ -602,16 +610,11 @@ public class SQLite_HIKARI implements DataSource { } } - @Override - public DataSourceType getType() { - return DataSourceType.SQLITE; - } - @Override public boolean isLogged(String user) { + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + columnName + ")=?;"); @@ -619,7 +622,7 @@ public class SQLite_HIKARI implements DataSource { rs = pst.executeQuery(); if (rs.next()) return (rs.getInt(columnLogged) == 1); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { @@ -632,15 +635,15 @@ public class SQLite_HIKARI implements DataSource { @Override public void setLogged(String user) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnLogged + "=? WHERE LOWER(" + columnName + ")=?;"); pst.setInt(1, 1); pst.setString(2, user); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return; } finally { @@ -652,8 +655,8 @@ public class SQLite_HIKARI implements DataSource { @Override public void setUnlogged(String user) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; if (user != null) try { con = getConnection(); @@ -661,7 +664,7 @@ public class SQLite_HIKARI implements DataSource { pst.setInt(1, 0); pst.setString(2, user); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return; } finally { @@ -673,15 +676,15 @@ public class SQLite_HIKARI implements DataSource { @Override public void purgeLogged() { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnLogged + "=? WHERE " + columnLogged + "=?;"); pst.setInt(1, 0); pst.setInt(2, 1); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return; } finally { @@ -693,10 +696,10 @@ public class SQLite_HIKARI implements DataSource { @Override public int getAccountsRegistered() { - int result = 0; + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; + int result = 0; try { con = getConnection(); pst = con.prepareStatement("SELECT COUNT(*) FROM " + tableName + ";"); @@ -704,7 +707,7 @@ public class SQLite_HIKARI implements DataSource { if (rs != null && rs.next()) { result = rs.getInt(1); } - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return result; } finally { @@ -716,15 +719,15 @@ public class SQLite_HIKARI implements DataSource { @Override public void updateName(String oldone, String newone) { - PreparedStatement pst = null; Connection con = null; + PreparedStatement pst = null; try { con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnName + "=? WHERE " + columnName + "=?;"); pst.setString(1, newone); pst.setString(2, oldone); pst.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return; } finally { @@ -736,10 +739,10 @@ public class SQLite_HIKARI implements DataSource { @Override public List getAllAuths() { - List auths = new ArrayList(); + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; + List auths = new ArrayList(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + ";"); @@ -758,7 +761,7 @@ public class SQLite_HIKARI implements DataSource { if (pAuth != null) auths.add(pAuth); } - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return auths; } finally { @@ -770,10 +773,10 @@ public class SQLite_HIKARI implements DataSource { @Override public List getLoggedPlayers() { - List auths = new ArrayList(); + Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - Connection con = null; + List auths = new ArrayList(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); @@ -792,7 +795,7 @@ public class SQLite_HIKARI implements DataSource { if (pAuth != null) auths.add(pAuth); } - } catch (Exception ex) { + } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); return auths; } finally { @@ -801,4 +804,47 @@ public class SQLite_HIKARI implements DataSource { } return auths; } + + @Override + public void reload() { + } + + @Override + public synchronized void close() { + try { + if (ds != null) + ds.close(); + } catch (Exception e) { + } + } + + private void close(Statement st) { + if (st != null) { + try { + st.close(); + } catch (Exception ex) { + ConsoleLogger.showError(ex.getMessage()); + } + } + } + + private void close(ResultSet rs) { + if (rs != null) { + try { + rs.close(); + } catch (Exception ex) { + ConsoleLogger.showError(ex.getMessage()); + } + } + } + + private void close(Connection con) { + if (con != null) { + try { + con.close(); + } catch (Exception ex) { + ConsoleLogger.showError(ex.getMessage()); + } + } + } } diff --git a/src/main/java/fr/xephi/authme/modules/ModuleManager.java b/src/main/java/fr/xephi/authme/modules/ModuleManager.java index fc1d07f62..25c750b38 100644 --- a/src/main/java/fr/xephi/authme/modules/ModuleManager.java +++ b/src/main/java/fr/xephi/authme/modules/ModuleManager.java @@ -48,9 +48,11 @@ public class ModuleManager implements Module { @Override public boolean load() { File dir = new File(plugin.getDataFolder() + File.separator + "modules"); - if (dir == null || !dir.exists() || !dir.isDirectory() || dir.listFiles() == null || dir.listFiles().length <= 0) + String[] files = dir.list(); + if (files == null || files.length == 0){ return false; - for (File pathToJar : dir.listFiles()) { + } + for (File pathToJar : dir.listFiles()) { // FindBugs: "possible null pointers" O_o ? JarFile jarFile = null; try { jarFile = new JarFile(pathToJar); From 1e52cd0c30e23c63bd8c683828686f17127896d9 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 27 Aug 2015 00:39:54 +0100 Subject: [PATCH 005/115] Changed to HikariCP-Log4j --- .../HikariCP-Log4J-2.4.2-SNAPSHOT.jar | Bin 0 -> 125868 bytes .../HikariCP-Log4J-2.4.2-SNAPSHOT.pom | 443 ++++++++++++++++++ pom.xml | 30 +- 3 files changed, 454 insertions(+), 19 deletions(-) create mode 100644 localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.jar create mode 100644 localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom diff --git a/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.jar b/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..4d9c1be988b81e0dacbb271ec60a81e13dd1714a GIT binary patch literal 125868 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

bQAgg9@JTNAD_- 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

{O+` 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υuH<9|^0jzN~S*|u<{ZQFKM+O}=mHY#n~wr$(C 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 literal 0 HcmV?d00001 diff --git a/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom b/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom new file mode 100644 index 000000000..4479ed0f2 --- /dev/null +++ b/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom @@ -0,0 +1,443 @@ + + 4.0.0 + + com.zaxxer + HikariCP-Log4j + 2.4.2-SNAPSHOT + bundle + + HikariCP-Log4J + Ultimate JDBC Connection Pool [Log4j Version] + https://github.com/brettwooldridge/HikariCP + + + Zaxxer.com + https://github.com/brettwooldridge + + + + scm:git:git@github.com:brettwooldridge/HikariCP.git + scm:git:git@github.com:brettwooldridge/HikariCP.git + git@github.com:brettwooldridge/HikariCP.git + HEAD + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + Brett Wooldridge + brett.wooldridge@gmail.com + + + + + UTF-8 + 4.3.9.Final + 3.18.2-GA + 0.11.4.1 + 3.1.2 + 1.10.19 + 4.5.0 + 2.4.1 + 1.7.12 + 2.5.3 + 5.0.0 + 2.3 + + + + org.sonatype.oss + oss-parent + 7 + + + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + compile + true + + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + compile + true + + + org.mockito + mockito-all + ${mockito.version} + test + + + org.javassist + javassist + ${javassist.version} + true + + + org.hibernate + hibernate-core + ${hibernate.version} + provided + true + + + io.dropwizard.metrics + metrics-core + ${metrics.version} + provided + true + + + io.dropwizard.metrics + metrics-healthchecks + ${metrics.version} + provided + true + + + simple-jndi + simple-jndi + ${jndi.version} + test + + + + + javax.inject + javax.inject + 1 + test + + + org.apache.felix + org.apache.felix.framework + ${felix.version} + test + + + org.ops4j.pax.exam + pax-exam-container-native + ${pax.exam.version} + test + + + org.ops4j.pax.exam + pax-exam-junit4 + ${pax.exam.version} + test + + + org.ops4j.pax.exam + pax-exam-link-mvn + ${pax.exam.version} + test + + + org.ops4j.pax.url + pax-url-aether + ${pax.url.version} + test + + + org.ops4j.pax.url + pax-url-reference + ${pax.url.version} + test + + + + + ${project.name}-${project.version} + + + + org.codehaus.mojo + exec-maven-plugin + 1.4.0 + + + compile + + + java + + + + + com.zaxxer.hikari.proxy.JavassistProxyFactory + + + + + org.jacoco + jacoco-maven-plugin + 0.7.4.201502262128 + + + + pre-unit-test + + prepare-agent + + + + ${project.build.directory}/coverage-reports/jacoco.exec + + surefireArgLine + + **/com/zaxxer/hikari/proxy/** + **/com/zaxxer/hikari/metrics/** + + + + + + post-unit-test + test + + report + + + + ${project.build.directory}/coverage-reports/jacoco.exec + + ${project.reporting.outputDirectory}/jacoco + + **/com/zaxxer/hikari/proxy/** + **/com/zaxxer/hikari/metrics/** + + + + + + + + org.apache.felix + maven-bundle-plugin + ${felix.bundle.plugin.version} + true + + + HikariCP + + com.zaxxer.hikari, + com.zaxxer.hikari.hibernate, + com.zaxxer.hikari.metrics + + com.zaxxer.hikari.* + <_exportcontents> + com.zaxxer.hikari.pool, + com.zaxxer.hikari.util, + com.zaxxer.hikari.proxy + + + javax.management, + javax.naming, + javax.naming.spi, + javax.sql, + javax.sql.rowset, + javax.sql.rowset.serial, + javax.sql.rowset.spi, + com.codahale.metrics;resolution:=optional, + com.codahale.metrics.health;resolution:=optional, + org.slf4j;version="[1.6,2)", + org.hibernate;resolution:=optional, + org.hibernate.cfg;resolution:=optional, + org.hibernate.engine.jdbc.connections.spi;resolution:=optional, + org.hibernate.service;resolution:=optional, + org.hibernate.service.spi;resolution:=optional + + ${project.groupId}.${project.artifactId} + * + + + + + + + manifest + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + true + + 1.7 + 1.7 + + + + + org.apache.maven.plugins + maven-release-plugin + 2.5 + + true + HikariCP-@{project.version} + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + ${surefireArgLine} + + ${skip.unit.tests} + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + true + + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + public + + true + 1024m + + + + bundle-sources + package + + jar + + + + + + + + + + + coverage + + + + org.eluder.coveralls + coveralls-maven-plugin + 3.1.0 + + + coveralls + verify + + jacoco + + false + + + + + + + + + release-sign-artifacts + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + + felix + + true + + pax.exam.framework + felix + + + + felix + none + + + + org.apache.felix + org.apache.felix.framework + ${felix.version} + test + + + + + diff --git a/pom.xml b/pom.xml index e02a3baeb..f3b276c17 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,6 @@ com.comphenix.attribute:* org.mcstats.*:* com.zaxxer:* - org.slf4j:* @@ -164,6 +163,12 @@ http://repo.mcstats.org/content/repositories/snapshots/ + + + local-repo + file://${basedir}/localrepo + + @@ -171,21 +176,10 @@ - - mysql - mysql-connector-java - 5.1.36 - - - org.slf4j - slf4j-simple - 1.7.12 - compile - com.zaxxer - HikariCP - 2.4.1 + HikariCP-Log4j + 2.4.2-SNAPSHOT compile @@ -193,8 +187,8 @@ slf4j-api - org.slf4j - slf4j-simple + org.apache.logging.log4j + log4j-core @@ -557,9 +551,7 @@ simplechestlock - - com.webkonsept.bukkit.simplechestlock - + com.webkonsept.bukkit.simplechestlock commandbook From 6545ad3aea4b3b9a35a3af33817852189d76bcac Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 4 Sep 2015 19:49:33 +0200 Subject: [PATCH 006/115] slf4j log4j implementation enhancement --- pom.xml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pom.xml b/pom.xml index f3b276c17..390d04eeb 100644 --- a/pom.xml +++ b/pom.xml @@ -176,6 +176,32 @@ + + org.slf4j + slf4j-api + 1.7.12 + compile + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.0.3 + compile + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + compile + true + + com.zaxxer HikariCP-Log4j From 1f66a7474d5cf5f83295bfe98415329bc873dcf6 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 5 Sep 2015 00:45:48 +0200 Subject: [PATCH 007/115] Stuff! + HikariCP Log4J --- .../HikariCP-Log4J-2.4.2-SNAPSHOT.jar | Bin 125868 -> 0 bytes .../HikariCP-Log4J-2.4.2-SNAPSHOT.pom | 443 ------------------ pom.xml | 69 ++- .../java/fr/xephi/authme/DataManager.java | 11 +- .../fr/xephi/authme/settings/Messages.java | 13 +- .../fr/xephi/authme/settings/Settings.java | 2 +- .../resources/{ => messages}/messages_bg.yml | 0 .../resources/{ => messages}/messages_br.yml | 0 .../resources/{ => messages}/messages_cz.yml | 0 .../resources/{ => messages}/messages_de.yml | 0 .../resources/{ => messages}/messages_en.yml | 0 .../resources/{ => messages}/messages_es.yml | 0 .../resources/{ => messages}/messages_eu.yml | 0 .../resources/{ => messages}/messages_fi.yml | 0 .../resources/{ => messages}/messages_fr.yml | 0 .../resources/{ => messages}/messages_gl.yml | 0 .../resources/{ => messages}/messages_hu.yml | 0 .../resources/{ => messages}/messages_it.yml | 0 .../resources/{ => messages}/messages_ko.yml | 0 .../resources/{ => messages}/messages_lt.yml | 0 .../resources/{ => messages}/messages_nl.yml | 0 .../resources/{ => messages}/messages_pl.yml | 0 .../resources/{ => messages}/messages_pt.yml | 0 .../resources/{ => messages}/messages_ru.yml | 116 ++--- .../resources/{ => messages}/messages_sk.yml | 0 .../resources/{ => messages}/messages_tr.yml | 0 .../resources/{ => messages}/messages_uk.yml | 0 .../resources/{ => messages}/messages_vn.yml | 116 ++--- .../{ => messages}/messages_zhcn.yml | Bin .../{ => messages}/messages_zhhk.yml | 122 ++--- .../{ => messages}/messages_zhtw.yml | 122 ++--- 31 files changed, 279 insertions(+), 735 deletions(-) delete mode 100644 localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.jar delete mode 100644 localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom rename src/main/resources/{ => messages}/messages_bg.yml (100%) rename src/main/resources/{ => messages}/messages_br.yml (100%) rename src/main/resources/{ => messages}/messages_cz.yml (100%) rename src/main/resources/{ => messages}/messages_de.yml (100%) rename src/main/resources/{ => messages}/messages_en.yml (100%) rename src/main/resources/{ => messages}/messages_es.yml (100%) rename src/main/resources/{ => messages}/messages_eu.yml (100%) rename src/main/resources/{ => messages}/messages_fi.yml (100%) rename src/main/resources/{ => messages}/messages_fr.yml (100%) rename src/main/resources/{ => messages}/messages_gl.yml (100%) rename src/main/resources/{ => messages}/messages_hu.yml (100%) rename src/main/resources/{ => messages}/messages_it.yml (100%) rename src/main/resources/{ => messages}/messages_ko.yml (100%) rename src/main/resources/{ => messages}/messages_lt.yml (100%) rename src/main/resources/{ => messages}/messages_nl.yml (100%) rename src/main/resources/{ => messages}/messages_pl.yml (100%) rename src/main/resources/{ => messages}/messages_pt.yml (100%) rename src/main/resources/{ => messages}/messages_ru.yml (98%) rename src/main/resources/{ => messages}/messages_sk.yml (100%) rename src/main/resources/{ => messages}/messages_tr.yml (100%) rename src/main/resources/{ => messages}/messages_uk.yml (100%) rename src/main/resources/{ => messages}/messages_vn.yml (98%) rename src/main/resources/{ => messages}/messages_zhcn.yml (100%) rename src/main/resources/{ => messages}/messages_zhhk.yml (98%) rename src/main/resources/{ => messages}/messages_zhtw.yml (98%) diff --git a/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.jar b/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.jar deleted file mode 100644 index 4d9c1be988b81e0dacbb271ec60a81e13dd1714a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125868 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

bQAgg9@JTNAD_- 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 #####Sponsor -GameHosting.it is leader in Italy in Game Server Provider. With its own DataCenter offers Anti-DDoS solutions at affordable prices. Game Server of Minecraft based on Multicraft are equipped with the latest technology in hardware. +GameHosting.it is leader in Italy as Game Server Provider. With its own DataCenter offers Anti-DDoS solutions at affordable prices. Game Server of Minecraft based on Multicraft are equipped with the latest technology in hardware. [![GameHosting](http://www.gamehosting.it/images/bn3.png)](http://www.gamehosting.it) #####Credits From 84b5dcc62583f0827988413c74d95931b3f6fa4c Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Mon, 7 Sep 2015 14:05:50 +0200 Subject: [PATCH 017/115] Cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 3 +- .../fr/xephi/authme/datasource/MySQL.java | 10 +--- .../authme/datasource/SQLite_HIKARI.java | 55 ++++++++----------- 3 files changed, 26 insertions(+), 42 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 131991dcf..353c96198 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -231,8 +231,9 @@ public class AuthMe extends JavaPlugin { dataManager = new DataManager(this); - // Setup API + // Setup the new API api = new NewAPI(this); + // Old deprecated API new API(this); // Setup Management diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 24e37dbcd..594d489f9 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -154,15 +154,9 @@ public class MySQL implements DataSource { ConsoleLogger.info("Hikari ConnectionPool arguments reloaded!"); } - private synchronized Connection getConnection() { + private synchronized Connection getConnection() throws SQLException { Connection con = null; - while(con == null){ - try { - con = ds.getConnection(); - } catch (SQLException ce) { - return null; - } - } + con = ds.getConnection(); return con; } diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java index 2b6ea3869..9ac800553 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java @@ -100,7 +100,7 @@ public class SQLite_HIKARI implements DataSource { this.setupConnection(); } catch (SQLException e) { ConsoleLogger.showError(e.getMessage()); - ConsoleLogger.showError("Can't initialize the MySQL database... Please check your database settings in the config.yml file! SHUTDOWN..."); + ConsoleLogger.showError("Can't initialize the SQLite database... Please check your database settings in the config.yml file! SHUTDOWN..."); ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); this.close(); if (Settings.isStopEnabled) { @@ -133,30 +133,18 @@ public class SQLite_HIKARI implements DataSource { ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); } - private synchronized Connection getRawConnection() { - Connection con = null; - while(con == null){ - try { - con = ds.getConnection(); - } catch (SQLException ce) { - return null; - } + private synchronized void reloadArguments() + throws ClassNotFoundException, IllegalArgumentException { + if (ds != null){ + ds.close(); } - return con; + setConnectionArguments(); + ConsoleLogger.info("Hikari ConnectionPool arguments reloaded!"); } - private synchronized Connection getConnection() { - Connection con; - con = getRawConnection(); - if(con == null){ - ds.close(); - ConsoleLogger.showError("Database connection is LOST! SHUTDOWN..."); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - } + private synchronized Connection getConnection() throws SQLException { + Connection con = null; + con = ds.getConnection(); return con; } @@ -165,17 +153,7 @@ public class SQLite_HIKARI implements DataSource { Statement st = null; ResultSet rs = null; try { - con = getRawConnection(); - if(con == null){ - ds.close(); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't connect to the SQLite database... Please check your database settings in the config.yml file! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - return; - } + con = getConnection(); st = con.createStatement(); st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" + columnID + " INTEGER AUTO_INCREMENT," + columnName + " VARCHAR(255) NOT NULL UNIQUE," + columnPassword + " VARCHAR(255) NOT NULL," + columnIp + " VARCHAR(40) NOT NULL," + columnLastLogin + " BIGINT," + lastlocX + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocY + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocZ + " DOUBLE NOT NULL DEFAULT '0.0'," + lastlocWorld + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," + columnEmail + " VARCHAR(255) DEFAULT 'your@email.com'," + "CONSTRAINT table_const_prim PRIMARY KEY (" + columnID + "));"); rs = con.getMetaData().getColumns(null, null, tableName, columnPassword); @@ -807,6 +785,17 @@ public class SQLite_HIKARI implements DataSource { @Override public void reload() { + try { + reloadArguments(); + } catch (Exception e) { + ConsoleLogger.showError(e.getMessage()); + ConsoleLogger.showError("Can't reconnect to SQLite database... Please check your SQLite informations ! SHUTDOWN..."); + if (Settings.isStopEnabled) { + AuthMe.getInstance().getServer().shutdown(); + } + if (!Settings.isStopEnabled) + AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + } } @Override From 65bb488f4cee61a60167f17bc723098867e68991 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Mon, 7 Sep 2015 14:30:56 +0200 Subject: [PATCH 018/115] PBKDF2DJANGO Hash --- .../xephi/authme/commands/AdminCommand.java | 3 ++ .../xephi/authme/security/HashAlgorithm.java | 1 + .../authme/security/crypts/CryptPBKDF2.java | 13 ++++---- .../security/crypts/CryptPBKDF2Django.java | 32 +++++++++++++++++++ src/main/resources/config.yml | 2 +- 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 1cc04829b..76269f8fd 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -520,6 +520,7 @@ public class AdminCommand implements CommandExecutor { m.send(sender, "error"); return true; } + @SuppressWarnings("deprecation") Player target = Bukkit.getPlayer(name); PlayerCache.getInstance().removePlayer(name); Utils.getInstance().setGroup(name, groupType.UNREGISTERED); @@ -602,6 +603,7 @@ public class AdminCommand implements CommandExecutor { sender.sendMessage("Usage: /authme getip "); return true; } + @SuppressWarnings("deprecation") Player player = Bukkit.getPlayer(args[1]); if (player == null) { sender.sendMessage("This player is not actually online"); @@ -617,6 +619,7 @@ public class AdminCommand implements CommandExecutor { return true; } try { + @SuppressWarnings("deprecation") Player player = Bukkit.getPlayer(args[1]); if (player == null || !player.isOnline()) { sender.sendMessage("Player needs to be online!"); diff --git a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java index 312b6df01..935c9c1c1 100644 --- a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java +++ b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java @@ -25,6 +25,7 @@ public enum HashAlgorithm { SHA512(fr.xephi.authme.security.crypts.SHA512.class), DOUBLEMD5(fr.xephi.authme.security.crypts.DOUBLEMD5.class), PBKDF2(fr.xephi.authme.security.crypts.CryptPBKDF2.class), + PBKDF2DJANGO(fr.xephi.authme.security.crypts.CryptPBKDF2Django.class), WORDPRESS(fr.xephi.authme.security.crypts.WORDPRESS.class), ROYALAUTH(fr.xephi.authme.security.crypts.ROYALAUTH.class), CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class), diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java index 7e672ea79..2914e47c8 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java @@ -4,18 +4,17 @@ import java.security.NoSuchAlgorithmException; import fr.xephi.authme.security.pbkdf2.PBKDF2Engine; import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters; -import javax.xml.bind.DatatypeConverter; public class CryptPBKDF2 implements EncryptionMethod { @Override public String getHash(String password, String salt, String name) throws NoSuchAlgorithmException { - String result = "pbkdf2_sha256$15000$" + salt + "$"; - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000); + String result = "pbkdf2_sha256$10000$" + salt + "$"; + PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000); PBKDF2Engine engine = new PBKDF2Engine(params); - return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32))); + return result + String.valueOf(engine.deriveKey(password, 64)); } @Override @@ -23,10 +22,10 @@ public class CryptPBKDF2 implements EncryptionMethod { String playerName) throws NoSuchAlgorithmException { String[] line = hash.split("\\$"); String salt = line[2]; - byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]); - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000, derivedKey); + String derivedKey = line[3]; + PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000, derivedKey.getBytes()); PBKDF2Engine engine = new PBKDF2Engine(params); return engine.verifyKey(password); } -} +} \ No newline at end of file diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java new file mode 100644 index 000000000..fc9986649 --- /dev/null +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java @@ -0,0 +1,32 @@ +package fr.xephi.authme.security.crypts; + +import java.security.NoSuchAlgorithmException; + +import fr.xephi.authme.security.pbkdf2.PBKDF2Engine; +import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters; +import javax.xml.bind.DatatypeConverter; + +public class CryptPBKDF2Django implements EncryptionMethod { + + @Override + public String getHash(String password, String salt, String name) + throws NoSuchAlgorithmException { + String result = "pbkdf2_sha256$15000$" + salt + "$"; + PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000); + PBKDF2Engine engine = new PBKDF2Engine(params); + + return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32))); + } + + @Override + public boolean comparePassword(String hash, String password, + String playerName) throws NoSuchAlgorithmException { + String[] line = hash.split("\\$"); + String salt = line[2]; + byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]); + PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000, derivedKey); + PBKDF2Engine engine = new PBKDF2Engine(params); + return engine.verifyKey(password); + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 89f16d2c2..768ce22f3 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -200,7 +200,7 @@ settings: # possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB, # PLAINTEXT ( unhashed password), # MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512, - # DOUBLEMD5, PBKDF2, WORDPRESS, ROYALAUTH, CUSTOM(for developpers only) + # DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM(for developpers only) passwordHash: SHA256 # salt length for the SALTED2MD5 MD5(MD5(password)+salt) doubleMD5SaltLength: 8 From 7a82bb7ba8366c27d4c3f33105d62f70d59dbbed Mon Sep 17 00:00:00 2001 From: "Gabriele C." Date: Mon, 7 Sep 2015 15:41:22 +0200 Subject: [PATCH 019/115] Update team.txt --- team.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/team.txt b/team.txt index 634bcee58..e5ac3a1a6 100644 --- a/team.txt +++ b/team.txt @@ -3,6 +3,7 @@ AuthMe-Team: Xephi (Xephi59) - Leader, Main developer darkwarriors (d4rkwarriors) - Old AuthMe Reloaded Author Kloudy - Developer (Inactive, Will be avariable soon) +DNx5 - Developer Gabriele C. (sgdc3) - Ticket Manager, Project Page and Structure Manager, Contributor Maxetto - Ticket Manager, Italian Translator, Basic Developer, Contributor Gnat008 - Contributor From 90c7187babc32b4f38a1a4b77c390e2aea199f66 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 7 Sep 2015 23:28:15 +0700 Subject: [PATCH 020/115] run task async, fix #200 --- .../commands/ChangePasswordCommand.java | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java b/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java index 7577a2029..0b50da50f 100644 --- a/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java +++ b/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java @@ -25,8 +25,8 @@ public class ChangePasswordCommand implements CommandExecutor { } @Override - public boolean onCommand(CommandSender sender, Command cmnd, String label, - String[] args) { + public boolean onCommand(final CommandSender sender, Command cmnd, String label, + final String[] args) { if (!(sender instanceof Player)) { return true; } @@ -36,8 +36,8 @@ public class ChangePasswordCommand implements CommandExecutor { return true; } - Player player = (Player) sender; - String name = player.getName().toLowerCase(); + final Player player = (Player) sender; + final String name = player.getName().toLowerCase(); if (!PlayerCache.getInstance().isAuthenticated(name)) { m.send(player, "not_logged_in"); return true; @@ -67,30 +67,35 @@ public class ChangePasswordCommand implements CommandExecutor { return true; } } - try { - String hashnew = PasswordSecurity.getHash(Settings.getPasswordHash, args[1], name); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { + @Override + public void run() { + try { + String hashnew = PasswordSecurity.getHash(Settings.getPasswordHash, args[1], name); - if (PasswordSecurity.comparePasswordWithHash(args[0], PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) { - PlayerAuth auth = PlayerCache.getInstance().getAuth(name); - auth.setHash(hashnew); - if (PasswordSecurity.userSalt.containsKey(name) && PasswordSecurity.userSalt.get(name) != null) - auth.setSalt(PasswordSecurity.userSalt.get(name)); - else auth.setSalt(""); - if (!plugin.database.updatePassword(auth)) { - m.send(player, "error"); - return true; + if (PasswordSecurity.comparePasswordWithHash(args[0], PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) { + PlayerAuth auth = PlayerCache.getInstance().getAuth(name); + auth.setHash(hashnew); + if (PasswordSecurity.userSalt.containsKey(name) && PasswordSecurity.userSalt.get(name) != null) + auth.setSalt(PasswordSecurity.userSalt.get(name)); + else auth.setSalt(""); + if (!plugin.database.updatePassword(auth)) { + m.send(player, "error"); + return; + } + plugin.database.updateSalt(auth); + PlayerCache.getInstance().updatePlayer(auth); + m.send(player, "pwd_changed"); + ConsoleLogger.info(player.getName() + " changed his password"); + } else { + m.send(player, "wrong_pwd"); + } + } catch (NoSuchAlgorithmException ex) { + ConsoleLogger.showError(ex.getMessage()); + m.send(sender, "error"); } - plugin.database.updateSalt(auth); - PlayerCache.getInstance().updatePlayer(auth); - m.send(player, "pwd_changed"); - ConsoleLogger.info(player.getName() + " changed his password"); - } else { - m.send(player, "wrong_pwd"); } - } catch (NoSuchAlgorithmException ex) { - ConsoleLogger.showError(ex.getMessage()); - m.send(sender, "error"); - } + }); return true; } } From c0eb15ee49b26bce18be0a78487d4df325691699 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Mon, 7 Sep 2015 20:38:29 +0200 Subject: [PATCH 021/115] Cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 14 +++++++++++--- src/main/java/fr/xephi/authme/ConsoleLogger.java | 2 +- .../fr/xephi/authme/datasource/DataSource.java | 3 ++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index ff8a6babb..38a485fca 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -61,6 +61,7 @@ import fr.xephi.authme.datasource.DatabaseCalls; import fr.xephi.authme.datasource.FlatFile; import fr.xephi.authme.datasource.MySQL; import fr.xephi.authme.datasource.SQLite; +import fr.xephi.authme.datasource.SQLite_HIKARI; import fr.xephi.authme.listener.AuthMeBlockListener; import fr.xephi.authme.listener.AuthMeChestShopListener; import fr.xephi.authme.listener.AuthMeEntityListener; @@ -307,9 +308,10 @@ public class AuthMe extends JavaPlugin { // Start Email recall task if needed recallEmail(); - // Sponsor message + // Sponsor messages ConsoleLogger.info("AuthMe hooks perfectly with the VERYGAMES server hosting!"); - ConsoleLogger.info("Development builds are available on our jenkins, thanks to our sponsor GameHosting.it - leader in Italy as Game Server Provider"); + ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt."); + ConsoleLogger.info("Do you want a good gameserver? Look at our sponsor GameHosting.it leader in Italy as Game Server Provider!"); ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!"); } @@ -816,7 +818,7 @@ public class AuthMe extends JavaPlugin { public void setupDatabase() throws ClassNotFoundException, PoolInitializationException, SQLException { /* - * Backend MYSQL - FILE - SQLITE + * Backend MYSQL - FILE - SQLITE - SQLITEHIKARI */ switch (Settings.getDataSource) { case FILE: @@ -831,6 +833,12 @@ public class AuthMe extends JavaPlugin { if (b >= 4000) ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + b + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); break; + case SQLITEHIKARI: + database = new SQLite_HIKARI(); + final int b2 = database.getAccountsRegistered(); + if (b2 >= 8000) + ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + b2 + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); + break; } if (Settings.isCachingEnabled) { diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index 010b66192..84cad3386 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -33,7 +33,7 @@ public class ConsoleLogger { public static void showError(String message) { if (AuthMe.getInstance().isEnabled()) { - log.warning("[AuthMe] ERROR: " + message); + log.warning("[AuthMe] " + message); if (Settings.useLogging) { Calendar date = Calendar.getInstance(); final String actually = "[" + DateFormat.getDateInstance().format(date.getTime()) + ", " + date.get(Calendar.HOUR_OF_DAY) + ":" + date.get(Calendar.MINUTE) + ":" + date.get(Calendar.SECOND) + "] ERROR : " + message; diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index 41dc8923d..4592ec569 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -9,7 +9,8 @@ public interface DataSource { public enum DataSourceType { MYSQL, FILE, - SQLITE + SQLITE, + SQLITEHIKARI } boolean isAuthAvailable(String user); From e2b3c51cabed4beac60bb6fc22b7ed112042c64b Mon Sep 17 00:00:00 2001 From: "Gabriele C." Date: Tue, 8 Sep 2015 16:49:47 +0200 Subject: [PATCH 022/115] Update MySQL.java --- src/main/java/fr/xephi/authme/datasource/MySQL.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index a12bc3d25..9ffbf64ee 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -124,7 +124,8 @@ public class MySQL implements DataSource { throws ClassNotFoundException, IllegalArgumentException { HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeMYSQLPool"); - config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); + config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"); + config.setDriverClassName("com.mysql.jdbc.Driver"); config.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); config.setUsername(this.username); config.setPassword(this.password); From c1d56d5ee52286870ff7c1ba363b99f9d5e8e881 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 8 Sep 2015 17:33:52 +0200 Subject: [PATCH 023/115] Fix hikari for mysql and sqlite --- src/main/java/fr/xephi/authme/PerformBackup.java | 5 ++--- src/main/java/fr/xephi/authme/datasource/MySQL.java | 1 - src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java | 3 ++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/xephi/authme/PerformBackup.java b/src/main/java/fr/xephi/authme/PerformBackup.java index 71a69f04a..556ece3c9 100644 --- a/src/main/java/fr/xephi/authme/PerformBackup.java +++ b/src/main/java/fr/xephi/authme/PerformBackup.java @@ -35,13 +35,12 @@ public class PerformBackup { switch (Settings.getDataSource) { case FILE: return FileBackup("auths.db"); - case MYSQL: return MySqlBackup(); - case SQLITE: return FileBackup(Settings.getMySQLDatabase + ".db"); - + case SQLITEHIKARI: + return FileBackup(Settings.getMySQLDatabase + ".db"); } return false; diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 9ffbf64ee..e477ea4da 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -37,7 +37,6 @@ public class MySQL implements DataSource { private List columnOthers; private HikariDataSource ds; private String columnRealName; - private Connection connection; public MySQL() throws ClassNotFoundException, SQLException, PoolInitializationException { this.host = Settings.getMySQLHost; diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java index 9ac800553..602dec5f8 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java @@ -122,7 +122,8 @@ public class SQLite_HIKARI implements DataSource { throws ClassNotFoundException, IllegalArgumentException { HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeSQLitePool"); - config.setDataSourceClassName("org.sqlite.SQLiteDataSource"); + config.setDriverClassName("org.sqlite.JDBC"); + config.setDataSourceClassName("org.sqlite.javax.SQLiteConnectionPoolDataSource"); config.setJdbcUrl("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable config.setConnectionTestQuery("SELECT 1"); From 46002b95e32b419d5137f76e35ed6069af6db9ed Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 8 Sep 2015 18:12:31 +0200 Subject: [PATCH 024/115] Cleanup --- src/main/java/fr/xephi/authme/modules/ModuleManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/modules/ModuleManager.java b/src/main/java/fr/xephi/authme/modules/ModuleManager.java index 25c750b38..87dabc53a 100644 --- a/src/main/java/fr/xephi/authme/modules/ModuleManager.java +++ b/src/main/java/fr/xephi/authme/modules/ModuleManager.java @@ -48,11 +48,11 @@ public class ModuleManager implements Module { @Override public boolean load() { File dir = new File(plugin.getDataFolder() + File.separator + "modules"); - String[] files = dir.list(); - if (files == null || files.length == 0){ + File[] files = dir.listFiles(); + if (files == null) { return false; } - for (File pathToJar : dir.listFiles()) { // FindBugs: "possible null pointers" O_o ? + for (File pathToJar : files) { JarFile jarFile = null; try { jarFile = new JarFile(pathToJar); From afeb359b73e684f97922f20752f9ad5362a1f924 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 9 Sep 2015 01:28:27 +0700 Subject: [PATCH 025/115] cleanup & improvements --- src/main/java/fr/xephi/authme/AuthMe.java | 128 +++++------------- .../java/fr/xephi/authme/ConsoleLogger.java | 4 + src/main/java/fr/xephi/authme/Utils.java | 39 ++++-- src/main/java/fr/xephi/authme/api/NewAPI.java | 12 +- .../xephi/authme/cache/backup/FileCache.java | 98 +++++--------- .../xephi/authme/cache/limbo/LimboCache.java | 9 +- .../commands/ChangePasswordCommand.java | 53 ++------ .../authme/listener/AuthMePlayerListener.java | 15 +- .../xephi/authme/task/ChangePasswordTask.java | 55 ++++++++ 9 files changed, 169 insertions(+), 244 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/task/ChangePasswordTask.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index ff8a6babb..71d7c7e83 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -79,7 +79,7 @@ import net.milkbowl.vault.permission.Permission; public class AuthMe extends JavaPlugin { - public DataSource database = null; + public DataSource database; private Settings settings; private Messages m; public OtherAccounts otherAccounts; @@ -177,9 +177,7 @@ public class AuthMe extends JavaPlugin { try { Class.forName("org.apache.logging.log4j.core.Filter"); setLog4JFilter(); - } catch (ClassNotFoundException e) { - ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled"); - } catch (NoClassDefFoundError e) { + } catch (ClassNotFoundException | NoClassDefFoundError e) { ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled"); } } @@ -218,13 +216,8 @@ public class AuthMe extends JavaPlugin { try { setupDatabase(); - } catch (ClassNotFoundException nfe) { - ConsoleLogger.showError("Fatal error occurred! Authme initialization ABORTED!"); - return; - } catch (SQLException sqle) { - ConsoleLogger.showError("Fatal error occurred! Authme initialization ABORTED!"); - return; - } catch (PoolInitializationException pie) { + } catch (ClassNotFoundException | SQLException | PoolInitializationException ex) { + ConsoleLogger.writeStackTrace(ex); ConsoleLogger.showError("Fatal error occurred! Authme initialization ABORTED!"); return; } @@ -274,25 +267,18 @@ public class AuthMe extends JavaPlugin { if (Settings.reloadSupport) { try { - int playersOnline = 0; - try { - if (Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).getReturnType() == Collection.class) - playersOnline = ((Collection) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).size(); - else playersOnline = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).length; - } catch (Exception ex) { - } - if (playersOnline < 1) { - try { + int playersOnline = Utils.getOnlinePlayers().length; + if (database != null) { + if (playersOnline < 1) { database.purgeLogged(); - } catch (NullPointerException npe) { - } - } else { - for (PlayerAuth auth : database.getLoggedPlayers()) { - if (auth == null) - continue; - auth.setLastLogin(new Date().getTime()); - database.updateSession(auth); - PlayerCache.getInstance().addPlayer(auth); + } else { + for (PlayerAuth auth : database.getLoggedPlayers()) { + if (auth == null) + continue; + auth.setLastLogin(new Date().getTime()); + database.updateSession(auth); + PlayerCache.getInstance().addPlayer(auth); + } } } } catch (Exception ex) { @@ -398,38 +384,27 @@ public class AuthMe extends JavaPlugin { multiverse = null; return; } - if (this.getServer().getPluginManager().getPlugin("Multiverse-Core") != null && this.getServer().getPluginManager().getPlugin("Multiverse-Core").isEnabled()) { + if (this.getServer().getPluginManager().isPluginEnabled("Multiverse-Core")) { try { multiverse = (MultiverseCore) this.getServer().getPluginManager().getPlugin("Multiverse-Core"); ConsoleLogger.info("Hooked correctly with Multiverse-Core"); - } catch (NullPointerException npe) { - multiverse = null; - } catch (ClassCastException cce) { - multiverse = null; - } catch (NoClassDefFoundError ncdfe) { - multiverse = null; + } catch (Exception | NoClassDefFoundError ignored) { } - } else { - multiverse = null; } } public void checkEssentials() { - if (this.getServer().getPluginManager().getPlugin("Essentials") != null && this.getServer().getPluginManager().getPlugin("Essentials").isEnabled()) { + if (this.getServer().getPluginManager().isPluginEnabled("Essentials")) { try { ess = (Essentials) this.getServer().getPluginManager().getPlugin("Essentials"); ConsoleLogger.info("Hooked correctly with Essentials"); - } catch (NullPointerException npe) { - ess = null; - } catch (ClassCastException cce) { - ess = null; - } catch (NoClassDefFoundError ncdfe) { + } catch (Exception | NoClassDefFoundError e) { ess = null; } } else { ess = null; } - if (this.getServer().getPluginManager().getPlugin("EssentialsSpawn") != null && this.getServer().getPluginManager().getPlugin("EssentialsSpawn").isEnabled()) { + if (this.getServer().getPluginManager().isPluginEnabled("EssentialsSpawn")) { try { essentialsSpawn = new EssSpawn().getLocation(); ConsoleLogger.info("Hooked correctly with EssentialsSpawn"); @@ -443,42 +418,24 @@ public class AuthMe extends JavaPlugin { } public void checkCombatTag() { - if (this.getServer().getPluginManager().getPlugin("CombatTag") != null && this.getServer().getPluginManager().getPlugin("CombatTag").isEnabled()) { - this.CombatTag = true; - } else { - this.CombatTag = false; - } + this.CombatTag = this.getServer().getPluginManager().isPluginEnabled("CombatTag"); } public void checkCitizens() { - if (this.getServer().getPluginManager().getPlugin("Citizens") != null && this.getServer().getPluginManager().getPlugin("Citizens").isEnabled()) - this.isCitizensActive = true; - else this.isCitizensActive = false; + this.isCitizensActive = this.getServer().getPluginManager().isPluginEnabled("Citizens"); } @Override public void onDisable() { - int playersOnline = 0; - try { - if (Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).getReturnType() == Collection.class) - playersOnline = ((Collection) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).size(); - else playersOnline = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).length; - } catch (NoSuchMethodException ex) { - } // can never happen - catch (InvocationTargetException ex) { - } // can also never happen - catch (IllegalAccessException ex) { - } // can still never happen - if (playersOnline != 0) - for (Player player : Bukkit.getOnlinePlayers()) { + Player[] players = Utils.getOnlinePlayers(); + if (players != null) { + for (Player player : players) { this.savePlayer(player); } + } if (database != null) { - try { - database.close(); - } catch (Exception e) { - } + database.close(); } if (Settings.isBackupActivated && Settings.isBackupOnStop) { @@ -495,11 +452,8 @@ public class AuthMe extends JavaPlugin { } public void savePlayer(Player player) { - try { - if ((citizens.isNPC(player)) || (Utils.getInstance().isUnrestricted(player)) || (CombatTagComunicator.isNPC(player))) { - return; - } - } catch (Exception e) { + if ((citizens.isNPC(player)) || (Utils.getInstance().isUnrestricted(player)) || (CombatTagComunicator.isNPC(player))) { + return; } try { String name = player.getName().toLowerCase(); @@ -509,7 +463,7 @@ public class AuthMe extends JavaPlugin { } if (LimboCache.getInstance().hasLimboPlayer(name)) { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); - if (Settings.protectInventoryBeforeLogInEnabled.booleanValue()) { + if (Settings.protectInventoryBeforeLogInEnabled) { player.getInventory().setArmorContents(limbo.getArmour()); player.getInventory().setContents(limbo.getInventory()); } @@ -728,18 +682,8 @@ public class AuthMe extends JavaPlugin { } public String replaceAllInfos(String message, Player player) { - int playersOnline = 0; - try { - if (Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).getReturnType() == Collection.class) - playersOnline = ((Collection) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).size(); - else playersOnline = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).length; - } catch (NoSuchMethodException ex) { - } // can never happen - catch (InvocationTargetException ex) { - } // can also never happen - catch (IllegalAccessException ex) { - } // can still never happen try { + int playersOnline = Utils.getOnlinePlayers().length; message = message.replace("&", "\u00a7"); message = message.replace("{PLAYER}", player.getName()); message = message.replace("{ONLINE}", "" + playersOnline); @@ -774,9 +718,7 @@ public class AuthMe extends JavaPlugin { if (ip.equalsIgnoreCase(getIP(player)) && database.isLogged(player.getName().toLowerCase()) && !player.getName().equalsIgnoreCase(name)) count++; } - if (count >= Settings.getMaxLoginPerIp) - return true; - return false; + return count >= Settings.getMaxLoginPerIp; } public boolean hasJoinedIp(String name, String ip) { @@ -785,14 +727,12 @@ public class AuthMe extends JavaPlugin { if (ip.equalsIgnoreCase(getIP(player)) && !player.getName().equalsIgnoreCase(name)) count++; } - if (count >= Settings.getMaxJoinPerIp) - return true; - return false; + return count >= Settings.getMaxJoinPerIp; } /** * Get Player real IP through VeryGames method - * + * * @param player * player */ diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index 010b66192..f455f9168 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -1,5 +1,6 @@ package fr.xephi.authme; +import com.google.common.base.Throwables; import fr.xephi.authme.settings.Settings; import org.bukkit.Bukkit; @@ -59,4 +60,7 @@ public class ConsoleLogger { } } + public static void writeStackTrace(Exception ex){ + writeLog(Throwables.getStackTraceAsString(ex)); + } } diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index c19754868..39d5bf554 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -1,18 +1,19 @@ package fr.xephi.authme; -import java.io.File; -import java.util.Iterator; - +import fr.xephi.authme.cache.limbo.LimboCache; +import fr.xephi.authme.cache.limbo.LimboPlayer; +import fr.xephi.authme.events.AuthMeTeleportEvent; +import fr.xephi.authme.settings.Settings; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; -import fr.xephi.authme.cache.limbo.LimboCache; -import fr.xephi.authme.cache.limbo.LimboPlayer; -import fr.xephi.authme.events.AuthMeTeleportEvent; -import fr.xephi.authme.settings.Settings; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Iterator; public class Utils { @@ -130,7 +131,7 @@ public class Utils { } public void packCoords(double x, double y, double z, String w, - final Player pl) { + final Player pl) { World theWorld; if (w.equals("unavailableworld")) { theWorld = pl.getWorld(); @@ -171,13 +172,13 @@ public class Utils { NOTLOGGEDIN, LOGGEDIN } - - public static void purgeDirectory(File file){ + + public static void purgeDirectory(File file) { String files[] = file.list(); - if (files != null && files.length != 0){ + if (files != null && files.length != 0) { for (String temp : files) { File fileDelete = new File(file, temp); - if (fileDelete.isDirectory()){ + if (fileDelete.isDirectory()) { purgeDirectory(fileDelete); fileDelete.delete(); } else { @@ -186,4 +187,18 @@ public class Utils { } } } + + public static Player[] getOnlinePlayers() { + Player[] players = null; + try { + if (Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).getReturnType() == Collection.class) { + players = (Player[]) ((Collection) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null)).toArray(); + } else { + players = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null)); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { + // can never happen + } + return players; + } } diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index a632ea607..48ce0705a 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -70,9 +70,7 @@ public class NewAPI { * @return true if player is a npc */ public boolean isNPC(Player player) { - if (plugin.getCitizensCommunicator().isNPC(player)) - return true; - return CombatTagComunicator.isNPC(player); + return plugin.getCitizensCommunicator().isNPC(player) || CombatTagComunicator.isNPC(player); } /** @@ -89,8 +87,7 @@ public class NewAPI { PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase()); if (auth != null) { - Location loc = new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ()); - return loc; + return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ()); } else { return null; } @@ -152,10 +149,7 @@ public class NewAPI { return false; } PlayerAuth auth = new PlayerAuth(name, hash, "192.168.0.1", 0, "your@email.com"); - if (!plugin.database.saveAuth(auth)) { - return false; - } - return true; + return plugin.database.saveAuth(auth); } catch (NoSuchAlgorithmException ex) { return false; } diff --git a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java index f06b63f03..3a3e7cbd1 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java @@ -2,11 +2,7 @@ package fr.xephi.authme.cache.backup; import java.io.File; import java.io.FileWriter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Scanner; -import java.util.UUID; +import java.util.*; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; @@ -44,9 +40,7 @@ public class FileCache { return; try { path = player.getUniqueId().toString(); - } catch (Exception e) { - path = player.getName().toLowerCase(); - } catch (Error e) { + } catch (Exception | Error e) { path = player.getName().toLowerCase(); } File file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "playerdatas.cache"); @@ -109,22 +103,19 @@ public class FileCache { if (Settings.customAttributes) { try { Attributes attributes = new Attributes(item); - if (attributes != null) { - Iterator iter = attributes.values().iterator(); - Attribute a = null; - while (iter.hasNext()) { - Attribute b = iter.next(); - if (a != null && a == b) - break; - a = b; - if (a != null) { - if (a.getName() != null && a.getAttributeType() != null && a.getOperation() != null && a.getUUID() != null) - writer.write("attribute=" + a.getName() + ";" + a.getAttributeType().getMinecraftId() + ";" + a.getAmount() + ";" + a.getOperation().getId() + ";" + a.getUUID().toString()); - } + Iterator iter = attributes.values().iterator(); + Attribute a = null; + while (iter.hasNext()) { + Attribute b = iter.next(); + if (a != null && a == b) + break; + a = b; + if (a != null) { + if (a.getName() != null && a.getAttributeType() != null && a.getOperation() != null && a.getUUID() != null) + writer.write("attribute=" + a.getName() + ";" + a.getAttributeType().getMinecraftId() + ";" + a.getAmount() + ";" + a.getOperation().getId() + ";" + a.getUUID().toString()); } } - } catch (Exception e) { - } catch (Error e) { + } catch (Exception | Error e) { } } } else { @@ -172,14 +163,13 @@ public class FileCache { if (Settings.customAttributes) { try { Attributes attributes = new Attributes(item); - if (attributes != null) - while (attributes.values().iterator().hasNext()) { - Attribute a = attributes.values().iterator().next(); - if (a != null) { - if (a.getName() != null && a.getAttributeType() != null && a.getOperation() != null && a.getUUID() != null && a.getAttributeType().getMinecraftId() != null) - writer.write("attribute=" + a.getName() + ";" + a.getAttributeType().getMinecraftId() + ";" + a.getAmount() + ";" + a.getOperation().getId() + ";" + a.getUUID().toString()); - } + while (attributes.values().iterator().hasNext()) { + Attribute a = attributes.values().iterator().next(); + if (a != null) { + if (a.getName() != null && a.getAttributeType() != null && a.getOperation() != null && a.getUUID() != null && a.getAttributeType().getMinecraftId() != null) + writer.write("attribute=" + a.getName() + ";" + a.getAttributeType().getMinecraftId() + ";" + a.getAmount() + ";" + a.getOperation().getId() + ";" + a.getUUID().toString()); } + } } catch (Exception e) { } } @@ -197,9 +187,7 @@ public class FileCache { String path = ""; try { path = player.getUniqueId().toString(); - } catch (Exception e) { - path = player.getName().toLowerCase(); - } catch (Error e) { + } catch (Exception | Error e) { path = player.getName().toLowerCase(); } try { @@ -232,13 +220,9 @@ public class FileCache { final String[] playerInfo = line.split(";"); group = playerInfo[0]; - if (Integer.parseInt(playerInfo[1]) == 1) { - op = true; - } else op = false; + op = Integer.parseInt(playerInfo[1]) == 1; if (playerInfo.length > 2) { - if (Integer.parseInt(playerInfo[2]) == 1) - flying = true; - else flying = false; + flying = Integer.parseInt(playerInfo[2]) == 1; } continue; @@ -275,9 +259,7 @@ public class FileCache { } if (!lores.isEmpty()) { List loreList = new ArrayList(); - for (String s : lores.split("%newline%")) { - loreList.add(s); - } + Collections.addAll(loreList, lores.split("%newline%")); meta.setLore(loreList); } if (meta != null) @@ -296,9 +278,7 @@ public class FileCache { meta.setDisplayName(name); if (!lores.isEmpty()) { List loreList = new ArrayList(); - for (String s : lores.split("%newline%")) { - loreList.add(s); - } + Collections.addAll(loreList, lores.split("%newline%")); meta.setLore(loreList); } if (meta != null) @@ -348,14 +328,13 @@ public class FileCache { Attributes attributes = null; count = 1; boolean v = true; - while (reader.hasNextLine() && v == true) { + while (reader.hasNextLine() && v) { String line = reader.nextLine(); switch (count) { case 1: item = new ItemStack(Material.getMaterial(line)); if (item.getType() == Material.AIR) v = false; - meta = item.getItemMeta(); count++; continue; case 2: @@ -379,8 +358,7 @@ public class FileCache { if (line.startsWith("lore=")) { line = line.substring(5); List lore = new ArrayList(); - for (String s : line.split("%newline%")) - lore.add(s); + Collections.addAll(lore, line.split("%newline%")); meta.setLore(lore); item.setItemMeta(meta); continue; @@ -430,7 +408,7 @@ public class FileCache { Attributes attributes = null; count = 1; boolean v = true; - while (reader.hasNextLine() && v == true) { + while (reader.hasNextLine() && v) { String line = reader.nextLine(); switch (count) { case 1: @@ -460,9 +438,8 @@ public class FileCache { } if (line.startsWith("lore=")) { line = line.substring(5); - List lore = new ArrayList(); - for (String s : line.split("%newline%")) - lore.add(s); + List lore = new ArrayList<>(); + Collections.addAll(lore, line.split("%newline%")); meta.setLore(lore); item.setItemMeta(meta); continue; @@ -504,10 +481,6 @@ public class FileCache { armours[i] = attributes.getStack(); else armours[i] = item; } - } catch (final RuntimeException e) { - //verbose - e.printStackTrace(); - ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); } catch (final Exception e) { //verbose e.printStackTrace(); @@ -518,11 +491,6 @@ public class FileCache { } return new DataFileCache(inv, armours, group, op, flying); } - } catch (RuntimeException e) { - // Verbose - e.printStackTrace(); - ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); - return null; } catch (Exception e) { // Verbose e.printStackTrace(); @@ -535,9 +503,7 @@ public class FileCache { String path = ""; try { path = player.getUniqueId().toString(); - } catch (Exception e) { - path = player.getName().toLowerCase(); - } catch (Error e) { + } catch (Exception | Error e) { path = player.getName().toLowerCase(); } try { @@ -562,9 +528,7 @@ public class FileCache { String path = ""; try { path = player.getUniqueId().toString(); - } catch (Exception e) { - path = player.getName().toLowerCase(); - } catch (Error e) { + } catch (Exception | Error e) { path = player.getName().toLowerCase(); } File file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "playerdatas.cache"); diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 2c3d89be6..96185c2e6 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -53,6 +53,7 @@ public class LimboCache { operator = playerData.readCache(player).getOperator(); flying = playerData.readCache(player).isFlying(); } catch (Exception e) { + ConsoleLogger.writeStackTrace(e); ConsoleLogger.showError("Some error on reading cache of " + name); } } else { @@ -65,12 +66,8 @@ public class LimboCache { inv = null; arm = null; } - if (player.isOp()) - operator = true; - else operator = false; - if (player.isFlying()) - flying = true; - else flying = false; + operator = player.isOp(); + flying = player.isFlying(); if (plugin.permission != null) { try { playerGroup = plugin.permission.getPrimaryGroup(player); diff --git a/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java b/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java index 0b50da50f..6d3c1f2f7 100644 --- a/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java +++ b/src/main/java/fr/xephi/authme/commands/ChangePasswordCommand.java @@ -1,20 +1,15 @@ package fr.xephi.authme.commands; -import java.security.NoSuchAlgorithmException; - +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.cache.auth.PlayerCache; +import fr.xephi.authme.settings.Messages; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.task.ChangePasswordTask; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.settings.Messages; -import fr.xephi.authme.settings.Settings; - public class ChangePasswordCommand implements CommandExecutor { private Messages m = Messages.getInstance(); @@ -25,8 +20,8 @@ public class ChangePasswordCommand implements CommandExecutor { } @Override - public boolean onCommand(final CommandSender sender, Command cmnd, String label, - final String[] args) { + public boolean onCommand(CommandSender sender, Command cmnd, String label, + String[] args) { if (!(sender instanceof Player)) { return true; } @@ -36,8 +31,8 @@ public class ChangePasswordCommand implements CommandExecutor { return true; } - final Player player = (Player) sender; - final String name = player.getName().toLowerCase(); + Player player = (Player) sender; + String name = player.getName().toLowerCase(); if (!PlayerCache.getInstance().isAuthenticated(name)) { m.send(player, "not_logged_in"); return true; @@ -67,35 +62,7 @@ public class ChangePasswordCommand implements CommandExecutor { return true; } } - plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { - @Override - public void run() { - try { - String hashnew = PasswordSecurity.getHash(Settings.getPasswordHash, args[1], name); - - if (PasswordSecurity.comparePasswordWithHash(args[0], PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) { - PlayerAuth auth = PlayerCache.getInstance().getAuth(name); - auth.setHash(hashnew); - if (PasswordSecurity.userSalt.containsKey(name) && PasswordSecurity.userSalt.get(name) != null) - auth.setSalt(PasswordSecurity.userSalt.get(name)); - else auth.setSalt(""); - if (!plugin.database.updatePassword(auth)) { - m.send(player, "error"); - return; - } - plugin.database.updateSalt(auth); - PlayerCache.getInstance().updatePlayer(auth); - m.send(player, "pwd_changed"); - ConsoleLogger.info(player.getName() + " changed his password"); - } else { - m.send(player, "wrong_pwd"); - } - } catch (NoSuchAlgorithmException ex) { - ConsoleLogger.showError(ex.getMessage()); - m.send(sender, "error"); - } - } - }); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new ChangePasswordTask(plugin, player, args[0])); return true; } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index fda470e6d..6ffde849b 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -575,17 +575,7 @@ public class AuthMePlayerListener implements Listener { return; } - int playersOnline = 0; - try { - if (Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).getReturnType() == Collection.class) - playersOnline = ((Collection) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).size(); - else playersOnline = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null, new Object[0])).length; - } catch (NoSuchMethodException ex) { - } // can never happen - catch (InvocationTargetException ex) { - } // can also never happen - catch (IllegalAccessException ex) { - } // can still never happen + int playersOnline = Utils.getOnlinePlayers().length; if (playersOnline > plugin.getServer().getMaxPlayers()) { event.allow(); return; @@ -625,13 +615,12 @@ public class AuthMePlayerListener implements Listener { return; } - Player player = event.getPlayer(); - if ((!Settings.isForceSingleSessionEnabled) && (event.getReason().contains(m.getString("same_nick")))) { event.setCancelled(true); return; } + Player player = event.getPlayer(); plugin.management.performQuit(player, true); } diff --git a/src/main/java/fr/xephi/authme/task/ChangePasswordTask.java b/src/main/java/fr/xephi/authme/task/ChangePasswordTask.java new file mode 100644 index 000000000..c9cb72d66 --- /dev/null +++ b/src/main/java/fr/xephi/authme/task/ChangePasswordTask.java @@ -0,0 +1,55 @@ +package fr.xephi.authme.task; + +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.cache.auth.PlayerCache; +import fr.xephi.authme.security.PasswordSecurity; +import fr.xephi.authme.settings.Messages; +import fr.xephi.authme.settings.Settings; +import org.bukkit.entity.Player; + +import java.security.NoSuchAlgorithmException; + +public class ChangePasswordTask implements Runnable { + + private final AuthMe plugin; + private final Player player; + private String password; + + public ChangePasswordTask(AuthMe plugin, Player player, String password) { + this.plugin = plugin; + this.player = player; + this.password = password; + } + + @Override + public void run() { + Messages m = Messages.getInstance(); + try { + String name = player.getName().toLowerCase(); + String hashnew = PasswordSecurity.getHash(Settings.getPasswordHash, password, name); + if (PasswordSecurity.comparePasswordWithHash(password, PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) { + PlayerAuth auth = PlayerCache.getInstance().getAuth(name); + auth.setHash(hashnew); + if (PasswordSecurity.userSalt.containsKey(name) && PasswordSecurity.userSalt.get(name) != null) + auth.setSalt(PasswordSecurity.userSalt.get(name)); + else auth.setSalt(""); + if (!plugin.database.updatePassword(auth)) { + m.send(player, "error"); + return; + } + plugin.database.updateSalt(auth); + PlayerCache.getInstance().updatePlayer(auth); + m.send(player, "pwd_changed"); + ConsoleLogger.info(player.getName() + " changed his password"); + } else { + m.send(player, "wrong_pwd"); + } + } catch (NoSuchAlgorithmException ex) { + ConsoleLogger.showError(ex.getMessage()); + m.send(player, "error"); + } + } +} + From 08c77b64839de6ae390a24b36199a31642250e68 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 9 Sep 2015 20:21:45 +0200 Subject: [PATCH 026/115] Cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index a199d25de..7748ebd70 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -243,7 +243,9 @@ public class AuthMe extends JavaPlugin { pm.registerEvents(new AuthMeBlockListener(this), this); pm.registerEvents(new AuthMeEntityListener(this), this); pm.registerEvents(new AuthMeServerListener(this), this); - if (ChestShop != 0) { + + // Legacy chestshop hook + if (ChestShop != 0 && ChestShop < 3.813) { pm.registerEvents(new AuthMeChestShopListener(this), this); ConsoleLogger.info("Hooked successfully with ChestShop!"); } From 08d72785b4a0796d879da8e21b164b9d83ffe26a Mon Sep 17 00:00:00 2001 From: DNx5 Date: Thu, 10 Sep 2015 13:29:11 +0700 Subject: [PATCH 027/115] improve inventory cache method --- .../xephi/authme/cache/backup/FileCache.java | 651 ++++++------------ .../xephi/authme/cache/limbo/LimboCache.java | 28 +- .../authme/events/StoreInventoryEvent.java | 14 +- .../process/logout/AsyncronousLogout.java | 3 +- 4 files changed, 214 insertions(+), 482 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java index 3a3e7cbd1..3e119ba6d 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java @@ -1,498 +1,233 @@ package fr.xephi.authme.cache.backup; -import java.io.File; -import java.io.FileWriter; -import java.util.*; - -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; - -import com.comphenix.attribute.Attributes; -import com.comphenix.attribute.Attributes.Attribute; -import com.comphenix.attribute.Attributes.Attribute.Builder; -import com.comphenix.attribute.Attributes.AttributeType; -import com.comphenix.attribute.Attributes.Operation; - +import com.google.common.io.BaseEncoding; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; import fr.xephi.authme.api.API; -import fr.xephi.authme.settings.Settings; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.util.io.BukkitObjectInputStream; +import org.bukkit.util.io.BukkitObjectOutputStream; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Scanner; public class FileCache { + private final File cacheDir; private AuthMe plugin; public FileCache(AuthMe plugin) { this.plugin = plugin; - final File file = new File(plugin.getDataFolder() + File.separator + "cache"); - if (!file.exists()) - file.mkdir(); + cacheDir = new File(plugin.getDataFolder() + File.separator + "cache"); + if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { + ConsoleLogger.showError("Failed to create cache directory."); + } } public void createCache(Player player, DataFileCache playerData, - String group, boolean operator, boolean flying) { - String path = ""; - if (player == null) + String group, boolean operator, boolean flying) { + if (player == null) { return; + } + + String path; try { path = player.getUniqueId().toString(); } catch (Exception | Error e) { path = player.getName().toLowerCase(); } - File file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "playerdatas.cache"); - if (!file.getParentFile().exists()) - file.getParentFile().mkdirs(); - if (file.exists()) { + File playerDir = new File(cacheDir, path); + if (!playerDir.exists() && !playerDir.isDirectory() && !playerDir.mkdir()) { return; } - FileWriter writer = null; - try { - file.createNewFile(); + File datafile = new File(playerDir, "playerdatas.cache"); + if (datafile.exists()) { + return; + } - writer = new FileWriter(file); + FileWriter writer; + try { + datafile.createNewFile(); + writer = new FileWriter(datafile); writer.write(group + API.newline); writer.write(String.valueOf(operator) + API.newline); writer.write(String.valueOf(flying) + API.newline); writer.close(); - - file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "inventory"); - - file.mkdirs(); - ItemStack[] inv = playerData.getInventory(); - for (int i = 0; i < inv.length; i++) { - ItemStack item = inv[i]; - file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "inventory" + File.separator + i + ".cache"); - file.createNewFile(); - writer = new FileWriter(file); - if (item != null) { - if (item.getType() == Material.AIR) { - writer.write("AIR"); - writer.close(); - continue; - } - writer.write(item.getType().name() + API.newline); - writer.write(item.getDurability() + API.newline); - writer.write(item.getAmount() + API.newline); - writer.flush(); - if (item.hasItemMeta()) { - ItemMeta meta = item.getItemMeta(); - if (meta.hasDisplayName()) - writer.write("name=" + meta.getDisplayName() + API.newline); - if (meta.hasLore()) { - String lores = ""; - for (String lore : meta.getLore()) - lores = lore + "%newline%"; - writer.write("lore=" + lores + API.newline); - } - if (meta.hasEnchants()) { - for (Enchantment ench : meta.getEnchants().keySet()) { - writer.write("metaenchant=" + ench.getName() + ":" + meta.getEnchants().get(ench) + API.newline); - } - } - writer.flush(); - } - for (Enchantment ench : item.getEnchantments().keySet()) { - writer.write("enchant=" + ench.getName() + ":" + item.getEnchantments().get(ench) + API.newline); - } - if (Settings.customAttributes) { - try { - Attributes attributes = new Attributes(item); - Iterator iter = attributes.values().iterator(); - Attribute a = null; - while (iter.hasNext()) { - Attribute b = iter.next(); - if (a != null && a == b) - break; - a = b; - if (a != null) { - if (a.getName() != null && a.getAttributeType() != null && a.getOperation() != null && a.getUUID() != null) - writer.write("attribute=" + a.getName() + ";" + a.getAttributeType().getMinecraftId() + ";" + a.getAmount() + ";" + a.getOperation().getId() + ";" + a.getUUID().toString()); - } - } - } catch (Exception | Error e) { - } - } - } else { - writer.write("AIR"); - } - writer.close(); - } - - file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "armours"); - if (!file.getParentFile().exists()) - file.getParentFile().mkdirs(); - file.mkdirs(); - - ItemStack[] armors = playerData.getArmour(); - for (int i = 0; i < armors.length; i++) { - ItemStack item = armors[i]; - file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "armours" + File.separator + i + ".cache"); - file.createNewFile(); - writer = new FileWriter(file); - if (item != null) { - if (item.getType() == Material.AIR) { - writer.write("AIR"); - writer.close(); - continue; - } - writer.write(item.getType().name() + API.newline); - writer.write(item.getDurability() + API.newline); - writer.write(item.getAmount() + API.newline); - writer.flush(); - if (item.hasItemMeta()) { - ItemMeta meta = item.getItemMeta(); - if (meta.hasDisplayName()) - writer.write("name=" + meta.getDisplayName() + API.newline); - if (meta.hasLore()) { - String lores = ""; - for (String lore : meta.getLore()) - lores = lore + "%newline%"; - writer.write("lore=" + lores + API.newline); - } - writer.flush(); - } - for (Enchantment ench : item.getEnchantments().keySet()) { - writer.write("enchant=" + ench.getName() + ":" + item.getEnchantments().get(ench) + API.newline); - } - if (Settings.customAttributes) { - try { - Attributes attributes = new Attributes(item); - while (attributes.values().iterator().hasNext()) { - Attribute a = attributes.values().iterator().next(); - if (a != null) { - if (a.getName() != null && a.getAttributeType() != null && a.getOperation() != null && a.getUUID() != null && a.getAttributeType().getMinecraftId() != null) - writer.write("attribute=" + a.getName() + ";" + a.getAttributeType().getMinecraftId() + ";" + a.getAmount() + ";" + a.getOperation().getId() + ";" + a.getUUID().toString()); - } - } - } catch (Exception e) { - } - } - } else { - writer.write("AIR" + API.newline); - } - writer.close(); - } - } catch (final Exception e) { - ConsoleLogger.showError("Some error on creating file cache..."); + } catch (IOException e) { + e.printStackTrace(); } + + BaseEncoding base64 = BaseEncoding.base64(); + + File invDir = new File(playerDir, "inventory"); + if (!invDir.isDirectory() && !invDir.mkdir()) + return; + + ItemStack[] inv = playerData.getInventory(); + for (int i = 0; i < inv.length; i++) { + ItemStack item = inv[i]; + if (item == null) { + item = new ItemStack(Material.AIR); + } + if (item.getType() == Material.SKULL_ITEM) { + SkullMeta meta = (SkullMeta) item.getItemMeta(); + if (meta.hasOwner() && (meta.getOwner() == null || meta.getOwner().isEmpty())) { + item.setItemMeta(plugin.getServer().getItemFactory().getItemMeta(Material.SKULL_ITEM)); + } + } + + try { + File cacheFile = new File(invDir, i + ".cache"); + if (!cacheFile.isFile() && !cacheFile.createNewFile()) { + continue; + } + writer = new FileWriter(cacheFile); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BukkitObjectOutputStream objectOut = new BukkitObjectOutputStream(baos); + objectOut.writeObject(item); + objectOut.close(); + writer.write(base64.encode(baos.toByteArray())); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + File armourDir = new File(cacheDir, path + File.separator + "armours"); + if (!armourDir.isDirectory() && !armourDir.mkdir()) + return; + + ItemStack[] armors = playerData.getArmour(); + for (int i = 0; i < armors.length; i++) { + ItemStack item = armors[i]; + if (item == null) { + item = new ItemStack(Material.AIR); + } + if (item.getType() == Material.SKULL_ITEM) { + SkullMeta meta = (SkullMeta) item.getItemMeta(); + if (meta.hasOwner() && (meta.getOwner() == null || meta.getOwner().isEmpty())) { + item.setItemMeta(plugin.getServer().getItemFactory().getItemMeta(Material.SKULL_ITEM)); + } + } + + try { + File cacheFile = new File(armourDir, i + ".cache"); + if (!cacheFile.isFile() && !cacheFile.createNewFile()) { + continue; + } + writer = new FileWriter(cacheFile); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BukkitObjectOutputStream objectOut = new BukkitObjectOutputStream(baos); + objectOut.writeObject(item); + objectOut.close(); + writer.write(base64.encode(baos.toByteArray())); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } public DataFileCache readCache(Player player) { - String path = ""; + if (player == null) { + return null; + } + + String path; try { path = player.getUniqueId().toString(); } catch (Exception | Error e) { path = player.getName().toLowerCase(); } + + File playerDir = new File(cacheDir, path); + if (!playerDir.exists() && !playerDir.isDirectory()) { + return null; + } + try { - File file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "playerdatas.cache"); - String playername = player.getName().toLowerCase(); - if (!file.exists()) { - // OLD METHOD - file = new File("cache/" + playername + ".cache"); - ItemStack[] stacki = new ItemStack[36]; - ItemStack[] stacka = new ItemStack[4]; - if (!file.exists()) { - return new DataFileCache(stacki, stacka); - } - String group = null; - boolean op = false; - boolean flying = false; + File datafile = new File(playerDir, "playerdatas.cache"); + if (!datafile.exists() || !datafile.isFile()) { + return null; + } + ItemStack[] inv = new ItemStack[36]; + ItemStack[] armours = new ItemStack[4]; + String group = null; + boolean op = false; + boolean flying = false; - Scanner reader = new Scanner(file); - - int i = 0; - int a = 0; + Scanner reader; + try { + reader = new Scanner(datafile); + int count = 1; while (reader.hasNextLine()) { String line = reader.nextLine(); - - if (!line.contains(":")) { - // the fist line represent the player group, - // operator - // status - // and flying status - final String[] playerInfo = line.split(";"); - group = playerInfo[0]; - - op = Integer.parseInt(playerInfo[1]) == 1; - if (playerInfo.length > 2) { - flying = Integer.parseInt(playerInfo[2]) == 1; - } - - continue; - } - - if (!line.startsWith("i") && !line.startsWith("w")) { - continue; - } - String lores = ""; - String name = ""; - if (line.split("\\*").length > 1) { - lores = line.split("\\*")[1]; - line = line.split("\\*")[0]; - } - if (line.split(";").length > 1) { - name = line.split(";")[1]; - line = line.split(";")[0]; - } - final String[] in = line.split(":"); - // can enchant item? size ofstring in file - 4 all / 2 = - // number - // of enchant - if (in[0].equals("i")) { - stacki[i] = new ItemStack(Material.getMaterial(in[1]), Integer.parseInt(in[2]), Short.parseShort((in[3]))); - if (in.length > 4 && !in[4].isEmpty()) { - for (int k = 4; k < in.length - 1; k++) { - stacki[i].addUnsafeEnchantment(Enchantment.getByName(in[k]), Integer.parseInt(in[k + 1])); - k++; - } - } - ItemMeta meta = stacki[i].getItemMeta(); - if (!name.isEmpty()) { - meta.setDisplayName(name); - } - if (!lores.isEmpty()) { - List loreList = new ArrayList(); - Collections.addAll(loreList, lores.split("%newline%")); - meta.setLore(loreList); - } - if (meta != null) - stacki[i].setItemMeta(meta); - i++; - } else { - stacka[a] = new ItemStack(Material.getMaterial(in[1]), Integer.parseInt(in[2]), Short.parseShort((in[3]))); - if (in.length > 4 && !in[4].isEmpty()) { - for (int k = 4; k < in.length - 1; k++) { - stacka[a].addUnsafeEnchantment(Enchantment.getByName(in[k]), Integer.parseInt(in[k + 1])); - k++; - } - } - ItemMeta meta = stacka[a].getItemMeta(); - if (!name.isEmpty()) - meta.setDisplayName(name); - if (!lores.isEmpty()) { - List loreList = new ArrayList(); - Collections.addAll(loreList, lores.split("%newline%")); - meta.setLore(loreList); - } - if (meta != null) - stacki[i].setItemMeta(meta); - a++; + switch (count) { + case 1: + group = line; + break; + case 2: + op = Boolean.parseBoolean(line); + break; + case 3: + flying = Boolean.parseBoolean(line); + break; + default: + break; } + count++; } - if (reader != null) - reader.close(); - return new DataFileCache(stacki, stacka, group, op, flying); - } else { - // NEW METHOD - ItemStack[] inv = new ItemStack[36]; - ItemStack[] armours = new ItemStack[4]; - String group = null; - boolean op = false; - boolean flying = false; - - Scanner reader = null; - try { - reader = new Scanner(file); - - int count = 1; - while (reader.hasNextLine()) { - String line = reader.nextLine(); - switch (count) { - case 1: - group = line; - break; - case 2: - op = Boolean.parseBoolean(line); - break; - case 3: - flying = Boolean.parseBoolean(line); - break; - default: - break; - } - count++; - } - if (reader != null) - reader.close(); - for (int i = 0; i < inv.length; i++) { - reader = new Scanner(new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "inventory" + File.separator + i + ".cache")); - ItemStack item = new ItemStack(Material.AIR); - ItemMeta meta = item.getItemMeta(); - Attributes attributes = null; - count = 1; - boolean v = true; - while (reader.hasNextLine() && v) { - String line = reader.nextLine(); - switch (count) { - case 1: - item = new ItemStack(Material.getMaterial(line)); - if (item.getType() == Material.AIR) - v = false; - count++; - continue; - case 2: - item.setDurability((short) Integer.parseInt(line)); - count++; - continue; - case 3: - item.setAmount(Integer.parseInt(line)); - count++; - continue; - default: - break; - } - meta = item.getItemMeta(); - if (line.startsWith("name=")) { - line = line.substring(5); - meta.setDisplayName(line); - item.setItemMeta(meta); - continue; - } - if (line.startsWith("lore=")) { - line = line.substring(5); - List lore = new ArrayList(); - Collections.addAll(lore, line.split("%newline%")); - meta.setLore(lore); - item.setItemMeta(meta); - continue; - } - if (line.startsWith("enchant=")) { - line = line.substring(8); - item.addEnchantment(Enchantment.getByName(line.split(":")[0]), Integer.parseInt(line.split(":")[1])); - continue; - } - if (Settings.customAttributes) { - if (line.startsWith("attribute=")) { - if (attributes == null) - attributes = new Attributes(item); - try { - line = line.substring(10); - String[] args = line.split(";"); - if (args.length != 5) - continue; - String name = args[0]; - AttributeType type = AttributeType.fromId(args[1]); - double amount = Double.parseDouble(args[2]); - Operation operation = Operation.fromId(Integer.parseInt(args[3])); - UUID uuid = UUID.fromString(args[4]); - Builder build = Attribute.newBuilder(); - build.amount(amount); - build.operation(operation); - build.type(type); - build.name(name); - build.uuid(uuid); - attributes.add(build.build()); - } catch (Exception e) { - } - } - } - count++; - } - if (reader != null) - reader.close(); - if (Settings.customAttributes && attributes != null) - inv[i] = attributes.getStack(); - else inv[i] = item; - } - for (int i = 0; i < armours.length; i++) { - reader = new Scanner(new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "armours" + File.separator + i + ".cache")); - ItemStack item = new ItemStack(Material.AIR); - ItemMeta meta = null; - Attributes attributes = null; - count = 1; - boolean v = true; - while (reader.hasNextLine() && v) { - String line = reader.nextLine(); - switch (count) { - case 1: - item = new ItemStack(Material.getMaterial(line)); - if (item.getType() == Material.AIR) - v = false; - meta = item.getItemMeta(); - count++; - continue; - case 2: - item.setDurability((short) Integer.parseInt(line)); - count++; - continue; - case 3: - item.setAmount(Integer.parseInt(line)); - count++; - continue; - default: - break; - } - meta = item.getItemMeta(); - if (line.startsWith("name=")) { - line = line.substring(5); - meta.setDisplayName(line); - item.setItemMeta(meta); - continue; - } - if (line.startsWith("lore=")) { - line = line.substring(5); - List lore = new ArrayList<>(); - Collections.addAll(lore, line.split("%newline%")); - meta.setLore(lore); - item.setItemMeta(meta); - continue; - } - if (line.startsWith("enchant=")) { - line = line.substring(8); - item.addEnchantment(Enchantment.getByName(line.split(":")[0]), Integer.parseInt(line.split(":")[1])); - } - if (Settings.customAttributes) { - if (line.startsWith("attribute=")) { - if (attributes == null) - attributes = new Attributes(item); - try { - line = line.substring(10); - String[] args = line.split(";"); - if (args.length != 5) - continue; - String name = args[0]; - AttributeType type = AttributeType.fromId(args[1]); - double amount = Double.parseDouble(args[2]); - Operation operation = Operation.fromId(Integer.parseInt(args[3])); - UUID uuid = UUID.fromString(args[4]); - Builder build = Attribute.newBuilder(); - build.amount(amount); - build.operation(operation); - build.type(type); - build.name(name); - build.uuid(uuid); - attributes.add(build.build()); - } catch (Exception e) { - } - } - } - count++; - } - if (reader != null) - reader.close(); - if (attributes != null) - armours[i] = attributes.getStack(); - else armours[i] = item; - } - } catch (final Exception e) { - //verbose - e.printStackTrace(); - ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); - } finally { - if (reader != null) - reader.close(); - } - return new DataFileCache(inv, armours, group, op, flying); + reader.close(); + } catch (Exception e) { + e.printStackTrace(); } + + BaseEncoding base64 = BaseEncoding.base64(); + + File invDir = new File(playerDir, "inventory"); + for (int i = 0; i < inv.length; i++) { + byte[] bytes = Files.readAllBytes(Paths.get(invDir.getPath(), i + ".cache")); + String encodedItem = new String(bytes); + bytes = base64.decode(encodedItem); + ByteArrayInputStream baos = new ByteArrayInputStream(bytes); + BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos); + ItemStack item = (ItemStack) objectIn.readObject(); + objectIn.close(); + if (item == null) { + inv[i] = new ItemStack(Material.AIR); + } else { + inv[i] = item; + } + } + + File armourDir = new File(playerDir, "armours"); + for (int i = 0; i < armours.length; i++) { + byte[] bytes = Files.readAllBytes(Paths.get(armourDir.getPath(), i + ".cache")); + String encodedItem = new String(bytes); + bytes = base64.decode(encodedItem); + ByteArrayInputStream baos = new ByteArrayInputStream(bytes); + BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos); + ItemStack item = (ItemStack) objectIn.readObject(); + objectIn.close(); + if (item == null) { + armours[i] = new ItemStack(Material.AIR); + } else { + armours[i] = item; + } + } + + return new DataFileCache(inv, armours, group, op, flying); + } catch (Exception e) { - // Verbose e.printStackTrace(); ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); return null; @@ -500,23 +235,23 @@ public class FileCache { } public void removeCache(Player player) { - String path = ""; + String path; try { path = player.getUniqueId().toString(); } catch (Exception | Error e) { path = player.getName().toLowerCase(); } try { - File file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path); + File file = new File(cacheDir, path); if (file.list() != null) { Utils.purgeDirectory(file); - file.delete(); + if (!file.delete()) { + ConsoleLogger.showError("Failed to remove" + player.getName() + "cache."); + } } else { - file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + player.getName().toLowerCase() + ".cache"); - if (file.isFile()) { - file.delete(); - } else { - ConsoleLogger.showError("Failed to remove" + player.getName() + "cache, it doesn't exist!"); + file = new File(cacheDir, player.getName().toLowerCase() + ".cache"); + if (file.isFile() && !file.delete()) { + ConsoleLogger.showError("Failed to remove" + player.getName() + "cache."); } } } catch (Exception e) { @@ -525,15 +260,15 @@ public class FileCache { } public boolean doesCacheExist(Player player) { - String path = ""; + String path; try { path = player.getUniqueId().toString(); } catch (Exception | Error e) { path = player.getName().toLowerCase(); } - File file = new File(plugin.getDataFolder() + File.separator + "cache" + File.separator + path + File.separator + "playerdatas.cache"); + File file = new File(cacheDir, path + File.separator + "playerdatas.cache"); if (!file.exists()) { - file = new File("cache/" + player.getName().toLowerCase() + ".cache"); + file = new File(cacheDir, player.getName().toLowerCase() + ".cache"); } return file.exists(); diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 96185c2e6..6f7450244 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -1,19 +1,19 @@ package fr.xephi.authme.cache.limbo; -import java.util.concurrent.ConcurrentHashMap; - +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.backup.DataFileCache; +import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.events.ResetInventoryEvent; +import fr.xephi.authme.events.StoreInventoryEvent; +import fr.xephi.authme.settings.Settings; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.cache.backup.FileCache; -import fr.xephi.authme.events.ResetInventoryEvent; -import fr.xephi.authme.events.StoreInventoryEvent; -import fr.xephi.authme.settings.Settings; +import java.util.concurrent.ConcurrentHashMap; public class LimboCache { @@ -48,13 +48,11 @@ public class LimboCache { inv = null; arm = null; } - try { - playerGroup = playerData.readCache(player).getGroup(); - operator = playerData.readCache(player).getOperator(); - flying = playerData.readCache(player).isFlying(); - } catch (Exception e) { - ConsoleLogger.writeStackTrace(e); - ConsoleLogger.showError("Some error on reading cache of " + name); + DataFileCache cache = playerData.readCache(player); + if (cache != null) { + playerGroup = cache.getGroup(); + operator = cache.getOperator(); + flying = cache.isFlying(); } } else { StoreInventoryEvent event = new StoreInventoryEvent(player); diff --git a/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java b/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java index c91523d87..66911d187 100644 --- a/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java +++ b/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java @@ -1,12 +1,11 @@ package fr.xephi.authme.events; +import fr.xephi.authme.cache.backup.DataFileCache; +import fr.xephi.authme.cache.backup.FileCache; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import fr.xephi.authme.cache.backup.FileCache; - /** - * * This event is call just before write inventory content to cache * * @author Xephi59 @@ -25,10 +24,11 @@ public class StoreInventoryEvent extends CustomEvent { public StoreInventoryEvent(Player player, FileCache fileCache) { this.player = player; - try { - this.inventory = fileCache.readCache(player).getInventory(); - this.armor = fileCache.readCache(player).getArmour(); - } catch (Exception e) { + DataFileCache cache = fileCache.readCache(player); + if (cache != null) { + this.inventory = cache.getInventory(); + this.armor = cache.getArmour(); + } else { this.inventory = player.getInventory().getContents(); this.armor = player.getInventory().getArmorContents(); } diff --git a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java index d9931171e..366e72d4c 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java @@ -85,8 +85,7 @@ public class AsyncronousLogout { // create cache file for handling lost of inventories on unlogged in // status DataFileCache playerData = new DataFileCache(LimboCache.getInstance().getLimboPlayer(name).getInventory(), LimboCache.getInstance().getLimboPlayer(name).getArmour()); - if (playerData != null) - playerBackup.createCache(player, playerData, LimboCache.getInstance().getLimboPlayer(name).getGroup(), LimboCache.getInstance().getLimboPlayer(name).getOperator(), LimboCache.getInstance().getLimboPlayer(name).isFlying()); + playerBackup.createCache(player, playerData, LimboCache.getInstance().getLimboPlayer(name).getGroup(), LimboCache.getInstance().getLimboPlayer(name).getOperator(), LimboCache.getInstance().getLimboPlayer(name).isFlying()); } sched.scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerLogout(p, plugin)); } From d4cf7390819278166a3435e47145face86d32f2d Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 10 Sep 2015 19:56:33 +0200 Subject: [PATCH 028/115] Fix hikari --- src/main/java/fr/xephi/authme/AuthMe.java | 1 - .../fr/xephi/authme/datasource/MySQL.java | 1 - .../authme/datasource/SQLite_HIKARI.java | 3 +-- .../authme/listener/AuthMePlayerListener.java | 2 -- src/main/resources/config.yml | 26 +++---------------- 5 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 7748ebd70..7257d4d59 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -7,7 +7,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLConnection; import java.sql.SQLException; diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index e477ea4da..f30b76565 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -124,7 +124,6 @@ public class MySQL implements DataSource { HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeMYSQLPool"); config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"); - config.setDriverClassName("com.mysql.jdbc.Driver"); config.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); config.setUsername(this.username); config.setPassword(this.password); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java index 602dec5f8..0a9eac077 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java @@ -115,14 +115,13 @@ public class SQLite_HIKARI implements DataSource { @Override public DataSourceType getType() { - return DataSourceType.SQLITE; + return DataSourceType.SQLITEHIKARI; } private synchronized void setConnectionArguments() throws ClassNotFoundException, IllegalArgumentException { HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeSQLitePool"); - config.setDriverClassName("org.sqlite.JDBC"); config.setDataSourceClassName("org.sqlite.javax.SQLiteConnectionPoolDataSource"); config.setJdbcUrl("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 6ffde849b..cffd68507 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -3,10 +3,8 @@ package fr.xephi.authme.listener; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.PatternSyntaxException; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 768ce22f3..dda0cb84c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -39,26 +39,6 @@ DataSource: mySQLlastlocWorld: world # Column for RealName mySQLRealName: realname -GroupOptions: - # if you want to set up a particulary Permission Group for - # users that arent registered yet. Pay attention this option - # is casesensitive! - # Example: UnregisteredPlayerGroup: GuestUser - UnregisteredPlayerGroup: '' - # Same as UnregisteredGroup if u want to set a switch - # between unregistered and registered player group - # set the group name below - RegisteredPlayerGroup: '' - # with this option you can add specified permission onJoin - # like for example LoginBonus from another plugins, AuthMe - # will check onJoin if player has that permissions in his Group - # if true it add a temporany permissions to that user. This Field - # is needed beacuse AuthMe switch all unlogged players on a - # specified restricted Permission Group, so plugins that will use - # some particolary permissions on join doesnt work, without - # compiling option below! - Permissions: - PermissionsOnJoin: [] settings: sessions: # Do you want to enable session? When enabled @@ -290,10 +270,10 @@ ExternalBoardOptions: # WordPress prefix defined during WordPress installation process wordpressTablePrefix: 'wp_' permission: - # take care with this options, if u dont want + # Take care with this options, if you dont want # to use Vault and Group Switching of - # AuthMe for unloggedIn players put False - # below, default is true. + # AuthMe for unloggedIn players put true + # below, default is false. EnablePermissionCheck: false BackupSystem: # Enable or Disable Automatic Backup From c485a58036373f2d871574ae6932dc5b642d2ea8 Mon Sep 17 00:00:00 2001 From: "Gabriele C." Date: Sat, 12 Sep 2015 11:53:30 +0200 Subject: [PATCH 029/115] Update MySQL.java --- src/main/java/fr/xephi/authme/datasource/MySQL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index f30b76565..ee58973fe 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -123,7 +123,7 @@ public class MySQL implements DataSource { throws ClassNotFoundException, IllegalArgumentException { HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeMYSQLPool"); - config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"); + config.setDriverClassName("com.mysql.jdbc.Driver"); config.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); config.setUsername(this.username); config.setPassword(this.password); From 023e64c8d59a14340e72824c38517be9cb742121 Mon Sep 17 00:00:00 2001 From: DmitryRendov Date: Sun, 13 Sep 2015 09:48:11 +0000 Subject: [PATCH 030/115] Fixed PBKDF2DJANGO hash map --- src/main/java/fr/xephi/authme/security/PasswordSecurity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index 305b89b63..548bef129 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -85,6 +85,7 @@ public class PasswordSecurity { salt = BCRYPT.gensalt(8); userSalt.put(playerName, salt); break; + case PBKDF2DJANGO: case PBKDF2: salt = createSalt(12); userSalt.put(playerName, salt); From d8c2a2511612fe4e21915ec4a7752b801540fa2b Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 12:25:12 +0200 Subject: [PATCH 031/115] Working sqlitehikari! ;D --- src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java | 3 +-- src/main/resources/config.yml | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java index 0a9eac077..de91d2bb4 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java @@ -122,9 +122,8 @@ public class SQLite_HIKARI implements DataSource { throws ClassNotFoundException, IllegalArgumentException { HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeSQLitePool"); - config.setDataSourceClassName("org.sqlite.javax.SQLiteConnectionPoolDataSource"); + config.setDriverClassName("org.sqlite.JDBC"); config.setJdbcUrl("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); - config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable config.setConnectionTestQuery("SELECT 1"); config.setMaxLifetime(180000); // 3 Min config.setIdleTimeout(60000); // 1 Min diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index dda0cb84c..d66c5a141 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,6 @@ DataSource: - # Can be set to: sqlite, mysql + # Can be set to: sqlite, sqlitehikari, mysql + # sqlitehikari should be more fast than normal sqlite but it's an experimental feature! backend: sqlite # Enable database caching caching: true From 76b4f62e79fc2d316715beae6060ae683735dc15 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 15:01:22 +0200 Subject: [PATCH 032/115] cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 476 ++++++++++-------- .../java/fr/xephi/authme/PerformBackup.java | 3 +- .../authme/listener/AuthMeServerListener.java | 2 +- .../fr/xephi/authme/settings/Settings.java | 4 +- 4 files changed, 271 insertions(+), 214 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 7257d4d59..2f6c63679 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -93,7 +93,7 @@ public class AuthMe extends JavaPlugin { public boolean isCitizensActive = false; public SendMailSSL mail = null; public boolean CombatTag = false; - public double ChestShop = 0; + public boolean legacyChestShop = false; public boolean BungeeCord = false; public Essentials ess; public NewAPI api; @@ -110,6 +110,10 @@ public class AuthMe extends JavaPlugin { public DataManager dataManager; public ConcurrentHashMap sessions = new ConcurrentHashMap(); + public static AuthMe getInstance() { + return authme; + } + public Settings getSettings() { return settings; } @@ -122,12 +126,35 @@ public class AuthMe extends JavaPlugin { this.database = database; } + public void setMessages(Messages m) { + this.m = m; + } + + public Messages getMessages() { + return m; + } + + public CitizensCommunicator getCitizensCommunicator() { + return citizens; + } + @Override public void onEnable() { + server = getServer(); + PluginManager pm = server.getPluginManager(); + authme = this; - authmeLogger.setParent(this.getLogger()); + m = Messages.getInstance(); + otherAccounts = OtherAccounts.getInstance(); + + // TODOs + // TODO: split the plugin in more modules + // TODO: remove vault as hard dependency + + // Load settings and custom configurations + // TODO: new configuration style (more files) try { settings = new Settings(this); } catch (Exception e) { @@ -136,6 +163,16 @@ public class AuthMe extends JavaPlugin { return; } + // Configuration Security Warnings + if (!Settings.isForceSingleSessionEnabled) { + ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); + } + if (Settings.getSessionTimeout == 0 && Settings.isSessionsEnabled) { + ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!"); + } + + // Start the metrics service + // TODO: add a setting to disable metrics try { Metrics metrics = new Metrics(this); metrics.start(); @@ -145,27 +182,6 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.showError("Can't start Metrics! The plugin will work anyway..."); } - citizens = new CitizensCommunicator(this); - - if (Settings.enableAntiBot) { - Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { - - @Override - public void run() { - delayedAntiBot = false; - } - }, 2400); - } - - m = Messages.getInstance(); - - otherAccounts = OtherAccounts.getInstance(); - - server = getServer(); - - // Find Permissions - checkVault(); - // Set Console Filter if (Settings.removePassword) { ConsoleFilter filter = new ConsoleFilter(); @@ -182,11 +198,30 @@ public class AuthMe extends JavaPlugin { } } - // Load MailApi - if (!Settings.getmailAccount.isEmpty() && !Settings.getmailPassword.isEmpty()) + // AntiBot delay + if (Settings.enableAntiBot) { + Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { + + @Override + public void run() { + delayedAntiBot = false; + } + }, 2400); + } + + // Download GeoIp.dat file + downloadGeoIp(); + + // Load MailApi if needed + if (!Settings.getmailAccount.isEmpty() && !Settings.getmailPassword.isEmpty()) { mail = new SendMailSSL(this); + } + + // Find Permissions + checkVault(); // Check Citizens Version + citizens = new CitizensCommunicator(this); checkCitizens(); // Check Combat Tag Version @@ -204,69 +239,50 @@ public class AuthMe extends JavaPlugin { // Check Essentials checkEssentials(); - /* - * Back style on start if avalaible - */ + // Do backup on start if enabled if (Settings.isBackupActivated && Settings.isBackupOnStart) { - Boolean Backup = new PerformBackup(this).DoBackup(); - if (Backup) + // Do backup and check return value! + if (new PerformBackup(this).DoBackup()){ ConsoleLogger.info("Backup performed correctly"); - else ConsoleLogger.showError("Error while performing the backup!"); + } else { + ConsoleLogger.showError("Error while performing the backup!"); + } } + // Connect to the database and setup tables try { setupDatabase(); } catch (ClassNotFoundException | SQLException | PoolInitializationException ex) { ConsoleLogger.writeStackTrace(ex); - ConsoleLogger.showError("Fatal error occurred! Authme initialization ABORTED!"); + ConsoleLogger.showError("Fatal error occurred during database connection! Authme initialization ABORTED!"); + stopOrUnload(); return; } + // Set the DataManager dataManager = new DataManager(this); // Setup the new API api = new NewAPI(this); - // Old deprecated API + // Setup the old deprecated API new API(this); // Setup Management management = new Management(this); - PluginManager pm = getServer().getPluginManager(); + // Bungeecord hook if (Settings.bungee) { Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); Bukkit.getMessenger().registerIncomingPluginChannel(this, "BungeeCord", new BungeeCordMessage(this)); } - pm.registerEvents(new AuthMePlayerListener(this), this); - pm.registerEvents(new AuthMeBlockListener(this), this); - pm.registerEvents(new AuthMeEntityListener(this), this); - pm.registerEvents(new AuthMeServerListener(this), this); - // Legacy chestshop hook - if (ChestShop != 0 && ChestShop < 3.813) { + if (legacyChestShop) { pm.registerEvents(new AuthMeChestShopListener(this), this); ConsoleLogger.info("Hooked successfully with ChestShop!"); } - this.getCommand("authme").setExecutor(new AdminCommand(this)); - this.getCommand("register").setExecutor(new RegisterCommand(this)); - this.getCommand("login").setExecutor(new LoginCommand(this)); - this.getCommand("changepassword").setExecutor(new ChangePasswordCommand(this)); - this.getCommand("logout").setExecutor(new LogoutCommand(this)); - this.getCommand("unregister").setExecutor(new UnregisterCommand(this)); - this.getCommand("email").setExecutor(new EmailCommand(this)); - this.getCommand("captcha").setExecutor(new CaptchaCommand(this)); - this.getCommand("converter").setExecutor(new ConverterCommand(this)); - - if (!Settings.isForceSingleSessionEnabled) { - ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); - } - - if (Settings.getSessionTimeout == 0 && Settings.isSessionsEnabled) { - ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!"); - } - + // Reload support hook if (Settings.reloadSupport) { try { int playersOnline = Utils.getOnlinePlayers().length; @@ -287,10 +303,25 @@ public class AuthMe extends JavaPlugin { } } - autoPurge(); + // Register events + pm.registerEvents(new AuthMePlayerListener(this), this); + pm.registerEvents(new AuthMeBlockListener(this), this); + pm.registerEvents(new AuthMeEntityListener(this), this); + pm.registerEvents(new AuthMeServerListener(this), this); - // Download GeoIp.dat file - downloadGeoIp(); + // Register commands + this.getCommand("authme").setExecutor(new AdminCommand(this)); + this.getCommand("register").setExecutor(new RegisterCommand(this)); + this.getCommand("login").setExecutor(new LoginCommand(this)); + this.getCommand("changepassword").setExecutor(new ChangePasswordCommand(this)); + this.getCommand("logout").setExecutor(new LogoutCommand(this)); + this.getCommand("unregister").setExecutor(new UnregisterCommand(this)); + this.getCommand("email").setExecutor(new EmailCommand(this)); + this.getCommand("captcha").setExecutor(new CaptchaCommand(this)); + this.getCommand("converter").setExecutor(new ConverterCommand(this)); + + // Purge on start if enabled + autoPurge(); // Start Email recall task if needed recallEmail(); @@ -300,9 +331,97 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt."); ConsoleLogger.info("Do you want a good gameserver? Look at our sponsor GameHosting.it leader in Italy as Game Server Provider!"); + // Successful message ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!"); } + @Override + public void onDisable() { + // Save player data + Player[] players = Utils.getOnlinePlayers(); + if (players != null) { + for (Player player : players) { + this.savePlayer(player); + } + } + + // Close the database + if (database != null) { + database.close(); + } + + // Do backup on stop if enabled + if (Settings.isBackupActivated && Settings.isBackupOnStop) { + Boolean Backup = new PerformBackup(this).DoBackup(); + if (Backup) + ConsoleLogger.info("Backup performed correctly."); + else ConsoleLogger.showError("Error while performing the backup!"); + } + + // Disabled correctly + ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!"); + } + + // Stop/unload the server/plugin as defined in the configuration + public void stopOrUnload(){ + if (Settings.isStopEnabled) { + ConsoleLogger.showError("THE SERVER IS GOING TO SHUTDOWN AS DEFINED IN THE CONFIGURATION!"); + AuthMe.getInstance().getServer().shutdown(); + } else { + server.getPluginManager().disablePlugin(AuthMe.getInstance()); + } + } + + // Show the exception message and stop/unload the server/plugin as defined in the configuration + public void stopOrUnload(Exception e){ + ConsoleLogger.showError(e.getMessage()); + stopOrUnload(); + } + + // Initialize and setup the database + public void setupDatabase() throws ClassNotFoundException, PoolInitializationException, SQLException { + // Backend MYSQL - FILE - SQLITE - SQLITEHIKARI + int accounts = 0; + switch (Settings.getDataSource) { + case FILE: + database = new FlatFile(); + break; + case MYSQL: + database = new MySQL(); + break; + case SQLITE: + database = new SQLite(); + accounts = database.getAccountsRegistered(); + if (accounts >= 4000) + ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + accounts + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); + break; + case SQLITEHIKARI: + database = new SQLite_HIKARI(); + accounts = database.getAccountsRegistered(); + if (accounts >= 8000) + ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + accounts + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); + break; + } + + if (Settings.isCachingEnabled) { + database = new CacheDataSource(this, database); + } + + database = new DatabaseCalls(database); + + if (Settings.getDataSource == DataSource.DataSourceType.FILE) { + Converter converter = new ForceFlatToSqlite(database, this); + try { + Thread t = new Thread(converter); + t.start(); + } catch (Exception e) { + } + ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated, next time server starts up, it will be changed to SQLite... Conversion will be started Asynchronously, it will not drop down your performance !"); + ConsoleLogger.showError("If you want to keep FlatFile, set file again into config at backend, but this message and this change will appear again at the next restart"); + } + } + + // Set the console filter to remove the passwords private void setLog4JFilter() { Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { @@ -314,9 +433,10 @@ public class AuthMe extends JavaPlugin { }); } + // Check the presence of the Vault plugin and a permissions provider public void checkVault() { - if (this.getServer().getPluginManager().getPlugin("Vault") != null && this.getServer().getPluginManager().getPlugin("Vault").isEnabled()) { - RegisteredServiceProvider permissionProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class); + if (server.getPluginManager().getPlugin("Vault").isEnabled()) { + RegisteredServiceProvider permissionProvider = server.getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class); if (permissionProvider != null) { permission = permissionProvider.getProvider(); ConsoleLogger.info("Vault detected, hooking with the " + permission.getName() + " permissions system..."); @@ -328,86 +448,86 @@ public class AuthMe extends JavaPlugin { } } + // Check the version of the ChestShop plugin public void checkChestShop() { - if (!Settings.chestshop) { - this.ChestShop = 0; - return; - } - if (this.getServer().getPluginManager().getPlugin("ChestShop") != null && this.getServer().getPluginManager().getPlugin("ChestShop").isEnabled()) { + if (Settings.legacyChestShop && server.getPluginManager().getPlugin("ChestShop").isEnabled()) { try { - String ver = com.Acrobot.ChestShop.ChestShop.getVersion(); + String rawver = com.Acrobot.ChestShop.ChestShop.getVersion(); + double version = 0; try { - double version = Double.valueOf(ver.split(" ")[0]); - if (version >= 3.50) { - this.ChestShop = version; - } else { - ConsoleLogger.showError("Please Update your ChestShop version! Bugs may occur!"); - } + version = Double.valueOf(rawver.split(" ")[0]); } catch (NumberFormatException nfe) { try { - double version = Double.valueOf(ver.split("t")[0]); - if (version >= 3.50) { - this.ChestShop = version; - } else { - ConsoleLogger.showError("Please Update your ChestShop version! Bugs may occur!"); - } + version = Double.valueOf(rawver.split("t")[0]); } catch (NumberFormatException nfee) { + legacyChestShop = false; + return; } } + if (version >= 3.813){ + return; + } + if (version < 3.50) { + ConsoleLogger.showError("Please Update your ChestShop version! Bugs may occur!"); + return; + } + legacyChestShop = true; } catch (Exception e) { } } else { - this.ChestShop = 0; + legacyChestShop = false; } } + // Check PerWorldInventories version public void checkPerWorldInventories() { - if (this.getServer().getPluginManager().getPlugin("PerWorldInventories") != null && this.getServer().getPluginManager().getPlugin("PerWorldInventories").isEnabled()) { + if (server.getPluginManager().getPlugin("PerWorldInventories").isEnabled()) { try { - String ver = Bukkit.getServer().getPluginManager().getPlugin("PerWorldInventories").getDescription().getVersion(); + double version = 0; + String ver = server.getPluginManager().getPlugin("PerWorldInventories").getDescription().getVersion(); try { - double version = Double.valueOf(ver.split(" ")[0]); - if (version < 1.57) - ConsoleLogger.showError("Please Update your PerWorldInventories version! INVENTORY WIPE may occur!"); + version = Double.valueOf(ver.split(" ")[0]); } catch (NumberFormatException nfe) { try { - double version = Double.valueOf(ver.split("t")[0]); - if (version < 1.57) - ConsoleLogger.showError("Please Update your PerWorldInventories version! INVENTORY WIPE may occur!"); + version = Double.valueOf(ver.split("t")[0]); } catch (NumberFormatException nfee) { } } + if (version < 1.57){ + ConsoleLogger.showError("Please Update your PerWorldInventories version! INVENTORY WIPE may occur!"); + } } catch (Exception e) { - } + } } } + // Get the Multiverse plugin public void checkMultiverse() { - if (!Settings.multiverse) { - multiverse = null; - return; - } - if (this.getServer().getPluginManager().isPluginEnabled("Multiverse-Core")) { + if (Settings.multiverse && this.getServer().getPluginManager().isPluginEnabled("Multiverse-Core")) { try { - multiverse = (MultiverseCore) this.getServer().getPluginManager().getPlugin("Multiverse-Core"); + multiverse = (MultiverseCore) server.getPluginManager().getPlugin("Multiverse-Core"); ConsoleLogger.info("Hooked correctly with Multiverse-Core"); } catch (Exception | NoClassDefFoundError ignored) { + multiverse = null; } + } else { + multiverse = null; } } + // Get the Essentials plugin public void checkEssentials() { - if (this.getServer().getPluginManager().isPluginEnabled("Essentials")) { + if (server.getPluginManager().isPluginEnabled("Essentials")) { try { - ess = (Essentials) this.getServer().getPluginManager().getPlugin("Essentials"); + ess = (Essentials) server.getPluginManager().getPlugin("Essentials"); ConsoleLogger.info("Hooked correctly with Essentials"); - } catch (Exception | NoClassDefFoundError e) { + } catch (Exception | NoClassDefFoundError ingnored) { ess = null; } } else { ess = null; } - if (this.getServer().getPluginManager().isPluginEnabled("EssentialsSpawn")) { + if (server.getPluginManager().isPluginEnabled("EssentialsSpawn")) { try { essentialsSpawn = new EssSpawn().getLocation(); ConsoleLogger.info("Hooked correctly with EssentialsSpawn"); @@ -420,40 +540,35 @@ public class AuthMe extends JavaPlugin { } } + // Check the presence of CombatTag public void checkCombatTag() { this.CombatTag = this.getServer().getPluginManager().isPluginEnabled("CombatTag"); } + // Check if Citizens is active public void checkCitizens() { this.isCitizensActive = this.getServer().getPluginManager().isPluginEnabled("Citizens"); } - @Override - public void onDisable() { - Player[] players = Utils.getOnlinePlayers(); - if (players != null) { - for (Player player : players) { - this.savePlayer(player); - } + // Check if a player/command sender have a permission + public boolean authmePermissible(Player player, String perm) { + if (player.hasPermission(perm)) { + return true; + } else if (permission != null) { + return permission.playerHas(player, perm); } - - if (database != null) { - database.close(); + return false; + } + public boolean authmePermissible(CommandSender sender, String perm) { + if (sender.hasPermission(perm)) { + return true; + } else if (permission != null) { + return permission.has(sender, perm); } - - if (Settings.isBackupActivated && Settings.isBackupOnStop) { - Boolean Backup = new PerformBackup(this).DoBackup(); - if (Backup) - ConsoleLogger.info("Backup performed correctly."); - else ConsoleLogger.showError("Error while performing the backup!"); - } - ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!"); - } - - public static AuthMe getInstance() { - return authme; + return false; } + // Save Player Data public void savePlayer(Player player) { if ((citizens.isNPC(player)) || (Utils.getInstance().isUnrestricted(player)) || (CombatTagComunicator.isNPC(player))) { return; @@ -470,8 +585,9 @@ public class AuthMe extends JavaPlugin { player.getInventory().setArmorContents(limbo.getArmour()); player.getInventory().setContents(limbo.getInventory()); } - if (!Settings.noTeleport) + if (!Settings.noTeleport) { player.teleport(limbo.getLoc()); + } this.utils.addNormal(player, limbo.getGroup()); player.setOp(limbo.getOperator()); limbo.getTimeoutTaskId().cancel(); @@ -487,18 +603,7 @@ public class AuthMe extends JavaPlugin { } } - public CitizensCommunicator getCitizensCommunicator() { - return citizens; - } - - public void setMessages(Messages m) { - this.m = m; - } - - public Messages getMessages() { - return m; - } - + // Select the player to kick when a vip player join the server when full public Player generateKickPlayer(Collection collection) { Player player = null; for (Player p : collection) { @@ -510,24 +615,7 @@ public class AuthMe extends JavaPlugin { return player; } - public boolean authmePermissible(Player player, String perm) { - if (player.hasPermission(perm)) - return true; - else if (permission != null) { - return permission.playerHas(player, perm); - } - return false; - } - - public boolean authmePermissible(CommandSender sender, String perm) { - if (sender.hasPermission(perm)) - return true; - else if (permission != null) { - return permission.has(sender, perm); - } - return false; - } - + // Purge inactive players from the database, as defined in the configuration private void autoPurge() { if (!Settings.usePurge) { return; @@ -536,27 +624,26 @@ public class AuthMe extends JavaPlugin { calendar.add(Calendar.DATE, -(Settings.purgeDelay)); long until = calendar.getTimeInMillis(); List cleared = database.autoPurgeDatabase(until); - if (cleared == null) + if (cleared == null) { return; - if (cleared.isEmpty()) + } + if (cleared.isEmpty()){ return; + } ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!"); if (Settings.purgeEssentialsFile && this.ess != null) - dataManager.purgeEssentials(cleared); // name to UUID convertion - // needed with latest versions + dataManager.purgeEssentials(cleared); // name to UUID convertion needed with latest versions if (Settings.purgePlayerDat) - dataManager.purgeDat(cleared); // name to UUID convertion needed - // with latest versions of MC + dataManager.purgeDat(cleared); // name to UUID convertion needed with latest versions of MC if (Settings.purgeLimitedCreative) dataManager.purgeLimitedCreative(cleared); if (Settings.purgeAntiXray) - dataManager.purgeAntiXray(cleared); // IDK if it uses UUID or - // names... (Actually it purges - // only names!) + dataManager.purgeAntiXray(cleared); // IDK if it uses UUID or names... (Actually it purges only names!) if (Settings.purgePermissions) dataManager.purgePermissions(cleared, permission); } + // Return the spawn location of a player public Location getSpawnLocation(Player player) { World world = player.getWorld(); String[] spawnPriority = Settings.spawnPriority.split(","); @@ -572,15 +659,18 @@ public class AuthMe extends JavaPlugin { if (s.equalsIgnoreCase("authme") && getAuthMeSpawn(player) != null) spawnLoc = getAuthMeSpawn(player); } - if (spawnLoc == null) + if (spawnLoc == null) { spawnLoc = world.getSpawnLocation(); + } return spawnLoc; } + // Return the default spawnpoint of a world private Location getDefaultSpawn(World world) { return world.getSpawnLocation(); } + // Return the multiverse spawnpoint of a world private Location getMultiverseSpawn(World world) { if (multiverse != null && Settings.multiverse) { try { @@ -592,20 +682,26 @@ public class AuthMe extends JavaPlugin { return null; } + // Return the essentials spawnpoint private Location getEssentialsSpawn() { - if (essentialsSpawn != null) + if (essentialsSpawn != null){ return essentialsSpawn; + } return null; } + // Return the authme soawnpoint private Location getAuthMeSpawn(Player player) { - if ((!database.isAuthAvailable(player.getName().toLowerCase()) || !player.hasPlayedBefore()) && (Spawn.getInstance().getFirstSpawn() != null)) + if ((!database.isAuthAvailable(player.getName().toLowerCase()) || !player.hasPlayedBefore()) && (Spawn.getInstance().getFirstSpawn() != null)) { return Spawn.getInstance().getFirstSpawn(); - if (Spawn.getInstance().getSpawn() != null) + } + if (Spawn.getInstance().getSpawn() != null) { return Spawn.getInstance().getSpawn(); + } return player.getWorld().getSpawnLocation(); } + // Download GeoIp data public void downloadGeoIp() { ConsoleLogger.info("[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com"); File file = new File(getDataFolder(), "GeoIP.dat"); @@ -617,8 +713,9 @@ public class AuthMe extends JavaPlugin { conn.setConnectTimeout(10000); conn.connect(); InputStream input = conn.getInputStream(); - if (url.endsWith(".gz")) + if (url.endsWith(".gz")) { input = new GZIPInputStream(input); + } OutputStream output = new FileOutputStream(file); byte[] buffer = new byte[2048]; int length = input.read(buffer); @@ -633,6 +730,8 @@ public class AuthMe extends JavaPlugin { } } + // TODO: Need to review the code below! + public String getCountryCode(String ip) { try { if (ls == null) @@ -757,46 +856,5 @@ public class AuthMe extends JavaPlugin { return realIP; } - public void setupDatabase() throws ClassNotFoundException, PoolInitializationException, SQLException { - /* - * Backend MYSQL - FILE - SQLITE - SQLITEHIKARI - */ - switch (Settings.getDataSource) { - case FILE: - database = new FlatFile(); - break; - case MYSQL: - database = new MySQL(); - break; - case SQLITE: - database = new SQLite(); - final int b = database.getAccountsRegistered(); - if (b >= 4000) - ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + b + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); - break; - case SQLITEHIKARI: - database = new SQLite_HIKARI(); - final int b2 = database.getAccountsRegistered(); - if (b2 >= 8000) - ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + b2 + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); - break; - } - if (Settings.isCachingEnabled) { - database = new CacheDataSource(this, database); - } - - database = new DatabaseCalls(database); - - if (Settings.getDataSource == DataSource.DataSourceType.FILE) { - Converter converter = new ForceFlatToSqlite(database, this); - try { - Thread t = new Thread(converter); - t.start(); - } catch (Exception e) { - } - ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated, next time server starts up, it will be changed to SQLite... Conversion will be started Asynchronously, it will not drop down your performance !"); - ConsoleLogger.showError("If you want to keep FlatFile, set file again into config at backend, but this message and this change will appear again at the next restart"); - } - } } diff --git a/src/main/java/fr/xephi/authme/PerformBackup.java b/src/main/java/fr/xephi/authme/PerformBackup.java index 556ece3c9..72ae2faf2 100644 --- a/src/main/java/fr/xephi/authme/PerformBackup.java +++ b/src/main/java/fr/xephi/authme/PerformBackup.java @@ -37,9 +37,8 @@ public class PerformBackup { return FileBackup("auths.db"); case MYSQL: return MySqlBackup(); - case SQLITE: - return FileBackup(Settings.getMySQLDatabase + ".db"); case SQLITEHIKARI: + case SQLITE: return FileBackup(Settings.getMySQLDatabase + ".db"); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index 4f0b2ed50..b6d161f72 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -57,7 +57,7 @@ public class AuthMeServerListener implements Listener { return; } if (pluginName.equalsIgnoreCase("ChestShop")) { - plugin.ChestShop = 0; + plugin.legacyChestShop = false; ConsoleLogger.info("ChestShop has been disabled, unhook!"); } if (pluginName.equalsIgnoreCase("CombatTag")) { diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 41fbaff71..cd9159031 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -64,7 +64,7 @@ public final class Settings extends YamlConfiguration { protectInventoryBeforeLogInEnabled, isBackupActivated, isBackupOnStart, isBackupOnStop, isStopEnabled, reloadSupport, rakamakUseIp, noConsoleSpam, removePassword, displayOtherAccounts, - useCaptcha, emailRegistration, multiverse, chestshop, bungee, + useCaptcha, emailRegistration, multiverse, legacyChestShop, bungee, banUnsafeIp, doubleEmailCheck, sessionExpireOnIpChange, disableSocialSpy, forceOnlyAfterLogin, useEssentialsMotd, usePurge, purgePlayerDat, purgeEssentialsFile, supportOldPassword, @@ -227,7 +227,7 @@ public final class Settings extends YamlConfiguration { saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8); getmaxRegPerEmail = configFile.getInt("Email.maxRegPerEmail", 1); multiverse = configFile.getBoolean("Hooks.multiverse", true); - chestshop = configFile.getBoolean("Hooks.legacyChestshop", false); + legacyChestShop = configFile.getBoolean("Hooks.legacyChestshop", false); bungee = configFile.getBoolean("Hooks.bungeecord", false); getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds"); banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false); From 3cbc7ab18fffced6d0eea5e389b95777a60e6be4 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 15:18:22 +0200 Subject: [PATCH 033/115] should fix item usage issue --- .../java/fr/xephi/authme/listener/AuthMePlayerListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index cffd68507..e260bc636 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -651,7 +651,7 @@ public class AuthMePlayerListener implements Listener { event.setCancelled(true); } - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) public void onPlayerInteract(PlayerInteractEvent event) { if (event.getPlayer() == null) return; @@ -675,8 +675,9 @@ public class AuthMePlayerListener implements Listener { return; } } - if (event.getClickedBlock() != null && event.getClickedBlock().getType() != Material.AIR) + if (event.getClickedBlock() != null){ event.setUseInteractedBlock(org.bukkit.event.Event.Result.DENY); + } event.setUseItemInHand(org.bukkit.event.Event.Result.DENY); event.setCancelled(true); } From 1994683e47e3819b231639be7fdf7d6ef7fab1a3 Mon Sep 17 00:00:00 2001 From: "Gabriele C." Date: Sun, 13 Sep 2015 15:30:40 +0200 Subject: [PATCH 034/115] Update team.txt --- team.txt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/team.txt b/team.txt index e5ac3a1a6..bb2648888 100644 --- a/team.txt +++ b/team.txt @@ -1,13 +1,19 @@ AuthMe-Team: +Active staff: Xephi (Xephi59) - Leader, Main developer -darkwarriors (d4rkwarriors) - Old AuthMe Reloaded Author -Kloudy - Developer (Inactive, Will be avariable soon) -DNx5 - Developer Gabriele C. (sgdc3) - Ticket Manager, Project Page and Structure Manager, Contributor -Maxetto - Ticket Manager, Italian Translator, Basic Developer, Contributor +DNx5 - Developer +CryLegend - Contributor, AuthMeBridge Developer (Need activation) + +External Contributors: Gnat008 - Contributor -Trojaner25 - Ticket manager, Basic Developer (Need activation) + +Inactive staff: +Maxetto - Ticket Manager, Italian Translator, Basic Developer, Contributor (Inactive) +darkwarriors (d4rkwarriors) - Original AuthMeReloaded Author (Inactive) + +Translators: irobin591 - DE Translator WaterCXubic - ZHHK Translator Bodyash - Russian/Ukrainian translator From 680717dbca27dea5057553fb5ad4c904a8678021 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 16:28:41 +0200 Subject: [PATCH 035/115] Fix --- src/main/java/fr/xephi/authme/AuthMe.java | 27 +++++++++++-------- .../authme/listener/AuthMePlayerListener.java | 1 - 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 2f6c63679..b19c1cb4d 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -140,19 +140,22 @@ public class AuthMe extends JavaPlugin { @Override public void onEnable() { + + // TODO: split the plugin in more modules + // TODO: remove vault as hard dependency + server = getServer(); PluginManager pm = server.getPluginManager(); - authme = this; + // Setup the Logger authmeLogger.setParent(this.getLogger()); - m = Messages.getInstance(); + // Set the Instance + authme = this; + + // Setup otherAccounts file otherAccounts = OtherAccounts.getInstance(); - // TODOs - // TODO: split the plugin in more modules - // TODO: remove vault as hard dependency - // Load settings and custom configurations // TODO: new configuration style (more files) try { @@ -162,7 +165,6 @@ public class AuthMe extends JavaPlugin { this.getServer().shutdown(); return; } - // Configuration Security Warnings if (!Settings.isForceSingleSessionEnabled) { ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); @@ -171,6 +173,9 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!"); } + // Setup messages + m = Messages.getInstance(); + // Start the metrics service // TODO: add a setting to disable metrics try { @@ -435,7 +440,7 @@ public class AuthMe extends JavaPlugin { // Check the presence of the Vault plugin and a permissions provider public void checkVault() { - if (server.getPluginManager().getPlugin("Vault").isEnabled()) { + if (server.getPluginManager().isPluginEnabled("Vault")) { RegisteredServiceProvider permissionProvider = server.getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class); if (permissionProvider != null) { permission = permissionProvider.getProvider(); @@ -450,7 +455,7 @@ public class AuthMe extends JavaPlugin { // Check the version of the ChestShop plugin public void checkChestShop() { - if (Settings.legacyChestShop && server.getPluginManager().getPlugin("ChestShop").isEnabled()) { + if (Settings.legacyChestShop && server.getPluginManager().isPluginEnabled("ChestShop")) { try { String rawver = com.Acrobot.ChestShop.ChestShop.getVersion(); double version = 0; @@ -481,7 +486,7 @@ public class AuthMe extends JavaPlugin { // Check PerWorldInventories version public void checkPerWorldInventories() { - if (server.getPluginManager().getPlugin("PerWorldInventories").isEnabled()) { + if (server.getPluginManager().isPluginEnabled("PerWorldInventories")) { try { double version = 0; String ver = server.getPluginManager().getPlugin("PerWorldInventories").getDescription().getVersion(); @@ -503,7 +508,7 @@ public class AuthMe extends JavaPlugin { // Get the Multiverse plugin public void checkMultiverse() { - if (Settings.multiverse && this.getServer().getPluginManager().isPluginEnabled("Multiverse-Core")) { + if (Settings.multiverse && server.getPluginManager().isPluginEnabled("Multiverse-Core")) { try { multiverse = (MultiverseCore) server.getPluginManager().getPlugin("Multiverse-Core"); ConsoleLogger.info("Hooked correctly with Multiverse-Core"); diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index e260bc636..00f051c7e 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -12,7 +12,6 @@ import java.util.regex.PatternSyntaxException; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; From 851eab2fd051a9c0d707cf691df782731a394de7 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 13 Sep 2015 21:56:42 +0700 Subject: [PATCH 036/115] cleanup Utils.java --- src/main/java/fr/xephi/authme/Utils.java | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 39d5bf554..2d5b3e19a 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -12,6 +12,7 @@ import org.bukkit.entity.Player; import java.io.File; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Collection; import java.util.Iterator; @@ -19,8 +20,7 @@ public class Utils { private String currentGroup; private static Utils singleton; - int id; - public AuthMe plugin; + public final AuthMe plugin; public Utils(AuthMe plugin) { this.plugin = plugin; @@ -112,11 +112,7 @@ public class Utils { } public boolean isUnrestricted(Player player) { - if (!Settings.isAllowRestrictedIp) - return false; - if (Settings.getUnrestrictedName == null || Settings.getUnrestrictedName.isEmpty()) - return false; - return (Settings.getUnrestrictedName.contains(player.getName())); + return Settings.isAllowRestrictedIp && !(Settings.getUnrestrictedName == null || Settings.getUnrestrictedName.isEmpty()) && (Settings.getUnrestrictedName.contains(player.getName())); } public static Utils getInstance() { @@ -125,9 +121,7 @@ public class Utils { } private boolean useGroupSystem() { - if (Settings.isPermissionCheckEnabled && !Settings.getUnloggedinGroup.isEmpty()) - return true; - return false; + return Settings.isPermissionCheckEnabled && !Settings.getUnloggedinGroup.isEmpty(); } public void packCoords(double x, double y, double z, String w, @@ -189,15 +183,17 @@ public class Utils { } public static Player[] getOnlinePlayers() { - Player[] players = null; + Player[] players; try { - if (Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).getReturnType() == Collection.class) { - players = (Player[]) ((Collection) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null)).toArray(); + Method m = Bukkit.class.getMethod("getOnlinePlayers"); + if (m.getReturnType() == Collection.class) { + players = (Player[]) ((Collection) m.invoke(null)).toArray(); } else { - players = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null)); + players = ((Player[]) m.invoke(null)); } } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { // can never happen + players = null; } return players; } From f297609818d0df2b37a4daa9349f47e02344a527 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 17:07:02 +0200 Subject: [PATCH 037/115] cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index b19c1cb4d..26046e614 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -79,36 +79,36 @@ import net.milkbowl.vault.permission.Permission; public class AuthMe extends JavaPlugin { - public DataSource database; - private Settings settings; - private Messages m; - public OtherAccounts otherAccounts; public static Server server; public static Logger authmeLogger = Logger.getLogger("AuthMe"); public static AuthMe authme; - public Permission permission; + public Management management; + public NewAPI api; private Utils utils = Utils.getInstance(); + public SendMailSSL mail = null; + private Settings settings; + private Messages m; + public DataManager dataManager; + public DataSource database; private FileCache playerBackup = new FileCache(this); + public OtherAccounts otherAccounts; + public Permission permission; + public Essentials ess; + public Location essentialsSpawn; + public MultiverseCore multiverse = null; + public LookupService ls = null; public CitizensCommunicator citizens; public boolean isCitizensActive = false; - public SendMailSSL mail = null; public boolean CombatTag = false; public boolean legacyChestShop = false; public boolean BungeeCord = false; - public Essentials ess; - public NewAPI api; - public Management management; + public boolean antibotMod = false; + public boolean delayedAntiBot = true; + public ConcurrentHashMap sessions = new ConcurrentHashMap(); public ConcurrentHashMap captcha = new ConcurrentHashMap(); public ConcurrentHashMap cap = new ConcurrentHashMap(); public ConcurrentHashMap realIp = new ConcurrentHashMap(); - public MultiverseCore multiverse = null; - public Location essentialsSpawn; - public LookupService ls = null; - public boolean antibotMod = false; - public boolean delayedAntiBot = true; protected static String vgUrl = "http://monitor-1.verygames.net/api/?action=ipclean-real-ip&out=raw&ip=%IP%&port=%PORT%"; - public DataManager dataManager; - public ConcurrentHashMap sessions = new ConcurrentHashMap(); public static AuthMe getInstance() { return authme; From 576ff59fcd344512a082a47a5039aaf19c0229cb Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 13 Sep 2015 22:08:18 +0700 Subject: [PATCH 038/115] replace cache with Json --- src/main/java/fr/xephi/authme/AuthMe.java | 4 +- .../xephi/authme/cache/backup/FileCache.java | 277 ------------------ .../xephi/authme/cache/backup/JsonCache.java | 206 +++++++++++++ .../xephi/authme/cache/limbo/LimboCache.java | 6 +- .../authme/commands/UnregisterCommand.java | 6 +- .../authme/events/StoreInventoryEvent.java | 6 +- .../authme/process/join/AsyncronousJoin.java | 6 +- .../login/ProcessSyncronousPlayerLogin.java | 6 +- .../process/logout/AsyncronousLogout.java | 6 +- 9 files changed, 226 insertions(+), 297 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/cache/backup/FileCache.java create mode 100644 src/main/java/fr/xephi/authme/cache/backup/JsonCache.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index b19c1cb4d..ff4ed6c11 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -40,7 +40,7 @@ import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.commands.AdminCommand; @@ -88,7 +88,7 @@ public class AuthMe extends JavaPlugin { public static AuthMe authme; public Permission permission; private Utils utils = Utils.getInstance(); - private FileCache playerBackup = new FileCache(this); + private JsonCache playerBackup = new JsonCache(this); public CitizensCommunicator citizens; public boolean isCitizensActive = false; public SendMailSSL mail = null; diff --git a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java b/src/main/java/fr/xephi/authme/cache/backup/FileCache.java deleted file mode 100644 index 3e119ba6d..000000000 --- a/src/main/java/fr/xephi/authme/cache/backup/FileCache.java +++ /dev/null @@ -1,277 +0,0 @@ -package fr.xephi.authme.cache.backup; - -import com.google.common.io.BaseEncoding; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.Utils; -import fr.xephi.authme.api.API; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.SkullMeta; -import org.bukkit.util.io.BukkitObjectInputStream; -import org.bukkit.util.io.BukkitObjectOutputStream; - -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Scanner; - -public class FileCache { - - private final File cacheDir; - private AuthMe plugin; - - public FileCache(AuthMe plugin) { - this.plugin = plugin; - cacheDir = new File(plugin.getDataFolder() + File.separator + "cache"); - if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { - ConsoleLogger.showError("Failed to create cache directory."); - } - } - - public void createCache(Player player, DataFileCache playerData, - String group, boolean operator, boolean flying) { - if (player == null) { - return; - } - - String path; - try { - path = player.getUniqueId().toString(); - } catch (Exception | Error e) { - path = player.getName().toLowerCase(); - } - - File playerDir = new File(cacheDir, path); - if (!playerDir.exists() && !playerDir.isDirectory() && !playerDir.mkdir()) { - return; - } - - File datafile = new File(playerDir, "playerdatas.cache"); - if (datafile.exists()) { - return; - } - - FileWriter writer; - try { - datafile.createNewFile(); - writer = new FileWriter(datafile); - writer.write(group + API.newline); - writer.write(String.valueOf(operator) + API.newline); - writer.write(String.valueOf(flying) + API.newline); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - BaseEncoding base64 = BaseEncoding.base64(); - - File invDir = new File(playerDir, "inventory"); - if (!invDir.isDirectory() && !invDir.mkdir()) - return; - - ItemStack[] inv = playerData.getInventory(); - for (int i = 0; i < inv.length; i++) { - ItemStack item = inv[i]; - if (item == null) { - item = new ItemStack(Material.AIR); - } - if (item.getType() == Material.SKULL_ITEM) { - SkullMeta meta = (SkullMeta) item.getItemMeta(); - if (meta.hasOwner() && (meta.getOwner() == null || meta.getOwner().isEmpty())) { - item.setItemMeta(plugin.getServer().getItemFactory().getItemMeta(Material.SKULL_ITEM)); - } - } - - try { - File cacheFile = new File(invDir, i + ".cache"); - if (!cacheFile.isFile() && !cacheFile.createNewFile()) { - continue; - } - writer = new FileWriter(cacheFile); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - BukkitObjectOutputStream objectOut = new BukkitObjectOutputStream(baos); - objectOut.writeObject(item); - objectOut.close(); - writer.write(base64.encode(baos.toByteArray())); - writer.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - File armourDir = new File(cacheDir, path + File.separator + "armours"); - if (!armourDir.isDirectory() && !armourDir.mkdir()) - return; - - ItemStack[] armors = playerData.getArmour(); - for (int i = 0; i < armors.length; i++) { - ItemStack item = armors[i]; - if (item == null) { - item = new ItemStack(Material.AIR); - } - if (item.getType() == Material.SKULL_ITEM) { - SkullMeta meta = (SkullMeta) item.getItemMeta(); - if (meta.hasOwner() && (meta.getOwner() == null || meta.getOwner().isEmpty())) { - item.setItemMeta(plugin.getServer().getItemFactory().getItemMeta(Material.SKULL_ITEM)); - } - } - - try { - File cacheFile = new File(armourDir, i + ".cache"); - if (!cacheFile.isFile() && !cacheFile.createNewFile()) { - continue; - } - writer = new FileWriter(cacheFile); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - BukkitObjectOutputStream objectOut = new BukkitObjectOutputStream(baos); - objectOut.writeObject(item); - objectOut.close(); - writer.write(base64.encode(baos.toByteArray())); - writer.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - } - - public DataFileCache readCache(Player player) { - if (player == null) { - return null; - } - - String path; - try { - path = player.getUniqueId().toString(); - } catch (Exception | Error e) { - path = player.getName().toLowerCase(); - } - - File playerDir = new File(cacheDir, path); - if (!playerDir.exists() && !playerDir.isDirectory()) { - return null; - } - - try { - File datafile = new File(playerDir, "playerdatas.cache"); - if (!datafile.exists() || !datafile.isFile()) { - return null; - } - ItemStack[] inv = new ItemStack[36]; - ItemStack[] armours = new ItemStack[4]; - String group = null; - boolean op = false; - boolean flying = false; - - Scanner reader; - try { - reader = new Scanner(datafile); - int count = 1; - while (reader.hasNextLine()) { - String line = reader.nextLine(); - switch (count) { - case 1: - group = line; - break; - case 2: - op = Boolean.parseBoolean(line); - break; - case 3: - flying = Boolean.parseBoolean(line); - break; - default: - break; - } - count++; - } - reader.close(); - } catch (Exception e) { - e.printStackTrace(); - } - - BaseEncoding base64 = BaseEncoding.base64(); - - File invDir = new File(playerDir, "inventory"); - for (int i = 0; i < inv.length; i++) { - byte[] bytes = Files.readAllBytes(Paths.get(invDir.getPath(), i + ".cache")); - String encodedItem = new String(bytes); - bytes = base64.decode(encodedItem); - ByteArrayInputStream baos = new ByteArrayInputStream(bytes); - BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos); - ItemStack item = (ItemStack) objectIn.readObject(); - objectIn.close(); - if (item == null) { - inv[i] = new ItemStack(Material.AIR); - } else { - inv[i] = item; - } - } - - File armourDir = new File(playerDir, "armours"); - for (int i = 0; i < armours.length; i++) { - byte[] bytes = Files.readAllBytes(Paths.get(armourDir.getPath(), i + ".cache")); - String encodedItem = new String(bytes); - bytes = base64.decode(encodedItem); - ByteArrayInputStream baos = new ByteArrayInputStream(bytes); - BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos); - ItemStack item = (ItemStack) objectIn.readObject(); - objectIn.close(); - if (item == null) { - armours[i] = new ItemStack(Material.AIR); - } else { - armours[i] = item; - } - } - - return new DataFileCache(inv, armours, group, op, flying); - - } catch (Exception e) { - e.printStackTrace(); - ConsoleLogger.showError("Error while reading file for " + player.getName() + ", some wipe inventory incoming..."); - return null; - } - } - - public void removeCache(Player player) { - String path; - try { - path = player.getUniqueId().toString(); - } catch (Exception | Error e) { - path = player.getName().toLowerCase(); - } - try { - File file = new File(cacheDir, path); - if (file.list() != null) { - Utils.purgeDirectory(file); - if (!file.delete()) { - ConsoleLogger.showError("Failed to remove" + player.getName() + "cache."); - } - } else { - file = new File(cacheDir, player.getName().toLowerCase() + ".cache"); - if (file.isFile() && !file.delete()) { - ConsoleLogger.showError("Failed to remove" + player.getName() + "cache."); - } - } - } catch (Exception e) { - ConsoleLogger.showError("Failed to remove" + player.getName() + "cache :/"); - } - } - - public boolean doesCacheExist(Player player) { - String path; - try { - path = player.getUniqueId().toString(); - } catch (Exception | Error e) { - path = player.getName().toLowerCase(); - } - File file = new File(cacheDir, path + File.separator + "playerdatas.cache"); - if (!file.exists()) { - file = new File(cacheDir, player.getName().toLowerCase() + ".cache"); - } - - return file.exists(); - } - -} diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java new file mode 100644 index 000000000..25db2afbf --- /dev/null +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -0,0 +1,206 @@ +package fr.xephi.authme.cache.backup; + +import com.google.common.io.BaseEncoding; +import com.google.gson.*; +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.Utils; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.util.io.BukkitObjectInputStream; +import org.bukkit.util.io.BukkitObjectOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class JsonCache { + + private final Gson gson; + private final AuthMe plugin; + private final File cacheDir; + + public JsonCache(AuthMe plugin) { + this.plugin = plugin; + cacheDir = new File(plugin.getDataFolder() + File.separator + "cache"); + if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { + ConsoleLogger.showError("Failed to create cache directory."); + } + gson = new GsonBuilder() + .registerTypeAdapter(DataFileCache.class, new PlayerDataSerializer()) + .registerTypeAdapter(DataFileCache.class, new PlayerDataDeserializer()) + .setPrettyPrinting() + .create(); + } + + public void createCache(Player player, DataFileCache playerData) { + if (player == null) { + return; + } + + String path; + try { + path = player.getUniqueId().toString(); + } catch (Exception | Error e) { + path = player.getName().toLowerCase(); + } + + File file = new File(cacheDir, path + File.separator + "cache.json"); + if (file.exists()) { + return; + } + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) { + return; + } + + try { + String data = gson.toJson(playerData); + Files.write(Paths.get(file.getPath()), data.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public DataFileCache readCache(Player player) { + String path; + try { + path = player.getUniqueId().toString(); + } catch (Exception | Error e) { + path = player.getName().toLowerCase(); + } + + File file = new File(cacheDir, path + File.separator + "cache.json"); + try { + byte[] bytes = Files.readAllBytes(Paths.get(file.getPath())); + String str = new String(bytes); + return gson.fromJson(str, DataFileCache.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private class PlayerDataSerializer implements JsonSerializer { + @Override + public JsonElement serialize(DataFileCache dataFileCache, Type type, JsonSerializationContext jsonSerializationContext) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("group", dataFileCache.getGroup()); + jsonObject.addProperty("operator", dataFileCache.getOperator()); + jsonObject.addProperty("flying", dataFileCache.isFlying()); + + JsonArray arr; + ItemStack[] contents; + + // inventory + contents = dataFileCache.getInventory(); + arr = new JsonArray(); + putItems(contents, arr); + + // armour + contents = dataFileCache.getArmour(); + arr = new JsonArray(); + putItems(contents, arr); + jsonObject.add("armour", arr); + + return jsonObject; + } + + private void putItems(ItemStack[] contents, JsonArray target) { + for (ItemStack item : contents) { + if (item == null) { + item = new ItemStack(Material.AIR); + } + JsonObject val = new JsonObject(); + if (item.getType() == Material.SKULL_ITEM) { + SkullMeta meta = (SkullMeta) item.getItemMeta(); + if (meta.hasOwner() && (meta.getOwner() == null || meta.getOwner().isEmpty())) { + item.setItemMeta(plugin.getServer().getItemFactory().getItemMeta(Material.SKULL_ITEM)); + } + } + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BukkitObjectOutputStream objectOut = new BukkitObjectOutputStream(baos); + objectOut.writeObject(item); + objectOut.close(); + val.addProperty("item", BaseEncoding.base64().encode(baos.toByteArray())); + } catch (IOException e) { + e.printStackTrace(); + continue; + } + target.add(val); + } + } + } + + private class PlayerDataDeserializer implements JsonDeserializer { + @Override + public DataFileCache deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + String group = jsonObject.get("group").getAsString(); + boolean operator = jsonObject.get("operator").getAsBoolean(); + boolean flying = jsonObject.get("flying").getAsBoolean(); + + JsonArray arr; + + arr = jsonObject.get("inventory").getAsJsonArray(); + ItemStack[] inv = getItems(arr); + + arr = jsonObject.get("armour").getAsJsonArray(); + ItemStack[] armour = getItems(arr); + + return new DataFileCache(inv, armour, group, operator, flying); + } + + private ItemStack[] getItems(JsonArray arr) { + ItemStack[] contents = new ItemStack[arr.size()]; + for (int i = 0; i < arr.size(); i++) { + JsonObject item = arr.get(i).getAsJsonObject(); + String encoded = item.get("item").getAsString(); + byte[] decoded = BaseEncoding.base64().decode(encoded); + try { + ByteArrayInputStream baos = new ByteArrayInputStream(decoded); + BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos); + contents[i] = (ItemStack) objectIn.readObject(); + objectIn.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + return contents; + } + } + + public void removeCache(Player player) { + String path; + try { + path = player.getUniqueId().toString(); + } catch (Exception | Error e) { + path = player.getName().toLowerCase(); + } + File file = new File(cacheDir, path + File.separator + "cache.json"); + if (file.exists()) { + Utils.purgeDirectory(file); + if (!file.delete()) { + ConsoleLogger.showError("Failed to remove" + player.getName() + "cache."); + } + } + } + + public boolean doesCacheExist(Player player) { + String path; + try { + path = player.getUniqueId().toString(); + } catch (Exception | Error e) { + path = player.getName().toLowerCase(); + } + File file = new File(cacheDir, path + File.separator + "cache.json"); + return file.exists(); + } + +} diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 6f7450244..b158a8ccf 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -3,7 +3,7 @@ package fr.xephi.authme.cache.limbo; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.backup.DataFileCache; -import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.events.ResetInventoryEvent; import fr.xephi.authme.events.StoreInventoryEvent; import fr.xephi.authme.settings.Settings; @@ -19,13 +19,13 @@ public class LimboCache { private volatile static LimboCache singleton = null; public ConcurrentHashMap cache; - private FileCache playerData; + private JsonCache playerData; public AuthMe plugin; private LimboCache(AuthMe plugin) { this.plugin = plugin; this.cache = new ConcurrentHashMap(); - this.playerData = new FileCache(plugin); + this.playerData = new JsonCache(plugin); } public void addLimboPlayer(Player player) { diff --git a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java index 1361656d6..57e653039 100644 --- a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java +++ b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java @@ -18,7 +18,7 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; import fr.xephi.authme.Utils.groupType; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.events.SpawnTeleportEvent; import fr.xephi.authme.security.PasswordSecurity; @@ -31,11 +31,11 @@ public class UnregisterCommand implements CommandExecutor { private Messages m = Messages.getInstance(); public AuthMe plugin; - private FileCache playerCache; + private JsonCache playerCache; public UnregisterCommand(AuthMe plugin) { this.plugin = plugin; - this.playerCache = new FileCache(plugin); + this.playerCache = new JsonCache(plugin); } @Override diff --git a/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java b/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java index 66911d187..e8a78806c 100644 --- a/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java +++ b/src/main/java/fr/xephi/authme/events/StoreInventoryEvent.java @@ -1,7 +1,7 @@ package fr.xephi.authme.events; import fr.xephi.authme.cache.backup.DataFileCache; -import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.cache.backup.JsonCache; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -22,9 +22,9 @@ public class StoreInventoryEvent extends CustomEvent { this.armor = player.getInventory().getArmorContents(); } - public StoreInventoryEvent(Player player, FileCache fileCache) { + public StoreInventoryEvent(Player player, JsonCache jsonCache) { this.player = player; - DataFileCache cache = fileCache.readCache(player); + DataFileCache cache = jsonCache.readCache(player); if (cache != null) { this.inventory = cache.getInventory(); this.armor = cache.getArmour(); diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index 3a3e8e1f3..c0cd93d72 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -19,7 +19,7 @@ import fr.xephi.authme.Utils.groupType; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.DataFileCache; -import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.datasource.DataSource; @@ -42,13 +42,13 @@ public class AsyncronousJoin { protected String name; private Utils utils = Utils.getInstance(); private Messages m = Messages.getInstance(); - private FileCache playerBackup; + private JsonCache playerBackup; public AsyncronousJoin(Player player, AuthMe plugin, DataSource database) { this.player = player; this.plugin = plugin; this.database = database; - this.playerBackup = new FileCache(plugin); + this.playerBackup = new JsonCache(plugin); this.name = player.getName().toLowerCase(); } diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index 276a8c23b..acb1f832e 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -11,7 +11,7 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; import fr.xephi.authme.Utils.groupType; import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.datasource.DataSource; @@ -31,7 +31,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { private AuthMe plugin; private DataSource database; private PluginManager pm; - private FileCache playerCache; + private JsonCache playerCache; public ProcessSyncronousPlayerLogin(Player player, AuthMe plugin, DataSource data) { @@ -42,7 +42,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { this.name = player.getName().toLowerCase(); this.limbo = LimboCache.getInstance().getLimboPlayer(name); this.auth = database.getAuth(name); - this.playerCache = new FileCache(plugin); + this.playerCache = new JsonCache(plugin); } public LimboPlayer getLimbo() { diff --git a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java index 366e72d4c..a665a229d 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java @@ -10,7 +10,7 @@ import fr.xephi.authme.Utils.groupType; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.DataFileCache; -import fr.xephi.authme.cache.backup.FileCache; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.AuthMeTeleportEvent; @@ -26,7 +26,7 @@ public class AsyncronousLogout { protected boolean canLogout = true; private Messages m = Messages.getInstance(); private Utils utils = Utils.getInstance(); - private FileCache playerBackup; + private JsonCache playerBackup; public AsyncronousLogout(Player player, AuthMe plugin, DataSource database) { @@ -34,7 +34,7 @@ public class AsyncronousLogout { this.plugin = plugin; this.database = database; this.name = player.getName().toLowerCase(); - this.playerBackup = new FileCache(plugin); + this.playerBackup = new JsonCache(plugin); } private void preLogout() { From b0fc123229e6ff401def79d4a77ed220364ef2cd Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 13 Sep 2015 22:10:41 +0700 Subject: [PATCH 039/115] replace cache with Json --- src/main/java/fr/xephi/authme/AuthMe.java | 141 +++++++++------------- 1 file changed, 58 insertions(+), 83 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 26046e614..e7ad1c890 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -1,23 +1,31 @@ package fr.xephi.authme; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLConnection; -import java.sql.SQLException; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; -import java.util.zip.GZIPInputStream; - +import com.earth2me.essentials.Essentials; +import com.maxmind.geoip.LookupService; +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.zaxxer.hikari.pool.PoolInitializationException; +import fr.xephi.authme.api.API; +import fr.xephi.authme.api.NewAPI; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.cache.auth.PlayerCache; +import fr.xephi.authme.cache.backup.JsonCache; +import fr.xephi.authme.cache.limbo.LimboCache; +import fr.xephi.authme.cache.limbo.LimboPlayer; +import fr.xephi.authme.commands.*; +import fr.xephi.authme.converter.Converter; +import fr.xephi.authme.converter.ForceFlatToSqlite; +import fr.xephi.authme.datasource.*; +import fr.xephi.authme.listener.*; +import fr.xephi.authme.plugin.manager.BungeeCordMessage; +import fr.xephi.authme.plugin.manager.CitizensCommunicator; +import fr.xephi.authme.plugin.manager.CombatTagComunicator; +import fr.xephi.authme.plugin.manager.EssSpawn; +import fr.xephi.authme.process.Management; +import fr.xephi.authme.settings.Messages; +import fr.xephi.authme.settings.OtherAccounts; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.Spawn; +import net.milkbowl.vault.permission.Permission; import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -31,51 +39,17 @@ import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitTask; import org.mcstats.Metrics; -import com.earth2me.essentials.Essentials; -import com.maxmind.geoip.LookupService; -import com.onarandombox.MultiverseCore.MultiverseCore; -import com.zaxxer.hikari.pool.PoolInitializationException; - -import fr.xephi.authme.api.API; -import fr.xephi.authme.api.NewAPI; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.cache.backup.FileCache; -import fr.xephi.authme.cache.limbo.LimboCache; -import fr.xephi.authme.cache.limbo.LimboPlayer; -import fr.xephi.authme.commands.AdminCommand; -import fr.xephi.authme.commands.CaptchaCommand; -import fr.xephi.authme.commands.ChangePasswordCommand; -import fr.xephi.authme.commands.ConverterCommand; -import fr.xephi.authme.commands.EmailCommand; -import fr.xephi.authme.commands.LoginCommand; -import fr.xephi.authme.commands.LogoutCommand; -import fr.xephi.authme.commands.RegisterCommand; -import fr.xephi.authme.commands.UnregisterCommand; -import fr.xephi.authme.converter.Converter; -import fr.xephi.authme.converter.ForceFlatToSqlite; -import fr.xephi.authme.datasource.CacheDataSource; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DatabaseCalls; -import fr.xephi.authme.datasource.FlatFile; -import fr.xephi.authme.datasource.MySQL; -import fr.xephi.authme.datasource.SQLite; -import fr.xephi.authme.datasource.SQLite_HIKARI; -import fr.xephi.authme.listener.AuthMeBlockListener; -import fr.xephi.authme.listener.AuthMeChestShopListener; -import fr.xephi.authme.listener.AuthMeEntityListener; -import fr.xephi.authme.listener.AuthMePlayerListener; -import fr.xephi.authme.listener.AuthMeServerListener; -import fr.xephi.authme.plugin.manager.BungeeCordMessage; -import fr.xephi.authme.plugin.manager.CitizensCommunicator; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; -import fr.xephi.authme.plugin.manager.EssSpawn; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.settings.Messages; -import fr.xephi.authme.settings.OtherAccounts; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.Spawn; -import net.milkbowl.vault.permission.Permission; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.sql.SQLException; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; +import java.util.zip.GZIPInputStream; public class AuthMe extends JavaPlugin { @@ -90,7 +64,8 @@ public class AuthMe extends JavaPlugin { private Messages m; public DataManager dataManager; public DataSource database; - private FileCache playerBackup = new FileCache(this); + + private JsonCache playerBackup = new JsonCache(this); public OtherAccounts otherAccounts; public Permission permission; public Essentials ess; @@ -246,11 +221,11 @@ public class AuthMe extends JavaPlugin { // Do backup on start if enabled if (Settings.isBackupActivated && Settings.isBackupOnStart) { - // Do backup and check return value! - if (new PerformBackup(this).DoBackup()){ + // Do backup and check return value! + if (new PerformBackup(this).DoBackup()) { ConsoleLogger.info("Backup performed correctly"); } else { - ConsoleLogger.showError("Error while performing the backup!"); + ConsoleLogger.showError("Error while performing the backup!"); } } @@ -342,7 +317,7 @@ public class AuthMe extends JavaPlugin { @Override public void onDisable() { - // Save player data + // Save player data Player[] players = Utils.getOnlinePlayers(); if (players != null) { for (Player player : players) { @@ -368,7 +343,7 @@ public class AuthMe extends JavaPlugin { } // Stop/unload the server/plugin as defined in the configuration - public void stopOrUnload(){ + public void stopOrUnload() { if (Settings.isStopEnabled) { ConsoleLogger.showError("THE SERVER IS GOING TO SHUTDOWN AS DEFINED IN THE CONFIGURATION!"); AuthMe.getInstance().getServer().shutdown(); @@ -378,7 +353,7 @@ public class AuthMe extends JavaPlugin { } // Show the exception message and stop/unload the server/plugin as defined in the configuration - public void stopOrUnload(Exception e){ + public void stopOrUnload(Exception e) { ConsoleLogger.showError(e.getMessage()); stopOrUnload(); } @@ -386,7 +361,7 @@ public class AuthMe extends JavaPlugin { // Initialize and setup the database public void setupDatabase() throws ClassNotFoundException, PoolInitializationException, SQLException { // Backend MYSQL - FILE - SQLITE - SQLITEHIKARI - int accounts = 0; + int accounts = 0; switch (Settings.getDataSource) { case FILE: database = new FlatFile(); @@ -469,8 +444,8 @@ public class AuthMe extends JavaPlugin { return; } } - if (version >= 3.813){ - return; + if (version >= 3.813) { + return; } if (version < 3.50) { ConsoleLogger.showError("Please Update your ChestShop version! Bugs may occur!"); @@ -488,7 +463,7 @@ public class AuthMe extends JavaPlugin { public void checkPerWorldInventories() { if (server.getPluginManager().isPluginEnabled("PerWorldInventories")) { try { - double version = 0; + double version = 0; String ver = server.getPluginManager().getPlugin("PerWorldInventories").getDescription().getVersion(); try { version = Double.valueOf(ver.split(" ")[0]); @@ -498,11 +473,11 @@ public class AuthMe extends JavaPlugin { } catch (NumberFormatException nfee) { } } - if (version < 1.57){ + if (version < 1.57) { ConsoleLogger.showError("Please Update your PerWorldInventories version! INVENTORY WIPE may occur!"); - } + } } catch (Exception e) { - } + } } } @@ -513,10 +488,10 @@ public class AuthMe extends JavaPlugin { multiverse = (MultiverseCore) server.getPluginManager().getPlugin("Multiverse-Core"); ConsoleLogger.info("Hooked correctly with Multiverse-Core"); } catch (Exception | NoClassDefFoundError ignored) { - multiverse = null; + multiverse = null; } } else { - multiverse = null; + multiverse = null; } } @@ -564,6 +539,7 @@ public class AuthMe extends JavaPlugin { } return false; } + public boolean authmePermissible(CommandSender sender, String perm) { if (sender.hasPermission(perm)) { return true; @@ -632,7 +608,7 @@ public class AuthMe extends JavaPlugin { if (cleared == null) { return; } - if (cleared.isEmpty()){ + if (cleared.isEmpty()) { return; } ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!"); @@ -689,7 +665,7 @@ public class AuthMe extends JavaPlugin { // Return the essentials spawnpoint private Location getEssentialsSpawn() { - if (essentialsSpawn != null){ + if (essentialsSpawn != null) { return essentialsSpawn; } return null; @@ -840,8 +816,7 @@ public class AuthMe extends JavaPlugin { /** * Get Player real IP through VeryGames method * - * @param player - * player + * @param player player */ @Deprecated public String getVeryGamesIP(Player player) { From e85d8acc24ac7645b6904a967b4cc521672dffe8 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 13 Sep 2015 22:40:19 +0700 Subject: [PATCH 040/115] refactor, --- src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java | 2 +- .../java/fr/xephi/authme/process/logout/AsyncronousLogout.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index c0cd93d72..b1db6afe8 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -134,7 +134,7 @@ public class AsyncronousJoin { LimboCache.getInstance().updateLimboPlayer(player); try { DataFileCache dataFile = new DataFileCache(LimboCache.getInstance().getLimboPlayer(name).getInventory(), LimboCache.getInstance().getLimboPlayer(name).getArmour()); - playerBackup.createCache(player, dataFile, LimboCache.getInstance().getLimboPlayer(name).getGroup(), LimboCache.getInstance().getLimboPlayer(name).getOperator(), LimboCache.getInstance().getLimboPlayer(name).isFlying()); + playerBackup.createCache(player, dataFile); } catch (Exception e) { ConsoleLogger.showError("Error on creating an inventory cache for " + name + ", maybe inventory wipe in preparation..."); } diff --git a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java index a665a229d..f1dde5873 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java @@ -85,7 +85,7 @@ public class AsyncronousLogout { // create cache file for handling lost of inventories on unlogged in // status DataFileCache playerData = new DataFileCache(LimboCache.getInstance().getLimboPlayer(name).getInventory(), LimboCache.getInstance().getLimboPlayer(name).getArmour()); - playerBackup.createCache(player, playerData, LimboCache.getInstance().getLimboPlayer(name).getGroup(), LimboCache.getInstance().getLimboPlayer(name).getOperator(), LimboCache.getInstance().getLimboPlayer(name).isFlying()); + playerBackup.createCache(player, playerData); } sched.scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerLogout(p, plugin)); } From 7458224ada0480f8ac389497d8e6aab9693ff621 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 13 Sep 2015 23:41:28 +0700 Subject: [PATCH 041/115] Enhance mainclass --- src/main/java/fr/xephi/authme/AuthMe.java | 210 ++++++++---------- src/main/java/fr/xephi/authme/Utils.java | 41 ++-- .../authme/listener/AuthMePlayerListener.java | 2 +- 3 files changed, 121 insertions(+), 132 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index e7ad1c890..0c9c57491 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -71,7 +71,7 @@ public class AuthMe extends JavaPlugin { public Essentials ess; public Location essentialsSpawn; public MultiverseCore multiverse = null; - public LookupService ls = null; + public LookupService lookupService = null; public CitizensCommunicator citizens; public boolean isCitizensActive = false; public boolean CombatTag = false; @@ -79,10 +79,10 @@ public class AuthMe extends JavaPlugin { public boolean BungeeCord = false; public boolean antibotMod = false; public boolean delayedAntiBot = true; - public ConcurrentHashMap sessions = new ConcurrentHashMap(); - public ConcurrentHashMap captcha = new ConcurrentHashMap(); - public ConcurrentHashMap cap = new ConcurrentHashMap(); - public ConcurrentHashMap realIp = new ConcurrentHashMap(); + public ConcurrentHashMap sessions = new ConcurrentHashMap<>(); + public ConcurrentHashMap captcha = new ConcurrentHashMap<>(); + public ConcurrentHashMap cap = new ConcurrentHashMap<>(); + public ConcurrentHashMap realIp = new ConcurrentHashMap<>(); protected static String vgUrl = "http://monitor-1.verygames.net/api/?action=ipclean-real-ip&out=raw&ip=%IP%&port=%PORT%"; public static AuthMe getInstance() { @@ -264,22 +264,19 @@ public class AuthMe extends JavaPlugin { // Reload support hook if (Settings.reloadSupport) { - try { - int playersOnline = Utils.getOnlinePlayers().length; - if (database != null) { - if (playersOnline < 1) { - database.purgeLogged(); - } else { - for (PlayerAuth auth : database.getLoggedPlayers()) { - if (auth == null) - continue; - auth.setLastLogin(new Date().getTime()); - database.updateSession(auth); - PlayerCache.getInstance().addPlayer(auth); - } + int playersOnline = Utils.getOnlinePlayers().size(); + if (database != null) { + if (playersOnline < 1) { + database.purgeLogged(); + } else { + for (PlayerAuth auth : database.getLoggedPlayers()) { + if (auth == null) + continue; + auth.setLastLogin(new Date().getTime()); + database.updateSession(auth); + PlayerCache.getInstance().addPlayer(auth); } } - } catch (Exception ex) { } } @@ -318,7 +315,7 @@ public class AuthMe extends JavaPlugin { @Override public void onDisable() { // Save player data - Player[] players = Utils.getOnlinePlayers(); + Collection players = Utils.getOnlinePlayers(); if (players != null) { for (Player player : players) { this.savePlayer(player); @@ -361,7 +358,7 @@ public class AuthMe extends JavaPlugin { // Initialize and setup the database public void setupDatabase() throws ClassNotFoundException, PoolInitializationException, SQLException { // Backend MYSQL - FILE - SQLITE - SQLITEHIKARI - int accounts = 0; + int accounts; switch (Settings.getDataSource) { case FILE: database = new FlatFile(); @@ -391,11 +388,7 @@ public class AuthMe extends JavaPlugin { if (Settings.getDataSource == DataSource.DataSourceType.FILE) { Converter converter = new ForceFlatToSqlite(database, this); - try { - Thread t = new Thread(converter); - t.start(); - } catch (Exception e) { - } + getServer().getScheduler().runTaskAsynchronously(this, converter); ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated, next time server starts up, it will be changed to SQLite... Conversion will be started Asynchronously, it will not drop down your performance !"); ConsoleLogger.showError("If you want to keep FlatFile, set file again into config at backend, but this message and this change will appear again at the next restart"); } @@ -431,29 +424,26 @@ public class AuthMe extends JavaPlugin { // Check the version of the ChestShop plugin public void checkChestShop() { if (Settings.legacyChestShop && server.getPluginManager().isPluginEnabled("ChestShop")) { + String rawver = com.Acrobot.ChestShop.ChestShop.getVersion(); + double version; try { - String rawver = com.Acrobot.ChestShop.ChestShop.getVersion(); - double version = 0; + version = Double.valueOf(rawver.split(" ")[0]); + } catch (NumberFormatException nfe) { try { - version = Double.valueOf(rawver.split(" ")[0]); - } catch (NumberFormatException nfe) { - try { - version = Double.valueOf(rawver.split("t")[0]); - } catch (NumberFormatException nfee) { - legacyChestShop = false; - return; - } - } - if (version >= 3.813) { + version = Double.valueOf(rawver.split("t")[0]); + } catch (NumberFormatException nfee) { + legacyChestShop = false; return; } - if (version < 3.50) { - ConsoleLogger.showError("Please Update your ChestShop version! Bugs may occur!"); - return; - } - legacyChestShop = true; - } catch (Exception e) { } + if (version >= 3.813) { + return; + } + if (version < 3.50) { + ConsoleLogger.showError("Please Update your ChestShop version! Bugs may occur!"); + return; + } + legacyChestShop = true; } else { legacyChestShop = false; } @@ -462,21 +452,18 @@ public class AuthMe extends JavaPlugin { // Check PerWorldInventories version public void checkPerWorldInventories() { if (server.getPluginManager().isPluginEnabled("PerWorldInventories")) { + double version = 0; + String ver = server.getPluginManager().getPlugin("PerWorldInventories").getDescription().getVersion(); try { - double version = 0; - String ver = server.getPluginManager().getPlugin("PerWorldInventories").getDescription().getVersion(); + version = Double.valueOf(ver.split(" ")[0]); + } catch (NumberFormatException nfe) { try { - version = Double.valueOf(ver.split(" ")[0]); - } catch (NumberFormatException nfe) { - try { - version = Double.valueOf(ver.split("t")[0]); - } catch (NumberFormatException nfee) { - } + version = Double.valueOf(ver.split("t")[0]); + } catch (NumberFormatException ignore) { } - if (version < 1.57) { - ConsoleLogger.showError("Please Update your PerWorldInventories version! INVENTORY WIPE may occur!"); - } - } catch (Exception e) { + } + if (version < 1.57) { + ConsoleLogger.showError("Please Update your PerWorldInventories version! INVENTORY WIPE may occur!"); } } } @@ -554,34 +541,31 @@ public class AuthMe extends JavaPlugin { if ((citizens.isNPC(player)) || (Utils.getInstance().isUnrestricted(player)) || (CombatTagComunicator.isNPC(player))) { return; } - try { - String name = player.getName().toLowerCase(); - if (PlayerCache.getInstance().isAuthenticated(name) && !player.isDead() && Settings.isSaveQuitLocationEnabled) { - final PlayerAuth auth = new PlayerAuth(player.getName().toLowerCase(), player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player.getWorld().getName(), player.getName()); - database.updateQuitLoc(auth); - } - if (LimboCache.getInstance().hasLimboPlayer(name)) { - LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); - if (Settings.protectInventoryBeforeLogInEnabled) { - player.getInventory().setArmorContents(limbo.getArmour()); - player.getInventory().setContents(limbo.getInventory()); - } - if (!Settings.noTeleport) { - player.teleport(limbo.getLoc()); - } - this.utils.addNormal(player, limbo.getGroup()); - player.setOp(limbo.getOperator()); - limbo.getTimeoutTaskId().cancel(); - LimboCache.getInstance().deleteLimboPlayer(name); - if (this.playerBackup.doesCacheExist(player)) { - this.playerBackup.removeCache(player); - } - } - PlayerCache.getInstance().removePlayer(name); - database.setUnlogged(name); - player.saveData(); - } catch (Exception ex) { + String name = player.getName().toLowerCase(); + if (PlayerCache.getInstance().isAuthenticated(name) && !player.isDead() && Settings.isSaveQuitLocationEnabled) { + final PlayerAuth auth = new PlayerAuth(player.getName().toLowerCase(), player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player.getWorld().getName(), player.getName()); + database.updateQuitLoc(auth); } + if (LimboCache.getInstance().hasLimboPlayer(name)) { + LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); + if (Settings.protectInventoryBeforeLogInEnabled) { + player.getInventory().setArmorContents(limbo.getArmour()); + player.getInventory().setContents(limbo.getInventory()); + } + if (!Settings.noTeleport) { + player.teleport(limbo.getLoc()); + } + this.utils.addNormal(player, limbo.getGroup()); + player.setOp(limbo.getOperator()); + limbo.getTimeoutTaskId().cancel(); + LimboCache.getInstance().deleteLimboPlayer(name); + if (this.playerBackup.doesCacheExist(player)) { + this.playerBackup.removeCache(player); + } + } + PlayerCache.getInstance().removePlayer(name); + database.setUnlogged(name); + player.saveData(); } // Select the player to kick when a vip player join the server when full @@ -686,8 +670,12 @@ public class AuthMe extends JavaPlugin { public void downloadGeoIp() { ConsoleLogger.info("[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com"); File file = new File(getDataFolder(), "GeoIP.dat"); - if (!file.exists()) { - try { + try { + if (file.exists()) { + if (lookupService == null) { + lookupService = new LookupService(file); + } + } else { String url = "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"; URL downloadUrl = new URL(url); URLConnection conn = downloadUrl.openConnection(); @@ -706,35 +694,26 @@ public class AuthMe extends JavaPlugin { } output.close(); input.close(); - } catch (Exception e) { } + } catch (Exception e) { + ConsoleLogger.writeStackTrace(e); } } // TODO: Need to review the code below! public String getCountryCode(String ip) { - try { - if (ls == null) - ls = new LookupService(new File(getDataFolder(), "GeoIP.dat")); - String code = ls.getCountry(ip).getCode(); - if (code != null && !code.isEmpty()) - return code; - } catch (Exception e) { + if (lookupService != null) { + return lookupService.getCountry(ip).getCode(); } - return null; + return "--"; } public String getCountryName(String ip) { - try { - if (ls == null) - ls = new LookupService(new File(getDataFolder(), "GeoIP.dat")); - String code = ls.getCountry(ip).getName(); - if (code != null && !code.isEmpty()) - return code; - } catch (Exception e) { + if (lookupService != null) { + return lookupService.getCountry(ip).getName(); } - return null; + return "N/A"; } public void switchAntiBotMod(boolean mode) { @@ -765,20 +744,17 @@ public class AuthMe extends JavaPlugin { } public String replaceAllInfos(String message, Player player) { - try { - int playersOnline = Utils.getOnlinePlayers().length; - message = message.replace("&", "\u00a7"); - message = message.replace("{PLAYER}", player.getName()); - message = message.replace("{ONLINE}", "" + playersOnline); - message = message.replace("{MAXPLAYERS}", "" + this.getServer().getMaxPlayers()); - message = message.replace("{IP}", getIP(player)); - message = message.replace("{LOGINS}", "" + PlayerCache.getInstance().getLogged()); - message = message.replace("{WORLD}", player.getWorld().getName()); - message = message.replace("{SERVER}", this.getServer().getServerName()); - message = message.replace("{VERSION}", this.getServer().getBukkitVersion()); - message = message.replace("{COUNTRY}", this.getCountryName(getIP(player))); - } catch (Exception e) { - } + int playersOnline = Utils.getOnlinePlayers().size(); + message = message.replace("&", "\u00a7"); + message = message.replace("{PLAYER}", player.getName()); + message = message.replace("{ONLINE}", "" + playersOnline); + message = message.replace("{MAXPLAYERS}", "" + this.getServer().getMaxPlayers()); + message = message.replace("{IP}", getIP(player)); + message = message.replace("{LOGINS}", "" + PlayerCache.getInstance().getLogged()); + message = message.replace("{WORLD}", player.getWorld().getName()); + message = message.replace("{SERVER}", this.getServer().getServerName()); + message = message.replace("{VERSION}", this.getServer().getBukkitVersion()); + message = message.replace("{COUNTRY}", this.getCountryName(getIP(player))); return message; } @@ -831,7 +807,7 @@ public class AuthMe extends JavaPlugin { if (inputLine != null && !inputLine.isEmpty() && !inputLine.equalsIgnoreCase("error") && !inputLine.contains("error")) { realIP = inputLine; } - } catch (Exception e) { + } catch (Exception ignored) { } return realIP; } diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 2d5b3e19a..7d4e9b775 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -11,21 +11,32 @@ import org.bukkit.World; import org.bukkit.entity.Player; import java.io.File; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; public class Utils { + private static boolean getOnlinePlayersIsCollection; private String currentGroup; private static Utils singleton; + private static Method getOnlinePlayers; public final AuthMe plugin; public Utils(AuthMe plugin) { this.plugin = plugin; } + static { + try { + Method m = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); + getOnlinePlayersIsCollection = m.getReturnType() == Collection.class; + } catch (Exception ignored) { + } + } + public void setGroup(Player player, groupType group) { setGroup(player.getName(), group); } @@ -182,19 +193,21 @@ public class Utils { } } - public static Player[] getOnlinePlayers() { - Player[] players; - try { - Method m = Bukkit.class.getMethod("getOnlinePlayers"); - if (m.getReturnType() == Collection.class) { - players = (Player[]) ((Collection) m.invoke(null)).toArray(); - } else { - players = ((Player[]) m.invoke(null)); - } - } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { - // can never happen - players = null; + public static Collection getOnlinePlayers() { + if (getOnlinePlayersIsCollection) { + return Bukkit.getOnlinePlayers(); } - return players; + try { + if (getOnlinePlayers == null) { + getOnlinePlayers = Bukkit.class.getMethod("getOnlinePlayers"); + } + Object obj = getOnlinePlayers.invoke(null); + if (obj instanceof Collection) { + return (Collection) obj; + } + return Arrays.asList((Player[]) obj); + } catch (Exception ignored) { + } + return Collections.emptyList(); } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 00f051c7e..2e506a401 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -572,7 +572,7 @@ public class AuthMePlayerListener implements Listener { return; } - int playersOnline = Utils.getOnlinePlayers().length; + int playersOnline = Utils.getOnlinePlayers().size(); if (playersOnline > plugin.getServer().getMaxPlayers()) { event.allow(); return; From 355c04c361c15412636794f89735c0b340d9e304 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 00:19:37 +0700 Subject: [PATCH 042/115] prevent eating food --- .../authme/listener/AuthMePlayerListener.java | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 2e506a401..3f2dfc2cb 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -21,21 +21,7 @@ import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.AsyncPlayerPreLoginEvent; -import org.bukkit.event.player.PlayerBedEnterEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerGameModeChangeEvent; -import org.bukkit.event.player.PlayerInteractEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.*; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; @@ -407,7 +393,7 @@ public class AuthMePlayerListener implements Listener { // Shedule login task so works after the prelogin // (Fix found by Koolaid5000) - Bukkit.getScheduler().runTask(plugin, new Runnable(){ + Bukkit.getScheduler().runTask(plugin, new Runnable() { @Override public void run() { Player player = event.getPlayer(); @@ -421,7 +407,7 @@ public class AuthMePlayerListener implements Listener { event.setJoinMessage(null); } } - }); + }); } @SuppressWarnings("deprecation") @@ -429,7 +415,7 @@ public class AuthMePlayerListener implements Listener { public void onPreLogin(AsyncPlayerPreLoginEvent event){ final String name = event.getName().toLowerCase(); final Player player = Bukkit.getServer().getPlayer(name); - + if (player == null) return; @@ -440,7 +426,7 @@ public class AuthMePlayerListener implements Listener { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); if (LimboCache.getInstance().hasLimboPlayer(name)) Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { - + @Override public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); @@ -449,7 +435,7 @@ public class AuthMePlayerListener implements Listener { LimboCache.getInstance().deleteLimboPlayer(player.getName().toLowerCase()); } } - + }); return; } @@ -681,6 +667,35 @@ public class AuthMePlayerListener implements Listener { event.setCancelled(true); } + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerConsumeItem(PlayerItemConsumeEvent event) { + if (event.getPlayer() == null) + return; + + Player player = event.getPlayer(); + String name = player.getName().toLowerCase(); + + if (Utils.getInstance().isUnrestricted(player)) { + return; + } + + if (plugin.getCitizensCommunicator().isNPC(player)) { + return; + } + + if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { + return; + } + + if (!plugin.database.isAuthAvailable(name)) { + if (!Settings.isForcedRegistrationEnabled) { + return; + } + } + + event.setCancelled(true); + } + @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerInventoryOpen(InventoryOpenEvent event) { if (event.getPlayer() == null) From b1b441fac24d6569e291ea3446b587cea6a5a293 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 19:58:54 +0200 Subject: [PATCH 043/115] cleanup --- src/main/java/fr/xephi/authme/Utils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 7d4e9b775..d92a753c2 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -193,7 +193,8 @@ public class Utils { } } - public static Collection getOnlinePlayers() { + @SuppressWarnings("unchecked") + public static Collection getOnlinePlayers() { if (getOnlinePlayersIsCollection) { return Bukkit.getOnlinePlayers(); } @@ -203,7 +204,7 @@ public class Utils { } Object obj = getOnlinePlayers.invoke(null); if (obj instanceof Collection) { - return (Collection) obj; + return (Collection) obj; } return Arrays.asList((Player[]) obj); } catch (Exception ignored) { From c0e75dbbd28de82cc123ec431d1a914965b02539 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 20:01:55 +0200 Subject: [PATCH 044/115] fix tabulation --- .../process/register/ProcessSyncronousEmailRegister.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java index 96a200c23..9da830028 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java @@ -39,12 +39,12 @@ public class ProcessSyncronousEmailRegister implements Runnable { BukkitScheduler sched = plugin.getServer().getScheduler(); if (time != 0 && limbo != null) { - limbo.getTimeoutTaskId().cancel(); + limbo.getTimeoutTaskId().cancel(); BukkitTask id = sched.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, name, player), time); limbo.setTimeoutTaskId(id); } if (limbo != null){ - limbo.getMessageTaskId().cancel(); + limbo.getMessageTaskId().cancel(); BukkitTask nwMsg = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.send("login_msg"), msgInterval)); limbo.setMessageTaskId(nwMsg); } From e11a1e9b09490b0fc1ced428d55232f69fa87976 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 13 Sep 2015 20:03:28 +0200 Subject: [PATCH 045/115] damn --- src/main/java/fr/xephi/authme/Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index d92a753c2..563a76f6b 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -194,7 +194,7 @@ public class Utils { } @SuppressWarnings("unchecked") - public static Collection getOnlinePlayers() { + public static Collection getOnlinePlayers() { if (getOnlinePlayersIsCollection) { return Bukkit.getOnlinePlayers(); } From f60604c86c35b904da64addda6e25973321d4ac5 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 01:21:33 +0700 Subject: [PATCH 046/115] run admin register task async. --- .../xephi/authme/commands/AdminCommand.java | 105 +++++++++--------- .../process/register/AsyncronousRegister.java | 8 +- .../authme/security/PasswordSecurity.java | 10 +- .../fr/xephi/authme/settings/Messages.java | 5 +- 4 files changed, 61 insertions(+), 67 deletions(-) diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 76269f8fd..3e3961508 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -1,30 +1,6 @@ package fr.xephi.authme.commands; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.security.NoSuchAlgorithmException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - import com.zaxxer.hikari.pool.PoolInitializationException; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; @@ -39,6 +15,28 @@ import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.TimeoutTask; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.security.NoSuchAlgorithmException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; public class AdminCommand implements CommandExecutor { @@ -51,7 +49,7 @@ public class AdminCommand implements CommandExecutor { @Override public boolean onCommand(final CommandSender sender, Command cmnd, - String label, String[] args) { + String label, String[] args) { if (args.length == 0) { sender.sendMessage("Usage:"); sender.sendMessage("/authme reload - Reload the config"); @@ -289,13 +287,13 @@ public class AdminCommand implements CommandExecutor { }); return true; } - } else - if (args[0].equalsIgnoreCase("register") || args[0].equalsIgnoreCase("reg")) { + } else if (args[0].equalsIgnoreCase("register") || args[0].equalsIgnoreCase("reg")) { if (args.length != 3) { sender.sendMessage("Usage: /authme register "); return true; } - String lowpass = args[2].toLowerCase(); + final String name = args[1].toLowerCase(); + final String lowpass = args[2].toLowerCase(); if (lowpass.contains("delete") || lowpass.contains("where") || lowpass.contains("insert") || lowpass.contains("modify") || lowpass.contains("from") || lowpass.contains("select") || lowpass.contains(";") || lowpass.contains("null") || !lowpass.matches(Settings.getPassRegex)) { m.send(sender, "password_error"); return true; @@ -314,27 +312,32 @@ public class AdminCommand implements CommandExecutor { return true; } } - try { - String name = args[1].toLowerCase(); - if (plugin.database.isAuthAvailable(name)) { - m.send(sender, "user_regged"); - return true; + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { + @Override + public void run() { + try { + if (plugin.database.isAuthAvailable(name)) { + m.send(sender, "user_regged"); + return; + } + String hash = PasswordSecurity.getHash(Settings.getPasswordHash, lowpass, name); + PlayerAuth auth = new PlayerAuth(name, hash, "192.168.0.1", 0L, "your@email.com"); + if (PasswordSecurity.userSalt.containsKey(name) && PasswordSecurity.userSalt.get(name) != null) + auth.setSalt(PasswordSecurity.userSalt.get(name)); + else auth.setSalt(""); + if (!plugin.database.saveAuth(auth)) { + m.send(sender, "error"); + return; + } + m.send(sender, "registered"); + ConsoleLogger.info(name + " registered"); + } catch (NoSuchAlgorithmException ex) { + ConsoleLogger.showError(ex.getMessage()); + m.send(sender, "error"); + } + } - String hash = PasswordSecurity.getHash(Settings.getPasswordHash, args[2], name); - PlayerAuth auth = new PlayerAuth(name, hash, "192.168.0.1", 0L, "your@email.com"); - if (PasswordSecurity.userSalt.containsKey(name) && PasswordSecurity.userSalt.get(name) != null) - auth.setSalt(PasswordSecurity.userSalt.get(name)); - else auth.setSalt(""); - if (!plugin.database.saveAuth(auth)) { - m.send(sender, "error"); - return true; - } - m.send(sender, "registered"); - ConsoleLogger.info(args[1] + " registered"); - } catch (NoSuchAlgorithmException ex) { - ConsoleLogger.showError(ex.getMessage()); - m.send(sender, "error"); - } + }); return true; } else if (args[0].equalsIgnoreCase("getemail")) { if (args.length != 2) { @@ -443,8 +446,7 @@ public class AdminCommand implements CommandExecutor { ConsoleLogger.showError(ex.getMessage()); } return true; - } else - if (args[0].equalsIgnoreCase("changepassword") || args[0].equalsIgnoreCase("cp")) { + } else if (args[0].equalsIgnoreCase("changepassword") || args[0].equalsIgnoreCase("cp")) { if (args.length != 3) { sender.sendMessage("Usage: /authme changepassword "); return true; @@ -555,8 +557,7 @@ public class AdminCommand implements CommandExecutor { m.send(sender, "unregistered"); ConsoleLogger.info(args[1] + " unregistered"); return true; - } else - if (args[0].equalsIgnoreCase("purgelastpos") || args[0].equalsIgnoreCase("resetposition")) { + } else if (args[0].equalsIgnoreCase("purgelastpos") || args[0].equalsIgnoreCase("resetposition")) { if (args.length != 2) { sender.sendMessage("Usage: /authme purgelastpos "); return true; diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncronousRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncronousRegister.java index 72f14459c..255c696d5 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncronousRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncronousRegister.java @@ -112,7 +112,7 @@ public class AsyncronousRegister { return; } } - PlayerAuth auth = null; + PlayerAuth auth; try { final String hashnew = PasswordSecurity.getHash(Settings.getPasswordHash, password, name); auth = new PlayerAuth(name, hashnew, getIp(), 0, (int) player.getLocation().getX(), (int) player.getLocation().getY(), (int) player.getLocation().getZ(), player.getLocation().getWorld().getName(), email, player.getName()); @@ -130,12 +130,11 @@ public class AsyncronousRegister { plugin.mail.main(auth, password); ProcessSyncronousEmailRegister syncronous = new ProcessSyncronousEmailRegister(player, plugin); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, syncronous); - return; } protected void passwordRegister() { - PlayerAuth auth = null; - String hash = ""; + PlayerAuth auth; + String hash; try { hash = PasswordSecurity.getHash(Settings.getPasswordHash, password, name); } catch (NoSuchAlgorithmException e) { @@ -159,6 +158,5 @@ public class AsyncronousRegister { plugin.otherAccounts.addPlayer(player.getUniqueId()); ProcessSyncronousPasswordRegister syncronous = new ProcessSyncronousPasswordRegister(player, plugin); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, syncronous); - return; } } diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index 548bef129..3cc83cfc1 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -18,7 +18,7 @@ import fr.xephi.authme.settings.Settings; public class PasswordSecurity { private static SecureRandom rnd = new SecureRandom(); - public static HashMap userSalt = new HashMap(); + public static HashMap userSalt = new HashMap<>(); public static String createSalt(int length) throws NoSuchAlgorithmException { @@ -37,9 +37,7 @@ public class PasswordSecurity { if (alg != HashAlgorithm.CUSTOM) method = (EncryptionMethod) alg.getclasse().newInstance(); else method = null; - } catch (InstantiationException e) { - throw new NoSuchAlgorithmException("Problem with this hash algorithm"); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { throw new NoSuchAlgorithmException("Problem with this hash algorithm"); } String salt = ""; @@ -135,9 +133,7 @@ public class PasswordSecurity { if (algo != HashAlgorithm.CUSTOM) method = (EncryptionMethod) algo.getclasse().newInstance(); else method = null; - } catch (InstantiationException e) { - throw new NoSuchAlgorithmException("Problem with this hash algorithm"); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { throw new NoSuchAlgorithmException("Problem with this hash algorithm"); } PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName); diff --git a/src/main/java/fr/xephi/authme/settings/Messages.java b/src/main/java/fr/xephi/authme/settings/Messages.java index 1845d739d..197ddae59 100644 --- a/src/main/java/fr/xephi/authme/settings/Messages.java +++ b/src/main/java/fr/xephi/authme/settings/Messages.java @@ -23,14 +23,13 @@ public class Messages extends CustomConfiguration { /** * Loads a file from the plugin jar and sets as default * - * @param filename + * @param file * The filename to open */ public final void loadDefaults(File file) { if(file.isFile()){ setDefaults(YamlConfiguration.loadConfiguration(file)); } - return; } /** @@ -101,7 +100,7 @@ public class Messages extends CustomConfiguration { for (a = 0; a < i; a++) { loc[a] = ((String) this.get(msg)).split("&n")[a].replace("&", "\u00a7"); } - if (loc == null || loc.length == 0) { + if (loc.length == 0) { loc[0] = "Error with " + msg + " translation; Please contact the admin for verify or update translation files"; } return loc; From b4124bc46dac4c632eece90d8d5fdcf6ef938dbf Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 01:42:31 +0700 Subject: [PATCH 047/115] cleanup Listeners. --- .../authme/listener/AuthMeBlockListener.java | 11 ++- .../listener/AuthMeChestShopListener.java | 10 +-- .../authme/listener/AuthMeEntityListener.java | 18 ++-- .../authme/listener/AuthMePlayerListener.java | 83 ++++++++----------- .../authme/listener/AuthMeServerListener.java | 9 +- 5 files changed, 53 insertions(+), 78 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java index c6bf45ed3..d6c64582b 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java @@ -1,15 +1,14 @@ package fr.xephi.authme.listener; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockPlaceEvent; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.settings.Settings; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; public class AuthMeBlockListener implements Listener { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java index c26f18865..bafa9c4c2 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java @@ -1,17 +1,15 @@ package fr.xephi.authme.listener; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; - import com.Acrobot.ChestShop.Events.PreTransactionEvent; import com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.settings.Settings; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; public class AuthMeChestShopListener implements Listener { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index db4bf5f6f..162381337 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -1,22 +1,16 @@ package fr.xephi.authme.listener; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntityInteractEvent; -import org.bukkit.event.entity.EntityRegainHealthEvent; -import org.bukkit.event.entity.EntityTargetEvent; -import org.bukkit.event.entity.FoodLevelChangeEvent; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.settings.Settings; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.*; public class AuthMeEntityListener implements Listener { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 3f2dfc2cb..e98de7e59 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -1,14 +1,16 @@ package fr.xephi.authme.listener; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.PatternSyntaxException; - +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.Utils; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.cache.auth.PlayerCache; +import fr.xephi.authme.cache.limbo.LimboCache; +import fr.xephi.authme.cache.limbo.LimboPlayer; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.plugin.manager.CombatTagComunicator; +import fr.xephi.authme.settings.Messages; +import fr.xephi.authme.settings.Settings; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -23,26 +25,23 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.*; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.Utils; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.cache.limbo.LimboCache; -import fr.xephi.authme.cache.limbo.LimboPlayer; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; -import fr.xephi.authme.settings.Messages; -import fr.xephi.authme.settings.Settings; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.PatternSyntaxException; public class AuthMePlayerListener implements Listener { - public static ConcurrentHashMap gameMode = new ConcurrentHashMap(); - public static ConcurrentHashMap joinMessage = new ConcurrentHashMap(); + public static ConcurrentHashMap gameMode = new ConcurrentHashMap<>(); + public static ConcurrentHashMap joinMessage = new ConcurrentHashMap<>(); private Messages m = Messages.getInstance(); public AuthMe plugin; - public static ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap(); - private List antibot = new ArrayList(); + public static ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap<>(); + private List antibot = new ArrayList<>(); public AuthMePlayerListener(AuthMe plugin) { this.plugin = plugin; @@ -115,7 +114,6 @@ public class AuthMePlayerListener implements Listener { if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { event.setCancelled(true); - return; } } @@ -152,7 +150,6 @@ public class AuthMePlayerListener implements Listener { if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { event.setCancelled(true); - return; } } @@ -189,7 +186,6 @@ public class AuthMePlayerListener implements Listener { if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { event.setCancelled(true); - return; } } @@ -226,7 +222,6 @@ public class AuthMePlayerListener implements Listener { if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { event.setCancelled(true); - return; } } @@ -264,7 +259,6 @@ public class AuthMePlayerListener implements Listener { if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { event.setCancelled(true); - return; } } @@ -299,7 +293,6 @@ public class AuthMePlayerListener implements Listener { if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { event.setCancelled(true); - return; } } @@ -345,7 +338,6 @@ public class AuthMePlayerListener implements Listener { } if ((spawn.distance(player.getLocation()) > radius)) { event.getPlayer().teleport(spawn); - return; } } } @@ -402,7 +394,7 @@ public class AuthMePlayerListener implements Listener { plugin.management.performJoin(player); // Remove the join message while the player isn't logging in - if ((Settings.enableProtection || Settings.delayJoinMessage) && name != null && event.getJoinMessage() != null) { + if ((Settings.enableProtection || Settings.delayJoinMessage) && event.getJoinMessage() != null) { joinMessage.put(name, event.getJoinMessage()); event.setJoinMessage(null); } @@ -412,7 +404,7 @@ public class AuthMePlayerListener implements Listener { @SuppressWarnings("deprecation") @EventHandler(priority = EventPriority.HIGHEST) - public void onPreLogin(AsyncPlayerPreLoginEvent event){ + public void onPreLogin(AsyncPlayerPreLoginEvent event) { final String name = event.getName().toLowerCase(); final Player player = Bukkit.getServer().getPlayer(name); @@ -437,7 +429,6 @@ public class AuthMePlayerListener implements Listener { } }); - return; } } @@ -539,14 +530,14 @@ public class AuthMePlayerListener implements Listener { if (event.getResult() == PlayerLoginEvent.Result.ALLOWED) { checkAntiBotMod(player); if (Settings.bungee) { - final ByteArrayOutputStream b = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(b); - try { + final ByteArrayOutputStream b = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(b); out.writeUTF("IP"); + player.sendPluginMessage(plugin, "BungeeCord", b.toByteArray()); } catch (IOException e) { + ConsoleLogger.writeStackTrace(e); } - player.sendPluginMessage(plugin, "BungeeCord", b.toByteArray()); } return; } @@ -561,18 +552,15 @@ public class AuthMePlayerListener implements Listener { int playersOnline = Utils.getOnlinePlayers().size(); if (playersOnline > plugin.getServer().getMaxPlayers()) { event.allow(); - return; } else { final Player pl = plugin.generateKickPlayer(plugin.getServer().getOnlinePlayers()); if (pl != null) { pl.kickPlayer(m.send("kick_forvip")[0]); event.allow(); - return; } else { ConsoleLogger.info("The player " + player.getName() + " tryed to join, but the server was full"); event.setKickMessage(m.send("kick_fullserver")[0]); event.setResult(PlayerLoginEvent.Result.KICK_FULL); - return; } } } @@ -660,7 +648,7 @@ public class AuthMePlayerListener implements Listener { return; } } - if (event.getClickedBlock() != null){ + if (event.getClickedBlock() != null) { event.setUseInteractedBlock(org.bukkit.event.Event.Result.DENY); } event.setUseItemInHand(org.bukkit.event.Event.Result.DENY); @@ -726,7 +714,6 @@ public class AuthMePlayerListener implements Listener { @Override public void run() { player.closeInventory(); - ; } }, 1); @@ -764,7 +751,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void playerHitPlayerEvent(EntityDamageByEntityEvent event) { Entity damager = event.getDamager(); - if (!(damager instanceof Player)){ + if (!(damager instanceof Player)) { return; } @@ -912,13 +899,11 @@ public class AuthMePlayerListener implements Listener { Location spawn = plugin.getSpawnLocation(player); if (Settings.isSaveQuitLocationEnabled && plugin.database.isAuthAvailable(name)) { final PlayerAuth auth = new PlayerAuth(name, spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getWorld().getName(), player.getName()); - try { - plugin.database.updateQuitLoc(auth); - } catch (NullPointerException npe) { - } + plugin.database.updateQuitLoc(auth); } - if (spawn != null && spawn.getWorld() != null) + if (spawn != null && spawn.getWorld() != null) { event.setRespawnLocation(spawn); + } } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index b6d161f72..f493af635 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -1,5 +1,9 @@ package fr.xephi.authme.listener; +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.settings.Messages; +import fr.xephi.authme.settings.Settings; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -7,11 +11,6 @@ import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.event.server.ServerListPingEvent; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.settings.Messages; -import fr.xephi.authme.settings.Settings; - public class AuthMeServerListener implements Listener { public AuthMe plugin; From a4fd60a6f653f741fe98a76aa084c6508ac00337 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 03:45:09 +0700 Subject: [PATCH 048/115] fix cache, still not add null check. --- .../authme/cache/backup/DataFileCache.java | 3 +- .../authme/commands/RegisterCommand.java | 34 +++++++------------ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/DataFileCache.java b/src/main/java/fr/xephi/authme/cache/backup/DataFileCache.java index ef5ab501d..6644166fc 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/DataFileCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/DataFileCache.java @@ -11,8 +11,7 @@ public class DataFileCache { private boolean flying; public DataFileCache(ItemStack[] inventory, ItemStack[] armor) { - this.inventory = inventory; - this.armor = armor; + this(inventory, armor, "", false, false); } public DataFileCache(ItemStack[] inventory, ItemStack[] armor, diff --git a/src/main/java/fr/xephi/authme/commands/RegisterCommand.java b/src/main/java/fr/xephi/authme/commands/RegisterCommand.java index 11ab0a124..68f59b94c 100644 --- a/src/main/java/fr/xephi/authme/commands/RegisterCommand.java +++ b/src/main/java/fr/xephi/authme/commands/RegisterCommand.java @@ -1,15 +1,14 @@ package fr.xephi.authme.commands; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.security.RandomString; import fr.xephi.authme.settings.Messages; import fr.xephi.authme.settings.Settings; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; public class RegisterCommand implements CommandExecutor { @@ -23,26 +22,23 @@ public class RegisterCommand implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command cmnd, String label, - String[] args) { + String[] args) { if (!(sender instanceof Player)) { sender.sendMessage("Player Only! Use 'authme register ' instead"); return true; } - if (args.length == 0) { - m.send(sender, "usage_reg"); - } - if (!plugin.authmePermissible(sender, "authme." + label.toLowerCase())) { - m.send(sender, "no_perm"); + final Player player = (Player) sender; + if (args.length == 0 || (Settings.getEnablePasswordVerifier && args.length < 2)) { + m.send(player, "usage_reg"); + return true; + } + if (!plugin.authmePermissible(player, "authme." + label.toLowerCase())) { + m.send(player, "no_perm"); return true; } - final Player player = (Player) sender; if (Settings.emailRegistration && !Settings.getmailAccount.isEmpty()) { if (Settings.doubleEmailCheck) { - if (args.length < 2) { - m.send(player, "usage_reg"); - return true; - } - if (!args[0].equals(args[1])) { + if (args.length < 2 || !args[0].equals(args[1])) { m.send(player, "usage_reg"); return true; } @@ -57,10 +53,6 @@ public class RegisterCommand implements CommandExecutor { plugin.management.performRegister(player, thePass, email); return true; } - if (args.length == 0 || (Settings.getEnablePasswordVerifier && args.length < 2)) { - m.send(player, "usage_reg"); - return true; - } if (args.length > 1 && Settings.getEnablePasswordVerifier) if (!args[0].equals(args[1])) { m.send(player, "password_error"); From 2fe9e735a1fb5658e4cdf9d241946fa71a36871e Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 04:21:38 +0700 Subject: [PATCH 049/115] init playerBackup field on enable. --- src/main/java/fr/xephi/authme/AuthMe.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 0c9c57491..161925a7b 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -65,7 +65,7 @@ public class AuthMe extends JavaPlugin { public DataManager dataManager; public DataSource database; - private JsonCache playerBackup = new JsonCache(this); + private JsonCache playerBackup; public OtherAccounts otherAccounts; public Permission permission; public Essentials ess; @@ -239,6 +239,9 @@ public class AuthMe extends JavaPlugin { return; } + // Setup the inventory backup + playerBackup = new JsonCache(this); + // Set the DataManager dataManager = new DataManager(this); From 9736e4c2075f370a28ac3d3a46a34aa767f96c2d Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 04:32:12 +0700 Subject: [PATCH 050/115] init instance at the top, to avoid problems. --- src/main/java/fr/xephi/authme/AuthMe.java | 11 +++++------ .../java/fr/xephi/authme/cache/backup/JsonCache.java | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 161925a7b..8c5732e3f 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -53,9 +53,9 @@ import java.util.zip.GZIPInputStream; public class AuthMe extends JavaPlugin { - public static Server server; - public static Logger authmeLogger = Logger.getLogger("AuthMe"); - public static AuthMe authme; + private static Server server; + private static Logger authmeLogger = Logger.getLogger("AuthMe"); + private static AuthMe authme; public Management management; public NewAPI api; private Utils utils = Utils.getInstance(); @@ -115,6 +115,8 @@ public class AuthMe extends JavaPlugin { @Override public void onEnable() { + // Set the Instance + authme = this; // TODO: split the plugin in more modules // TODO: remove vault as hard dependency @@ -125,9 +127,6 @@ public class AuthMe extends JavaPlugin { // Setup the Logger authmeLogger.setParent(this.getLogger()); - // Set the Instance - authme = this; - // Setup otherAccounts file otherAccounts = OtherAccounts.getInstance(); diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 25db2afbf..1a952c93a 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -28,7 +28,7 @@ public class JsonCache { public JsonCache(AuthMe plugin) { this.plugin = plugin; - cacheDir = new File(plugin.getDataFolder() + File.separator + "cache"); + cacheDir = new File(plugin.getDataFolder(), "cache"); if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { ConsoleLogger.showError("Failed to create cache directory."); } From 670caaea4bb2dd3a88f71947fe57d119ca820263 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 08:23:02 +0700 Subject: [PATCH 051/115] fix resource extracting. --- .../authme/settings/CustomConfiguration.java | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java index 7d02487fc..5123ef581 100644 --- a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java +++ b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java @@ -1,21 +1,15 @@ package fr.xephi.authme.settings; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; - +import com.google.common.io.Files; +import com.google.common.io.Resources; +import fr.xephi.authme.ConsoleLogger; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; -import fr.xephi.authme.ConsoleLogger; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; public class CustomConfiguration extends YamlConfiguration { @@ -43,7 +37,7 @@ public class CustomConfiguration extends YamlConfiguration { public boolean reLoad() { boolean out = true; if (!configFile.exists()) { - out = loadRessource(configFile); + out = loadResource(configFile); } if (out) load(); @@ -58,28 +52,28 @@ public class CustomConfiguration extends YamlConfiguration { } } - public boolean loadRessource(File file) { - boolean out = true; + public boolean loadResource(File file) { if (!file.exists()) { try { - String charset = System.getProperty("file.encoding"); - String newline = System.getProperty("line.separator"); - InputStream fis = getClass().getResourceAsStream("/" + file.getName()); - BufferedReader reader = new BufferedReader(new InputStreamReader(fis, StandardCharsets.UTF_8)); - String str; - Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)); - while ((str = reader.readLine()) != null) { - writer.append(str).append(newline); + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) { + return false; + } + if (!file.exists() && !file.createNewFile()) { + return false; + } + int i = file.getPath().indexOf("AuthMe"); + if (i > -1) { + String path = file.getPath().substring(i + 6).replace('\\', '/'); + URL url = Resources.getResource(getClass(), path); + byte[] bytes = Resources.toByteArray(url); + Files.write(bytes, file); + return true; } - writer.flush(); - writer.close(); - reader.close(); - fis.close(); } catch (Exception e) { + ConsoleLogger.writeStackTrace(e); ConsoleLogger.showError("Failed to load config from JAR"); - out = false; } } - return out; + return false; } } From 981da0a0f3dc30c65309c42c65a7b2ee40682736 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 09:26:52 +0700 Subject: [PATCH 052/115] extract language if available. --- src/main/java/fr/xephi/authme/AuthMe.java | 7 +- .../xephi/authme/commands/AdminCommand.java | 29 +------- .../fr/xephi/authme/datasource/FlatFile.java | 27 +++----- .../authme/settings/CustomConfiguration.java | 4 ++ .../fr/xephi/authme/settings/Messages.java | 26 +++---- .../fr/xephi/authme/settings/Settings.java | 68 ++++++++----------- 6 files changed, 59 insertions(+), 102 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 8c5732e3f..0bd83cb6b 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -127,9 +127,6 @@ public class AuthMe extends JavaPlugin { // Setup the Logger authmeLogger.setParent(this.getLogger()); - // Setup otherAccounts file - otherAccounts = OtherAccounts.getInstance(); - // Load settings and custom configurations // TODO: new configuration style (more files) try { @@ -139,6 +136,10 @@ public class AuthMe extends JavaPlugin { this.getServer().shutdown(); return; } + + // Setup otherAccounts file + otherAccounts = OtherAccounts.getInstance(); + // Configuration Security Warnings if (!Settings.isForceSingleSessionEnabled) { ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 3e3961508..5862b8269 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -114,34 +114,7 @@ public class AdminCommand implements CommandExecutor { return true; } } else if (args[0].equalsIgnoreCase("reload")) { - File newConfigFile = new File("plugins" + File.separator + "AuthMe", "config.yml"); - if (!newConfigFile.exists()) { - InputStream fis = getClass().getResourceAsStream("" + File.separator + "config.yml"); - FileOutputStream fos = null; - try { - fos = new FileOutputStream(newConfigFile); - byte[] buf = new byte[1024]; - int i = 0; - - while ((i = fis.read(buf)) != -1) { - fos.write(buf, 0, i); - } - } catch (Exception e) { - ConsoleLogger.showError("Failed to load config from JAR"); - } finally { - try { - if (fis != null) { - fis.close(); - } - if (fos != null) { - fos.close(); - } - } catch (Exception e) { - } - } - } - YamlConfiguration newConfig = YamlConfiguration.loadConfiguration(newConfigFile); - Settings.reloadConfigOptions(newConfig); + plugin.getSettings().reload(); m.reloadMessages(); plugin.database.close(); diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index 2b54e4df9..22fee78cd 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -1,21 +1,15 @@ package fr.xephi.authme.datasource; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.settings.Settings; +import java.io.*; +import java.util.ArrayList; +import java.util.List; + public class FlatFile implements DataSource { /* @@ -32,7 +26,7 @@ public class FlatFile implements DataSource { private File source; public FlatFile() { - source = new File(Settings.AUTH_FILE); + source = Settings.AUTH_FILE; try { source.createNewFile(); } catch (IOException e) { @@ -41,9 +35,10 @@ public class FlatFile implements DataSource { ConsoleLogger.showError("Can't use FLAT FILE... SHUTDOWN..."); AuthMe.getInstance().getServer().shutdown(); } - if (!Settings.isStopEnabled) + if (!Settings.isStopEnabled) { AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; + } + e.printStackTrace(); } } @@ -108,7 +103,7 @@ public class FlatFile implements DataSource { BufferedReader br = null; try { br = new BufferedReader(new FileReader(source)); - String line = ""; + String line; while ((line = br.readLine()) != null) { String[] args = line.split(":"); if (args[0].equals(auth.getNickname())) { @@ -167,7 +162,7 @@ public class FlatFile implements DataSource { BufferedReader br = null; try { br = new BufferedReader(new FileReader(source)); - String line = ""; + String line; while ((line = br.readLine()) != null) { String[] args = line.split(":"); if (args[0].equalsIgnoreCase(auth.getNickname())) { @@ -226,7 +221,7 @@ public class FlatFile implements DataSource { BufferedReader br = null; try { br = new BufferedReader(new FileReader(source)); - String line = ""; + String line; while ((line = br.readLine()) != null) { String[] args = line.split(":"); if (args[0].equalsIgnoreCase(auth.getNickname())) { diff --git a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java index 5123ef581..88de17d7b 100644 --- a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java +++ b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java @@ -52,6 +52,10 @@ public class CustomConfiguration extends YamlConfiguration { } } + public File getConfigFile() { + return configFile; + } + public boolean loadResource(File file) { if (!file.exists()) { try { diff --git a/src/main/java/fr/xephi/authme/settings/Messages.java b/src/main/java/fr/xephi/authme/settings/Messages.java index 197ddae59..7f3f04c31 100644 --- a/src/main/java/fr/xephi/authme/settings/Messages.java +++ b/src/main/java/fr/xephi/authme/settings/Messages.java @@ -1,10 +1,10 @@ package fr.xephi.authme.settings; -import java.io.File; +import fr.xephi.authme.ConsoleLogger; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.YamlConfiguration; -import fr.xephi.authme.ConsoleLogger; +import java.io.File; public class Messages extends CustomConfiguration { @@ -23,11 +23,10 @@ public class Messages extends CustomConfiguration { /** * Loads a file from the plugin jar and sets as default * - * @param file - * The filename to open + * @param file The filename to open */ public final void loadDefaults(File file) { - if(file.isFile()){ + if (file.isFile()) { setDefaults(YamlConfiguration.loadConfiguration(file)); } } @@ -48,7 +47,7 @@ public class Messages extends CustomConfiguration { /** * Saves current configuration (plus defaults) to disk. - * + *

* If defaults and configuration are empty, saves blank file. * * @return True if saved successfully @@ -73,7 +72,7 @@ public class Messages extends CustomConfiguration { String loc = (String) singleton.get(msg); if (loc == null) { loc = "Error with Translation files, please contact the admin for verify or update translation"; - ConsoleLogger.showError("Error with the " + msg + " translation, verify in your " + Settings.MESSAGE_FILE + "_" + Settings.messagesLanguage + ".yml !"); + ConsoleLogger.showError("Error with the " + msg + " translation, verify in your " + getConfigFile() + " !"); } for (String l : loc.split("&n")) { sender.sendMessage(l.replace("&", "\u00a7")); @@ -81,15 +80,12 @@ public class Messages extends CustomConfiguration { } public String[] send(String msg) { - if (!Settings.messagesLanguage.equalsIgnoreCase(singleton.lang)) + if (!Settings.messagesLanguage.equalsIgnoreCase(singleton.lang)) { singleton.reloadMessages(); - String s = null; - try { - s = (String) singleton.get(msg); - } catch (Exception e) { } + String s = (String) singleton.get(msg); if (s == null) { - ConsoleLogger.showError("Error with the " + msg + " translation, verify in your " + Settings.MESSAGE_FILE + "_" + Settings.messagesLanguage + ".yml !"); + ConsoleLogger.showError("Error with the " + msg + " translation, verify in your " + getConfigFile() + " !"); String[] loc = new String[1]; loc[0] = "Error with " + msg + " translation; Please contact the admin for verify or update translation files"; return (loc); @@ -108,13 +104,13 @@ public class Messages extends CustomConfiguration { public static Messages getInstance() { if (singleton == null) { - singleton = new Messages(new File(Settings.MESSAGE_FILE + "_" + Settings.messagesLanguage + ".yml"), Settings.messagesLanguage); + singleton = new Messages(new File(Settings.MESSAGE_DIR, "messages_" + Settings.messagesLanguage + ".yml"), Settings.messagesLanguage); } return singleton; } public void reloadMessages() { - singleton = new Messages(new File(Settings.MESSAGE_FILE + "_" + Settings.messagesLanguage + ".yml"), Settings.messagesLanguage); + singleton = new Messages(new File(Settings.MESSAGE_DIR, "messages_" + Settings.messagesLanguage + ".yml"), Settings.messagesLanguage); } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index cd9159031..e7d34b994 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -1,35 +1,28 @@ package fr.xephi.authme.settings; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.bukkit.configuration.MemoryConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource.DataSourceType; import fr.xephi.authme.security.HashAlgorithm; +import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; public final class Settings extends YamlConfiguration { // This is not an option! public static Boolean antiBotInAction = false; - public static String PLUGIN_FOLDER = "." + File.separator + "plugins" + File.separator + "AuthMe"; - public static final String CACHE_FOLDER = Settings.PLUGIN_FOLDER + File.separator + "cache"; - public static final String AUTH_FILE = Settings.PLUGIN_FOLDER + File.separator + "auths.db"; - public static final String MESSAGE_FILE = Settings.PLUGIN_FOLDER + File.separator + "messages" + File.separator + "messages"; - public static final String SETTINGS_FILE = Settings.PLUGIN_FOLDER + File.separator + "config.yml"; + public static final File PLUGIN_FOLDER = AuthMe.getInstance().getDataFolder(); + public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); + public static final File AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db"); + public static final File MESSAGE_DIR = new File(PLUGIN_FOLDER, "messages"); + public static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); public static List allowCommands = null; public static List getJoinPermissions = null; public static List getUnrestrictedName = null; @@ -43,7 +36,6 @@ public final class Settings extends YamlConfiguration { public static List forceRegisterCommands = null; public static List forceRegisterCommandsAsConsole = null; private AuthMe plugin; - private final File file; public static DataSourceType getDataSource; public static HashAlgorithm getPasswordHash; public static Boolean useLogging = false; @@ -100,7 +92,7 @@ public final class Settings extends YamlConfiguration { protected static YamlConfiguration configFile; public Settings(AuthMe plugin) { - this.file = new File(plugin.getDataFolder(), "config.yml"); + configFile = (YamlConfiguration) plugin.getConfig(); this.plugin = plugin; boolean exist = exists(); if (exist) { @@ -109,8 +101,6 @@ public final class Settings extends YamlConfiguration { plugin.saveDefaultConfig(); load(); } - configFile = (YamlConfiguration) plugin.getConfig(); - PLUGIN_FOLDER = plugin.getDataFolder().toString(); loadConfigOptions(exist); } @@ -519,14 +509,10 @@ public final class Settings extends YamlConfiguration { ; } } - if (namefound == false) { + if (!namefound) { return true; } else { - if (trueonce == true) { - return true; - } else { - return false; - } + return trueonce; } } @@ -537,7 +523,7 @@ public final class Settings extends YamlConfiguration { */ public final boolean load() { try { - load(file); + load(SETTINGS_FILE); return true; } catch (Exception ex) { return false; @@ -545,8 +531,9 @@ public final class Settings extends YamlConfiguration { } public final void reload() { - if (!exists()) + if (!exists()) { plugin.saveDefaultConfig(); + } load(); } @@ -557,7 +544,7 @@ public final class Settings extends YamlConfiguration { */ public final boolean save() { try { - save(file); + save(SETTINGS_FILE); return true; } catch (Exception ex) { return false; @@ -570,12 +557,12 @@ public final class Settings extends YamlConfiguration { * @return True if configuration exists on disk */ public final boolean exists() { - return file.exists(); + return SETTINGS_FILE.exists(); } /** * Saves current configuration (plus defaults) to disk. - * + *

* If defaults and configuration are empty, saves blank file. * * @return True if saved successfully @@ -602,14 +589,15 @@ public final class Settings extends YamlConfiguration { * @return false When all defaults aren't present in config */ public boolean checkDefaults() { - if (getDefaults() == null) { - return true; - } - return getKeys(true).containsAll(getDefaults().getKeys(true)); + return getDefaults() == null || getKeys(true).containsAll(getDefaults().getKeys(true)); } public static String checkLang(String lang) { - if (new File(MESSAGE_FILE + "_" + lang + ".yml").exists()) { + if (new File(MESSAGE_DIR, "messages_" + lang + ".yml").exists()) { + ConsoleLogger.info("Set Language to: " + lang); + return lang; + } + if (AuthMe.class.getResourceAsStream("/messages/messages_" + lang + ".yml") != null) { ConsoleLogger.info("Set Language to: " + lang); return lang; } @@ -629,7 +617,7 @@ public final class Settings extends YamlConfiguration { private static void getWelcomeMessage() { AuthMe plugin = AuthMe.getInstance(); - welcomeMsg = new ArrayList(); + welcomeMsg = new ArrayList<>(); if (!useWelcomeMessage) { return; } From 550cffcc421f76802273a476b2a3be2119541dde Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Mon, 14 Sep 2015 12:34:52 +0200 Subject: [PATCH 053/115] cleanup --- src/main/java/fr/xephi/authme/commands/AdminCommand.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 5862b8269..3b4cee253 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -21,16 +21,12 @@ import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; import java.util.ArrayList; From 9cb6dce6133ab79eeb4ed22751f22c6934b6ec90 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Mon, 14 Sep 2015 13:40:57 +0200 Subject: [PATCH 054/115] pom enhancements --- pom.xml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index b34222f3e..7b5562aa0 100644 --- a/pom.xml +++ b/pom.xml @@ -177,12 +177,6 @@ http://repo.mcstats.org/content/repositories/snapshots/ - - - hikaricp-log4j-releases - http://nexus-sgdc3.rhcloud.com/nexus/content/repositories/hikaricp-log4j-releases/ - - @@ -195,12 +189,12 @@ HikariCP 2.4.1 compile - - - org.slf4j - slf4j-api - 1.7.12 - compile + + + slf4j-api + org.slf4j + + org.slf4j @@ -229,6 +223,12 @@ javax.mail 1.5.4 compile + + + activation + javax.activation + + From 0768642e85f788a38fe47142f90cddf70af9e3d5 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 18:58:37 +0700 Subject: [PATCH 055/115] cleanup Settings --- .../xephi/authme/cache/backup/JsonCache.java | 3 +- .../xephi/authme/commands/AdminCommand.java | 4 - .../fr/xephi/authme/settings/Messages.java | 4 +- .../fr/xephi/authme/settings/Settings.java | 139 ++++++++---------- 4 files changed, 63 insertions(+), 87 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 1a952c93a..720780c69 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -5,6 +5,7 @@ import com.google.gson.*; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; +import fr.xephi.authme.settings.Settings; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -28,7 +29,7 @@ public class JsonCache { public JsonCache(AuthMe plugin) { this.plugin = plugin; - cacheDir = new File(plugin.getDataFolder(), "cache"); + cacheDir = Settings.CACHE_FOLDER; if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { ConsoleLogger.showError("Failed to create cache directory."); } diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 3b4cee253..6852564d8 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -517,11 +517,7 @@ public class AdminCommand implements CommandExecutor { if (Settings.applyBlindEffect) target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); m.send(target, "unregistered"); - } else { - // Player isn't online, do nothing else } - } else { - // Player does not exist, do nothing else } m.send(sender, "unregistered"); ConsoleLogger.info(args[1] + " unregistered"); diff --git a/src/main/java/fr/xephi/authme/settings/Messages.java b/src/main/java/fr/xephi/authme/settings/Messages.java index 7f3f04c31..4ddb95198 100644 --- a/src/main/java/fr/xephi/authme/settings/Messages.java +++ b/src/main/java/fr/xephi/authme/settings/Messages.java @@ -104,13 +104,13 @@ public class Messages extends CustomConfiguration { public static Messages getInstance() { if (singleton == null) { - singleton = new Messages(new File(Settings.MESSAGE_DIR, "messages_" + Settings.messagesLanguage + ".yml"), Settings.messagesLanguage); + singleton = new Messages(Settings.messageFile, Settings.messagesLanguage); } return singleton; } public void reloadMessages() { - singleton = new Messages(new File(Settings.MESSAGE_DIR, "messages_" + Settings.messagesLanguage + ".yml"), Settings.messagesLanguage); + singleton = new Messages(Settings.messageFile, Settings.messagesLanguage); } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index e7d34b994..5b1a6b980 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -5,7 +5,6 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource.DataSourceType; import fr.xephi.authme.security.HashAlgorithm; -import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import java.io.*; @@ -15,14 +14,16 @@ import java.util.List; public final class Settings extends YamlConfiguration { + private AuthMe plugin; + // This is not an option! public static Boolean antiBotInAction = false; - public static final File PLUGIN_FOLDER = AuthMe.getInstance().getDataFolder(); - public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); - public static final File AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db"); - public static final File MESSAGE_DIR = new File(PLUGIN_FOLDER, "messages"); - public static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); + public static final File PLUGIN_FOLDER; + public static final File CACHE_FOLDER; + public static final File AUTH_FILE; + public static final File SETTINGS_FILE; + public static File messageFile; public static List allowCommands = null; public static List getJoinPermissions = null; public static List getUnrestrictedName = null; @@ -35,7 +36,6 @@ public final class Settings extends YamlConfiguration { public static List forceCommandsAsConsole = null; public static List forceRegisterCommands = null; public static List forceRegisterCommandsAsConsole = null; - private AuthMe plugin; public static DataSourceType getDataSource; public static HashAlgorithm getPasswordHash; public static Boolean useLogging = false; @@ -71,7 +71,7 @@ public final class Settings extends YamlConfiguration { getMySQLTablename, getMySQLColumnName, getMySQLColumnPassword, getMySQLColumnIp, getMySQLColumnLastLogin, getMySQLColumnSalt, getMySQLColumnGroup, getMySQLColumnEmail, unRegisteredGroup, - backupWindowsPath, getcUnrestrictedName, getRegisteredGroup, + backupWindowsPath, getRegisteredGroup, messagesLanguage, getMySQLlastlocX, getMySQLlastlocY, getMySQLlastlocZ, rakamakUsers, rakamakUsersIp, getmailAccount, getmailPassword, getmailSMTP, getMySQLColumnId, getmailSenderName, @@ -91,17 +91,23 @@ public final class Settings extends YamlConfiguration { protected static YamlConfiguration configFile; + static { + PLUGIN_FOLDER = AuthMe.getInstance().getDataFolder(); + CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); + AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db"); + SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); + } + public Settings(AuthMe plugin) { configFile = (YamlConfiguration) plugin.getConfig(); this.plugin = plugin; boolean exist = exists(); - if (exist) { - load(); - } else { + if (!exist) { plugin.saveDefaultConfig(); - load(); } + load(); loadConfigOptions(exist); + messageFile = new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + messagesLanguage + ".yml"); } public void loadConfigOptions(boolean exist) { @@ -277,133 +283,127 @@ public final class Settings extends YamlConfiguration { } - public static void reloadConfigOptions(YamlConfiguration newConfig) { - configFile = newConfig; - - loadVariables(); - } - public void mergeConfig() { - boolean changes = false; + int changes = 0; if (contains("Xenoforo.predefinedSalt")) set("Xenoforo.predefinedSalt", null); if (configFile.getString("settings.security.passwordHash", "SHA256").toUpperCase().equals("XFSHA1") || configFile.getString("settings.security.passwordHash", "SHA256").toUpperCase().equals("XFSHA256")) set("settings.security.passwordHash", "XENFORO"); if (!contains("Protection.enableProtection")) { set("Protection.enableProtection", false); - changes = true; + changes++; } if (!contains("Protection.countries")) { - countries = new ArrayList(); + countries = new ArrayList<>(); countries.add("US"); countries.add("GB"); set("Protection.countries", countries); - changes = true; + changes++; } if (!contains("Protection.enableAntiBot")) { set("Protection.enableAntiBot", false); - changes = true; + changes++; } if (!contains("Protection.antiBotSensibility")) { set("Protection.antiBotSensibility", 5); - changes = true; + changes++; } if (!contains("Protection.antiBotDuration")) { set("Protection.antiBotDuration", 10); - changes = true; + changes++; } if (!contains("settings.forceCommands")) { set("settings.forceCommands", new ArrayList()); - changes = true; + changes++; } if (!contains("settings.forceCommandsAsConsole")) { set("settings.forceCommandsAsConsole", new ArrayList()); - changes = true; + changes++; } if (!contains("Email.recallPlayers")) { set("Email.recallPlayers", false); - changes = true; + changes++; } if (!contains("Email.delayRecall")) { set("Email.delayRecall", 5); - changes = true; + changes++; } if (!contains("settings.useWelcomeMessage")) { set("settings.useWelcomeMessage", true); - changes = true; + changes++; } if (!contains("settings.security.unsafePasswords")) { - List str = new ArrayList(); + List str = new ArrayList<>(); str.add("123456"); str.add("password"); set("settings.security.unsafePasswords", str); - changes = true; + changes++; } if (!contains("Protection.countriesBlacklist")) { - countriesBlacklist = new ArrayList(); + countriesBlacklist = new ArrayList<>(); countriesBlacklist.add("A1"); set("Protection.countriesBlacklist", countriesBlacklist); - changes = true; + changes++; } if (!contains("settings.broadcastWelcomeMessage")) { set("settings.broadcastWelcomeMessage", false); - changes = true; + changes++; } if (!contains("settings.registration.forceKickAfterRegister")) { set("settings.registration.forceKickAfterRegister", false); - changes = true; + changes++; } if (!contains("settings.registration.forceLoginAfterRegister")) { set("settings.registration.forceLoginAfterRegister", false); - changes = true; + changes++; } if (!contains("DataSource.mySQLColumnLogged")) { set("DataSource.mySQLColumnLogged", "isLogged"); - changes = true; + changes++; } if (!contains("settings.restrictions.spawnPriority")) { set("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default"); - changes = true; + changes++; } if (!contains("settings.restrictions.maxLoginPerIp")) { set("settings.restrictions.maxLoginPerIp", 0); - changes = true; + changes++; } if (!contains("settings.restrictions.maxJoinPerIp")) { set("settings.restrictions.maxJoinPerIp", 0); - changes = true; + changes++; } if (!contains("VeryGames.enableIpCheck")) { set("VeryGames.enableIpCheck", false); - changes = true; + changes++; } if (getString("settings.restrictions.allowedNicknameCharacters").equals("[a-zA-Z0-9_?]*")) set("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*"); if (!contains("settings.delayJoinMessage")) { set("settings.delayJoinMessage", false); - changes = true; + changes++; } if (!contains("settings.restrictions.noTeleport")) { set("settings.restrictions.noTeleport", false); - changes = true; + changes++; } if (contains("Converter.Rakamak.newPasswordHash")) set("Converter.Rakamak.newPasswordHash", null); if (!contains("Converter.CrazyLogin.fileName")) { set("Converter.CrazyLogin.fileName", "accounts.db"); - changes = true; + changes++; } if (!contains("settings.restrictions.allowedPasswordCharacters")) { set("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*"); - changes = true; + changes++; } if (!contains("settings.applyBlindEffect")) { set("settings.applyBlindEffect", false); - changes = true; + changes++; } if (!contains("Email.emailBlacklisted")) { set("Email.emailBlacklisted", new ArrayList()); - changes = true; + changes++; } if (contains("Performances.useMultiThreading")) set("Performances.useMultiThreading", null); @@ -419,23 +419,23 @@ public final class Settings extends YamlConfiguration { if (!contains("Email.emailWhitelisted")) { set("Email.emailWhitelisted", new ArrayList()); - changes = true; + changes++; } if (!contains("settings.forceRegisterCommands")) { set("settings.forceRegisterCommands", new ArrayList()); - changes = true; + changes++; } if (!contains("settings.forceRegisterCommandsAsConsole")) { set("settings.forceRegisterCommandsAsConsole", new ArrayList()); - changes = true; + changes++; } if (!contains("Hooks.customAttributes")) { set("Hooks.customAttributes", false); - changes = true; + changes++; } if (!contains("Purge.removePermissions")) { set("Purge.removePermissions", false); - changes = true; + changes++; } if (contains("Hooks.notifications")) set("Hooks.notifications", null); @@ -447,19 +447,17 @@ public final class Settings extends YamlConfiguration { set("Hooks.legacyChestshop", useChestShop); if (!contains("Email.generateImage")) { set("Email.generateImage", true); - changes = true; + changes++; } if (!contains("DataSource.mySQLRealName")) { set("DataSource.mySQLRealName", "realname"); - changes = true; + changes++; } - if (changes) { - plugin.getLogger().warning("Merge new Config Options - I'm not an error, please don't report me"); + if (changes > 0) { + plugin.getLogger().warning("Merge " + changes + " new Config Options - I'm not an error, please don't report me"); plugin.getLogger().warning("Please check your config.yml file for new configs!"); } - - return; } public void setValue(String key, Object value) { @@ -506,7 +504,6 @@ public final class Settings extends YamlConfiguration { if (testip.equalsIgnoreCase(ip)) { trueonce = true; } - ; } } if (!namefound) { @@ -576,24 +573,8 @@ public final class Settings extends YamlConfiguration { return success; } - /** - * Clears current configuration defaults - */ - public final void clearDefaults() { - setDefaults(new MemoryConfiguration()); - } - - /** - * Check loaded defaults against current configuration - * - * @return false When all defaults aren't present in config - */ - public boolean checkDefaults() { - return getDefaults() == null || getKeys(true).containsAll(getDefaults().getKeys(true)); - } - public static String checkLang(String lang) { - if (new File(MESSAGE_DIR, "messages_" + lang + ".yml").exists()) { + if (new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + lang + ".yml").exists()) { ConsoleLogger.info("Set Language to: " + lang); return lang; } @@ -636,13 +617,11 @@ public final class Settings extends YamlConfiguration { try { FileReader fr = new FileReader(plugin.getDataFolder() + File.separator + "welcome.txt"); BufferedReader br = new BufferedReader(fr); - String line = ""; + String line; while ((line = br.readLine()) != null) { welcomeMsg.add(line); } br.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } From 7c56dec47686ae263e5c3c62e15f976a7eda9063 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 19:50:32 +0700 Subject: [PATCH 056/115] change all usage of getOnlinePlayers --- src/main/java/fr/xephi/authme/AuthMe.java | 6 +++--- src/main/java/fr/xephi/authme/DataManager.java | 2 +- .../fr/xephi/authme/cache/backup/JsonCache.java | 4 ++-- .../xephi/authme/datasource/CacheDataSource.java | 3 ++- .../authme/listener/AuthMePlayerListener.java | 2 +- .../authme/process/login/AsyncronousLogin.java | 3 ++- .../login/ProcessSyncronousPlayerLogin.java | 2 +- .../xephi/authme/settings/CustomConfiguration.java | 14 +++++--------- .../java/fr/xephi/authme/task/MessageTask.java | 10 +++++----- 9 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 0bd83cb6b..321d83de2 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -731,7 +731,7 @@ public class AuthMe extends JavaPlugin { @Override public void run() { - for (Player player : Bukkit.getOnlinePlayers()) { + for (Player player : Utils.getOnlinePlayers()) { if (player.isOnline()) { String name = player.getName().toLowerCase(); if (database.isAuthAvailable(name)) @@ -776,7 +776,7 @@ public class AuthMe extends JavaPlugin { public boolean isLoggedIp(String name, String ip) { int count = 0; - for (Player player : this.getServer().getOnlinePlayers()) { + for (Player player : Utils.getOnlinePlayers()) { if (ip.equalsIgnoreCase(getIP(player)) && database.isLogged(player.getName().toLowerCase()) && !player.getName().equalsIgnoreCase(name)) count++; } @@ -785,7 +785,7 @@ public class AuthMe extends JavaPlugin { public boolean hasJoinedIp(String name, String ip) { int count = 0; - for (Player player : this.getServer().getOnlinePlayers()) { + for (Player player : Utils.getOnlinePlayers()) { if (ip.equalsIgnoreCase(getIP(player)) && !player.getName().equalsIgnoreCase(name)) count++; } diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 472a29e89..23aaedc1a 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -174,7 +174,7 @@ public class DataManager { public synchronized Boolean call() throws Exception { Boolean result = null; try { - for (OfflinePlayer op : Bukkit.getOnlinePlayers()) + for (OfflinePlayer op : Utils.getOnlinePlayers()) if (op.getName().equalsIgnoreCase(name)) { result = true; break; diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 720780c69..dce5a672b 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -62,7 +62,7 @@ public class JsonCache { try { String data = gson.toJson(playerData); - Files.write(Paths.get(file.getPath()), data.getBytes()); + Files.write(file.toPath(), data.getBytes()); } catch (IOException e) { e.printStackTrace(); } @@ -78,7 +78,7 @@ public class JsonCache { File file = new File(cacheDir, path + File.separator + "cache.json"); try { - byte[] bytes = Files.readAllBytes(Paths.get(file.getPath())); + byte[] bytes = Files.readAllBytes(file.toPath()); String str = new String(bytes); return gson.fromJson(str, DataFileCache.class); } catch (Exception e) { diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 3d1aa5cc2..5ac617151 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -3,6 +3,7 @@ package fr.xephi.authme.datasource; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import fr.xephi.authme.Utils; import org.bukkit.entity.Player; import fr.xephi.authme.AuthMe; @@ -140,7 +141,7 @@ public class CacheDataSource implements DataSource { public void reload() { cache.clear(); source.reload(); - for (Player player : plugin.getServer().getOnlinePlayers()) { + for (Player player : Utils.getOnlinePlayers()) { String user = player.getName().toLowerCase(); if (PlayerCache.getInstance().isAuthenticated(user)) { try { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index e98de7e59..349112fb6 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -553,7 +553,7 @@ public class AuthMePlayerListener implements Listener { if (playersOnline > plugin.getServer().getMaxPlayers()) { event.allow(); } else { - final Player pl = plugin.generateKickPlayer(plugin.getServer().getOnlinePlayers()); + final Player pl = plugin.generateKickPlayer(Utils.getOnlinePlayers()); if (pl != null) { pl.kickPlayer(m.send("kick_forvip")[0]); event.allow(); diff --git a/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java index 302203b7d..bfc7569ee 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java @@ -3,6 +3,7 @@ package fr.xephi.authme.process.login; import java.util.Date; import java.util.List; +import fr.xephi.authme.Utils; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; @@ -239,7 +240,7 @@ public class AsyncronousLogin { * uuidaccounts = uuidaccounts + ", "; } else { uuidaccounts = * uuidaccounts + "."; } } */ - for (Player player : plugin.getServer().getOnlinePlayers()) { + for (Player player : Utils.getOnlinePlayers()) { if (plugin.authmePermissible(player, "authme.seeOtherAccounts")) { player.sendMessage("[AuthMe] The player " + auth.getNickname() + " has " + auths.size() + " accounts"); player.sendMessage(message); diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index acb1f832e..b9d29411d 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -177,7 +177,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { // We can now display the join message if (AuthMePlayerListener.joinMessage.containsKey(name) && AuthMePlayerListener.joinMessage.get(name) != null && !AuthMePlayerListener.joinMessage.get(name).isEmpty()) { - for (Player p : Bukkit.getServer().getOnlinePlayers()) { + for (Player p : Utils.getOnlinePlayers()) { if (p.isOnline()) p.sendMessage(AuthMePlayerListener.joinMessage.get(name)); } diff --git a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java index 88de17d7b..abf637009 100644 --- a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java +++ b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java @@ -1,7 +1,5 @@ package fr.xephi.authme.settings; -import com.google.common.io.Files; -import com.google.common.io.Resources; import fr.xephi.authme.ConsoleLogger; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; @@ -9,7 +7,9 @@ import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.net.URL; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; public class CustomConfiguration extends YamlConfiguration { @@ -62,15 +62,11 @@ public class CustomConfiguration extends YamlConfiguration { if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) { return false; } - if (!file.exists() && !file.createNewFile()) { - return false; - } int i = file.getPath().indexOf("AuthMe"); if (i > -1) { String path = file.getPath().substring(i + 6).replace('\\', '/'); - URL url = Resources.getResource(getClass(), path); - byte[] bytes = Resources.toByteArray(url); - Files.write(bytes, file); + InputStream is = getClass().getResourceAsStream(path); + Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING); return true; } } catch (Exception e) { diff --git a/src/main/java/fr/xephi/authme/task/MessageTask.java b/src/main/java/fr/xephi/authme/task/MessageTask.java index 94d203470..e4ac9e3af 100644 --- a/src/main/java/fr/xephi/authme/task/MessageTask.java +++ b/src/main/java/fr/xephi/authme/task/MessageTask.java @@ -1,11 +1,11 @@ package fr.xephi.authme.task; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitTask; - import fr.xephi.authme.AuthMe; +import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; public class MessageTask implements Runnable { @@ -15,7 +15,7 @@ public class MessageTask implements Runnable { private int interval; public MessageTask(AuthMe plugin, String name, String[] strings, - int interval) { + int interval) { this.plugin = plugin; this.name = name; this.msg = strings; @@ -27,7 +27,7 @@ public class MessageTask implements Runnable { if (PlayerCache.getInstance().isAuthenticated(name)) return; - for (Player player : plugin.getServer().getOnlinePlayers()) { + for (Player player : Utils.getOnlinePlayers()) { if (player.getName().toLowerCase().equals(name)) { for (String ms : msg) { player.sendMessage(ms); From 0b230747703b76a2ee6a0dd3a6a31751f1f0c7e8 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 20:46:56 +0700 Subject: [PATCH 057/115] changed settings load method. --- src/main/java/fr/xephi/authme/AuthMe.java | 35 ++---- .../java/fr/xephi/authme/DataManager.java | 36 +++--- .../xephi/authme/commands/AdminCommand.java | 67 +++-------- .../authme/datasource/CacheDataSource.java | 26 ++--- .../fr/xephi/authme/settings/Settings.java | 108 ++++++------------ 5 files changed, 93 insertions(+), 179 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 321d83de2..0a1e35790 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -53,7 +53,7 @@ import java.util.zip.GZIPInputStream; public class AuthMe extends JavaPlugin { - private static Server server; + private final Server server = getServer(); private static Logger authmeLogger = Logger.getLogger("AuthMe"); private static AuthMe authme; public Management management; @@ -76,7 +76,6 @@ public class AuthMe extends JavaPlugin { public boolean isCitizensActive = false; public boolean CombatTag = false; public boolean legacyChestShop = false; - public boolean BungeeCord = false; public boolean antibotMod = false; public boolean delayedAntiBot = true; public ConcurrentHashMap sessions = new ConcurrentHashMap<>(); @@ -93,14 +92,6 @@ public class AuthMe extends JavaPlugin { return settings; } - public DataSource getAuthMeDatabase() { - return database; - } - - public void setAuthMeDatabase(DataSource database) { - this.database = database; - } - public void setMessages(Messages m) { this.m = m; } @@ -120,8 +111,6 @@ public class AuthMe extends JavaPlugin { // TODO: split the plugin in more modules // TODO: remove vault as hard dependency - - server = getServer(); PluginManager pm = server.getPluginManager(); // Setup the Logger @@ -131,9 +120,11 @@ public class AuthMe extends JavaPlugin { // TODO: new configuration style (more files) try { settings = new Settings(this); + settings.reload(); } catch (Exception e) { + ConsoleLogger.writeStackTrace(e); ConsoleLogger.showError("Can't load the configuration file... Something went wrong, to avoid security issues the server will shutdown!"); - this.getServer().shutdown(); + server.shutdown(); return; } @@ -232,7 +223,7 @@ public class AuthMe extends JavaPlugin { // Connect to the database and setup tables try { setupDatabase(); - } catch (ClassNotFoundException | SQLException | PoolInitializationException ex) { + } catch (Exception ex) { ConsoleLogger.writeStackTrace(ex); ConsoleLogger.showError("Fatal error occurred during database connection! Authme initialization ABORTED!"); stopOrUnload(); @@ -346,7 +337,7 @@ public class AuthMe extends JavaPlugin { public void stopOrUnload() { if (Settings.isStopEnabled) { ConsoleLogger.showError("THE SERVER IS GOING TO SHUTDOWN AS DEFINED IN THE CONFIGURATION!"); - AuthMe.getInstance().getServer().shutdown(); + server.shutdown(); } else { server.getPluginManager().disablePlugin(AuthMe.getInstance()); } @@ -391,7 +382,7 @@ public class AuthMe extends JavaPlugin { if (Settings.getDataSource == DataSource.DataSourceType.FILE) { Converter converter = new ForceFlatToSqlite(database, this); - getServer().getScheduler().runTaskAsynchronously(this, converter); + server.getScheduler().runTaskAsynchronously(this, converter); ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated, next time server starts up, it will be changed to SQLite... Conversion will be started Asynchronously, it will not drop down your performance !"); ConsoleLogger.showError("If you want to keep FlatFile, set file again into config at backend, but this message and this change will appear again at the next restart"); } @@ -512,12 +503,12 @@ public class AuthMe extends JavaPlugin { // Check the presence of CombatTag public void checkCombatTag() { - this.CombatTag = this.getServer().getPluginManager().isPluginEnabled("CombatTag"); + this.CombatTag = server.getPluginManager().isPluginEnabled("CombatTag"); } // Check if Citizens is active public void checkCitizens() { - this.isCitizensActive = this.getServer().getPluginManager().isPluginEnabled("Citizens"); + this.isCitizensActive = server.getPluginManager().isPluginEnabled("Citizens"); } // Check if a player/command sender have a permission @@ -703,8 +694,6 @@ public class AuthMe extends JavaPlugin { } } - // TODO: Need to review the code below! - public String getCountryCode(String ip) { if (lookupService != null) { return lookupService.getCountry(ip).getCode(); @@ -751,12 +740,12 @@ public class AuthMe extends JavaPlugin { message = message.replace("&", "\u00a7"); message = message.replace("{PLAYER}", player.getName()); message = message.replace("{ONLINE}", "" + playersOnline); - message = message.replace("{MAXPLAYERS}", "" + this.getServer().getMaxPlayers()); + message = message.replace("{MAXPLAYERS}", "" + server.getMaxPlayers()); message = message.replace("{IP}", getIP(player)); message = message.replace("{LOGINS}", "" + PlayerCache.getInstance().getLogged()); message = message.replace("{WORLD}", player.getWorld().getName()); - message = message.replace("{SERVER}", this.getServer().getServerName()); - message = message.replace("{VERSION}", this.getServer().getBukkitVersion()); + message = message.replace("{SERVER}", server.getServerName()); + message = message.replace("{VERSION}", server.getBukkitVersion()); message = message.replace("{COUNTRY}", this.getCountryName(getIP(player))); return message; } diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 23aaedc1a..43782c5b3 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -1,5 +1,11 @@ package fr.xephi.authme; +import fr.xephi.authme.settings.Settings; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + import java.io.File; import java.util.List; import java.util.concurrent.Callable; @@ -7,13 +13,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; - -import fr.xephi.authme.settings.Settings; -import net.milkbowl.vault.permission.Permission; - public class DataManager { public AuthMe plugin; @@ -150,7 +149,7 @@ public class DataManager { } public synchronized void purgePermissions(List cleared, - Permission permission) { + Permission permission) { int i = 0; for (String name : cleared) { try { @@ -170,24 +169,19 @@ public class DataManager { return true; ExecutorService executor = Executors.newSingleThreadExecutor(); Future result = executor.submit(new Callable() { - + @Override public synchronized Boolean call() throws Exception { - Boolean result = null; - try { - for (OfflinePlayer op : Utils.getOnlinePlayers()) - if (op.getName().equalsIgnoreCase(name)) { - result = true; - break; - } - } catch (Exception e) { - } - return result; + for (OfflinePlayer op : Utils.getOnlinePlayers()) + if (op.getName().equalsIgnoreCase(name)) { + return true; + } + return false; } }); try { - return result.get().booleanValue(); + return result.get(); } catch (Exception e) { - return (false); + return false; } finally { executor.shutdown(); } diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 6852564d8..64b00031a 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -1,6 +1,5 @@ package fr.xephi.authme.commands; -import com.zaxxer.hikari.pool.PoolInitializationException; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; @@ -28,7 +27,6 @@ import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; import java.security.NoSuchAlgorithmException; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -110,48 +108,23 @@ public class AdminCommand implements CommandExecutor { return true; } } else if (args[0].equalsIgnoreCase("reload")) { - plugin.getSettings().reload(); - m.reloadMessages(); - plugin.database.close(); - try { + plugin.getSettings().reload(); + m.reloadMessages(); + plugin.database.close(); plugin.setupDatabase(); - } catch (ClassNotFoundException nfe) { + } catch (Exception e) { ConsoleLogger.showError("Fatal error occurred! Authme instance ABORTED!"); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - return false; - } catch (SQLException sqle) { - ConsoleLogger.showError("Fatal error occurred! Authme instance ABORTED!"); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - return false; - } catch (PoolInitializationException pie) { - ConsoleLogger.showError("Fatal error occurred! Authme instance ABORTED!"); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } + plugin.stopOrUnload(); return false; } - m.send(sender, "reload"); } else if (args[0].equalsIgnoreCase("lastlogin")) { if (args.length != 2) { sender.sendMessage("Usage: /authme lastlogin "); return true; } - PlayerAuth auth = null; + PlayerAuth auth; try { auth = plugin.database.getAuth(args[1].toLowerCase()); } catch (NullPointerException e) { @@ -177,31 +150,30 @@ public class AdminCommand implements CommandExecutor { return true; } if (!args[1].contains(".")) { - final CommandSender fSender = sender; final String[] arguments = args; Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { @Override public void run() { - PlayerAuth auth = null; + PlayerAuth auth; String message = "[AuthMe] "; try { auth = plugin.database.getAuth(arguments[1].toLowerCase()); } catch (NullPointerException npe) { - m.send(fSender, "unknown_user"); + m.send(sender, "unknown_user"); return; } if (auth == null) { - m.send(fSender, "unknown_user"); + m.send(sender, "unknown_user"); return; } List accountList = plugin.database.getAllAuthsByName(auth); if (accountList == null || accountList.isEmpty()) { - m.send(fSender, "user_unknown"); + m.send(sender, "user_unknown"); return; } if (accountList.size() == 1) { - fSender.sendMessage("[AuthMe] " + arguments[1] + " is a single account player"); + sender.sendMessage("[AuthMe] " + arguments[1] + " is a single account player"); return; } int i = 0; @@ -214,13 +186,12 @@ public class AdminCommand implements CommandExecutor { message = message + "."; } } - fSender.sendMessage("[AuthMe] " + arguments[1] + " has " + String.valueOf(accountList.size()) + " accounts"); - fSender.sendMessage(message); + sender.sendMessage("[AuthMe] " + arguments[1] + " has " + String.valueOf(accountList.size()) + " accounts"); + sender.sendMessage(message); } }); return true; } else { - final CommandSender fSender = sender; final String[] arguments = args; Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { @@ -228,16 +199,16 @@ public class AdminCommand implements CommandExecutor { public void run() { String message = "[AuthMe] "; if (arguments[1] == null) { - fSender.sendMessage("[AuthMe] Please put a valid IP"); + sender.sendMessage("[AuthMe] Please put a valid IP"); return; } List accountList = plugin.database.getAllAuthsByIp(arguments[1]); if (accountList == null || accountList.isEmpty()) { - fSender.sendMessage("[AuthMe] This IP does not exist in the database"); + sender.sendMessage("[AuthMe] This IP does not exist in the database"); return; } if (accountList.size() == 1) { - fSender.sendMessage("[AuthMe] " + arguments[1] + " is a single account player"); + sender.sendMessage("[AuthMe] " + arguments[1] + " is a single account player"); return; } int i = 0; @@ -250,8 +221,8 @@ public class AdminCommand implements CommandExecutor { message = message + "."; } } - fSender.sendMessage("[AuthMe] " + arguments[1] + " has " + String.valueOf(accountList.size()) + " accounts"); - fSender.sendMessage(message); + sender.sendMessage("[AuthMe] " + arguments[1] + " has " + String.valueOf(accountList.size()) + " accounts"); + sender.sendMessage(message); } }); return true; @@ -374,7 +345,7 @@ public class AdminCommand implements CommandExecutor { } return true; } else if (args[0].equalsIgnoreCase("purgebannedplayers")) { - List bannedPlayers = new ArrayList(); + List bannedPlayers = new ArrayList<>(); for (OfflinePlayer off : plugin.getServer().getBannedPlayers()) { bannedPlayers.add(off.getName().toLowerCase()); } diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 5ac617151..0b6dfe17d 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -1,20 +1,19 @@ package fr.xephi.authme.datasource; +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.Utils; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.cache.auth.PlayerCache; +import org.bukkit.entity.Player; + import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import fr.xephi.authme.Utils; -import org.bukkit.entity.Player; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.cache.auth.PlayerCache; - public class CacheDataSource implements DataSource { private DataSource source; public AuthMe plugin; - private ConcurrentHashMap cache = new ConcurrentHashMap(); + private ConcurrentHashMap cache = new ConcurrentHashMap<>(); public CacheDataSource(AuthMe plugin, DataSource source) { this.plugin = plugin; @@ -24,8 +23,9 @@ public class CacheDataSource implements DataSource { * load the server, but it will be much easier to check for an * isAuthAvailable ! */ - for (PlayerAuth auth : source.getAllAuths()) + for (PlayerAuth auth : source.getAllAuths()) { cache.put(auth.getNickname().toLowerCase(), auth); + } } @Override @@ -144,12 +144,8 @@ public class CacheDataSource implements DataSource { for (Player player : Utils.getOnlinePlayers()) { String user = player.getName().toLowerCase(); if (PlayerCache.getInstance().isAuthenticated(user)) { - try { - PlayerAuth auth = source.getAuth(user); - cache.put(user, auth); - } catch (NullPointerException npe) { - } - + PlayerAuth auth = source.getAuth(user); + cache.put(user, auth); } } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 5b1a6b980..7b6758f45 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -19,33 +19,34 @@ public final class Settings extends YamlConfiguration { // This is not an option! public static Boolean antiBotInAction = false; - public static final File PLUGIN_FOLDER; - public static final File CACHE_FOLDER; - public static final File AUTH_FILE; - public static final File SETTINGS_FILE; + public static final File PLUGIN_FOLDER = AuthMe.getInstance().getDataFolder(); + public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); + public static final File AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db"); + public static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); + public static File messageFile; - public static List allowCommands = null; - public static List getJoinPermissions = null; - public static List getUnrestrictedName = null; - private static List getRestrictedIp; - public static List getMySQLOtherUsernameColumn = null; - public static List getForcedWorlds = null; - public static List countries = null; - public static List countriesBlacklist = null; - public static List forceCommands = null; - public static List forceCommandsAsConsole = null; - public static List forceRegisterCommands = null; - public static List forceRegisterCommandsAsConsole = null; + public static List allowCommands; + public static List getJoinPermissions; + public static List getUnrestrictedName; + public static List getRestrictedIp; + public static List getMySQLOtherUsernameColumn; + public static List getForcedWorlds; + public static List countries; + public static List countriesBlacklist; + public static List forceCommands; + public static List forceCommandsAsConsole; + public static List forceRegisterCommands; + public static List forceRegisterCommandsAsConsole; + public static List welcomeMsg; + public static List unsafePasswords; + public static List emailBlacklist; + public static List emailWhitelist; public static DataSourceType getDataSource; public static HashAlgorithm getPasswordHash; - public static Boolean useLogging = false; + public static boolean useLogging = false; public static int purgeDelay = 60; - public static List welcomeMsg = null; - public static List unsafePasswords; - public static List emailBlacklist = null; - public static List emailWhitelist = null; - public static Boolean isPermissionCheckEnabled, isRegistrationEnabled, + public static boolean isPermissionCheckEnabled, isRegistrationEnabled, isForcedRegistrationEnabled, isTeleportToSpawnEnabled, isSessionsEnabled, isChatAllowed, isAllowRestrictedIp, isMovementAllowed, isKickNonRegisteredEnabled, @@ -91,35 +92,28 @@ public final class Settings extends YamlConfiguration { protected static YamlConfiguration configFile; - static { - PLUGIN_FOLDER = AuthMe.getInstance().getDataFolder(); - CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); - AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db"); - SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); - } - public Settings(AuthMe plugin) { configFile = (YamlConfiguration) plugin.getConfig(); this.plugin = plugin; - boolean exist = exists(); + } + + public final void reload() throws Exception { + plugin.getLogger().info("Loading Configuration File..."); + boolean exist = SETTINGS_FILE.exists(); if (!exist) { plugin.saveDefaultConfig(); } - load(); - loadConfigOptions(exist); + load(SETTINGS_FILE); + if (exist) { + mergeConfig(); + } + loadVariables(); + if (exist) { + saveDefaults(); + } messageFile = new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + messagesLanguage + ".yml"); } - public void loadConfigOptions(boolean exist) { - plugin.getLogger().info("Loading Configuration File..."); - if (exist) - mergeConfig(); - - loadVariables(); - - if (exist) - saveDefaults(); - } @SuppressWarnings("unchecked") public static void loadVariables() { @@ -513,27 +507,6 @@ public final class Settings extends YamlConfiguration { } } - /** - * Loads the configuration from disk - * - * @return True if loaded successfully - */ - public final boolean load() { - try { - load(SETTINGS_FILE); - return true; - } catch (Exception ex) { - return false; - } - } - - public final void reload() { - if (!exists()) { - plugin.saveDefaultConfig(); - } - load(); - } - /** * Saves the configuration to disk * @@ -548,15 +521,6 @@ public final class Settings extends YamlConfiguration { } } - /** - * Simple function for if the Configuration file exists - * - * @return True if configuration exists on disk - */ - public final boolean exists() { - return SETTINGS_FILE.exists(); - } - /** * Saves current configuration (plus defaults) to disk. *

From b8abe7158490af47c7691aff993f717181dbc997 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 23:35:31 +0700 Subject: [PATCH 058/115] remove message 'bad_database_email' --- src/main/resources/messages/messages_bg.yml | 2 - src/main/resources/messages/messages_br.yml | 1 - src/main/resources/messages/messages_cz.yml | 1 - src/main/resources/messages/messages_de.yml | 1 - src/main/resources/messages/messages_en.yml | 1 - src/main/resources/messages/messages_es.yml | 1 - src/main/resources/messages/messages_eu.yml | 1 - src/main/resources/messages/messages_fi.yml | 1 - src/main/resources/messages/messages_fr.yml | 1 - src/main/resources/messages/messages_gl.yml | 2 - src/main/resources/messages/messages_hu.yml | 1 - src/main/resources/messages/messages_it.yml | 1 - src/main/resources/messages/messages_ko.yml | 1 - src/main/resources/messages/messages_lt.yml | 1 - src/main/resources/messages/messages_nl.yml | 1 - src/main/resources/messages/messages_pl.yml | 1 - src/main/resources/messages/messages_pt.yml | 1 - src/main/resources/messages/messages_ru.yml | 1 - src/main/resources/messages/messages_sk.yml | 1 - src/main/resources/messages/messages_tr.yml | 1 - src/main/resources/messages/messages_uk.yml | 1 - src/main/resources/messages/messages_vn.yml | 8 +- src/main/resources/messages/messages_zhcn.yml | Bin 4566 -> 4406 bytes src/main/resources/messages/messages_zhhk.yml | 117 +++++++++--------- src/main/resources/messages/messages_zhtw.yml | 1 - 25 files changed, 60 insertions(+), 89 deletions(-) diff --git a/src/main/resources/messages/messages_bg.yml b/src/main/resources/messages/messages_bg.yml index 866931cc3..81a7e7088 100644 --- a/src/main/resources/messages/messages_bg.yml +++ b/src/main/resources/messages/messages_bg.yml @@ -37,8 +37,6 @@ usage_changepassword: '&fКоманда: /changepassword СтараПарола name_len: '&cÐ¢Ð²Ð¾Ñ Ð½Ð¸ÐºÐ½ÐµÐ¹Ð¼ е твърде малък или голÑм' regex: '&cÐ¢Ð²Ð¾Ñ Ð½Ð¸ÐºÐ½ÐµÐ¹Ð¼ Ñъдържа забранени знацхи. Позволените Ñа: REG_EX' add_email: '&cÐœÐ¾Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð¸ ÑÐ²Ð¾Ñ Ð¸Ð¼ÐµÐ¹Ð» Ñ : /email add имейл имейл' -bad_database_email: '[AuthMe] Тази /email команда работи Ñамо Ñ Ð‘Ð” (MySQL и SQLite), - Ñвържи Ñе Ñ Ðдмин' recovery_email: '&cЗабравихте ÑвоÑта парола? ÐœÐ¾Ð»Ñ Ð¸Ð·Ð¿Ð¾Ð»Ð·Ð²Ð°Ð¹ /email recovery <имейл>' usage_captcha: '&cYou need to type a captcha, please type: /captcha <код>' wrong_captcha: '&cГрешен код, използвай : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_br.yml b/src/main/resources/messages/messages_br.yml index 044443fbf..20243c687 100644 --- a/src/main/resources/messages/messages_br.yml +++ b/src/main/resources/messages/messages_br.yml @@ -36,7 +36,6 @@ usage_changepassword: '&fUse: /changepassword PasswordAntiga PasswordNova' name_len: '&cO seu nickname é muito curto, ou muito longo.' regex: '&cO seu nickname contém caracteres não permitidos. Permitido: REG_EX' add_email: '&cPor favor adicione o seu email com : /email add seuEmail confirmarSeuEmail' -bad_database_email: '[AuthMe] O comando /email não está disponível contacte o staff via ticket' recovery_email: '&cPerdeu/esqueceu a sua password(senha)? Para a recupera-la escreva /email recovery ' usage_captcha: '&cVocê precisa digitar um captcha, escreva: /captcha ' wrong_captcha: '&cCaptcha errado, por favor escreva: /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_cz.yml b/src/main/resources/messages/messages_cz.yml index 9d1b10315..7492503d7 100644 --- a/src/main/resources/messages/messages_cz.yml +++ b/src/main/resources/messages/messages_cz.yml @@ -36,7 +36,6 @@ usage_changepassword: '&cPouzij: "/changepassword stareHeslo noveHeslo".' name_len: '&cTvuj nick je prilis kratky, nebo prilis dlouhy' regex: '&cTvuj nick obsahuje nepovolene znaky. Pripustne znaky jsou: REG_EX' add_email: '&cPridej prosim svuj email pomoci : /email add TvujEmail TvujEmail' -bad_database_email: '[AuthMe] Prikaz /email je mozno pouzit jen s MySQL a SQLite, kontaktuj Admina' recovery_email: '&cZapomel jsi heslo? Zadej: /email recovery ' usage_captcha: '&cPouzij: /captcha ' wrong_captcha: '&cSpatne opsana Captcha, pouzij prosim: /captcha CAPTCHA_TEXT' diff --git a/src/main/resources/messages/messages_de.yml b/src/main/resources/messages/messages_de.yml index 17a1657b2..fa086015a 100644 --- a/src/main/resources/messages/messages_de.yml +++ b/src/main/resources/messages/messages_de.yml @@ -36,7 +36,6 @@ usage_changepassword: '&cBenutze: /changepassword ' -bad_database_email: '&4Der /email Befehl ist nur mit MySQL und SQLite kompatibel. Bitte kontaktiere einen Administrator!' recovery_email: '&3Passwort vergessen? Nutze "/email recovery " für ein neues Passwort' usage_captcha: '&3Um dich einzuloggen, tippe dieses Captcha so ein: /captcha ' wrong_captcha: '&cFalsches Captcha, bitte nutze: /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml index 8f07d88b3..16218f329 100644 --- a/src/main/resources/messages/messages_en.yml +++ b/src/main/resources/messages/messages_en.yml @@ -36,7 +36,6 @@ usage_changepassword: '&cUsage: /changepassword ' name_len: '&4Your username is either too short or too long!' regex: '&4Your username contains illegal characters. Allowed chars: REG_EX' add_email: '&3Please add your email to your account with the command "/email add "' -bad_database_email: '&4The /email command is available only with MySQL and SQLite databases, please contact an Admin!' #This should be removed! recovery_email: '&3Forgot your password? Please use the command "/email recovery "' usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "' wrong_captcha: '&cWrong Captcha, please type "/captcha THE_CAPTCHA" into the chat!' diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml index 62fbc53a1..e91e310e8 100644 --- a/src/main/resources/messages/messages_es.yml +++ b/src/main/resources/messages/messages_es.yml @@ -37,7 +37,6 @@ usage_changepassword: '&fUso: /changepw contraseñaaActual contraseñaNueva' name_len: '&cTu nombre de usuario es muy largo o muy corto' regex: '&cTu usuario tiene carácteres no admitidos, los cuales son: REG_EX' add_email: '&cPor favor agrega tu e-mail con: /email add tuEmail confirmarEmail' -bad_database_email: '[AuthMe] El comando /email sólo está disponible con MySQL y SQLite, contacta a un administrador' recovery_email: '&c¿Olvidaste tu contraseña? Por favor usa /email recovery ' usage_captcha: '&cUso: /captcha ' wrong_captcha: '&cCaptcha incorrecto, please use : /captcha EL_CAPTCHA' diff --git a/src/main/resources/messages/messages_eu.yml b/src/main/resources/messages/messages_eu.yml index 4a45b3f9b..44d961de0 100644 --- a/src/main/resources/messages/messages_eu.yml +++ b/src/main/resources/messages/messages_eu.yml @@ -36,7 +36,6 @@ usage_changepassword: '&fErabili: /changepassword pasahitzZaharra pasahitzBerria name_len: '&cZure erabiltzaile izena motzegia edo luzeegia da' regex: '&cZure erabiltzaileak karaktere debekatuak ditu. Karaktere onartuak: REG_EX' add_email: '&cMesedez gehitu zure emaila : /email add yourEmail confirmEmail' -bad_database_email: '[AuthMe] /email komandoa MySql-rekin bakarrik dago erabilgarri. Jarri kontaktuan administratzaile batekin' recovery_email: '&cPasahitza ahaztu duzu? Erabili /email recovery ' usage_captcha: '&cYou need to type a captcha, please type: /captcha ' wrong_captcha: '&cWrong Captcha, please use : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_fi.yml b/src/main/resources/messages/messages_fi.yml index 211928fe9..be3779c7d 100644 --- a/src/main/resources/messages/messages_fi.yml +++ b/src/main/resources/messages/messages_fi.yml @@ -36,7 +36,6 @@ usage_changepassword: '&fKäyttötapa: /changepassword vanhaSalasana uusiSalasan name_len: '&cPelaajanimesi on liian lyhyt tai pitkä' regex: '&cPelaajanimesi sisältää luvattomia merkkejä. Hyväksytyt merkit: REG_EX' add_email: '&cLisää sähköpostisi: /email add sähköpostisi sähköpostisiUudelleen' -bad_database_email: '[AuthMe] Tämä /email komento on vain käytössä MySQLlän kanssa. Ota yhteys palveluntarjoojaan' recovery_email: '&cUnohtuiko salasana? Käytä komentoa: /email recovery ' usage_captcha: '&cKäyttötapa: /captcha ' wrong_captcha: '&cVäärä varmistus, käytä : /captcha CAPTCHA' diff --git a/src/main/resources/messages/messages_fr.yml b/src/main/resources/messages/messages_fr.yml index d337962a2..51a2a53af 100644 --- a/src/main/resources/messages/messages_fr.yml +++ b/src/main/resources/messages/messages_fr.yml @@ -37,7 +37,6 @@ usage_changepassword: '&fPour changer de mot de passe, utilisez: /changepassword name_len: '&cVotre pseudo est trop long ou trop court' regex: '&cCaractères autorisés: REG_EX' add_email: '&cMerci d''ajouter votre email : /email add yourEmail confirmEmail' -bad_database_email: '[AuthMe] La commande /email est disponible uniquement pour MySQL et SQLite, contactez un Admin' recovery_email: '&cVous avez oublié votre MotdePasse? Utilisez /email recovery ' usage_captcha: '&cTrop de tentatives de connexion échouées, utilisez: /captcha ' wrong_captcha: '&cCaptcha incorrect, écrivez de nouveau : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_gl.yml b/src/main/resources/messages/messages_gl.yml index 5a43e796d..2ead0316e 100644 --- a/src/main/resources/messages/messages_gl.yml +++ b/src/main/resources/messages/messages_gl.yml @@ -37,8 +37,6 @@ usage_changepassword: '&fUso: /changepassword ' -bad_database_email: '[AuthMe] Este comando /email só está dispoñible con MySQL e SQLite, - contacta cun administrador' recovery_email: '&cOlvidaches o contrasinal? Por favor, usa /email recovery ' usage_captcha: '&cNecesitas escribir un captcha, por favor escribe: /captcha ' wrong_captcha: '&cCaptcha equivocado, por favor usa: /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml index e71dae62b..68fde4d1f 100644 --- a/src/main/resources/messages/messages_hu.yml +++ b/src/main/resources/messages/messages_hu.yml @@ -36,7 +36,6 @@ usage_changepassword: 'használat: /changepassword régiJelszó újJelszó' name_len: '&cYour nickname is too Short or too long' regex: '&cYour nickname contains illegal characters. Allowed chars: REG_EX' add_email: '&cPlease add your email with : /email add yourEmail confirmEmail' -bad_database_email: '[AuthMe] This /email command only available with MySQL and SQLite, contact an Admin' recovery_email: '&cForgot your password? Please use /email recovery ' usage_captcha: '&cUsage: /captcha ' wrong_captcha: '&cWrong Captcha, please use : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml index 5a58cb28d..4e4a0fa91 100644 --- a/src/main/resources/messages/messages_it.yml +++ b/src/main/resources/messages/messages_it.yml @@ -36,7 +36,6 @@ usage_changepassword: 'Utilizzo: /changepassword "' -bad_database_email: 'Il comando /email è utilizzabile solo con un database MySQL o SQLite, riporta questo errore ad un Admin!' recovery_email: '&cHai dimenticato la tua password? Puoi recuperarla eseguendo il comando: "/email recovery "' usage_captcha: '&cAbbiamo bisogno che tu inserisca un captcha, perfavore scrivi: "/captcha THE_CAPTCHA"' wrong_captcha: '&cCaptcha sbagliato, perfavore riprova con il comando: "/captcha THE_CAPTCHA"' diff --git a/src/main/resources/messages/messages_ko.yml b/src/main/resources/messages/messages_ko.yml index 2dc851162..db1bd4214 100644 --- a/src/main/resources/messages/messages_ko.yml +++ b/src/main/resources/messages/messages_ko.yml @@ -40,7 +40,6 @@ usage_changepassword: '&f사용법: /changepassword 기존비밀번호 새로운 name_len: '&cë‹¹ì‹ ì˜ ì´ë¦„ì€ ë„ˆë¬´ 짧거나 너무 ê¹ë‹ˆë‹¤' regex: '&cë‹¹ì‹ ì˜ ì´ë¦„ì—는 불법ì ì¸ 글ìžë“¤ì´ í¬í•¨ë˜ì–´ìžˆìŠµë‹ˆë‹¤. í—ˆìš©ëœ ê¸€ìž: REG_EX' add_email: '&cë‹¹ì‹ ì˜ ì´ë©”ì¼ì„ 추가해주세요 : /email add 당신ì˜ì´ë©”ì¼ ì´ë©”ì¼ìž¬ìž…ë ¥' -bad_database_email: '[AuthMe] ì´ /email 명령어는 ì˜¤ì§ MySQL와 SQLiteì—서만 가능합니다, 관리ìžì—게 문ì˜í•´ì£¼ì„¸ìš”' recovery_email: '&c비밀번호를 잊어버리셨다고요? /email recovery <당신ì˜ì´ë©”ì¼>ì„ ì‚¬ìš©í•˜ì„¸ìš”' usage_captcha: '&cë³´ì•ˆë¬¸ìž ìž…ë ¥ì´ í•„ìš”í•©ë‹ˆë‹¤, 입력해주세요: /captcha ' wrong_captcha: '&cìž˜ëª»ëœ ë³´ì•ˆë¬¸ìž, 사용해주세요 : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_lt.yml b/src/main/resources/messages/messages_lt.yml index c270da9f4..80a7b3abb 100644 --- a/src/main/resources/messages/messages_lt.yml +++ b/src/main/resources/messages/messages_lt.yml @@ -36,7 +36,6 @@ usage_changepassword: '&ePanaudojimas: /changepassword senasSlaptazodis naujasSl name_len: '&cJusu varsdas yra per ilgas arba per trumpas.' regex: '&cJusu varde yra neledziamu simboliu, leidziami: REG_EX' add_email: '&ePrasau pridekite savo el.pasta : /email add Email confirmEmail' -bad_database_email: '&c[AuthMe] si /email komanda leidziama tik su MySQL ir SQLite, susisiekite su administratorium' recovery_email: '&cPamirsote slaptazodi? Rasykite: /email recovery el.pastas' usage_captcha: '&cPanaudojimas: /captcha ' wrong_captcha: '&cNeteisinga Captcha, naudokite : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_nl.yml b/src/main/resources/messages/messages_nl.yml index 65c8a0fce..acd42a2cf 100644 --- a/src/main/resources/messages/messages_nl.yml +++ b/src/main/resources/messages/messages_nl.yml @@ -35,7 +35,6 @@ usage_changepassword: 'Gebruik: /changepassword ' usage_captcha: '&cGebruik: /captcha ' wrong_captcha: '&cverkeerde Captcha, Gebruik alstublieft : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_pl.yml b/src/main/resources/messages/messages_pl.yml index e9df21394..952fd1cc0 100644 --- a/src/main/resources/messages/messages_pl.yml +++ b/src/main/resources/messages/messages_pl.yml @@ -36,7 +36,6 @@ usage_changepassword: '&fUzycie: /changepassword starehaslo nowehaslo' name_len: '&cTwoje konto ma za dluga badz za krotka nazwe' regex: '&cTwoje konto ma w nazwie niedozwolone znaki. Dozwolone znaki: REG_EX' add_email: '&cProsze dodac swoj email: /email add twojEmail powtorzEmail' -bad_database_email: '[AuthMe] Ta komenda /email dostepna jedynie z baza adnych MySQL lub SQLite, skontaktuj sie z Administratorem' recovery_email: '&cZapomniales hasla? Prosze uzyj komendy /email recovery ' usage_captcha: '&cWpisz: /captcha ' wrong_captcha: '&cZly kod, prosze wpisac: /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_pt.yml b/src/main/resources/messages/messages_pt.yml index 680f7c1bd..02ec04208 100644 --- a/src/main/resources/messages/messages_pt.yml +++ b/src/main/resources/messages/messages_pt.yml @@ -36,7 +36,6 @@ usage_changepassword: '&fUse: /changepassword passwordAntiga passwordNova' name_len: '&cO seu nick é demasiado curto ou muito longo.' regex: '&cO seu nickname contém caracteres não permitidos. Permitido: REG_EX' add_email: '&cPor favor adicione o seu email com : /email add seuEmail confirmarSeuEmail' -bad_database_email: '[AuthMe] O comando /email não está disponível contacte o staff via ticket' recovery_email: '&cPerdeu a sua password? Para a recuperar escreva /email recovery ' usage_captcha: '&cVocê precisa digitar um captcha, escreva: /captcha ' wrong_captcha: '&cCaptcha errado, por favor escreva: /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_ru.yml b/src/main/resources/messages/messages_ru.yml index 4a6a2bf16..ddb84cdb5 100644 --- a/src/main/resources/messages/messages_ru.yml +++ b/src/main/resources/messages/messages_ru.yml @@ -36,7 +36,6 @@ usage_changepassword: '&4ИÑпользование: &5/changepassword СТÐР name_len: '&4Ваш логин Ñлишком длинный или Ñлишком короткий' regex: '&4Ваш логин Ñодержит запрещенные Ñимволы. Разрешенные Ñимволы: REG_EX' add_email: '&4Добавьте Ñвой email: &5/email add Ð’ÐШ_EMAIL Ð’ÐШ_EMAIL' -bad_database_email: '&4[AuthMe] Команда &5/email&4 доÑтупна только при работе Ñ MySQL или SQLite. ОбратититеÑÑŒ к админиÑтрации Ñервера' recovery_email: '&4Забыли пароль? ИÑпользуйте &5/email recovery Ð’ÐШ_EMAIL' usage_captcha: '&4Ð’Ñ‹ должны ввеÑти код, иÑпользуйте: &5/captcha ' wrong_captcha: '&4Ðеверный код, иÑпользуйте: &5/captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_sk.yml b/src/main/resources/messages/messages_sk.yml index 95d293c31..010533fe8 100644 --- a/src/main/resources/messages/messages_sk.yml +++ b/src/main/resources/messages/messages_sk.yml @@ -40,7 +40,6 @@ usage_changepassword: '&fPríkaz: /changepassword stareHeslo noveHeslo' name_len: '&cTvoje meno je velmi krátke alebo dlhé' regex: '&cTvoje meno obsahuje zakázané znaky. Povolené znaky: REG_EX' add_email: '&cPridaj svoj e-mail príkazom "/email add email zopakujEmail"' -bad_database_email: '[AuthMe] Tento príkaz je dostupny iba pri MySQL SQLite' recovery_email: '&cZabudol si heslo? Pouzi príkaz /email recovery ' usage_captcha: '&cUsage: /captcha ' wrong_captcha: '&cWrong Captcha, please use : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_tr.yml b/src/main/resources/messages/messages_tr.yml index 899bee304..7f0003962 100644 --- a/src/main/resources/messages/messages_tr.yml +++ b/src/main/resources/messages/messages_tr.yml @@ -36,7 +36,6 @@ usage_changepassword: '&fkullanimi: /changepassword eskisifre yenisifre' name_len: '&cKullanici adin cok kisa ya da cok uzun' regex: '&cKullanici adin ozel karakterler iceriyor. Uygun karakterler: REG_EX' add_email: '&cLutfen emailini ekle : /email add ' -bad_database_email: '[AuthMe] Bu /email komutu sadece MySql ve SQLite ile etkinlestireilebilir' recovery_email: '&cSifreni mi unuttun? Degistirmek icin : /email recovery ' usage_captcha: '&cBir captcha yazman lazim , yazmak icin: /captcha ' wrong_captcha: '&cYanlis Captcha, kullanmak icin : /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_uk.yml b/src/main/resources/messages/messages_uk.yml index aad7fc0c6..6b132d8da 100644 --- a/src/main/resources/messages/messages_uk.yml +++ b/src/main/resources/messages/messages_uk.yml @@ -36,7 +36,6 @@ usage_changepassword: '&fВикориÑтовуйте: /changepassword Стар name_len: '&cВаш нікнейм занадто довгий, або занадто короткий' regex: '&cВаш нікнейм міÑтить заборонені Ñимволи. ДоÑтупні Ñимволи: REG_EX' add_email: '&cБудь лаÑка додайте Ñвою електронну Ñкриньку: /email add ВашEmail ВашEmail' -bad_database_email: '[AuthMe] Команда /email доÑтупна лише при роботі з MySQL, або SQLite, звернітьÑÑ Ð´Ð¾ адмініÑтратора.' recovery_email: '&cЗабули пароль? Введіть /email recovery ВашПароль' usage_captcha: '&cБудь лаÑка введіть капчу: /captcha ' wrong_captcha: '&cÐевірне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ°Ð¿Ñ‡Ð¸: /captcha THE_CAPTCHA' diff --git a/src/main/resources/messages/messages_vn.yml b/src/main/resources/messages/messages_vn.yml index 1722385a1..7acb49885 100644 --- a/src/main/resources/messages/messages_vn.yml +++ b/src/main/resources/messages/messages_vn.yml @@ -1,8 +1,7 @@ unknown_user: '&fNgÆ°á»i chÆ¡i không tồn tại trong cÆ¡ sở dữ liệu' unsafe_spawn: '&fNÆ¡i thoát server của bạn không an toàn, Ä‘ang dịch chuyển bạn tá»›i Ä‘iểm spawn của server' not_logged_in: '&cChÆ°a đăng nhập!' -reg_voluntarily: '&fBạn có thể đăng kí tài khoản vá»›i lệnh - "/register mật-khẩu nhập-lại-mật-khẩu"' +reg_voluntarily: '&fBạn có thể đăng kí tài khoản vá»›i lệnh "/register mật-khẩu nhập-lại-mật-khẩu"' usage_log: '&eSá»­ dụng: /login password' wrong_pwd: '&cSai mật khẩu' unregistered: '&cHuá»· đăng kí thành công!' @@ -35,8 +34,6 @@ usage_changepassword: '&eSá»­ dụng: /changepassword mật-khẩu-cÅ© mật-kh name_len: '&cTên đăng nhập của bạn quá ngắn hoặc quá dài' regex: '&cTên đăng nhập của bạn có chứa kí tá»± đặc biệt không được cho phép. Các kí tá»± hợp lệ: REG_EX' add_email: '&cVui lòng thêm địa chỉ email cho tài khoản vá»›i lệnh: /email add email-của-bạn nhập-lại-email-của-bạn' -bad_database_email: '[AuthMe] Lệnh /email chỉ hoạt Ä‘á»™ng vá»›i cÆ¡ sở dữ liệu MySQL và SQLite, - hãy liên hệ Ä‘iá»u hành viên của server' recovery_email: '&cQuên mật khẩu? Hãy dùng lệnh /email recovery ' usage_captcha: '&cBạn cần nhập mã xác nhận: /captcha ' wrong_captcha: '&cSai mã xác nhận, nhập lại: /captcha ' @@ -55,5 +52,4 @@ email_changed: '[AuthMe] Äã thay đổi email !' email_send: '[AuthMe] Äã gá»­i email khôi phục mật khẩu tá»›i bạn !' country_banned: 'Rất tiếc, quốc gia của bạn không được phép gia nhập server' antibot_auto_enabled: '[AuthMe] AntiBot đã được kích hoạt vì lượng ngÆ°á»i chÆ¡i kết nối vượt quá giá»›i hạn!' -antibot_auto_disabled: '[AuthMe] AntiBot tá»± huá»· kích hoạt sau %m phút, - hi vá»ng lượng kết nối sẽ giảm bá»›t' \ No newline at end of file +antibot_auto_disabled: '[AuthMe] AntiBot tá»± huá»· kích hoạt sau %m phút, hi vá»ng lượng kết nối sẽ giảm bá»›t' \ No newline at end of file diff --git a/src/main/resources/messages/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml index 2571a88e637aa2323ca65b35c7dce1b94d166253..2d28081eb221a0d9712b8104796f2297aacc7690 100644 GIT binary patch delta 12 TcmcbnyiIAtKd#O5xGmTKCm#hQ delta 168 zcmdm{bWM4~Kd$;DhD3%GhIk-OWGDe*5Wkoq6)2L*kPBpIGUPB=F(@#oGek2uGL!<< zWH9&w+bb0P4;D|WC&&mWbk1S yOJZ$+urh%rr7{#qr{*P3j{BDCoAf?dqm<|W_wJB}-!%)X*-9cpHvizVV*>ySD>H-u diff --git a/src/main/resources/messages/messages_zhhk.yml b/src/main/resources/messages/messages_zhhk.yml index d66f1003c..db8b158b2 100644 --- a/src/main/resources/messages/messages_zhhk.yml +++ b/src/main/resources/messages/messages_zhhk.yml @@ -1,61 +1,60 @@ # Translator: uSoc_lifehome (http://lifeho.me) # -# Translator: WaterXCubic ¤ô¤è¶ô # +# Translator: WaterXCubic ����� # # -------------------------------------------- # -unknown_user: '&8[&6¥Î¤á¨t²Î&8] &f¥Î¤á¸ê®Æ¨Ã¤£¦s¦b©ó¸ê®Æ®w¤¤¡C' -unsafe_spawn: '&8[&6¥Î¤á¨t²Î&8] &f§Aªºµn¥X¦ì¸m¤£¦w¥þ¡A²{¦b±N¶Ç°e§A¨ì­«¥ÍÂI¡C' -not_logged_in: '&8[&6¥Î¤á¨t²Î&8] &c§AÁÙ¨S¦³µn¤J ¡I' -reg_voluntarily: '&8[&6¥Î¤á¨t²Î&8] &f§A¥i¥H¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' -usage_log: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /login <±K½X> ¡n' -wrong_pwd: '&8[&6¥Î¤á¨t²Î&8] &c§A¿é¤J¤F¿ù»~ªº±K½X¡C' -unregistered: '&8[&6¥Î¤á¨t²Î&8] &c§A¤w¦¨¥\¨ú®ø·|­ûµù¥U°O¿ý¡C' -reg_disabled: '&8[&6¥Î¤á¨t²Î&8] &c¥»¦øªA¾¹¤w°±¤î·sª±®aµù¥U¡C' -valid_session: '&8[&6¥Î¤á¨t²Î&8] &b¶Ù ¡I §Ú°O±o§A¡AÅwªï¦^¨Ó¡ã' -login: '&8[&6¥Î¤á¨t²Î&8] &c§A¦¨¥\ªºµn¤J¤F¡C' -password_error_nick: '&f§A¤£¥i¥H¨Ï¥Î§Aªº¦W¦r¬°±K½X!' -password_error_unsafe: '&f§A¤£¥i¥H¨Ï¥Î¤£¦w¥þªº±K½X' -vb_nonActiv: '&8[&6¥Î¤á¨t²Î&8] &f§Aªº±b¤áÁÙ¨S¦³¸g¹L¹q¶lÅçÃÒ ¡I' -user_regged: '&8[&6¥Î¤á¨t²Î&8] &c¦¹¥Î¤á¦W¤w¸gµù¥U¹L¤F¡C' -usage_reg: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' -max_reg: '&8[&6¥Î¤á¨t²Î&8] &f§AªºIP¦a§}¤w¹F¨ìµù¥U¼Æ¤W­­¡C' -no_perm: '&8[&6¥Î¤á¨t²Î&8] &b§A¥i¥H¨ì CraftingHK ª±®a¦Ê¬ì¤¤¬d¬Ý»¡©ú¤å¥ó¡C' -error: '&8[&6¥Î¤á¨t²Î&8] &fµo¥Í¿ù»~¡A½Ð»PºÞ²z­ûÁpµ¸¡C' -login_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Ó«ü¥O¨Óµn¤J¡G ¡m /login <±K½X> ¡n' -reg_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' -reg_email_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <¹q¶l> <­«Âйq¶l> ¡n' -usage_unreg: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /unregister <±K½X> ¡n' -pwd_changed: '&8[&6¥Î¤á¨t²Î&8] &c§A¦¨¥\ªº§ó´«¤F§Aªº±K½X ¡I' -user_unknown: '&8[&6¥Î¤á¨t²Î&8] &c¦¹¥Î¤á¦W¨S¦³¤wµn°O¸ê®Æ¡C' -password_error: '&8[&6¥Î¤á¨t²Î&8] &f±K½X¤£²Å¦X¡C' -invalid_session: '&8[&6¥Î¤á¨t²Î&8] &fµn¤J¶¥¬q¸ê®Æ¤w·lÃa¡A½Ðµ¥«Ýµn¤J¶¥¬qµ²§ô¡C' -reg_only: '&8[&6¥Î¤á¨t²Î&8] &f­­¤wµù¥U·|­û¡A½Ð¥ý¨ì https://www.example.com/ µù¥U¡C' -logged_in: '&8[&6¥Î¤á¨t²Î&8] &c§A¤w¸gµn¤J¹L¤F¡C' -logout: '&8[&6¥Î¤á¨t²Î&8] &b§A¦¨¥\ªºµn¥X¤F¡C' -same_nick: '&8[&6¥Î¤á¨t²Î&8] &f¦P¦Wª±®a¤w¦b¹Cª±¡C' -registered: '&8[&6¥Î¤á¨t²Î&8] &b§A¦¨¥\ªºµù¥U¤F¡C' -pass_len: '&8[&6¥Î¤á¨t²Î&8] &f§Aªº±K½X¨Ã¤£²Å¦X³W©wªø«×¡C' -reload: '&8[&6¥Î¤á¨t²Î&8] &bµn¤J¨t²Î³]©w¤Î¸ê®Æ®w­«·s¸ü¤J§¹²¦¡C' -timeout: '&8[&6¥Î¤á¨t²Î&8] &fµn¤J¹O®É¡C' -usage_changepassword: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /changepassword <±K½X> <·s±K½X> ¡n' -name_len: '&8[&6¥Î¤á¨t²Î&8] &c§Aªº¥Î¤á¦W¤£²Å¦X³W©wªø«×¡C' -regex: '&8[&6¥Î¤á¨t²Î&8] &c§Aªº¥Î¤á¦W§t¦³¤£®e³\¤§¦r²Å¡C¥H¤U¬°­ã³\¤§¦r¥À¡G REG_EX' -add_email: '&8[&6¥Î¤á¨t²Î&8] &b½Ð¬°§Aªº±b¤á¥ß§Y²K¥[¹q¶l¦a§}¡G ¡m /email add <¹q¶l¦a§}> <­«Âйq¶l¦a§}> ¡n' -bad_database_email: '&8[&6¥Î¤á¨t²Î&8] ¦¹«ü¥O¥u¾A¥Î©ó¨Ï¥ÎMySQL©ÎSQLite¤§¦øªA¾¹¡C' -recovery_email: '&8[&6¥Î¤á¨t²Î&8] &c§Ñ°O±K½X ¡H ½Ð¨Ï¥Î³o­Óªº«ü¥O¨Ó§ó·s±K½X¡G ¡m /email recovery <¹q¶l¦a§}> ¡n' -usage_captcha: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /captcha ¡n' -wrong_captcha: '&8[&6¥Î¤á¨t²Î&8] &c§A¿é¤J¤F¿ù»~ªºÅçÃÒ½X¡A½Ð¨Ï¥Î ¡m /captcha <ÅçÃÒ½X> ¡n ¦A¦¸¿é¤J¡C' -valid_captcha: '&8[&6¥Î¤á¨t²Î&8] &c§A©Ò¿é¤JªºÅçÃÒ½X¬OµL®Äªº ¡I' -kick_forvip: '&c¦]¬°¦³VIPª±®aµn¤J¤F¦øªA¾¹¡C' -kick_fullserver: '&c©êºp¡I ¦]¬°¦øªA¾¹º¡¤H¤F¡A©Ò¥H§A¥Ø«e¥¼¯àµn¤J¦øªA¾¹¡C' -usage_email_add: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email add <¹q¶l> <­«Âйq¶l> ¡n' -usage_email_change: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email change <¹q¶l> <·s¹q¶l> ¡n' -usage_email_recovery: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email recovery <¹q¶l> ¡n' -new_email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªº·s¹q¶l¦a§}¨Ã¤£¥¿½T¡C' -old_email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªºÂ¹q¶l¦a§}¨Ã¤£¥¿½T¡C' -email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªº¹q¶l¦a§}¨Ã¤£¥¿½T¡C' -email_added: '&8[&6¥Î¤á¨t²Î&8] ¤w¥[¤J§Aªº¹q¶l¦a§}°O¿ý¡C' -email_confirm: '&8[&6¥Î¤á¨t²Î&8] ½Ð­«Âпé¤J§Aªº¹q¶l¦a§}¡C' -email_changed: '&8[&6¥Î¤á¨t²Î&8] §Aªº¹q¶l¦a§}°O¿ý¤w§ó§ï¡C' -email_send: '&8[&6¥Î¤á¨t²Î&8] §Ñ°O±K½X«H¥ó¤w±H¥X¡A½Ð¬d¦¬¡C' -country_banned: '&8[&6¥Î¤á¨t²Î&8] ¥»¦øªA¾¹¤w°±¤î¹ï§Aªº°ê®a´£¨Ñ¹CÀ¸ªA°È¡C' -antibot_auto_enabled: '&8[&6¥Î¤á¨t²Î&8] ¨¾¤î¾÷±ñ¤Hµ{§Ç¤w¦]À³²{®É¤j¶q¤£´M±`ªº³s½u¦Ó±Ò¥Î¡C' -antibot_auto_disabled: '&8[&6¥Î¤á¨t²Î&8] ¨¾¤î¾÷±ñ¤Hµ{§ÇÀˬd¨ì¤£¥¿±`³s±µ¼Æ¤w´î¤Ö¡A¨Ã©ó %m ¤ÀÄÁ«á°±¤î¹B§@¡C' +unknown_user: '&8[&6�Τ�t��&8] &f�Τ��ƨä��s�b���Ʈw���C' +unsafe_spawn: '&8[&6�Τ�t��&8] &f�A���n�X��m���w���A�{�b�N�ǰe�A�쭫���I�C' +not_logged_in: '&8[&6�Τ�t��&8] &c�A�٨S���n�J �I' +reg_voluntarily: '&8[&6�Τ�t��&8] &f�A�i�H�ϥγo�Ӫ����O�ӵ��U�G �m /register <�K�X> <���бK�X> �n' +usage_log: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /login <�K�X> �n' +wrong_pwd: '&8[&6�Τ�t��&8] &c�A��J�F���~���K�X�C' +unregistered: '&8[&6�Τ�t��&8] &c�A�w���\�����|�����U�O���C' +reg_disabled: '&8[&6�Τ�t��&8] &c�����A���w����s���a���U�C' +valid_session: '&8[&6�Τ�t��&8] &b�� �I �ڰO�o�A�A�w��^�ӡ�' +login: '&8[&6�Τ�t��&8] &c�A���\���n�J�F�C' +password_error_nick: '&f�A���i�H�ϥΧA���W�r���K�X!' +password_error_unsafe: '&f�A���i�H�ϥΤ��w�����K�X' +vb_nonActiv: '&8[&6�Τ�t��&8] &f�A���b���٨S���g�L�q�l���� �I' +user_regged: '&8[&6�Τ�t��&8] &c����W�w�g���U�L�F�C' +usage_reg: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /register <�K�X> <���бK�X> �n' +max_reg: '&8[&6�Τ�t��&8] &f�A��IP�a�}�w�F����U�ƤW���C' +no_perm: '&8[&6�Τ�t��&8] &b�A�i�H�� CraftingHK ���a�ʬ줤�d�ݻ������C' +error: '&8[&6�Τ�t��&8] &f�o�Ϳ��~�A�лP�޲z���p���C' +login_msg: '&8[&6�Τ�t��&8] &c�Шϥγo�ӫ��O�ӵn�J�G �m /login <�K�X> �n' +reg_msg: '&8[&6�Τ�t��&8] &c�Шϥγo�Ӫ����O�ӵ��U�G �m /register <�K�X> <���бK�X> �n' +reg_email_msg: '&8[&6�Τ�t��&8] &c�Шϥγo�Ӫ����O�ӵ��U�G �m /register <�q�l> <���йq�l> �n' +usage_unreg: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /unregister <�K�X> �n' +pwd_changed: '&8[&6�Τ�t��&8] &c�A���\���󴫤F�A���K�X �I' +user_unknown: '&8[&6�Τ�t��&8] &c����W�S���w�n�O��ơC' +password_error: '&8[&6�Τ�t��&8] &f�K�X���ŦX�C' +invalid_session: '&8[&6�Τ�t��&8] &f�n�J���q��Ƥw�l�a�A�е��ݵn�J���q�����C' +reg_only: '&8[&6�Τ�t��&8] &f���w���U�|���A���� https://www.example.com/ ���U�C' +logged_in: '&8[&6�Τ�t��&8] &c�A�w�g�n�J�L�F�C' +logout: '&8[&6�Τ�t��&8] &b�A���\���n�X�F�C' +same_nick: '&8[&6�Τ�t��&8] &f�P�W���a�w�b�C���C' +registered: '&8[&6�Τ�t��&8] &b�A���\�����U�F�C' +pass_len: '&8[&6�Τ�t��&8] &f�A���K�X�ä��ŦX�W�w���סC' +reload: '&8[&6�Τ�t��&8] &b�n�J�t�γ]�w�θ�Ʈw���s���J�����C' +timeout: '&8[&6�Τ�t��&8] &f�n�J�O�ɡC' +usage_changepassword: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /changepassword <�±K�X> <�s�K�X> �n' +name_len: '&8[&6�Τ�t��&8] &c�A����W���ŦX�W�w���סC' +regex: '&8[&6�Τ�t��&8] &c�A����W�t�����e�\���r�šC�H�U����\���r���G REG_EX' +add_email: '&8[&6�Τ�t��&8] &b���A���b��ߧY�K�[�q�l�a�}�G �m /email add <�q�l�a�}> <���йq�l�a�}> �n' +recovery_email: '&8[&6�Τ�t��&8] &c�ѰO�K�X �H �Шϥγo�Ӫ����O�ӧ�s�K�X�G �m /email recovery <�q�l�a�}> �n' +usage_captcha: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /captcha �n' +wrong_captcha: '&8[&6�Τ�t��&8] &c�A��J�F���~�����ҽX�A�Шϥ� �m /captcha <���ҽX> �n �A����J�C' +valid_captcha: '&8[&6�Τ�t��&8] &c�A�ҿ�J�����ҽX�O�L�Ī� �I' +kick_forvip: '&c�]����VIP���a�n�J�F���A���C' +kick_fullserver: '&c��p�I �]�����A�����H�F�A�ҥH�A�ثe����n�J���A���C' +usage_email_add: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /email add <�q�l> <���йq�l> �n' +usage_email_change: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /email change <�¹q�l> <�s�q�l> �n' +usage_email_recovery: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /email recovery <�q�l> �n' +new_email_invalid: '&8[&6�Τ�t��&8] �A�Ҷ�g���s�q�l�a�}����T�C' +old_email_invalid: '&8[&6�Τ�t��&8] �A�Ҷ�g���¹q�l�a�}����T�C' +email_invalid: '&8[&6�Τ�t��&8] �A�Ҷ�g���q�l�a�}����T�C' +email_added: '&8[&6�Τ�t��&8] �w�[�J�A���q�l�a�}�O���C' +email_confirm: '&8[&6�Τ�t��&8] �Э��п�J�A���q�l�a�}�C' +email_changed: '&8[&6�Τ�t��&8] �A���q�l�a�}�O���w���C' +email_send: '&8[&6�Τ�t��&8] �ѰO�K�X�H��w�H�X�A�Ьd���C' +country_banned: '&8[&6�Τ�t��&8] �����A���w�����A����a���ѹC���A�ȡC' +antibot_auto_enabled: '&8[&6�Τ�t��&8] �������H�{�Ǥw�]���{�ɤj�q���M�`���s�u�ӱҥΡC' +antibot_auto_disabled: '&8[&6�Τ�t��&8] �������H�{���ˬd�줣���`�s���Ƥw��֡A�é� %m �����ᰱ��B�@�C' diff --git a/src/main/resources/messages/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml index 5091f8414..34c213119 100644 --- a/src/main/resources/messages/messages_zhtw.yml +++ b/src/main/resources/messages/messages_zhtw.yml @@ -39,7 +39,6 @@ usage_changepassword: '&bã€AuthMe】&6用法: &c"/changepassword <舊密碼> < name_len: '&bã€AuthMe】&6你的暱稱 太長 / 太短 了!' regex: '&bã€AuthMe】&6暱稱裡包å«ä¸èƒ½ä½¿ç”¨çš„字符' add_email: '&bã€AuthMe】&6請使用 &c"/email add <ä½ çš„Email> <å†æ¬¡è¼¸å…¥ä½ çš„Email>" &6來添加 Email' -bad_database_email: '&bã€AuthMe】&6此指令åªé©ç”¨æ–¼æœ‰ä½¿ç”¨MySQLå’ŒSQLite的伺æœå™¨ã€‚' recovery_email: '&bã€AuthMe】&6忘記密碼了嗎? 使用 &c"/email recovery <ä½ çš„Email>"' usage_captcha: '&bã€AuthMe】&6請用 &c"/captcha " &6來輸入你的驗證碼' wrong_captcha: '&bã€AuthMe】&6錯誤的驗證碼' From e9cf5de663152155e3553a7318df862f7af5561a Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 14 Sep 2015 23:39:53 +0700 Subject: [PATCH 059/115] added ID messages translation. --- src/main/resources/messages/messages_id.yml | 58 +++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/main/resources/messages/messages_id.yml diff --git a/src/main/resources/messages/messages_id.yml b/src/main/resources/messages/messages_id.yml new file mode 100644 index 000000000..2b183f3d1 --- /dev/null +++ b/src/main/resources/messages/messages_id.yml @@ -0,0 +1,58 @@ +unknown_user: '&cTidak dapat menemukan user yg diminta di database!' +unsafe_spawn: '&cLokasi quit kamu tidak aman, kamu telah diteleport ke titik spawn world.' +not_logged_in: '&cKamu belum login!' +reg_voluntarily: 'Kamu bisa register menggunakan command "/register "' +usage_log: '&cUsage: /login ' +wrong_pwd: '&cPassword salah!' +unregistered: '&cUnregister berhasil!' +reg_disabled: '&cRegister dalam game tidak diaktifkan!' +valid_session: '&2Otomatis login, karena sesi masih terhubung.' +login: '&2Login berhasil!' +vb_nonActiv: '&cAkunmu belum diaktifkan, silahkan periksa email kamu!' +user_regged: '&cKamu telah mendaftarkan username ini!' +usage_reg: '&cUsage: /register ' +max_reg: '&Kamu telah mencapai batas maksimum pendaftaran di server ini!' +no_perm: '&4Kamu tidak mempunyai izin melakukan ini!' +error: '&4Terjadi kesalahan tak dikenal, silahkan hubungi Administrator!' +login_msg: '&cSilahkan login menggunakan command "/login "' +reg_msg: '&3Silahkan mendaftar ke server menggunakan command "/register "' +reg_email_msg: '&3Silahkan mendaftar ke server menggunakan command "/register "' +usage_unreg: '&cUsage: /unregister ' +pwd_changed: '&2Berhasil mengubah password!' +user_unknown: '&cUser ini belum terdaftar!' +password_error: '&cPassword tidak cocok, silahkan periksa dan ulangi kembali!' +password_error_nick: '&cKamu tidak bisa menggunakan namamu sebagai password, silahkan coba yg lain...' +password_error_unsafe: '&cPassword yg kamu pilih tidak aman, silahkan coba yg lain...' +invalid_session: '&cIP kamu telah berubah, dan sesi kamu telah berakhir!' +reg_only: '&4Hanya pengguna terdaftar yg bisa bergabung! Silahkan kunjungi http://example.com untuk mendaftar!' +logged_in: '&cKamu telah login!' +logout: '&2Berhasil logout!' +same_nick: '&4Username yg sama telah bermain di server ini!' +registered: '&2Register berhasil!' +pass_len: '&cPassword kamu terlalu panjang/pendek! Silahkan pilih yg lain!' +reload: '&2Konfigurasi dan database telah dimuat ulang!' +timeout: '&4Jangka waktu login telah habis, kamu di keluarkan dari server. Silahkan coba lagi!' +usage_changepassword: '&cUsage: /changepassword ' +name_len: '&4Username kamu terlalu panjang atau terlalu pendek!' +regex: '&4Username kamu mengandung karakter illegal. Karakter yg diijinkan: REG_EX' +add_email: '&3Silahkan tambahkan email ke akunmu menggunakan command "/email add "' +recovery_email: '&3Lupa password? silahkan gunakan command "/email recovery "' +usage_captcha: '&3Kamu harus menyelesaikan kode captcha untuk login, silahkan gunakan command "/captcha "' +wrong_captcha: '&cCaptcha salah, gunakan command "/captcha THE_CAPTCHA" pada chat!' +valid_captcha: '&2Kode captcha terselesaikan!' +kick_forvip: '&3Player VIP mencoba masuk pada saat server sedang penuh!' +kick_fullserver: '&4Server sedang penuh, silahkan coba lagi nanti!' +usage_email_add: '&cUsage: /email add ' +usage_email_change: '&cUsage: /email change ' +usage_email_recovery: '&cUsage: /email recovery ' +new_email_invalid: '&cEmail baru tidak valid, coba lagi!' +old_email_invalid: '&cEmail lama tidak valid, coba lagi!' +email_invalid: '&cAlamat email tidak valid, coba lagi!' +email_added: '&2Berhasil menambahkan alamat email ke akunmu!' +email_confirm: '&cSilahkan konfirmasi alamat email kamu!' +email_changed: '&2Alamat email telah diubah dengan benar!' +email_send: '&2Email pemulihan akun telah dikirim! Silahkan periksa kotak masuk emailmu!' +email_exists: '&cEmail pemulihan sudah dikirim! kamu bisa membatalkan dan mengirimkan yg baru dengan command dibawah:' +country_banned: '&4Your country is banned from this server!' +antibot_auto_enabled: '&4[AntiBotService] AntiBot diaktifkan dikarenakan banyak koneksi yg diterima!' +antibot_auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!' From 7add63869ee729160ff48efdc535414340b418c3 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 00:02:52 +0700 Subject: [PATCH 060/115] no need to rewrite language file. fix #206 --- .../authme/settings/CustomConfiguration.java | 1 - .../fr/xephi/authme/settings/Messages.java | 50 +------------------ 2 files changed, 1 insertion(+), 50 deletions(-) diff --git a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java index abf637009..ae274ca58 100644 --- a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java +++ b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java @@ -17,7 +17,6 @@ public class CustomConfiguration extends YamlConfiguration { public CustomConfiguration(File file) { this.configFile = file; - load(); } diff --git a/src/main/java/fr/xephi/authme/settings/Messages.java b/src/main/java/fr/xephi/authme/settings/Messages.java index 4ddb95198..f9c7272a0 100644 --- a/src/main/java/fr/xephi/authme/settings/Messages.java +++ b/src/main/java/fr/xephi/authme/settings/Messages.java @@ -13,59 +13,11 @@ public class Messages extends CustomConfiguration { public Messages(File file, String lang) { super(file); - loadDefaults(file); - loadFile(); - saveDefaults(file); + load(); singleton = this; this.lang = lang; } - /** - * Loads a file from the plugin jar and sets as default - * - * @param file The filename to open - */ - public final void loadDefaults(File file) { - if (file.isFile()) { - setDefaults(YamlConfiguration.loadConfiguration(file)); - } - } - - /** - * Saves the configuration to disk - * - * @return True if saved successfully - */ - public final boolean saved(File file) { - try { - save(file); - return true; - } catch (Exception ex) { - return false; - } - } - - /** - * Saves current configuration (plus defaults) to disk. - *

- * If defaults and configuration are empty, saves blank file. - * - * @return True if saved successfully - */ - public final boolean saveDefaults(File file) { - options().copyDefaults(true); - options().copyHeader(true); - boolean success = saved(file); - options().copyDefaults(false); - options().copyHeader(false); - return success; - } - - private void loadFile() { - load(); - save(); - } - public void send(CommandSender sender, String msg) { if (!Settings.messagesLanguage.equalsIgnoreCase(singleton.lang)) singleton.reloadMessages(); From b458547a176e90a28eee17ea7a95e70880c65864 Mon Sep 17 00:00:00 2001 From: "Gabriele C." Date: Tue, 15 Sep 2015 00:21:04 +0200 Subject: [PATCH 061/115] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7b5562aa0..ce943cac7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ fr.xephi authme - 5.0-SNAPSHOT + 5.1-SNAPSHOT AuthMeReloaded Authentication plugin for CraftBukkit/Spigot! From 232f332be250cc1b32083048ef33b0401db4d840 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 13:43:39 +0700 Subject: [PATCH 062/115] revert, bad file encoding. --- src/main/resources/messages/messages_zhhk.yml | 115 +++++++++--------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/src/main/resources/messages/messages_zhhk.yml b/src/main/resources/messages/messages_zhhk.yml index db8b158b2..b20ec71a0 100644 --- a/src/main/resources/messages/messages_zhhk.yml +++ b/src/main/resources/messages/messages_zhhk.yml @@ -1,60 +1,59 @@ # Translator: uSoc_lifehome (http://lifeho.me) # -# Translator: WaterXCubic ����� # # -------------------------------------------- # -unknown_user: '&8[&6�Τ�t��&8] &f�Τ��ƨä��s�b���Ʈw���C' -unsafe_spawn: '&8[&6�Τ�t��&8] &f�A���n�X��m���w���A�{�b�N�ǰe�A�쭫���I�C' -not_logged_in: '&8[&6�Τ�t��&8] &c�A�٨S���n�J �I' -reg_voluntarily: '&8[&6�Τ�t��&8] &f�A�i�H�ϥγo�Ӫ����O�ӵ��U�G �m /register <�K�X> <���бK�X> �n' -usage_log: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /login <�K�X> �n' -wrong_pwd: '&8[&6�Τ�t��&8] &c�A��J�F���~���K�X�C' -unregistered: '&8[&6�Τ�t��&8] &c�A�w���\�����|�����U�O���C' -reg_disabled: '&8[&6�Τ�t��&8] &c�����A���w����s���a���U�C' -valid_session: '&8[&6�Τ�t��&8] &b�� �I �ڰO�o�A�A�w��^�ӡ�' -login: '&8[&6�Τ�t��&8] &c�A���\���n�J�F�C' -password_error_nick: '&f�A���i�H�ϥΧA���W�r���K�X!' -password_error_unsafe: '&f�A���i�H�ϥΤ��w�����K�X' -vb_nonActiv: '&8[&6�Τ�t��&8] &f�A���b���٨S���g�L�q�l���� �I' -user_regged: '&8[&6�Τ�t��&8] &c����W�w�g���U�L�F�C' -usage_reg: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /register <�K�X> <���бK�X> �n' -max_reg: '&8[&6�Τ�t��&8] &f�A��IP�a�}�w�F����U�ƤW���C' -no_perm: '&8[&6�Τ�t��&8] &b�A�i�H�� CraftingHK ���a�ʬ줤�d�ݻ������C' -error: '&8[&6�Τ�t��&8] &f�o�Ϳ��~�A�лP�޲z���p���C' -login_msg: '&8[&6�Τ�t��&8] &c�Шϥγo�ӫ��O�ӵn�J�G �m /login <�K�X> �n' -reg_msg: '&8[&6�Τ�t��&8] &c�Шϥγo�Ӫ����O�ӵ��U�G �m /register <�K�X> <���бK�X> �n' -reg_email_msg: '&8[&6�Τ�t��&8] &c�Шϥγo�Ӫ����O�ӵ��U�G �m /register <�q�l> <���йq�l> �n' -usage_unreg: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /unregister <�K�X> �n' -pwd_changed: '&8[&6�Τ�t��&8] &c�A���\���󴫤F�A���K�X �I' -user_unknown: '&8[&6�Τ�t��&8] &c����W�S���w�n�O��ơC' -password_error: '&8[&6�Τ�t��&8] &f�K�X���ŦX�C' -invalid_session: '&8[&6�Τ�t��&8] &f�n�J���q��Ƥw�l�a�A�е��ݵn�J���q�����C' -reg_only: '&8[&6�Τ�t��&8] &f���w���U�|���A���� https://www.example.com/ ���U�C' -logged_in: '&8[&6�Τ�t��&8] &c�A�w�g�n�J�L�F�C' -logout: '&8[&6�Τ�t��&8] &b�A���\���n�X�F�C' -same_nick: '&8[&6�Τ�t��&8] &f�P�W���a�w�b�C���C' -registered: '&8[&6�Τ�t��&8] &b�A���\�����U�F�C' -pass_len: '&8[&6�Τ�t��&8] &f�A���K�X�ä��ŦX�W�w���סC' -reload: '&8[&6�Τ�t��&8] &b�n�J�t�γ]�w�θ�Ʈw���s���J�����C' -timeout: '&8[&6�Τ�t��&8] &f�n�J�O�ɡC' -usage_changepassword: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /changepassword <�±K�X> <�s�K�X> �n' -name_len: '&8[&6�Τ�t��&8] &c�A����W���ŦX�W�w���סC' -regex: '&8[&6�Τ�t��&8] &c�A����W�t�����e�\���r�šC�H�U����\���r���G REG_EX' -add_email: '&8[&6�Τ�t��&8] &b���A���b��ߧY�K�[�q�l�a�}�G �m /email add <�q�l�a�}> <���йq�l�a�}> �n' -recovery_email: '&8[&6�Τ�t��&8] &c�ѰO�K�X �H �Шϥγo�Ӫ����O�ӧ�s�K�X�G �m /email recovery <�q�l�a�}> �n' -usage_captcha: '&8[&6�Τ�t��&8] &c�Ϊk�G �m /captcha �n' -wrong_captcha: '&8[&6�Τ�t��&8] &c�A��J�F���~�����ҽX�A�Шϥ� �m /captcha <���ҽX> �n �A����J�C' -valid_captcha: '&8[&6�Τ�t��&8] &c�A�ҿ�J�����ҽX�O�L�Ī� �I' -kick_forvip: '&c�]����VIP���a�n�J�F���A���C' -kick_fullserver: '&c��p�I �]�����A�����H�F�A�ҥH�A�ثe����n�J���A���C' -usage_email_add: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /email add <�q�l> <���йq�l> �n' -usage_email_change: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /email change <�¹q�l> <�s�q�l> �n' -usage_email_recovery: '&8[&6�Τ�t��&8] &f�Ϊk�G �m /email recovery <�q�l> �n' -new_email_invalid: '&8[&6�Τ�t��&8] �A�Ҷ�g���s�q�l�a�}����T�C' -old_email_invalid: '&8[&6�Τ�t��&8] �A�Ҷ�g���¹q�l�a�}����T�C' -email_invalid: '&8[&6�Τ�t��&8] �A�Ҷ�g���q�l�a�}����T�C' -email_added: '&8[&6�Τ�t��&8] �w�[�J�A���q�l�a�}�O���C' -email_confirm: '&8[&6�Τ�t��&8] �Э��п�J�A���q�l�a�}�C' -email_changed: '&8[&6�Τ�t��&8] �A���q�l�a�}�O���w���C' -email_send: '&8[&6�Τ�t��&8] �ѰO�K�X�H��w�H�X�A�Ьd���C' -country_banned: '&8[&6�Τ�t��&8] �����A���w�����A����a���ѹC���A�ȡC' -antibot_auto_enabled: '&8[&6�Τ�t��&8] �������H�{�Ǥw�]���{�ɤj�q���M�`���s�u�ӱҥΡC' -antibot_auto_disabled: '&8[&6�Τ�t��&8] �������H�{���ˬd�줣���`�s���Ƥw��֡A�é� %m �����ᰱ��B�@�C' +unknown_user: '&8[&6用戶系統&8] &f用戶資料並ä¸å­˜åœ¨æ–¼è³‡æ–™åº«ä¸­ã€‚' +unsafe_spawn: '&8[&6用戶系統&8] &f你的登出ä½ç½®ä¸å®‰å…¨ï¼Œç¾åœ¨å°‡å‚³é€ä½ åˆ°é‡ç”Ÿé»žã€‚' +not_logged_in: '&8[&6用戶系統&8] &c你還沒有登入 ï¼' +reg_voluntarily: '&8[&6用戶系統&8] &fä½ å¯ä»¥ä½¿ç”¨é€™å€‹çš„指令來註冊: 《 /register <密碼> <é‡è¦†å¯†ç¢¼> 》' +usage_log: '&8[&6用戶系統&8] &c用法: 《 /login <密碼> 》' +wrong_pwd: '&8[&6用戶系統&8] &c你輸入了錯誤的密碼。' +unregistered: '&8[&6用戶系統&8] &cä½ å·²æˆåŠŸå–消會員註冊記錄。' +reg_disabled: '&8[&6用戶系統&8] &c本伺æœå™¨å·²åœæ­¢æ–°çŽ©å®¶è¨»å†Šã€‚' +valid_session: '&8[&6用戶系統&8] &bå—¨ ï¼ æˆ‘è¨˜å¾—ä½ ï¼Œæ­¡è¿Žå›žä¾†ï½ž' +login: '&8[&6用戶系統&8] &cä½ æˆåŠŸçš„登入了。' +password_error_nick: '&fYou can''t use your name as password' +password_error_unsafe: '&fYou can''t use unsafe passwords' +vb_nonActiv: '&8[&6用戶系統&8] &f你的帳戶還沒有經éŽé›»éƒµé©—è­‰ ï¼' +user_regged: '&8[&6用戶系統&8] &c此用戶å已經註冊éŽäº†ã€‚' +usage_reg: '&8[&6用戶系統&8] &c用法: 《 /register <密碼> <é‡è¦†å¯†ç¢¼> 》' +max_reg: '&8[&6用戶系統&8] &fä½ çš„IP地å€å·²é”到註冊數上é™ã€‚' +no_perm: '&8[&6用戶系統&8] &bä½ å¯ä»¥åˆ° CraftingHK 玩家百科中查看說明文件。' +error: '&8[&6用戶系統&8] &f發生錯誤,請與管ç†å“¡è¯çµ¡ã€‚' +login_msg: '&8[&6用戶系統&8] &c請使用這個指令來登入: 《 /login <密碼> 》' +reg_msg: '&8[&6用戶系統&8] &c請使用這個的指令來註冊: 《 /register <密碼> <é‡è¦†å¯†ç¢¼> 》' +reg_email_msg: '&8[&6用戶系統&8] &c請使用這個的指令來註冊: 《 /register <電郵> <é‡è¦†é›»éƒµ> 》' +usage_unreg: '&8[&6用戶系統&8] &c用法: 《 /unregister <密碼> 》' +pwd_changed: '&8[&6用戶系統&8] &cä½ æˆåŠŸçš„æ›´æ›äº†ä½ çš„密碼 ï¼' +user_unknown: '&8[&6用戶系統&8] &c此用戶å沒有已登記資料。' +password_error: '&8[&6用戶系統&8] &f密碼ä¸ç¬¦åˆã€‚' +invalid_session: '&8[&6用戶系統&8] &f登入階段資料已æ壞,請等待登入階段çµæŸã€‚' +reg_only: '&8[&6用戶系統&8] &fé™å·²è¨»å†Šæœƒå“¡ï¼Œè«‹å…ˆåˆ° https://www.example.com/ 註冊。' +logged_in: '&8[&6用戶系統&8] &c你已經登入éŽäº†ã€‚' +logout: '&8[&6用戶系統&8] &bä½ æˆåŠŸçš„登出了。' +same_nick: '&8[&6用戶系統&8] &fåŒå玩家已在éŠçŽ©ã€‚' +registered: '&8[&6用戶系統&8] &bä½ æˆåŠŸçš„註冊了。' +pass_len: '&8[&6用戶系統&8] &f你的密碼並ä¸ç¬¦åˆè¦å®šé•·åº¦ã€‚' +reload: '&8[&6用戶系統&8] &b登入系統設定åŠè³‡æ–™åº«é‡æ–°è¼‰å…¥å®Œç•¢ã€‚' +timeout: '&8[&6用戶系統&8] &f登入逾時。' +usage_changepassword: '&8[&6用戶系統&8] &f用法: 《 /changepassword <舊密碼> <新密碼> 》' +name_len: '&8[&6用戶系統&8] &c你的用戶åä¸ç¬¦åˆè¦å®šé•·åº¦ã€‚' +regex: '&8[&6用戶系統&8] &c你的用戶åå«æœ‰ä¸å®¹è¨±ä¹‹å­—符。以下為准許之字æ¯ï¼š REG_EX' +add_email: '&8[&6用戶系統&8] &b請為你的帳戶立å³æ·»åŠ é›»éƒµåœ°å€ï¼š 《 /email add <電郵地å€> <é‡è¦†é›»éƒµåœ°å€> 》' +recovery_email: '&8[&6用戶系統&8] &c忘記密碼 ? 請使用這個的指令來更新密碼: 《 /email recovery <電郵地å€> 》' +usage_captcha: '&8[&6用戶系統&8] &c用法: 《 /captcha <驗證碼> 》' +wrong_captcha: '&8[&6用戶系統&8] &c你輸入了錯誤的驗證碼,請使用 《 /captcha <驗證碼> 》 å†æ¬¡è¼¸å…¥ã€‚' +valid_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼是無效的 ï¼' +kick_forvip: '&c因為有VIP玩家登入了伺æœå™¨ã€‚' +kick_fullserver: '&cæŠ±æ­‰ï¼ å› ç‚ºä¼ºæœå™¨æ»¿äººäº†ï¼Œæ‰€ä»¥ä½ ç›®å‰æœªèƒ½ç™»å…¥ä¼ºæœå™¨ã€‚' +usage_email_add: '&8[&6用戶系統&8] &f用法: 《 /email add <電郵> <é‡è¦†é›»éƒµ> 》' +usage_email_change: '&8[&6用戶系統&8] &f用法: 《 /email change <舊電郵> <新電郵> 》' +usage_email_recovery: '&8[&6用戶系統&8] &f用法: 《 /email recovery <電郵> 》' +new_email_invalid: '&8[&6用戶系統&8] 你所填寫的新電郵地å€ä¸¦ä¸æ­£ç¢ºã€‚' +old_email_invalid: '&8[&6用戶系統&8] 你所填寫的舊電郵地å€ä¸¦ä¸æ­£ç¢ºã€‚' +email_invalid: '&8[&6用戶系統&8] 你所填寫的電郵地å€ä¸¦ä¸æ­£ç¢ºã€‚' +email_added: '&8[&6用戶系統&8] 已加入你的電郵地å€è¨˜éŒ„。' +email_confirm: '&8[&6用戶系統&8] è«‹é‡è¦†è¼¸å…¥ä½ çš„電郵地å€ã€‚' +email_changed: '&8[&6用戶系統&8] 你的電郵地å€è¨˜éŒ„已更改。' +email_send: '&8[&6用戶系統&8] 忘記密碼信件已寄出,請查收。' +country_banned: '&8[&6用戶系統&8] 本伺æœå™¨å·²åœæ­¢å°ä½ çš„國家æä¾›éŠæˆ²æœå‹™ã€‚' +antibot_auto_enabled: '&8[&6用戶系統&8] 防止機械人程åºå·²å› æ‡‰ç¾æ™‚大é‡ä¸å°‹å¸¸çš„連線而啟用。' +antibot_auto_disabled: '&8[&6用戶系統&8] 防止機械人程åºæª¢æŸ¥åˆ°ä¸æ­£å¸¸é€£æŽ¥æ•¸å·²æ¸›å°‘,並於 %m 分é˜å¾Œåœæ­¢é‹ä½œã€‚' From e1b2a1852cc0302bd155755e4a3054dceba2b33d Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 14:33:23 +0700 Subject: [PATCH 063/115] update ConsoleLogger --- .../java/fr/xephi/authme/ConsoleLogger.java | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index 4305f85d4..a632282a2 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -1,33 +1,27 @@ package fr.xephi.authme; import com.google.common.base.Throwables; +import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.settings.Settings; -import org.bukkit.Bukkit; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; import java.text.DateFormat; -import java.util.Calendar; +import java.util.Date; import java.util.logging.Logger; public class ConsoleLogger { - private static final Logger log = Logger.getLogger("AuthMe"); + private static final Logger log = AuthMe.getInstance().getLogger(); + private static final DateFormat format = DateFormat.getDateTimeInstance(); + public static void info(String message) { if (AuthMe.getInstance().isEnabled()) { log.info("[AuthMe] " + message); if (Settings.useLogging) { - Calendar date = Calendar.getInstance(); - final String actually = "[" + DateFormat.getDateInstance().format(date.getTime()) + ", " + date.get(Calendar.HOUR_OF_DAY) + ":" + date.get(Calendar.MINUTE) + ":" + date.get(Calendar.SECOND) + "] " + message; - Bukkit.getScheduler().runTaskAsynchronously(AuthMe.getInstance(), new Runnable() { - @Override - public void run() { - writeLog(actually); - } - }); + writeLog("[" + format.format(new Date()) + "] " + message); } } } @@ -36,31 +30,21 @@ public class ConsoleLogger { if (AuthMe.getInstance().isEnabled()) { log.warning("[AuthMe] " + message); if (Settings.useLogging) { - Calendar date = Calendar.getInstance(); - final String actually = "[" + DateFormat.getDateInstance().format(date.getTime()) + ", " + date.get(Calendar.HOUR_OF_DAY) + ":" + date.get(Calendar.MINUTE) + ":" + date.get(Calendar.SECOND) + "] ERROR : " + message; - Bukkit.getScheduler().runTaskAsynchronously(AuthMe.getInstance(), new Runnable() { - @Override - public void run() { - writeLog(actually); - } - }); + writeLog("[" + format.format(new Date()) + "] ERROR: " + message); } } } - public static void writeLog(String string) { + public static void writeLog(String message) { try { - FileWriter fw = new FileWriter(AuthMe.getInstance().getDataFolder() + File.separator + "authme.log", true); - BufferedWriter w = new BufferedWriter(fw); - w.write(string); - w.newLine(); - w.close(); - } catch (IOException e) { - e.printStackTrace(); + Files.write(Settings.LOG_FILE.toPath(), (message + NewAPI.newline).getBytes(), + StandardOpenOption.APPEND, + StandardOpenOption.CREATE); + } catch (IOException ignored) { } } - public static void writeStackTrace(Exception ex){ + public static void writeStackTrace(Exception ex) { writeLog(Throwables.getStackTraceAsString(ex)); } } From 91d6ead4665ab6d85c6bd68b8ee5ae52aff20622 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 14:34:07 +0700 Subject: [PATCH 064/115] update ConsoleLogger --- src/main/java/fr/xephi/authme/settings/Settings.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 7b6758f45..d57a82cf5 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -20,9 +20,11 @@ public final class Settings extends YamlConfiguration { public static Boolean antiBotInAction = false; public static final File PLUGIN_FOLDER = AuthMe.getInstance().getDataFolder(); + public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules"); public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); public static final File AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db"); public static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); + public static final File LOG_FILE = new File(PLUGIN_FOLDER, "authme.log"); public static File messageFile; public static List allowCommands; From 3620b712b76af7abad87adc5d9cfd00b4a93b5dc Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 14:38:55 +0700 Subject: [PATCH 065/115] improve DatabaseCalls, --- src/main/java/fr/xephi/authme/AuthMe.java | 55 +-- .../xephi/authme/cache/auth/PlayerCache.java | 2 +- .../authme/datasource/CacheDataSource.java | 19 +- .../xephi/authme/datasource/DataSource.java | 2 +- .../authme/datasource/DatabaseCalls.java | 345 +++--------------- .../fr/xephi/authme/datasource/MySQL.java | 13 +- .../fr/xephi/authme/process/Management.java | 6 +- 7 files changed, 109 insertions(+), 333 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 0a1e35790..6f2bd2fdb 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -53,13 +53,14 @@ import java.util.zip.GZIPInputStream; public class AuthMe extends JavaPlugin { - private final Server server = getServer(); - private static Logger authmeLogger = Logger.getLogger("AuthMe"); private static AuthMe authme; + + private final Server server = getServer(); + private final Logger authmeLogger = Logger.getLogger("AuthMe"); public Management management; public NewAPI api; private Utils utils = Utils.getInstance(); - public SendMailSSL mail = null; + public SendMailSSL mail; private Settings settings; private Messages m; public DataManager dataManager; @@ -70,8 +71,8 @@ public class AuthMe extends JavaPlugin { public Permission permission; public Essentials ess; public Location essentialsSpawn; - public MultiverseCore multiverse = null; - public LookupService lookupService = null; + public MultiverseCore multiverse; + public LookupService lookupService; public CitizensCommunicator citizens; public boolean isCitizensActive = false; public boolean CombatTag = false; @@ -82,7 +83,6 @@ public class AuthMe extends JavaPlugin { public ConcurrentHashMap captcha = new ConcurrentHashMap<>(); public ConcurrentHashMap cap = new ConcurrentHashMap<>(); public ConcurrentHashMap realIp = new ConcurrentHashMap<>(); - protected static String vgUrl = "http://monitor-1.verygames.net/api/?action=ipclean-real-ip&out=raw&ip=%IP%&port=%PORT%"; public static AuthMe getInstance() { return authme; @@ -131,14 +131,6 @@ public class AuthMe extends JavaPlugin { // Setup otherAccounts file otherAccounts = OtherAccounts.getInstance(); - // Configuration Security Warnings - if (!Settings.isForceSingleSessionEnabled) { - ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); - } - if (Settings.getSessionTimeout == 0 && Settings.isSessionsEnabled) { - ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!"); - } - // Setup messages m = Messages.getInstance(); @@ -148,8 +140,9 @@ public class AuthMe extends JavaPlugin { Metrics metrics = new Metrics(this); metrics.start(); ConsoleLogger.info("Metrics started successfully!"); - } catch (IOException e) { + } catch (Exception e) { // Failed to submit the metrics data + ConsoleLogger.writeStackTrace(e); ConsoleLogger.showError("Can't start Metrics! The plugin will work anyway..."); } @@ -258,8 +251,8 @@ public class AuthMe extends JavaPlugin { // Reload support hook if (Settings.reloadSupport) { - int playersOnline = Utils.getOnlinePlayers().size(); if (database != null) { + int playersOnline = Utils.getOnlinePlayers().size(); if (playersOnline < 1) { database.purgeLogged(); } else { @@ -281,15 +274,15 @@ public class AuthMe extends JavaPlugin { pm.registerEvents(new AuthMeServerListener(this), this); // Register commands - this.getCommand("authme").setExecutor(new AdminCommand(this)); - this.getCommand("register").setExecutor(new RegisterCommand(this)); - this.getCommand("login").setExecutor(new LoginCommand(this)); - this.getCommand("changepassword").setExecutor(new ChangePasswordCommand(this)); - this.getCommand("logout").setExecutor(new LogoutCommand(this)); - this.getCommand("unregister").setExecutor(new UnregisterCommand(this)); - this.getCommand("email").setExecutor(new EmailCommand(this)); - this.getCommand("captcha").setExecutor(new CaptchaCommand(this)); - this.getCommand("converter").setExecutor(new ConverterCommand(this)); + getCommand("authme").setExecutor(new AdminCommand(this)); + getCommand("register").setExecutor(new RegisterCommand(this)); + getCommand("login").setExecutor(new LoginCommand(this)); + getCommand("changepassword").setExecutor(new ChangePasswordCommand(this)); + getCommand("logout").setExecutor(new LogoutCommand(this)); + getCommand("unregister").setExecutor(new UnregisterCommand(this)); + getCommand("email").setExecutor(new EmailCommand(this)); + getCommand("captcha").setExecutor(new CaptchaCommand(this)); + getCommand("converter").setExecutor(new ConverterCommand(this)); // Purge on start if enabled autoPurge(); @@ -297,6 +290,14 @@ public class AuthMe extends JavaPlugin { // Start Email recall task if needed recallEmail(); + // Configuration Security Warnings + if (!Settings.isForceSingleSessionEnabled) { + ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); + } + if (Settings.getSessionTimeout == 0 && Settings.isSessionsEnabled) { + ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!"); + } + // Sponsor messages ConsoleLogger.info("AuthMe hooks perfectly with the VERYGAMES server hosting!"); ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt."); @@ -331,6 +332,8 @@ public class AuthMe extends JavaPlugin { // Disabled correctly ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!"); + + authme = null; } // Stop/unload the server/plugin as defined in the configuration @@ -789,7 +792,7 @@ public class AuthMe extends JavaPlugin { @Deprecated public String getVeryGamesIP(Player player) { String realIP = player.getAddress().getAddress().getHostAddress(); - String sUrl = vgUrl; + String sUrl = "http://monitor-1.verygames.net/api/?action=ipclean-real-ip&out=raw&ip=%IP%&port=%PORT%"; sUrl = sUrl.replace("%IP%", player.getAddress().getAddress().getHostAddress()).replace("%PORT%", "" + player.getAddress().getPort()); try { URL url = new URL(sUrl); diff --git a/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java b/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java index 8f39c0d36..491c33a4f 100644 --- a/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java +++ b/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java @@ -8,7 +8,7 @@ public class PlayerCache { private ConcurrentHashMap cache; private PlayerCache() { - cache = new ConcurrentHashMap(); + cache = new ConcurrentHashMap<>(); } public void addPlayer(PlayerAuth auth) { diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 0b6dfe17d..f9ba8898a 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -11,21 +11,24 @@ import java.util.concurrent.ConcurrentHashMap; public class CacheDataSource implements DataSource { - private DataSource source; - public AuthMe plugin; + private final DataSource source; private ConcurrentHashMap cache = new ConcurrentHashMap<>(); - public CacheDataSource(AuthMe plugin, DataSource source) { - this.plugin = plugin; - this.source = source; + public CacheDataSource(AuthMe plugin, DataSource src) { + this.source = src; /* * We need to load all players in cache ... It will took more time to * load the server, but it will be much easier to check for an * isAuthAvailable ! */ - for (PlayerAuth auth : source.getAllAuths()) { - cache.put(auth.getNickname().toLowerCase(), auth); - } + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ + @Override + public void run() { + for (PlayerAuth auth : source.getAllAuths()) { + cache.put(auth.getNickname().toLowerCase(), auth); + } + } + }); } @Override diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index 4592ec569..b89f13aaf 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -6,7 +6,7 @@ import java.util.List; public interface DataSource { - public enum DataSourceType { + enum DataSourceType { MYSQL, FILE, SQLITE, diff --git a/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java b/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java index 1b3e0993e..6b84c7d73 100644 --- a/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java +++ b/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java @@ -1,67 +1,42 @@ package fr.xephi.authme.datasource; +import fr.xephi.authme.cache.auth.PlayerAuth; + import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import fr.xephi.authme.cache.auth.PlayerAuth; +import java.util.concurrent.*; public class DatabaseCalls implements DataSource { private DataSource database; + private final ExecutorService exec; public DatabaseCalls(DataSource database) { this.database = database; + this.exec = Executors.newCachedThreadPool(); } @Override public synchronized boolean isAuthAvailable(final String user) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.isAuthAvailable(user); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized PlayerAuth getAuth(final String user) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - PlayerAuth result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public PlayerAuth call() throws Exception { return database.getAuth(user); } }).get(); - } catch (InterruptedException e1) { - return null; - } catch (ExecutionException e1) { - return null; - } finally { - executor.shutdown(); - } - try { - return result; } catch (Exception e) { return null; } @@ -69,332 +44,183 @@ public class DatabaseCalls implements DataSource { @Override public synchronized boolean saveAuth(final PlayerAuth auth) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.saveAuth(auth); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized boolean updateSession(final PlayerAuth auth) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.updateSession(auth); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized boolean updatePassword(final PlayerAuth auth) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.updatePassword(auth); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized int purgeDatabase(final long until) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Integer result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Integer call() throws Exception { return database.purgeDatabase(until); } }).get(); - } catch (InterruptedException e1) { - return 0; - } catch (ExecutionException e1) { - return 0; - } finally { - executor.shutdown(); - } - try { - return result.intValue(); } catch (Exception e) { - return (0); + return -1; } } @Override public synchronized List autoPurgeDatabase(final long until) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - List result; try { - result = executor.submit(new Callable>() { - + return exec.submit(new Callable>() { public List call() throws Exception { return database.autoPurgeDatabase(until); } }).get(); - } catch (InterruptedException e1) { - return new ArrayList(); - } catch (ExecutionException e1) { - return new ArrayList(); - } finally { - executor.shutdown(); - } - try { - return result; } catch (Exception e) { - return (new ArrayList()); + return new ArrayList<>(); } } @Override public synchronized boolean removeAuth(final String user) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.removeAuth(user); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized boolean updateQuitLoc(final PlayerAuth auth) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.updateQuitLoc(auth); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized int getIps(final String ip) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Integer result; try { - result = executor.submit(new Callable() { + return exec.submit(new Callable() { public Integer call() throws Exception { return database.getIps(ip); } }).get(); - } catch (InterruptedException e1) { - return 0; - } catch (ExecutionException e1) { - return 0; - } finally { - executor.shutdown(); - } - try { - return result.intValue(); } catch (Exception e) { - return (0); + return -1; } } @Override public synchronized List getAllAuthsByName(final PlayerAuth auth) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - List result; try { - result = executor.submit(new Callable>() { - + return exec.submit(new Callable>() { public List call() throws Exception { return database.getAllAuthsByName(auth); } }).get(); - } catch (InterruptedException e1) { - return new ArrayList(); - } catch (ExecutionException e1) { - return new ArrayList(); - } finally { - executor.shutdown(); - } - try { - return result; } catch (Exception e) { - return (new ArrayList()); + return new ArrayList<>(); } } @Override public synchronized List getAllAuthsByIp(final String ip) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - List result; try { - result = executor.submit(new Callable>() { - + return exec.submit(new Callable>() { public List call() throws Exception { return database.getAllAuthsByIp(ip); } }).get(); - } catch (InterruptedException e1) { - return new ArrayList(); - } catch (ExecutionException e1) { - return new ArrayList(); - } finally { - executor.shutdown(); - } - try { - return result; } catch (Exception e) { - return (new ArrayList()); + return new ArrayList<>(); } } @Override public synchronized List getAllAuthsByEmail(final String email) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - List result; try { - result = executor.submit(new Callable>() { - + return exec.submit(new Callable>() { public List call() throws Exception { return database.getAllAuthsByEmail(email); } }).get(); - } catch (InterruptedException e1) { - return new ArrayList(); - } catch (ExecutionException e1) { - return new ArrayList(); - } finally { - executor.shutdown(); - } - try { - return result; } catch (Exception e) { - return (new ArrayList()); + return new ArrayList<>(); } } @Override public synchronized boolean updateEmail(final PlayerAuth auth) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.updateEmail(auth); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized boolean updateSalt(final PlayerAuth auth) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.updateSalt(auth); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized void close() { - database.close(); + try { + exec.shutdown(); + exec.awaitTermination(10, TimeUnit.SECONDS); + database.close(); + } catch (Exception e) { + e.printStackTrace(); + } } @Override @@ -405,8 +231,6 @@ public class DatabaseCalls implements DataSource { @Override public synchronized void purgeBanned(final List banned) { new Thread(new Runnable() { - - @Override public synchronized void run() { database.purgeBanned(banned); } @@ -420,139 +244,90 @@ public class DatabaseCalls implements DataSource { @Override public synchronized boolean isLogged(final String user) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Boolean result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Boolean call() throws Exception { return database.isLogged(user); } }).get(); - } catch (InterruptedException e1) { - return false; - } catch (ExecutionException e1) { - return false; - } finally { - executor.shutdown(); - } - try { - return result.booleanValue(); } catch (Exception e) { - return (false); + return false; } } @Override public synchronized void setLogged(final String user) { - new Thread(new Runnable() { - - @Override + exec.execute(new Runnable() { public synchronized void run() { database.setLogged(user); } - }).start(); + }); } @Override public synchronized void setUnlogged(final String user) { - new Thread(new Runnable() { - - @Override + exec.execute(new Runnable() { public synchronized void run() { database.setUnlogged(user); } - }).start(); + }); } @Override public synchronized void purgeLogged() { - new Thread(new Runnable() { - - @Override + exec.execute(new Runnable() { public synchronized void run() { database.purgeLogged(); } - }).start(); + }); } @Override public synchronized int getAccountsRegistered() { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Integer result; try { - result = executor.submit(new Callable() { - + return exec.submit(new Callable() { public Integer call() throws Exception { return database.getAccountsRegistered(); } }).get(); - } catch (InterruptedException e1) { - return 0; - } catch (ExecutionException e1) { - return 0; - } finally { - executor.shutdown(); - } - try { - return result.intValue(); } catch (Exception e) { - return (0); + return -1; } } @Override - public synchronized void updateName(final String oldone, - final String newone) { - new Thread(new Runnable() { - - @Override + public synchronized void updateName(final String oldone, final String newone) { + exec.execute(new Runnable() { public synchronized void run() { database.updateName(oldone, newone); } - }).start(); + }); } @Override public synchronized List getAllAuths() { - ExecutorService executor = Executors.newSingleThreadExecutor(); - List result; try { - result = executor.submit(new Callable>() { - + return exec.submit(new Callable>() { public List call() throws Exception { return database.getAllAuths(); } }).get(); - } catch (InterruptedException e1) { - return (new ArrayList()); - } catch (ExecutionException e1) { - return (new ArrayList()); - } finally { - executor.shutdown(); + } catch (Exception e) { + return new ArrayList<>(); } - return result; } @Override public List getLoggedPlayers() { - ExecutorService executor = Executors.newSingleThreadExecutor(); - List result; try { - result = executor.submit(new Callable>() { - + return exec.submit(new Callable>() { public List call() throws Exception { return database.getLoggedPlayers(); } }).get(); - } catch (InterruptedException e1) { - return (new ArrayList()); - } catch (ExecutionException e1) { - return (new ArrayList()); - } finally { - executor.shutdown(); + } catch (Exception e) { + return new ArrayList<>(); } - return result; } } diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index ee58973fe..41adbeb2c 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -235,14 +235,13 @@ public class MySQL implements DataSource { } } - @SuppressWarnings("resource") @Override public synchronized PlayerAuth getAuth(String user) { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; PlayerAuth pAuth = null; - int id = -1; + int id; try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + columnName + ")=LOWER(?);"); @@ -1019,7 +1018,7 @@ public class MySQL implements DataSource { @Override public List getAllAuths() { - List auths = new ArrayList(); + List auths = new ArrayList<>(); Connection con = null; PreparedStatement pst = null; ResultSet rs = null; @@ -1028,7 +1027,7 @@ public class MySQL implements DataSource { pst = con.prepareStatement("SELECT * FROM " + tableName + ";"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth = null; + PlayerAuth pAuth; int id = rs.getInt(columnID); if (rs.getString(columnIp).isEmpty() && rs.getString(columnIp) != null) { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "192.168.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); @@ -1052,11 +1051,9 @@ public class MySQL implements DataSource { byte[] bytes = blob.getBytes(1, (int) blob.length()); pAuth.setHash(new String(bytes)); } - if (rsid != null) - rsid.close(); + rsid.close(); } - if (pAuth != null) - auths.add(pAuth); + auths.add(pAuth); } } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java index 479790e58..209e12a9a 100644 --- a/src/main/java/fr/xephi/authme/process/Management.java +++ b/src/main/java/fr/xephi/authme/process/Management.java @@ -30,8 +30,7 @@ public class Management { this.pm = plugin.getServer().getPluginManager(); } - public void performLogin(final Player player, final String password, - final boolean forceLogin) { + public void performLogin(final Player player, final String password, final boolean forceLogin) { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override @@ -41,8 +40,7 @@ public class Management { }); } - public void performRegister(final Player player, final String password, - final String email) { + public void performRegister(final Player player, final String password, final String email) { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override From 3996c8cfcaf905669cafbc875963bd817faad071 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 15:03:00 +0700 Subject: [PATCH 066/115] this should not cause lag anymore if database cache is enabled. --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- .../java/fr/xephi/authme/datasource/CacheDataSource.java | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 6f2bd2fdb..d1b48e61f 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -56,7 +56,7 @@ public class AuthMe extends JavaPlugin { private static AuthMe authme; private final Server server = getServer(); - private final Logger authmeLogger = Logger.getLogger("AuthMe"); + private final Logger authmeLogger = getLogger(); public Management management; public NewAPI api; private Utils utils = Utils.getInstance(); diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index f9ba8898a..a42c9ddf5 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -41,12 +41,8 @@ public class CacheDataSource implements DataSource { user = user.toLowerCase(); if (cache.containsKey(user)) { return cache.get(user); - } else { - PlayerAuth auth = source.getAuth(user); - if (auth != null) - cache.put(user, auth); - return auth; } + return null; } @Override From f975fefd4a23e5e8f3c8bb377fa2916e1b01f682 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 15:39:45 +0700 Subject: [PATCH 067/115] run saveAuth async in CacheDataSource --- .../authme/datasource/CacheDataSource.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index a42c9ddf5..d4b0772cd 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -12,16 +12,18 @@ import java.util.concurrent.ConcurrentHashMap; public class CacheDataSource implements DataSource { private final DataSource source; + private final AuthMe plugin; private ConcurrentHashMap cache = new ConcurrentHashMap<>(); - public CacheDataSource(AuthMe plugin, DataSource src) { + public CacheDataSource(AuthMe pl, DataSource src) { + this.plugin = pl; this.source = src; /* * We need to load all players in cache ... It will took more time to * load the server, but it will be much easier to check for an * isAuthAvailable ! */ - plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ + pl.getServer().getScheduler().runTaskAsynchronously(pl, new Runnable() { @Override public void run() { for (PlayerAuth auth : source.getAllAuths()) { @@ -46,12 +48,17 @@ public class CacheDataSource implements DataSource { } @Override - public synchronized boolean saveAuth(PlayerAuth auth) { - if (source.saveAuth(auth)) { - cache.put(auth.getNickname(), auth); - return true; - } - return false; + public synchronized boolean saveAuth(final PlayerAuth auth) { + cache.put(auth.getNickname(), auth); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { + @Override + public void run() { + if (!source.saveAuth(auth)) { + cache.remove(auth.getNickname()); + } + } + }); + return true; } @Override From c82aaa303d55c8cebb976d8a0427826919f580db Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 15:40:19 +0700 Subject: [PATCH 068/115] cleanup MySQL code. --- .../fr/xephi/authme/datasource/MySQL.java | 105 ++++++------------ 1 file changed, 34 insertions(+), 71 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 41adbeb2c..289e5dc0f 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -149,7 +149,7 @@ public class MySQL implements DataSource { } private synchronized Connection getConnection() throws SQLException { - Connection con = null; + Connection con; con = ds.getConnection(); return con; } @@ -290,6 +290,7 @@ public class MySQL implements DataSource { public synchronized boolean saveAuth(PlayerAuth auth) { Connection con = null; PreparedStatement pst = null; + ResultSet rs = null; try { con = getConnection(); if ((columnSalt == null || columnSalt.isEmpty()) || (auth.getSalt() == null || auth.getSalt().isEmpty())) { @@ -322,13 +323,11 @@ public class MySQL implements DataSource { } } if (Settings.getPasswordHash == HashAlgorithm.PHPBB) { - int id; - ResultSet rs = null; PreparedStatement pst2 = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnName + "=?;"); pst2.setString(1, auth.getNickname()); rs = pst2.executeQuery(); if (rs.next()) { - id = rs.getInt(columnID); + int id = rs.getInt(columnID); // Insert player in phpbb_user_group pst = con.prepareStatement("INSERT INTO " + Settings.getPhpbbPrefix + "user_group (group_id, user_id, group_leader, user_pending) VALUES (?,?,?,?);"); pst.setInt(1, Settings.getPhpbbGroup); @@ -368,16 +367,15 @@ public class MySQL implements DataSource { pst.executeUpdate(); pst.close(); } + rs.close(); pst2.close(); } if (Settings.getPasswordHash == HashAlgorithm.WORDPRESS) { - int id; - ResultSet rs = null; pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnName + "=?;"); pst.setString(1, auth.getNickname()); rs = pst.executeQuery(); if (rs.next()) { - id = rs.getInt(columnID); + int id = rs.getInt(columnID); // First Name pst = con.prepareStatement("INSERT INTO " + Settings.getWordPressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?);"); pst.setInt(1, id); @@ -463,15 +461,14 @@ public class MySQL implements DataSource { pst.executeUpdate(); pst.close(); } + rs.close(); } if (Settings.getPasswordHash == HashAlgorithm.XENFORO) { - int id; - ResultSet rs = null; pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnName + "=?;"); pst.setString(1, auth.getNickname()); rs = pst.executeQuery(); if (rs.next()) { - id = rs.getInt(columnID); + int id = rs.getInt(columnID); // Insert password in the correct table pst = con.prepareStatement("INSERT INTO xf_user_authenticate (user_id, scheme_class, data) VALUES (?,?,?);"); pst.setInt(1, id); @@ -482,13 +479,13 @@ public class MySQL implements DataSource { pst.setBlob(3, blob); pst.executeUpdate(); } - if (rs != null && !rs.isClosed()) - rs.close(); + rs.close(); } } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { + close(rs); close(pst); close(con); } @@ -499,6 +496,7 @@ public class MySQL implements DataSource { public synchronized boolean updatePassword(PlayerAuth auth) { Connection con = null; PreparedStatement pst = null; + ResultSet rs = null; try { con = getConnection(); pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnPassword + "=? WHERE LOWER(" + columnName + ")=?;"); @@ -507,13 +505,11 @@ public class MySQL implements DataSource { pst.executeUpdate(); pst.close(); if (Settings.getPasswordHash == HashAlgorithm.XENFORO) { - int id; - ResultSet rs = null; pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + columnName + ")=?;"); pst.setString(1, auth.getNickname()); rs = pst.executeQuery(); if (rs.next()) { - id = rs.getInt(columnID); + int id = rs.getInt(columnID); // Insert password in the correct table pst = con.prepareStatement("UPDATE xf_user_authenticate SET data=? WHERE " + columnID + "=?;"); byte[] bytes = auth.getHash().getBytes(); @@ -527,13 +523,13 @@ public class MySQL implements DataSource { pst.setInt(2, id); pst.executeUpdate(); } - if (rs != null && !rs.isClosed()) - rs.close(); + rs.close(); } } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); return false; } finally { + close(rs); close(pst); close(con); } @@ -585,7 +581,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List list = new ArrayList(); + List list = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLastLogin + "(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -617,7 +613,7 @@ public class MySQL implements DataSource { con = getConnection(); if (Settings.getPasswordHash == HashAlgorithm.XENFORO) { int id; - ResultSet rs = null; + ResultSet rs; pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + columnName + ")=?;"); pst.setString(1, user); rs = pst.executeQuery(); @@ -753,37 +749,14 @@ public class MySQL implements DataSource { @Override public synchronized void close() { - try { - if (ds != null) - ds.close(); - } catch (Exception e) { - } + if (ds != null) + ds.close(); } - private void close(Statement st) { - if (st != null) { + private void close(AutoCloseable o) { + if (o != null) { try { - st.close(); - } catch (Exception ex) { - ConsoleLogger.showError(ex.getMessage()); - } - } - } - - private void close(ResultSet rs) { - if (rs != null) { - try { - rs.close(); - } catch (Exception ex) { - ConsoleLogger.showError(ex.getMessage()); - } - } - } - - private void close(Connection con) { - if (con != null) { - try { - con.close(); + o.close(); } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); } @@ -795,7 +768,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List countIp = new ArrayList(); + List countIp = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); @@ -807,7 +780,7 @@ public class MySQL implements DataSource { return countIp; } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -820,7 +793,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List countIp = new ArrayList(); + List countIp = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); @@ -832,7 +805,7 @@ public class MySQL implements DataSource { return countIp; } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -845,7 +818,7 @@ public class MySQL implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List countEmail = new ArrayList(); + List countEmail = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnEmail + "=?;"); @@ -857,7 +830,7 @@ public class MySQL implements DataSource { return countEmail; } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -924,12 +897,10 @@ public class MySQL implements DataSource { pst.executeUpdate(); } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override @@ -945,12 +916,10 @@ public class MySQL implements DataSource { pst.executeUpdate(); } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override @@ -965,12 +934,10 @@ public class MySQL implements DataSource { pst.executeUpdate(); } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override @@ -978,7 +945,7 @@ public class MySQL implements DataSource { int result = 0; Connection con = null; PreparedStatement pst = null; - ResultSet rs = null; + ResultSet rs; try { con = getConnection(); pst = con.prepareStatement("SELECT COUNT(*) FROM " + tableName + ";"); @@ -1008,12 +975,10 @@ public class MySQL implements DataSource { pst.executeUpdate(); } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override @@ -1042,7 +1007,7 @@ public class MySQL implements DataSource { } } if (Settings.getPasswordHash == HashAlgorithm.XENFORO) { - ResultSet rsid = null; + ResultSet rsid; pst = con.prepareStatement("SELECT * FROM xf_user_authenticate WHERE " + columnID + "=?;"); pst.setInt(1, id); rsid = pst.executeQuery(); @@ -1068,7 +1033,7 @@ public class MySQL implements DataSource { @Override public List getLoggedPlayers() { - List auths = new ArrayList(); + List auths = new ArrayList<>(); Connection con = null; PreparedStatement pst = null; ResultSet rs = null; @@ -1077,7 +1042,7 @@ public class MySQL implements DataSource { pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth = null; + PlayerAuth pAuth; int id = rs.getInt(columnID); if (rs.getString(columnIp).isEmpty() && rs.getString(columnIp) != null) { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "192.168.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); @@ -1092,7 +1057,7 @@ public class MySQL implements DataSource { } } if (Settings.getPasswordHash == HashAlgorithm.XENFORO) { - ResultSet rsid = null; + ResultSet rsid; pst = con.prepareStatement("SELECT * FROM xf_user_authenticate WHERE " + columnID + "=?;"); pst.setInt(1, id); rsid = pst.executeQuery(); @@ -1101,11 +1066,9 @@ public class MySQL implements DataSource { byte[] bytes = blob.getBytes(1, (int) blob.length()); pAuth.setHash(new String(bytes)); } - if (rsid != null) - rsid.close(); + rsid.close(); } - if (pAuth != null) - auths.add(pAuth); + auths.add(pAuth); } } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); From 6f22aa779b0fbb52052b7dc9209c1e93e4e0ba90 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 16:23:56 +0700 Subject: [PATCH 069/115] sqlite fix, load AuthMe faster. --- src/main/java/fr/xephi/authme/AuthMe.java | 30 ++-- .../authme/datasource/SQLite_HIKARI.java | 162 +++++------------- 2 files changed, 58 insertions(+), 134 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index d1b48e61f..e7fa120d8 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -3,7 +3,6 @@ package fr.xephi.authme; import com.earth2me.essentials.Essentials; import com.maxmind.geoip.LookupService; import com.onarandombox.MultiverseCore.MultiverseCore; -import com.zaxxer.hikari.pool.PoolInitializationException; import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.cache.auth.PlayerAuth; @@ -42,7 +41,6 @@ import org.mcstats.Metrics; import java.io.*; import java.net.URL; import java.net.URLConnection; -import java.sql.SQLException; import java.util.Calendar; import java.util.Collection; import java.util.Date; @@ -216,8 +214,9 @@ public class AuthMe extends JavaPlugin { // Connect to the database and setup tables try { setupDatabase(); - } catch (Exception ex) { - ConsoleLogger.writeStackTrace(ex); + } catch (Exception e) { + ConsoleLogger.writeStackTrace(e); + ConsoleLogger.showError(e.getMessage()); ConsoleLogger.showError("Fatal error occurred during database connection! Authme initialization ABORTED!"); stopOrUnload(); return; @@ -353,9 +352,9 @@ public class AuthMe extends JavaPlugin { } // Initialize and setup the database - public void setupDatabase() throws ClassNotFoundException, PoolInitializationException, SQLException { + public void setupDatabase() throws Exception { // Backend MYSQL - FILE - SQLITE - SQLITEHIKARI - int accounts; + boolean isSQLite = false; switch (Settings.getDataSource) { case FILE: database = new FlatFile(); @@ -365,18 +364,25 @@ public class AuthMe extends JavaPlugin { break; case SQLITE: database = new SQLite(); - accounts = database.getAccountsRegistered(); - if (accounts >= 4000) - ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + accounts + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); + isSQLite = true; break; case SQLITEHIKARI: database = new SQLite_HIKARI(); - accounts = database.getAccountsRegistered(); - if (accounts >= 8000) - ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + accounts + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); + isSQLite = true; break; } + if (isSQLite) { + server.getScheduler().runTaskAsynchronously(this, new Runnable() { + @Override + public void run() { + int accounts = database.getAccountsRegistered(); + if (accounts >= 4000) + ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " + accounts + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); + } + }); + } + if (Settings.isCachingEnabled) { database = new CacheDataSource(this, database); } diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java index de91d2bb4..d0b14026c 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java @@ -1,22 +1,16 @@ package fr.xephi.authme.datasource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; - import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import com.zaxxer.hikari.pool.PoolInitializationException; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.settings.Settings; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + public class SQLite_HIKARI implements DataSource { private String database; @@ -37,7 +31,7 @@ public class SQLite_HIKARI implements DataSource { private String columnLogged; private String columnRealName; - public SQLite_HIKARI() throws ClassNotFoundException, SQLException, PoolInitializationException { + public SQLite_HIKARI() throws ClassNotFoundException, SQLException { this.database = Settings.getMySQLDatabase; this.tableName = Settings.getMySQLTablename; this.columnName = Settings.getMySQLColumnName; @@ -55,61 +49,22 @@ public class SQLite_HIKARI implements DataSource { this.columnLogged = Settings.getMySQLColumnLogged; this.columnRealName = Settings.getMySQLColumnRealName; - // Set the connection arguments (and check if connection is ok) + // Set the connection arguments try { this.setConnectionArguments(); - } catch (ClassNotFoundException ne) { - ConsoleLogger.showError(ne.getMessage()); - ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new ClassNotFoundException(ne.getMessage()); - } catch (IllegalArgumentException ae) { // This means that there are problems with the hikaricp pool arguments! - ConsoleLogger.showError(ae.getMessage()); - ConsoleLogger.showError("Invalid database arguments! Please check your configuration!"); - ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new IllegalArgumentException(ae); - } catch (PoolInitializationException ie) { // Can't initialize the connection pool! - ConsoleLogger.showError(ie.getMessage()); - ConsoleLogger.showError("Can't connect to the SQLite database! Please check your configuration!"); - ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new PoolInitializationException(ie); + } catch (RuntimeException rt) { + ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer!"); + throw rt; } // Initialize the database try { this.setupConnection(); } catch (SQLException e) { - ConsoleLogger.showError(e.getMessage()); + this.close(); ConsoleLogger.showError("Can't initialize the SQLite database... Please check your database settings in the config.yml file! SHUTDOWN..."); ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new SQLException(e); + throw e; } } @@ -118,11 +73,10 @@ public class SQLite_HIKARI implements DataSource { return DataSourceType.SQLITEHIKARI; } - private synchronized void setConnectionArguments() - throws ClassNotFoundException, IllegalArgumentException { + private synchronized void setConnectionArguments() throws RuntimeException { HikariConfig config = new HikariConfig(); config.setPoolName("AuthMeSQLitePool"); - config.setDriverClassName("org.sqlite.JDBC"); + config.setDriverClassName("org.sqlite.JDBC"); // RuntimeException config.setJdbcUrl("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); config.setConnectionTestQuery("SELECT 1"); config.setMaxLifetime(180000); // 3 Min @@ -134,7 +88,7 @@ public class SQLite_HIKARI implements DataSource { private synchronized void reloadArguments() throws ClassNotFoundException, IllegalArgumentException { - if (ds != null){ + if (ds != null) { ds.close(); } setConnectionArguments(); @@ -142,9 +96,7 @@ public class SQLite_HIKARI implements DataSource { } private synchronized Connection getConnection() throws SQLException { - Connection con = null; - con = ds.getConnection(); - return con; + return ds.getConnection(); } private synchronized void setupConnection() throws SQLException { @@ -357,7 +309,7 @@ public class SQLite_HIKARI implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List list = new ArrayList(); + List list = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLastLogin + "(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -492,7 +444,7 @@ public class SQLite_HIKARI implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List countIp = new ArrayList(); + List countIp = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); @@ -504,9 +456,9 @@ public class SQLite_HIKARI implements DataSource { return countIp; } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } catch (NullPointerException npe) { - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -519,7 +471,7 @@ public class SQLite_HIKARI implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List countIp = new ArrayList(); + List countIp = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); @@ -531,9 +483,9 @@ public class SQLite_HIKARI implements DataSource { return countIp; } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } catch (NullPointerException npe) { - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -546,7 +498,7 @@ public class SQLite_HIKARI implements DataSource { Connection con = null; PreparedStatement pst = null; ResultSet rs = null; - List countEmail = new ArrayList(); + List countEmail = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnEmail + "=?;"); @@ -558,9 +510,9 @@ public class SQLite_HIKARI implements DataSource { return countEmail; } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } catch (NullPointerException npe) { - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -622,12 +574,10 @@ public class SQLite_HIKARI implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override @@ -643,12 +593,10 @@ public class SQLite_HIKARI implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override @@ -663,19 +611,17 @@ public class SQLite_HIKARI implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override public int getAccountsRegistered() { Connection con = null; PreparedStatement pst = null; - ResultSet rs = null; + ResultSet rs; int result = 0; try { con = getConnection(); @@ -706,26 +652,24 @@ public class SQLite_HIKARI implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); close(con); } - return; } @Override public List getAllAuths() { Connection con = null; PreparedStatement pst = null; - ResultSet rs = null; - List auths = new ArrayList(); + ResultSet rs; + List auths = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + ";"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth = null; + PlayerAuth pAuth; if (rs.getString(columnIp).isEmpty()) { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } else { @@ -735,8 +679,7 @@ public class SQLite_HIKARI implements DataSource { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } } - if (pAuth != null) - auths.add(pAuth); + auths.add(pAuth); } } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); @@ -752,14 +695,14 @@ public class SQLite_HIKARI implements DataSource { public List getLoggedPlayers() { Connection con = null; PreparedStatement pst = null; - ResultSet rs = null; - List auths = new ArrayList(); + ResultSet rs; + List auths = new ArrayList<>(); try { con = getConnection(); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth = null; + PlayerAuth pAuth; if (rs.getString(columnIp).isEmpty()) { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } else { @@ -769,12 +712,10 @@ public class SQLite_HIKARI implements DataSource { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } } - if (pAuth != null) - auths.add(pAuth); + auths.add(pAuth); } } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return auths; } finally { close(pst); close(con); @@ -799,37 +740,14 @@ public class SQLite_HIKARI implements DataSource { @Override public synchronized void close() { - try { - if (ds != null) - ds.close(); - } catch (Exception e) { - } + if (ds != null) + ds.close(); } - private void close(Statement st) { - if (st != null) { + private void close(AutoCloseable o) { + if (o != null) { try { - st.close(); - } catch (Exception ex) { - ConsoleLogger.showError(ex.getMessage()); - } - } - } - - private void close(ResultSet rs) { - if (rs != null) { - try { - rs.close(); - } catch (Exception ex) { - ConsoleLogger.showError(ex.getMessage()); - } - } - } - - private void close(Connection con) { - if (con != null) { - try { - con.close(); + o.close(); } catch (Exception ex) { ConsoleLogger.showError(ex.getMessage()); } From c473e81eb9670421d46e304c9d7de74f389ce30e Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 16:31:07 +0700 Subject: [PATCH 070/115] same fix for normal sqlite --- .../fr/xephi/authme/datasource/SQLite.java | 90 ++++++------------- 1 file changed, 29 insertions(+), 61 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index a465ddd78..466dbe7f5 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -1,19 +1,13 @@ package fr.xephi.authme.datasource; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; - -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.settings.Settings; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + public class SQLite implements DataSource { private String database; @@ -34,7 +28,7 @@ public class SQLite implements DataSource { private String columnLogged; private String columnRealName; - public SQLite() { + public SQLite() throws ClassNotFoundException, SQLException { this.database = Settings.getMySQLDatabase; this.tableName = Settings.getMySQLTablename; this.columnName = Settings.getMySQLColumnName; @@ -55,29 +49,13 @@ public class SQLite implements DataSource { try { this.connect(); this.setup(); - } catch (ClassNotFoundException e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use SQLITE... ! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; - } catch (SQLException e) { - ConsoleLogger.showError(e.getMessage()); - if (Settings.isStopEnabled) { - ConsoleLogger.showError("Can't use SQLITE... ! SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); - } - if (!Settings.isStopEnabled) - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - return; + } catch (ClassNotFoundException | SQLException cnf) { + ConsoleLogger.showError("Can't use SQLITE... !"); + throw cnf; } } - private synchronized void connect() - throws ClassNotFoundException, SQLException { + private synchronized void connect() throws ClassNotFoundException, SQLException { Class.forName("org.sqlite.JDBC"); ConsoleLogger.info("SQLite driver loaded"); this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); @@ -273,7 +251,7 @@ public class SQLite implements DataSource { public List autoPurgeDatabase(long until) { PreparedStatement pst = null; ResultSet rs = null; - List list = new ArrayList(); + List list = new ArrayList<>(); try { pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLastLogin + "(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -423,7 +401,7 @@ public class SQLite implements DataSource { public List getAllAuthsByName(PlayerAuth auth) { PreparedStatement pst = null; ResultSet rs = null; - List countIp = new ArrayList(); + List countIp = new ArrayList<>(); try { pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); pst.setString(1, auth.getIp()); @@ -434,9 +412,9 @@ public class SQLite implements DataSource { return countIp; } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } catch (NullPointerException npe) { - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -447,7 +425,7 @@ public class SQLite implements DataSource { public List getAllAuthsByIp(String ip) { PreparedStatement pst = null; ResultSet rs = null; - List countIp = new ArrayList(); + List countIp = new ArrayList<>(); try { pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); pst.setString(1, ip); @@ -458,9 +436,9 @@ public class SQLite implements DataSource { return countIp; } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } catch (NullPointerException npe) { - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -471,7 +449,7 @@ public class SQLite implements DataSource { public List getAllAuthsByEmail(String email) { PreparedStatement pst = null; ResultSet rs = null; - List countEmail = new ArrayList(); + List countEmail = new ArrayList<>(); try { pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnEmail + "=?;"); pst.setString(1, email); @@ -482,9 +460,9 @@ public class SQLite implements DataSource { return countEmail; } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return new ArrayList(); + return new ArrayList<>(); } catch (NullPointerException npe) { - return new ArrayList(); + return new ArrayList<>(); } finally { close(rs); close(pst); @@ -542,11 +520,9 @@ public class SQLite implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); } - return; } @Override @@ -560,11 +536,9 @@ public class SQLite implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); } - return; } @Override @@ -577,18 +551,16 @@ public class SQLite implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); } - return; } @Override public int getAccountsRegistered() { int result = 0; PreparedStatement pst = null; - ResultSet rs = null; + ResultSet rs; try { pst = con.prepareStatement("SELECT COUNT(*) FROM " + tableName + ";"); rs = pst.executeQuery(); @@ -614,23 +586,21 @@ public class SQLite implements DataSource { pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); - return; } finally { close(pst); } - return; } @Override public List getAllAuths() { - List auths = new ArrayList(); + List auths = new ArrayList<>(); PreparedStatement pst = null; - ResultSet rs = null; + ResultSet rs; try { pst = con.prepareStatement("SELECT * FROM " + tableName + ";"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth = null; + PlayerAuth pAuth; if (rs.getString(columnIp).isEmpty()) { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } else { @@ -640,8 +610,7 @@ public class SQLite implements DataSource { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } } - if (pAuth != null) - auths.add(pAuth); + auths.add(pAuth); } } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); @@ -654,14 +623,14 @@ public class SQLite implements DataSource { @Override public List getLoggedPlayers() { - List auths = new ArrayList(); + List auths = new ArrayList<>(); PreparedStatement pst = null; - ResultSet rs = null; + ResultSet rs; try { pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth = null; + PlayerAuth pAuth; if (rs.getString(columnIp).isEmpty()) { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } else { @@ -671,8 +640,7 @@ public class SQLite implements DataSource { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } } - if (pAuth != null) - auths.add(pAuth); + auths.add(pAuth); } } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); From 026d84427b23352beab72f052438a36868bb9637 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 15 Sep 2015 16:33:32 +0200 Subject: [PATCH 071/115] General npc support, fixes and enhancements --- pom.xml | 24 ----------------- src/main/java/fr/xephi/authme/AuthMe.java | 17 +----------- .../java/fr/xephi/authme/ConsoleLogger.java | 5 ++-- src/main/java/fr/xephi/authme/Utils.java | 9 +++++++ src/main/java/fr/xephi/authme/api/API.java | 5 ++-- src/main/java/fr/xephi/authme/api/NewAPI.java | 3 ++- .../xephi/authme/cache/backup/JsonCache.java | 1 - .../fr/xephi/authme/datasource/MySQL.java | 1 + .../authme/listener/AuthMeEntityListener.java | 13 ++++----- .../authme/listener/AuthMePlayerListener.java | 25 ++++++++--------- .../authme/listener/AuthMeServerListener.java | 6 ----- .../plugin/manager/CitizensCommunicator.java | 27 ------------------- .../authme/process/join/AsyncronousJoin.java | 2 +- .../authme/process/quit/AsyncronousQuit.java | 2 +- .../fr/xephi/authme/settings/Messages.java | 2 -- 15 files changed, 40 insertions(+), 102 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/plugin/manager/CitizensCommunicator.java diff --git a/pom.xml b/pom.xml index ce943cac7..56c33e60c 100644 --- a/pom.xml +++ b/pom.xml @@ -129,12 +129,6 @@ https://ci.drtshock.net/plugin/repository/everything - - - citizensapi-repo - http://ci.citizensnpcs.co/plugin/repository/project/CitizensAPI/LastSuccessful/repository - - minelink-thirdparty @@ -299,24 +293,6 @@ - - - net.citizensnpcs - citizensapi - 2.0.16-SNAPSHOT - provided - - - org.bukkit - bukkit - - - org.bukkit - craftbukkit - - - - com.onarandombox.multiversecore diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index e7fa120d8..672df357c 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -16,7 +16,6 @@ import fr.xephi.authme.converter.ForceFlatToSqlite; import fr.xephi.authme.datasource.*; import fr.xephi.authme.listener.*; import fr.xephi.authme.plugin.manager.BungeeCordMessage; -import fr.xephi.authme.plugin.manager.CitizensCommunicator; import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.plugin.manager.EssSpawn; import fr.xephi.authme.process.Management; @@ -71,8 +70,6 @@ public class AuthMe extends JavaPlugin { public Location essentialsSpawn; public MultiverseCore multiverse; public LookupService lookupService; - public CitizensCommunicator citizens; - public boolean isCitizensActive = false; public boolean CombatTag = false; public boolean legacyChestShop = false; public boolean antibotMod = false; @@ -98,9 +95,6 @@ public class AuthMe extends JavaPlugin { return m; } - public CitizensCommunicator getCitizensCommunicator() { - return citizens; - } @Override public void onEnable() { @@ -182,10 +176,6 @@ public class AuthMe extends JavaPlugin { // Find Permissions checkVault(); - // Check Citizens Version - citizens = new CitizensCommunicator(this); - checkCitizens(); - // Check Combat Tag Version checkCombatTag(); @@ -515,11 +505,6 @@ public class AuthMe extends JavaPlugin { this.CombatTag = server.getPluginManager().isPluginEnabled("CombatTag"); } - // Check if Citizens is active - public void checkCitizens() { - this.isCitizensActive = server.getPluginManager().isPluginEnabled("Citizens"); - } - // Check if a player/command sender have a permission public boolean authmePermissible(Player player, String perm) { if (player.hasPermission(perm)) { @@ -541,7 +526,7 @@ public class AuthMe extends JavaPlugin { // Save Player Data public void savePlayer(Player player) { - if ((citizens.isNPC(player)) || (Utils.getInstance().isUnrestricted(player)) || (CombatTagComunicator.isNPC(player))) { + if ((utils.isNPC(player)) || (Utils.getInstance().isUnrestricted(player)) || (CombatTagComunicator.isNPC(player))) { return; } String name = player.getName().toLowerCase(); diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index a632282a2..f33ff1527 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -14,14 +14,13 @@ import java.util.logging.Logger; public class ConsoleLogger { private static final Logger log = AuthMe.getInstance().getLogger(); - private static final DateFormat format = DateFormat.getDateTimeInstance(); public static void info(String message) { if (AuthMe.getInstance().isEnabled()) { log.info("[AuthMe] " + message); if (Settings.useLogging) { - writeLog("[" + format.format(new Date()) + "] " + message); + writeLog("[" + DateFormat.getDateTimeInstance().format(new Date()) + "] " + message); } } } @@ -30,7 +29,7 @@ public class ConsoleLogger { if (AuthMe.getInstance().isEnabled()) { log.warning("[AuthMe] " + message); if (Settings.useLogging) { - writeLog("[" + format.format(new Date()) + "] ERROR: " + message); + writeLog("[" + DateFormat.getDateTimeInstance().format(new Date()) + "] ERROR: " + message); } } } diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 563a76f6b..eb794b484 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -8,6 +8,7 @@ import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.io.File; @@ -211,4 +212,12 @@ public class Utils { } return Collections.emptyList(); } + + public boolean isNPC(final Entity player) { + try { + return player.hasMetadata("NPC"); + } catch (Exception e) { + return false; + } + } } diff --git a/src/main/java/fr/xephi/authme/api/API.java b/src/main/java/fr/xephi/authme/api/API.java index 477494a20..eb9cf3ff6 100644 --- a/src/main/java/fr/xephi/authme/api/API.java +++ b/src/main/java/fr/xephi/authme/api/API.java @@ -20,6 +20,7 @@ public class API { public static final String newline = System.getProperty("line.separator"); public static AuthMe instance; + private Utils utils = Utils.getInstance(); @Deprecated public API(AuthMe instance) { @@ -65,7 +66,7 @@ public class API { */ @Deprecated public boolean isaNPC(Player player) { - if (instance.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return true; return CombatTagComunicator.isNPC(player); } @@ -77,7 +78,7 @@ public class API { */ @Deprecated public boolean isNPC(Player player) { - if (instance.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return true; return CombatTagComunicator.isNPC(player); } diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index 48ce0705a..41b955e6b 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -23,6 +23,7 @@ public class NewAPI { public static final String newline = System.getProperty("line.separator"); public static NewAPI singleton; public AuthMe plugin; + private Utils utils = Utils.getInstance(); public NewAPI(AuthMe plugin) { this.plugin = plugin; @@ -70,7 +71,7 @@ public class NewAPI { * @return true if player is a npc */ public boolean isNPC(Player player) { - return plugin.getCitizensCommunicator().isNPC(player) || CombatTagComunicator.isNPC(player); + return utils.isNPC(player) || CombatTagComunicator.isNPC(player); } /** diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index dce5a672b..912a1509d 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -19,7 +19,6 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.Type; import java.nio.file.Files; -import java.nio.file.Paths; public class JsonCache { diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 289e5dc0f..555ccf893 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -263,6 +263,7 @@ public class MySQL implements DataSource { } if (Settings.getPasswordHash == HashAlgorithm.XENFORO) { rs.close(); + pst.close(); pst = con.prepareStatement("SELECT * FROM xf_user_authenticate WHERE " + columnID + "=?;"); pst.setInt(1, id); rs = pst.executeQuery(); diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 162381337..90d5bd6e9 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -15,6 +15,7 @@ import org.bukkit.event.entity.*; public class AuthMeEntityListener implements Listener { public AuthMe instance; + private Utils utils = Utils.getInstance(); public AuthMeEntityListener(AuthMe instance) { this.instance = instance; @@ -32,7 +33,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (instance.citizens.isNPC(entity)) + if (utils.isNPC(entity)) return; Player player = (Player) entity; @@ -64,7 +65,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (instance.citizens.isNPC(entity)) + if (utils.isNPC(entity)) return; Player player = (Player) entity; @@ -114,7 +115,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (instance.citizens.isNPC(entity)) + if (utils.isNPC(entity)) return; Player player = (Player) entity; @@ -141,7 +142,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (instance.citizens.isNPC(entity)) + if (utils.isNPC(entity)) return; Player player = (Player) entity; @@ -174,7 +175,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (instance.citizens.isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName())) { @@ -202,7 +203,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (instance.citizens.isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName())) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 349112fb6..4386664ed 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -40,6 +40,7 @@ public class AuthMePlayerListener implements Listener { public static ConcurrentHashMap joinMessage = new ConcurrentHashMap<>(); private Messages m = Messages.getInstance(); public AuthMe plugin; + private Utils utils = Utils.getInstance(); public static ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap<>(); private List antibot = new ArrayList<>(); @@ -305,7 +306,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (plugin.getCitizensCommunicator().isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { return; } @@ -440,7 +441,7 @@ public class AuthMePlayerListener implements Listener { final String name = player.getName().toLowerCase(); boolean isAuthAvailable = plugin.database.isAuthAvailable(name); - if (plugin.getCitizensCommunicator().isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { return; } @@ -608,7 +609,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (plugin.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) { @@ -636,7 +637,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (plugin.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { @@ -667,7 +668,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (plugin.getCitizensCommunicator().isNPC(player)) { + if (utils.isNPC(player)) { return; } @@ -693,7 +694,7 @@ public class AuthMePlayerListener implements Listener { if (Utils.getInstance().isUnrestricted(player)) { return; } - if (plugin.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { return; @@ -732,7 +733,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (plugin.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { @@ -762,7 +763,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (plugin.getCitizensCommunicator().isNPC(player)) { + if (utils.isNPC(player)) { return; } @@ -786,7 +787,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (plugin.getCitizensCommunicator().isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { return; } @@ -814,7 +815,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (plugin.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { @@ -886,7 +887,7 @@ public class AuthMePlayerListener implements Listener { if (Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) return; - if (plugin.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -921,7 +922,7 @@ public class AuthMePlayerListener implements Listener { if (Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) return; - if (plugin.getCitizensCommunicator().isNPC(player)) + if (utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index f493af635..6ee60baa9 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -63,10 +63,6 @@ public class AuthMeServerListener implements Listener { plugin.CombatTag = false; ConsoleLogger.info("CombatTag has been disabled, unhook!"); } - if (pluginName.equalsIgnoreCase("Citizens")) { - plugin.isCitizensActive = false; - ConsoleLogger.info("Citizens has been disabled, unhook!"); - } if (pluginName.equalsIgnoreCase("Vault")) { plugin.permission = null; ConsoleLogger.showError("Vault has been disabled, unhook permissions!"); @@ -84,8 +80,6 @@ public class AuthMeServerListener implements Listener { plugin.checkChestShop(); if (pluginName.equalsIgnoreCase("CombatTag")) plugin.checkCombatTag(); - if (pluginName.equalsIgnoreCase("Citizens")) - plugin.checkCitizens(); if (pluginName.equalsIgnoreCase("Vault")) plugin.checkVault(); } diff --git a/src/main/java/fr/xephi/authme/plugin/manager/CitizensCommunicator.java b/src/main/java/fr/xephi/authme/plugin/manager/CitizensCommunicator.java deleted file mode 100644 index d09a5fcdd..000000000 --- a/src/main/java/fr/xephi/authme/plugin/manager/CitizensCommunicator.java +++ /dev/null @@ -1,27 +0,0 @@ -package fr.xephi.authme.plugin.manager; - -import org.bukkit.entity.Entity; - -import fr.xephi.authme.AuthMe; -import net.citizensnpcs.api.CitizensAPI; - -public class CitizensCommunicator { - - public AuthMe instance; - - public CitizensCommunicator(AuthMe instance) { - this.instance = instance; - } - - public boolean isNPC(final Entity player) { - if (!this.instance.isCitizensActive) - return false; - try { - return CitizensAPI.getNPCRegistry().isNPC(player); - } catch (NoClassDefFoundError ncdfe) { - return false; - } catch (Exception npe) { - return false; - } - } -} diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index b1db6afe8..455a937fe 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -58,7 +58,7 @@ public class AsyncronousJoin { AuthMePlayerListener.gameMode.putIfAbsent(name, player.getGameMode()); BukkitScheduler sched = plugin.getServer().getScheduler(); - if (plugin.getCitizensCommunicator().isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { return; } diff --git a/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java index dd84fdc85..b6cca4300 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java @@ -44,7 +44,7 @@ public class AsyncronousQuit { public void process() { if (player == null) return; - if (plugin.getCitizensCommunicator().isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { return; } diff --git a/src/main/java/fr/xephi/authme/settings/Messages.java b/src/main/java/fr/xephi/authme/settings/Messages.java index f9c7272a0..81c6a0382 100644 --- a/src/main/java/fr/xephi/authme/settings/Messages.java +++ b/src/main/java/fr/xephi/authme/settings/Messages.java @@ -2,8 +2,6 @@ package fr.xephi.authme.settings; import fr.xephi.authme.ConsoleLogger; import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.YamlConfiguration; - import java.io.File; public class Messages extends CustomConfiguration { From 221b32744cd70e5f2789cdc5b1310e0ba2ed3225 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 22:43:19 +0700 Subject: [PATCH 072/115] fix string concatenates performance --- .../xephi/authme/cache/backup/JsonCache.java | 2 +- .../xephi/authme/commands/AdminCommand.java | 21 +++++----- .../process/login/AsyncronousLogin.java | 38 ++++++++----------- .../xephi/authme/security/crypts/PHPBB.java | 35 +++++++---------- .../authme/security/crypts/WORDPRESS.java | 18 ++++----- 5 files changed, 50 insertions(+), 64 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 912a1509d..3203fae52 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -138,7 +138,7 @@ public class JsonCache { } } - private class PlayerDataDeserializer implements JsonDeserializer { + private static class PlayerDataDeserializer implements JsonDeserializer { @Override public DataFileCache deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { JsonObject jsonObject = jsonElement.getAsJsonObject(); diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 64b00031a..13105c0f8 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -156,7 +156,7 @@ public class AdminCommand implements CommandExecutor { @Override public void run() { PlayerAuth auth; - String message = "[AuthMe] "; + StringBuilder message = new StringBuilder("[AuthMe] "); try { auth = plugin.database.getAuth(arguments[1].toLowerCase()); } catch (NullPointerException npe) { @@ -179,25 +179,24 @@ public class AdminCommand implements CommandExecutor { int i = 0; for (String account : accountList) { i++; - message = message + account; + message.append(account); if (i != accountList.size()) { - message = message + ", "; + message.append(", "); } else { - message = message + "."; + message.append("."); } } sender.sendMessage("[AuthMe] " + arguments[1] + " has " + String.valueOf(accountList.size()) + " accounts"); - sender.sendMessage(message); + sender.sendMessage(message.toString()); } }); return true; } else { final String[] arguments = args; Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { - @Override public void run() { - String message = "[AuthMe] "; + StringBuilder message = new StringBuilder("[AuthMe] "); if (arguments[1] == null) { sender.sendMessage("[AuthMe] Please put a valid IP"); return; @@ -214,15 +213,15 @@ public class AdminCommand implements CommandExecutor { int i = 0; for (String account : accountList) { i++; - message = message + account; + message.append(account); if (i != accountList.size()) { - message = message + ", "; + message.append(", "); } else { - message = message + "."; + message.append("."); } } sender.sendMessage("[AuthMe] " + arguments[1] + " has " + String.valueOf(accountList.size()) + " accounts"); - sender.sendMessage(message); + sender.sendMessage(message.toString()); } }); return true; diff --git a/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java index bfc7569ee..e25c84571 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsyncronousLogin.java @@ -1,15 +1,8 @@ package fr.xephi.authme.process.login; -import java.util.Date; -import java.util.List; - -import fr.xephi.authme.Utils; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitTask; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; @@ -21,6 +14,12 @@ import fr.xephi.authme.security.RandomString; import fr.xephi.authme.settings.Messages; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.task.MessageTask; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; + +import java.util.Date; +import java.util.List; public class AsyncronousLogin { @@ -35,7 +34,7 @@ public class AsyncronousLogin { private Messages m = Messages.getInstance(); public AsyncronousLogin(Player player, String password, boolean forceLogin, - AuthMe plugin, DataSource data) { + AuthMe plugin, DataSource data) { this.player = player; this.password = password; name = player.getName().toLowerCase(); @@ -64,13 +63,9 @@ public class AsyncronousLogin { player.sendMessage(s.replace("THE_CAPTCHA", plugin.cap.get(name)).replace("", plugin.cap.get(name))); } return true; - } else - if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) >= Settings.maxLoginTry) { - try { - plugin.captcha.remove(name); - plugin.cap.remove(name); - } catch (NullPointerException npe) { - } + } else if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) >= Settings.maxLoginTry) { + plugin.captcha.remove(name); + plugin.cap.remove(name); } } return false; @@ -198,7 +193,6 @@ public class AsyncronousLogin { }); } else { m.send(player, "wrong_pwd"); - return; } } else { ConsoleLogger.showError("Player " + name + " wasn't online during login process, aborted... "); @@ -221,17 +215,17 @@ public class AsyncronousLogin { if (auths.size() == 1) { return; } - String message = "[AuthMe] "; + StringBuilder message = new StringBuilder("[AuthMe] "); // String uuidaccounts = // "[AuthMe] PlayerNames has %size% links to this UUID : "; int i = 0; for (String account : auths) { i++; - message = message + account; + message.append(account); if (i != auths.size()) { - message = message + ", "; + message.append(", "); } else { - message = message + "."; + message.append("."); } } /* @@ -243,7 +237,7 @@ public class AsyncronousLogin { for (Player player : Utils.getOnlinePlayers()) { if (plugin.authmePermissible(player, "authme.seeOtherAccounts")) { player.sendMessage("[AuthMe] The player " + auth.getNickname() + " has " + auths.size() + " accounts"); - player.sendMessage(message); + player.sendMessage(message.toString()); // player.sendMessage(uuidaccounts.replace("%size%", // ""+uuidlist.size())); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java index fc2f1896c..07eeef689 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java @@ -10,7 +10,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** - * * @author stefano */ public class PHPBB implements EncryptionMethod { @@ -20,19 +19,16 @@ public class PHPBB implements EncryptionMethod { public String phpbb_hash(String password, String salt) { String random_state = salt; - String random = ""; + StringBuilder random = new StringBuilder(); int count = 6; - if (random.length() < count) { - random = ""; - for (int i = 0; i < count; i += 16) { - random_state = md5(salt + random_state); - random += pack(md5(random_state)); - } - random = random.substring(0, count); + for (int i = 0; i < count; i += 16) { + random_state = md5(salt + random_state); + random.append(pack(md5(random_state))); } - String hash = _hash_crypt_private(password, _hash_gensalt_private(random, itoa64)); - if (hash.length() == 34) + String hash = _hash_crypt_private(password, _hash_gensalt_private(random.substring(0, count), itoa64)); + if (hash.length() == 34) { return hash; + } return md5(password); } @@ -40,9 +36,8 @@ public class PHPBB implements EncryptionMethod { return _hash_gensalt_private(input, itoa64, 6); } - @SuppressWarnings("unused") private String _hash_gensalt_private(String input, String itoa64, - int iteration_count_log2) { + int iteration_count_log2) { if (iteration_count_log2 < 4 || iteration_count_log2 > 31) { iteration_count_log2 = 8; } @@ -109,9 +104,7 @@ public class PHPBB implements EncryptionMethod { MessageDigest md5er = MessageDigest.getInstance("MD5"); byte[] hash = md5er.digest(bytes); return bytes2hex(hash); - } catch (GeneralSecurityException e) { - throw new RuntimeException(e); - } catch (UnsupportedEncodingException e) { + } catch (GeneralSecurityException | UnsupportedEncodingException e) { throw new RuntimeException(e); } } @@ -126,9 +119,9 @@ public class PHPBB implements EncryptionMethod { } private static String bytes2hex(byte[] bytes) { - StringBuffer r = new StringBuffer(32); - for (int i = 0; i < bytes.length; i++) { - String x = Integer.toHexString(bytes[i] & 0xff); + StringBuilder r = new StringBuilder(32); + for (byte b : bytes) { + String x = Integer.toHexString(b & 0xff); if (x.length() < 2) r.append("0"); r.append(x); @@ -137,7 +130,7 @@ public class PHPBB implements EncryptionMethod { } static String pack(String hex) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); for (int i = 0; i < hex.length(); i += 2) { char c1 = hex.charAt(i); char c2 = hex.charAt(i + 1); @@ -155,7 +148,7 @@ public class PHPBB implements EncryptionMethod { @Override public boolean comparePassword(String hash, String password, - String playerName) throws NoSuchAlgorithmException { + String playerName) throws NoSuchAlgorithmException { return phpbb_check_hash(password, hash); } } diff --git a/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java b/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java index 59871d7dc..c0ba2ffec 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java +++ b/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java @@ -8,13 +8,12 @@ import java.util.Arrays; public class WORDPRESS implements EncryptionMethod { - private static String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - private int iterationCountLog2 = 8; + private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private SecureRandom randomGen = new SecureRandom(); private String encode64(byte[] src, int count) { int i, value; - String output = ""; + StringBuilder output = new StringBuilder(); i = 0; if (src.length < count) { @@ -26,24 +25,24 @@ public class WORDPRESS implements EncryptionMethod { do { value = src[i] + (src[i] < 0 ? 256 : 0); ++i; - output += itoa64.charAt(value & 63); + output.append(itoa64.charAt(value & 63)); if (i < count) { value |= (src[i] + (src[i] < 0 ? 256 : 0)) << 8; } - output += itoa64.charAt((value >> 6) & 63); + output.append(itoa64.charAt((value >> 6) & 63)); if (i++ >= count) { break; } if (i < count) { value |= (src[i] + (src[i] < 0 ? 256 : 0)) << 16; } - output += itoa64.charAt((value >> 12) & 63); + output.append(itoa64.charAt((value >> 12) & 63)); if (i++ >= count) { break; } - output += itoa64.charAt((value >> 18) & 63); + output.append(itoa64.charAt((value >> 18) & 63)); } while (i < count); - return output; + return output.toString(); } private String crypt(String password, String setting) { @@ -86,7 +85,8 @@ public class WORDPRESS implements EncryptionMethod { private String gensaltPrivate(byte[] input) { String output = "$P$"; - output += itoa64.charAt(Math.min(this.iterationCountLog2 + 5, 30)); + int iterationCountLog2 = 8; + output += itoa64.charAt(Math.min(iterationCountLog2 + 5, 30)); output += encode64(input, 6); return output; } From 24c7efbd942ddc4b66b556983a60988ed2d3e544 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 23:10:52 +0700 Subject: [PATCH 073/115] update loadResource method --- .../java/fr/xephi/authme/settings/CustomConfiguration.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java index ae274ca58..d9db941e9 100644 --- a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java +++ b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java @@ -1,5 +1,6 @@ package fr.xephi.authme.settings; +import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; @@ -64,7 +65,7 @@ public class CustomConfiguration extends YamlConfiguration { int i = file.getPath().indexOf("AuthMe"); if (i > -1) { String path = file.getPath().substring(i + 6).replace('\\', '/'); - InputStream is = getClass().getResourceAsStream(path); + InputStream is = AuthMe.class.getResourceAsStream(path); Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING); return true; } From f2e207dab1d07b6a12c979488f6a8f0a4dacdd78 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 23:11:45 +0700 Subject: [PATCH 074/115] change structure of ModuleManager --- .../xephi/authme/modules/ModuleManager.java | 104 +++++++++++------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/src/main/java/fr/xephi/authme/modules/ModuleManager.java b/src/main/java/fr/xephi/authme/modules/ModuleManager.java index 87dabc53a..1050d93de 100644 --- a/src/main/java/fr/xephi/authme/modules/ModuleManager.java +++ b/src/main/java/fr/xephi/authme/modules/ModuleManager.java @@ -1,5 +1,9 @@ package fr.xephi.authme.modules; +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.settings.Settings; + import java.io.File; import java.io.IOException; import java.net.URL; @@ -10,56 +14,69 @@ import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; - -public class ModuleManager implements Module { +public class ModuleManager { private AuthMe plugin; - private ModuleManager instance; - private List modules = new ArrayList(); + + private List modules = new ArrayList<>(); public ModuleManager(AuthMe plugin) { this.plugin = plugin; } - @Override - public String getName() { - return "AuthMe Module Manager"; + public boolean isModuleEnabled(String name) { + for (Module m : modules) { + if (m.getName().equalsIgnoreCase(name)) + return true; + } + return false; } - @Override - public AuthMe getInstanceOfAuthMe() { - return this.plugin; + public boolean isModuleEnabled(Module.ModuleType type) { + for (Module m : modules) { + if (m.getType() == type) + return true; + } + return false; } - @Override - public Module getInstance() { - if (this.instance == null) - instance = new ModuleManager(AuthMe.getInstance()); - return instance; + public Module getModule(String name) { + for (Module m : modules) { + if (m.getName().equalsIgnoreCase(name)) + return m; + } + return null; } - @Override - public ModuleType getType() { - return (Module.ModuleType.MANAGER); + public Module getModule(Module.ModuleType type) { + for (Module m : modules) { + if (m.getType() == type) + return m; + } + return null; } - @Override - public boolean load() { - File dir = new File(plugin.getDataFolder() + File.separator + "modules"); + public int loadModules() { + File dir = Settings.MODULE_FOLDER; + int count = 0; + if (!dir.isDirectory()) { + dir.mkdirs(); + return count; + } + File[] files = dir.listFiles(); if (files == null) { - return false; + return count; } for (File pathToJar : files) { JarFile jarFile = null; + URLClassLoader cl = null; try { jarFile = new JarFile(pathToJar); - Enumeration e = jarFile.entries(); - URL[] urls = { new URL("jar:file:" + pathToJar.getAbsolutePath() + "!/") }; - URLClassLoader cl = URLClassLoader.newInstance(urls); + URL[] urls = {new URL("jar:file:" + pathToJar.getAbsolutePath() + "!/")}; + cl = URLClassLoader.newInstance(urls); + Enumeration e = jarFile.entries(); while (e.hasMoreElements()) { JarEntry je = (JarEntry) e.nextElement(); if (je.isDirectory() || !je.getName().endsWith("Main.class")) { @@ -68,35 +85,40 @@ public class ModuleManager implements Module { String className = je.getName().substring(0, je.getName().length() - 6); className = className.replace('/', '.'); Class c = cl.loadClass(className); + if (!Module.class.isAssignableFrom(c)) { + continue; + } + Module mod = (Module) c.newInstance(); mod.load(); modules.add(mod); + count++; break; - } + } catch (Exception ex) { + ConsoleLogger.writeStackTrace(ex); ConsoleLogger.showError("Cannot load " + pathToJar.getName() + " jar file !"); } finally { - if (jarFile != null) - try { + try { + if (jarFile != null) { jarFile.close(); - } catch (IOException e) { } + if (cl != null) { + cl.close(); + } + } catch (IOException ignored) { + } } } - return true; + return count; } - @Override - public boolean unload() { - try { - for (Module mod : modules) { - mod.unload(); - modules.remove(mod); - } - } catch (Exception e) { + public void unloadModules() { + for (Module m : modules) { + m.unload(); + modules.remove(m); } - return true; } } From b62e527b403f2ea7a45f780060986667bedcc579 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 15 Sep 2015 18:15:26 +0200 Subject: [PATCH 075/115] useless stuff --- src/main/java/fr/xephi/authme/modules/ModuleManager.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/modules/ModuleManager.java b/src/main/java/fr/xephi/authme/modules/ModuleManager.java index 1050d93de..f3c7df3c4 100644 --- a/src/main/java/fr/xephi/authme/modules/ModuleManager.java +++ b/src/main/java/fr/xephi/authme/modules/ModuleManager.java @@ -16,12 +16,9 @@ import java.util.jar.JarFile; public class ModuleManager { - private AuthMe plugin; - private List modules = new ArrayList<>(); public ModuleManager(AuthMe plugin) { - this.plugin = plugin; } public boolean isModuleEnabled(String name) { From 1de2705840da2480c492151ff7f66a24ec87df80 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 23:20:26 +0700 Subject: [PATCH 076/115] remove constant check --- src/main/java/fr/xephi/authme/security/crypts/PHPBB.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java index 07eeef689..107fb388b 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java @@ -14,7 +14,6 @@ import java.security.NoSuchAlgorithmException; */ public class PHPBB implements EncryptionMethod { - private static final int PHP_VERSION = 4; private String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; public String phpbb_hash(String password, String salt) { @@ -42,7 +41,7 @@ public class PHPBB implements EncryptionMethod { iteration_count_log2 = 8; } String output = "$H$"; - output += itoa64.charAt(Math.min(iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)); + output += itoa64.charAt(Math.min(iteration_count_log2 + 3, 30)); output += _hash_encode64(input, 6); return output; } From cdfdc06312a4b9ddbdd0ae5745be5dc9dbf17851 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 23:37:33 +0700 Subject: [PATCH 077/115] revert logger --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- src/main/java/fr/xephi/authme/security/crypts/PHPBB.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 672df357c..b9c84a017 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -53,7 +53,7 @@ public class AuthMe extends JavaPlugin { private static AuthMe authme; private final Server server = getServer(); - private final Logger authmeLogger = getLogger(); + private final Logger authmeLogger = Logger.getLogger("AuthMe"); public Management management; public NewAPI api; private Utils utils = Utils.getInstance(); diff --git a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java index 107fb388b..e5c666b61 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java @@ -41,7 +41,7 @@ public class PHPBB implements EncryptionMethod { iteration_count_log2 = 8; } String output = "$H$"; - output += itoa64.charAt(Math.min(iteration_count_log2 + 3, 30)); + output += itoa64.charAt(Math.min(iteration_count_log2 + 3, 30)); // PHP_VERSION >= 5 ? 5 : 3 output += _hash_encode64(input, 6); return output; } From 4fca6108d958de11d5278cea607b6e2fd0580143 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 15 Sep 2015 19:07:34 +0200 Subject: [PATCH 078/115] cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 8 ++++---- src/main/java/fr/xephi/authme/PerformBackup.java | 2 +- src/main/java/fr/xephi/authme/Utils.java | 6 +++--- src/main/java/fr/xephi/authme/commands/AdminCommand.java | 4 ++-- .../java/fr/xephi/authme/commands/UnregisterCommand.java | 6 +++--- .../fr/xephi/authme/converter/CrazyLoginConverter.java | 4 +--- src/main/java/fr/xephi/authme/converter/FlatToSql.java | 4 +--- src/main/java/fr/xephi/authme/converter/FlatToSqlite.java | 5 +---- .../java/fr/xephi/authme/converter/RakamakConverter.java | 5 +---- .../fr/xephi/authme/listener/AuthMeEntityListener.java | 2 +- .../fr/xephi/authme/listener/AuthMeServerListener.java | 2 +- .../xephi/authme/plugin/manager/CombatTagComunicator.java | 2 +- .../fr/xephi/authme/process/join/AsyncronousJoin.java | 8 ++++---- .../process/login/ProcessSyncronousPlayerLogin.java | 4 ++-- .../fr/xephi/authme/process/logout/AsyncronousLogout.java | 4 ++-- .../process/register/ProcessSyncronousEmailRegister.java | 2 +- .../register/ProcessSyncronousPasswordRegister.java | 2 +- 17 files changed, 30 insertions(+), 40 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index b9c84a017..d38fbf9b2 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -70,7 +70,7 @@ public class AuthMe extends JavaPlugin { public Location essentialsSpawn; public MultiverseCore multiverse; public LookupService lookupService; - public boolean CombatTag = false; + public boolean combatTag = false; public boolean legacyChestShop = false; public boolean antibotMod = false; public boolean delayedAntiBot = true; @@ -194,7 +194,7 @@ public class AuthMe extends JavaPlugin { // Do backup on start if enabled if (Settings.isBackupActivated && Settings.isBackupOnStart) { // Do backup and check return value! - if (new PerformBackup(this).DoBackup()) { + if (new PerformBackup(this).doBackup()) { ConsoleLogger.info("Backup performed correctly"); } else { ConsoleLogger.showError("Error while performing the backup!"); @@ -313,7 +313,7 @@ public class AuthMe extends JavaPlugin { // Do backup on stop if enabled if (Settings.isBackupActivated && Settings.isBackupOnStop) { - Boolean Backup = new PerformBackup(this).DoBackup(); + Boolean Backup = new PerformBackup(this).doBackup(); if (Backup) ConsoleLogger.info("Backup performed correctly."); else ConsoleLogger.showError("Error while performing the backup!"); @@ -502,7 +502,7 @@ public class AuthMe extends JavaPlugin { // Check the presence of CombatTag public void checkCombatTag() { - this.CombatTag = server.getPluginManager().isPluginEnabled("CombatTag"); + this.combatTag = server.getPluginManager().isPluginEnabled("CombatTag"); } // Check if a player/command sender have a permission diff --git a/src/main/java/fr/xephi/authme/PerformBackup.java b/src/main/java/fr/xephi/authme/PerformBackup.java index 72ae2faf2..5550a7c74 100644 --- a/src/main/java/fr/xephi/authme/PerformBackup.java +++ b/src/main/java/fr/xephi/authme/PerformBackup.java @@ -30,7 +30,7 @@ public class PerformBackup { this.setInstance(instance); } - public boolean DoBackup() { + public boolean doBackup() { switch (Settings.getDataSource) { case FILE: diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index eb794b484..21822566d 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -38,12 +38,12 @@ public class Utils { } } - public void setGroup(Player player, groupType group) { + public void setGroup(Player player, GroupType group) { setGroup(player.getName(), group); } @SuppressWarnings("deprecation") - public void setGroup(String player, groupType group) { + public void setGroup(String player, GroupType group) { if (!Settings.isPermissionCheckEnabled) return; if (plugin.permission == null) @@ -172,7 +172,7 @@ public class Utils { player.setGameMode(GameMode.SURVIVAL); } - public enum groupType { + public enum GroupType { UNREGISTERED, REGISTERED, NOTLOGGEDIN, diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 13105c0f8..41c4fbfd1 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -3,7 +3,7 @@ package fr.xephi.authme.commands; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; -import fr.xephi.authme.Utils.groupType; +import fr.xephi.authme.Utils.GroupType; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; @@ -464,7 +464,7 @@ public class AdminCommand implements CommandExecutor { @SuppressWarnings("deprecation") Player target = Bukkit.getPlayer(name); PlayerCache.getInstance().removePlayer(name); - Utils.getInstance().setGroup(name, groupType.UNREGISTERED); + Utils.getInstance().setGroup(name, GroupType.UNREGISTERED); if (target != null) { if (target.isOnline()) { if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { diff --git a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java index 57e653039..b9f5cd144 100644 --- a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java +++ b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java @@ -16,7 +16,7 @@ import org.bukkit.scheduler.BukkitTask; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; -import fr.xephi.authme.Utils.groupType; +import fr.xephi.authme.Utils.GroupType; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; @@ -82,7 +82,7 @@ public class UnregisterCommand implements CommandExecutor { player.saveData(); PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); if (!Settings.getRegisteredGroup.isEmpty()) - Utils.getInstance().setGroup(player, groupType.UNREGISTERED); + Utils.getInstance().setGroup(player, GroupType.UNREGISTERED); LimboCache.getInstance().addLimboPlayer(player); int delay = Settings.getRegistrationTimeout * 20; int interval = Settings.getWarnMessageInterval; @@ -97,7 +97,7 @@ public class UnregisterCommand implements CommandExecutor { return true; } if (!Settings.unRegisteredGroup.isEmpty()) { - Utils.getInstance().setGroup(player, Utils.groupType.UNREGISTERED); + Utils.getInstance().setGroup(player, Utils.GroupType.UNREGISTERED); } PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); // check if Player cache File Exist and delete it, preventing diff --git a/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java b/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java index 0ffae7db6..dbb247d0c 100644 --- a/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java +++ b/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java @@ -2,7 +2,6 @@ package fr.xephi.authme.converter; import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; @@ -70,10 +69,9 @@ public class CrazyLoginConverter implements Converter { } users.close(); ConsoleLogger.info("CrazyLogin database has been imported correctly"); - } catch (FileNotFoundException ex) { - ConsoleLogger.showError(ex.getMessage()); } catch (IOException ex) { ConsoleLogger.showError(ex.getMessage()); + ConsoleLogger.showError("Can't open the crazylogin database file! Does it exist?"); } } diff --git a/src/main/java/fr/xephi/authme/converter/FlatToSql.java b/src/main/java/fr/xephi/authme/converter/FlatToSql.java index 03112a604..0f0b7bf81 100644 --- a/src/main/java/fr/xephi/authme/converter/FlatToSql.java +++ b/src/main/java/fr/xephi/authme/converter/FlatToSql.java @@ -3,7 +3,6 @@ package fr.xephi.authme.converter; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; @@ -79,10 +78,9 @@ public class FlatToSql implements Converter { sql.close(); br.close(); ConsoleLogger.info("The FlatFile has been converted to authme.sql file"); - } catch (FileNotFoundException ex) { - ConsoleLogger.showError(ex.getMessage()); } catch (IOException ex) { ConsoleLogger.showError(ex.getMessage()); + ConsoleLogger.showError("Can't open the flat database file! Does it exist?"); } } } diff --git a/src/main/java/fr/xephi/authme/converter/FlatToSqlite.java b/src/main/java/fr/xephi/authme/converter/FlatToSqlite.java index 757a9d2db..f81d4a692 100644 --- a/src/main/java/fr/xephi/authme/converter/FlatToSqlite.java +++ b/src/main/java/fr/xephi/authme/converter/FlatToSqlite.java @@ -2,7 +2,6 @@ package fr.xephi.authme.converter; import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.sql.Connection; @@ -90,12 +89,10 @@ public class FlatToSqlite implements Converter { close(); sender.sendMessage("The FlatFile has been converted to " + database + ".db file"); return; - } catch (FileNotFoundException ex) { - ConsoleLogger.showError(ex.getMessage()); } catch (IOException ex) { ConsoleLogger.showError(ex.getMessage()); + sender.sendMessage("Can't open the flat database file! Does it exist?"); } - sender.sendMessage("Errors appears while trying to convert to SQLite"); return; } diff --git a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java index 333b6bdef..ae3b51d55 100644 --- a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java +++ b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java @@ -100,12 +100,9 @@ public class RakamakConverter implements Converter { } ConsoleLogger.info("Rakamak database has been imported correctly"); sender.sendMessage("Rakamak database has been imported correctly"); - } catch (FileNotFoundException ex) { - ConsoleLogger.showError(ex.getMessage()); - sender.sendMessage("Error file not found"); } catch (IOException ex) { ConsoleLogger.showError(ex.getMessage()); - sender.sendMessage("Error IOException"); + sender.sendMessage("Can't open the rakamak database file! Does it exist?"); } } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 90d5bd6e9..96ff1c813 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -136,7 +136,7 @@ public class AuthMeEntityListener implements Listener { } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void EntityRegainHealthEvent(EntityRegainHealthEvent event) { + public void entityRegainHealthEvent(EntityRegainHealthEvent event) { Entity entity = event.getEntity(); if (!(entity instanceof Player)) { return; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index 6ee60baa9..184cf8342 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -60,7 +60,7 @@ public class AuthMeServerListener implements Listener { ConsoleLogger.info("ChestShop has been disabled, unhook!"); } if (pluginName.equalsIgnoreCase("CombatTag")) { - plugin.CombatTag = false; + plugin.combatTag = false; ConsoleLogger.info("CombatTag has been disabled, unhook!"); } if (pluginName.equalsIgnoreCase("Vault")) { diff --git a/src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java b/src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java index ac80a632a..a98df2071 100644 --- a/src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java +++ b/src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java @@ -22,7 +22,7 @@ public abstract class CombatTagComunicator { * @return true if the player is an NPC */ public static boolean isNPC(Entity player) { - if (!AuthMe.getInstance().CombatTag) + if (!AuthMe.getInstance().combatTag) return false; try { if (Bukkit.getServer().getPluginManager().getPlugin("CombatTag") != null) { diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index 455a937fe..fda8c97cd 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -15,7 +15,7 @@ import org.bukkit.scheduler.BukkitTask; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; -import fr.xephi.authme.Utils.groupType; +import fr.xephi.authme.Utils.GroupType; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.DataFileCache; @@ -151,7 +151,7 @@ public class AsyncronousJoin { }); } if (!Settings.unRegisteredGroup.isEmpty()) { - utils.setGroup(player, Utils.groupType.UNREGISTERED); + utils.setGroup(player, Utils.GroupType.UNREGISTERED); } if (!Settings.isForcedRegistrationEnabled) { return; @@ -216,9 +216,9 @@ public class AsyncronousJoin { if (!LimboCache.getInstance().hasLimboPlayer(name)) LimboCache.getInstance().addLimboPlayer(player); if (database.isAuthAvailable(name)) { - utils.setGroup(player, groupType.NOTLOGGEDIN); + utils.setGroup(player, GroupType.NOTLOGGEDIN); } else { - utils.setGroup(player, groupType.UNREGISTERED); + utils.setGroup(player, GroupType.UNREGISTERED); } sched.scheduleSyncDelayedTask(plugin, new Runnable() { diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index b9d29411d..659825d74 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -9,7 +9,7 @@ import org.bukkit.potion.PotionEffectType; import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; -import fr.xephi.authme.Utils.groupType; +import fr.xephi.authme.Utils.GroupType; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; @@ -166,7 +166,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { Utils.forceGM(player); // Restore Permission Group - Utils.getInstance().setGroup(player, groupType.LOGGEDIN); + Utils.getInstance().setGroup(player, GroupType.LOGGEDIN); // Cleanup no longer used temporary data LimboCache.getInstance().deleteLimboPlayer(name); diff --git a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java index f1dde5873..1f44b3a3e 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java @@ -6,7 +6,7 @@ import org.bukkit.scheduler.BukkitScheduler; import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; -import fr.xephi.authme.Utils.groupType; +import fr.xephi.authme.Utils.GroupType; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.DataFileCache; @@ -79,7 +79,7 @@ public class AsyncronousLogout { if (LimboCache.getInstance().hasLimboPlayer(name)) LimboCache.getInstance().deleteLimboPlayer(name); LimboCache.getInstance().addLimboPlayer(player); - utils.setGroup(player, groupType.NOTLOGGEDIN); + utils.setGroup(player, GroupType.NOTLOGGEDIN); if (Settings.protectInventoryBeforeLogInEnabled) { player.getInventory().clear(); // create cache file for handling lost of inventories on unlogged in diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java index 9da830028..64eec84db 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java @@ -31,7 +31,7 @@ public class ProcessSyncronousEmailRegister implements Runnable { public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); if (!Settings.getRegisteredGroup.isEmpty()) { - Utils.getInstance().setGroup(player, Utils.groupType.REGISTERED); + Utils.getInstance().setGroup(player, Utils.GroupType.REGISTERED); } m.send(player, "vb_nonActiv"); int time = Settings.getRegistrationTimeout * 20; diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java index c8b64ed60..71d8292c6 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java @@ -108,7 +108,7 @@ public class ProcessSyncronousPasswordRegister implements Runnable { } if (!Settings.getRegisteredGroup.isEmpty()) { - Utils.getInstance().setGroup(player, Utils.groupType.REGISTERED); + Utils.getInstance().setGroup(player, Utils.GroupType.REGISTERED); } m.send(player, "registered"); if (!Settings.getmailAccount.isEmpty()) From 5fb3542ceaf85b8b807d5c8f7d15378a1437b3f8 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 15 Sep 2015 19:37:59 +0200 Subject: [PATCH 079/115] useledd imports --- src/main/java/fr/xephi/authme/converter/RakamakConverter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java index ae3b51d55..38697dbb8 100644 --- a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java +++ b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java @@ -2,7 +2,6 @@ package fr.xephi.authme.converter; import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.security.NoSuchAlgorithmException; From f63fe5bc374b0866d6ec34f5447c0c1918186e2b Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 15 Sep 2015 21:11:56 +0200 Subject: [PATCH 080/115] Enhance combattag hook --- pom.xml | 18 ------ src/main/java/fr/xephi/authme/AuthMe.java | 25 ++++++--- src/main/java/fr/xephi/authme/Utils.java | 9 ++- src/main/java/fr/xephi/authme/api/API.java | 9 +-- src/main/java/fr/xephi/authme/api/NewAPI.java | 3 +- .../authme/listener/AuthMeEntityListener.java | 16 +----- .../authme/listener/AuthMePlayerListener.java | 55 ++++++++----------- .../authme/listener/AuthMeServerListener.java | 10 ++-- .../plugin/manager/CombatTagComunicator.java | 49 ----------------- .../authme/process/join/AsyncronousJoin.java | 3 +- .../authme/process/quit/AsyncronousQuit.java | 3 +- 11 files changed, 59 insertions(+), 141 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java diff --git a/pom.xml b/pom.xml index 56c33e60c..69e0c32dc 100644 --- a/pom.xml +++ b/pom.xml @@ -412,24 +412,6 @@ - - - com.trc202 - CombatTag - 6.2.1-SNAPSHOT - provided - - - org.bukkit - bukkit - - - org.bukkit - craftbukkit - - - - de.luricos.bukkit diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index d38fbf9b2..6be444cd6 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -16,7 +16,6 @@ import fr.xephi.authme.converter.ForceFlatToSqlite; import fr.xephi.authme.datasource.*; import fr.xephi.authme.listener.*; import fr.xephi.authme.plugin.manager.BungeeCordMessage; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.plugin.manager.EssSpawn; import fr.xephi.authme.process.Management; import fr.xephi.authme.settings.Messages; @@ -24,6 +23,8 @@ import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; import net.milkbowl.vault.permission.Permission; +import net.minelink.ctplus.CombatTagPlus; + import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -62,7 +63,6 @@ public class AuthMe extends JavaPlugin { private Messages m; public DataManager dataManager; public DataSource database; - private JsonCache playerBackup; public OtherAccounts otherAccounts; public Permission permission; @@ -70,7 +70,7 @@ public class AuthMe extends JavaPlugin { public Location essentialsSpawn; public MultiverseCore multiverse; public LookupService lookupService; - public boolean combatTag = false; + public CombatTagPlus combatTagPlus = null; public boolean legacyChestShop = false; public boolean antibotMod = false; public boolean delayedAntiBot = true; @@ -176,8 +176,8 @@ public class AuthMe extends JavaPlugin { // Find Permissions checkVault(); - // Check Combat Tag Version - checkCombatTag(); + // Check Combat Tag Plus Version + checkCombatTagPlus(); // Check Multiverse checkMultiverse(); @@ -501,8 +501,17 @@ public class AuthMe extends JavaPlugin { } // Check the presence of CombatTag - public void checkCombatTag() { - this.combatTag = server.getPluginManager().isPluginEnabled("CombatTag"); + public void checkCombatTagPlus() { + if (server.getPluginManager().isPluginEnabled("CombatTagPlus")) { + try { + combatTagPlus = (CombatTagPlus) server.getPluginManager().getPlugin("CombatTagPlus"); + ConsoleLogger.info("Hooked correctly with CombatTagPlus"); + } catch (Exception | NoClassDefFoundError ingnored) { + combatTagPlus = null; + } + } else { + combatTagPlus = null; + } } // Check if a player/command sender have a permission @@ -526,7 +535,7 @@ public class AuthMe extends JavaPlugin { // Save Player Data public void savePlayer(Player player) { - if ((utils.isNPC(player)) || (Utils.getInstance().isUnrestricted(player)) || (CombatTagComunicator.isNPC(player))) { + if ((utils.isNPC(player)) || (Utils.getInstance().isUnrestricted(player))) { return; } String name = player.getName().toLowerCase(); diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 21822566d..7ba328b60 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -215,7 +215,14 @@ public class Utils { public boolean isNPC(final Entity player) { try { - return player.hasMetadata("NPC"); + if (player.hasMetadata("NPC")) { + return true; + } else if(plugin.combatTagPlus != null + && player instanceof Player + && plugin.combatTagPlus.getNpcPlayerHelper().isNpc((Player) player)) { + return true; + } + return false; } catch (Exception e) { return false; } diff --git a/src/main/java/fr/xephi/authme/api/API.java b/src/main/java/fr/xephi/authme/api/API.java index eb9cf3ff6..026a9577a 100644 --- a/src/main/java/fr/xephi/authme/api/API.java +++ b/src/main/java/fr/xephi/authme/api/API.java @@ -12,7 +12,6 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.settings.Settings; @@ -66,9 +65,7 @@ public class API { */ @Deprecated public boolean isaNPC(Player player) { - if (utils.isNPC(player)) - return true; - return CombatTagComunicator.isNPC(player); + return utils.isNPC(player); } /** @@ -78,9 +75,7 @@ public class API { */ @Deprecated public boolean isNPC(Player player) { - if (utils.isNPC(player)) - return true; - return CombatTagComunicator.isNPC(player); + return utils.isNPC(player); } /** diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index 41b955e6b..604d9d2d7 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -14,7 +14,6 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.settings.Settings; @@ -71,7 +70,7 @@ public class NewAPI { * @return true if player is a npc */ public boolean isNPC(Player player) { - return utils.isNPC(player) || CombatTagComunicator.isNPC(player); + return utils.isNPC(player); } /** diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 96ff1c813..e1bfea52b 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -3,7 +3,6 @@ package fr.xephi.authme.listener; import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.settings.Settings; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -39,9 +38,6 @@ public class AuthMeEntityListener implements Listener { Player player = (Player) entity; String name = player.getName().toLowerCase(); - if (CombatTagComunicator.isNPC(player)) - return; - if (PlayerCache.getInstance().isAuthenticated(name)) { return; } @@ -171,11 +167,7 @@ public class AuthMeEntityListener implements Listener { Player player = (Player) event.getEntity(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { - return; - } - - if (utils.isNPC(player)) + if (Utils.getInstance().isUnrestricted(player) || utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName())) { @@ -199,11 +191,7 @@ public class AuthMeEntityListener implements Listener { Player player = (Player) event.getEntity(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { - return; - } - - if (utils.isNPC(player)) + if (Utils.getInstance().isUnrestricted(player) || utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName())) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 4386664ed..93884b283 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -8,7 +8,6 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.settings.Messages; import fr.xephi.authme.settings.Settings; import org.bukkit.Bukkit; @@ -56,7 +55,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) + if (utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -90,7 +89,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) + if (utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -126,7 +125,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) + if (utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -162,7 +161,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) + if (utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -198,7 +197,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) + if (utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -234,7 +233,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) + if (utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) { @@ -271,7 +270,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) + if (utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -306,7 +305,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || utils.isUnrestricted(player)) { return; } @@ -424,7 +423,7 @@ public class AuthMePlayerListener implements Listener { public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); if (limbo != null && PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - Utils.getInstance().addNormal(player, limbo.getGroup()); + utils.addNormal(player, limbo.getGroup()); LimboCache.getInstance().deleteLimboPlayer(player.getName().toLowerCase()); } } @@ -441,7 +440,7 @@ public class AuthMePlayerListener implements Listener { final String name = player.getName().toLowerCase(); boolean isAuthAvailable = plugin.database.isAuthAvailable(name); - if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || utils.isUnrestricted(player)) { return; } @@ -605,7 +604,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } @@ -633,7 +632,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } @@ -664,7 +663,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } @@ -691,7 +690,7 @@ public class AuthMePlayerListener implements Listener { return; final Player player = (Player) event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } if (utils.isNPC(player)) @@ -729,7 +728,7 @@ public class AuthMePlayerListener implements Listener { Player player = (Player) event.getWhoClicked(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } @@ -759,7 +758,7 @@ public class AuthMePlayerListener implements Listener { Player player = (Player) damager; String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } @@ -787,7 +786,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || utils.isUnrestricted(player)) { return; } @@ -811,11 +810,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { - return; - } - - if (utils.isNPC(player)) + if (utils.isUnrestricted(player) || utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { @@ -838,7 +833,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } @@ -861,7 +856,7 @@ public class AuthMePlayerListener implements Listener { } Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (utils.isUnrestricted(player)) { return; } if (PlayerCache.getInstance().isAuthenticated(name)) { @@ -884,10 +879,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) - return; - - if (utils.isNPC(player)) + if (utils.isUnrestricted(player) || utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -919,10 +911,7 @@ public class AuthMePlayerListener implements Listener { String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) - return; - - if (utils.isNPC(player)) + if (utils.isUnrestricted(player) || utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index 184cf8342..8e7960210 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -59,9 +59,9 @@ public class AuthMeServerListener implements Listener { plugin.legacyChestShop = false; ConsoleLogger.info("ChestShop has been disabled, unhook!"); } - if (pluginName.equalsIgnoreCase("CombatTag")) { - plugin.combatTag = false; - ConsoleLogger.info("CombatTag has been disabled, unhook!"); + if (pluginName.equalsIgnoreCase("CombatTagPlus")) { + plugin.combatTagPlus = null; + ConsoleLogger.info("CombatTagPlus has been disabled, unhook!"); } if (pluginName.equalsIgnoreCase("Vault")) { plugin.permission = null; @@ -78,8 +78,8 @@ public class AuthMeServerListener implements Listener { plugin.checkMultiverse(); if (pluginName.equalsIgnoreCase("ChestShop")) plugin.checkChestShop(); - if (pluginName.equalsIgnoreCase("CombatTag")) - plugin.checkCombatTag(); + if (pluginName.equalsIgnoreCase("CombatTagPlus")) + plugin.checkCombatTagPlus(); if (pluginName.equalsIgnoreCase("Vault")) plugin.checkVault(); } diff --git a/src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java b/src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java deleted file mode 100644 index a98df2071..000000000 --- a/src/main/java/fr/xephi/authme/plugin/manager/CombatTagComunicator.java +++ /dev/null @@ -1,49 +0,0 @@ -package fr.xephi.authme.plugin.manager; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import com.trc202.CombatTag.CombatTag; -import com.trc202.CombatTagApi.CombatTagApi; - -import fr.xephi.authme.AuthMe; -import net.minelink.ctplus.CombatTagPlus; - -public abstract class CombatTagComunicator { - - public static CombatTagApi combatApi; - - /** - * Returns if the entity is an NPC - * - * @param player - * @return true if the player is an NPC - */ - public static boolean isNPC(Entity player) { - if (!AuthMe.getInstance().combatTag) - return false; - try { - if (Bukkit.getServer().getPluginManager().getPlugin("CombatTag") != null) { - combatApi = new CombatTagApi((CombatTag) Bukkit.getServer().getPluginManager().getPlugin("CombatTag")); - try { - combatApi.getClass().getMethod("isNPC"); - } catch (Exception e) { - return false; - } - return combatApi.isNPC(player); - } else { - Plugin plugin = Bukkit.getServer().getPluginManager().getPlugin("CombatTagPlus"); - return (plugin != null && plugin instanceof CombatTagPlus && player instanceof Player && ((CombatTagPlus) plugin).getNpcPlayerHelper().isNpc((Player) player)); - } - } catch (ClassCastException ex) { - return false; - } catch (NullPointerException npe) { - return false; - } catch (NoClassDefFoundError ncdfe) { - return false; - } - } - -} diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index fda8c97cd..a9e7d603e 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -27,7 +27,6 @@ import fr.xephi.authme.events.FirstSpawnTeleportEvent; import fr.xephi.authme.events.ProtectInventoryEvent; import fr.xephi.authme.events.SpawnTeleportEvent; import fr.xephi.authme.listener.AuthMePlayerListener; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.settings.Messages; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; @@ -58,7 +57,7 @@ public class AsyncronousJoin { AuthMePlayerListener.gameMode.putIfAbsent(name, player.getGameMode()); BukkitScheduler sched = plugin.getServer().getScheduler(); - if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player)) { return; } diff --git a/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java index b6cca4300..9a05229a9 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java @@ -15,7 +15,6 @@ import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.RestoreInventoryEvent; import fr.xephi.authme.listener.AuthMePlayerListener; -import fr.xephi.authme.plugin.manager.CombatTagComunicator; import fr.xephi.authme.settings.Settings; public class AsyncronousQuit { @@ -44,7 +43,7 @@ public class AsyncronousQuit { public void process() { if (player == null) return; - if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player) || CombatTagComunicator.isNPC(player)) { + if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player)) { return; } From 27f9b14067fe7d201f3939f6af3fff8d9bd4082e Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 15 Sep 2015 21:26:31 +0200 Subject: [PATCH 081/115] GSON library --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index 69e0c32dc..87feaae49 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,7 @@ com.zaxxer:HikariCP org.slf4j:slf4j-simple org.slf4j:slf4j-api + com.google.code.gson:gson com.maxmind.geoip:geoip-api com.sun.mail:javax.mail com.comphenix.attribute:AttributeStorage @@ -205,6 +206,14 @@ compile + + + com.google.code.gson + gson + 2.3.1 + compile + + javax.mail From 6a8e581ba852e1923dcf2008ac0c6a8d645ba062 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 15 Sep 2015 23:44:37 +0700 Subject: [PATCH 082/115] added softdepend for PerWorldInventories --- src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 68aab3b36..6b2e6174a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,7 +4,7 @@ website: http://dev.bukkit.org/bukkit-plugins/authme-reloaded/ description: AuthMe prevents people, which aren't logged in, from doing stuff like placing blocks, moving, typing commands or seeing the inventory of the player. main: fr.xephi.authme.AuthMe version: ${project.version} -softdepend: [Vault, ChestShop, Multiverse-Core, Citizens, CombatTag, Essentials, EssentialsSpawn] +softdepend: [Vault, ChestShop, Multiverse-Core, Citizens, CombatTag, Essentials, EssentialsSpawn, PerWorldInventories] commands: register: description: Register an account From 51067498eae837d8f7033d83c644effb272529a7 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 16 Sep 2015 11:36:08 +0700 Subject: [PATCH 083/115] cleanup MySQL throws --- .../fr/xephi/authme/datasource/MySQL.java | 57 +++++-------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 555ccf893..6557ebaca 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -64,58 +64,29 @@ public class MySQL implements DataSource { // Set the connection arguments (and check if connection is ok) try { this.setConnectionArguments(); - } catch (ClassNotFoundException ne) { - ConsoleLogger.showError(ne.getMessage()); + } catch (RuntimeException e) { + if (e instanceof IllegalArgumentException) { + ConsoleLogger.showError("Invalid database arguments! Please check your configuration!"); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + throw new IllegalArgumentException(e); + } + if (e instanceof PoolInitializationException) { + ConsoleLogger.showError("Can't initialize database connection! Please check your configuration!"); + ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); + throw new PoolInitializationException(e); + } ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new ClassNotFoundException(ne.getMessage()); - } catch (IllegalArgumentException ae) { // This means that there are problems with the hikaricp pool arguments! - ConsoleLogger.showError(ae.getMessage()); - ConsoleLogger.showError("Invalid database arguments! Please check your configuration!"); - ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new IllegalArgumentException(ae); - } catch (PoolInitializationException ie) { // Can't initialize the connection pool! - ConsoleLogger.showError(ie.getMessage()); - ConsoleLogger.showError("Can't connect to the MySql database! Please check your configuration!"); - ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new PoolInitializationException(ie); + throw e; } // Initialize the database try { this.setupConnection(); } catch (SQLException e) { - ConsoleLogger.showError(e.getMessage()); + this.close(); ConsoleLogger.showError("Can't initialize the MySQL database... Please check your database settings in the config.yml file! SHUTDOWN..."); ConsoleLogger.showError("If this error persists, please report it to the developer! SHUTDOWN..."); - this.close(); - if (Settings.isStopEnabled) { - AuthMe.getInstance().getServer().shutdown(); - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } else { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); - } - throw new SQLException(e); + throw e; } } From b5546c07b4fe1381f3527040ef9ec44ea7f2c747 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 16 Sep 2015 11:37:18 +0700 Subject: [PATCH 084/115] cleanup string concatenates --- src/main/java/fr/xephi/authme/Utils.java | 25 +++++++++++-------- .../xephi/authme/security/crypts/PHPBB.java | 12 ++++----- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 7ba328b60..645e7faf3 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -12,7 +12,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.io.File; +import java.io.IOException; import java.lang.reflect.Method; +import java.nio.file.Files; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -180,16 +182,19 @@ public class Utils { } public static void purgeDirectory(File file) { - String files[] = file.list(); - if (files != null && files.length != 0) { - for (String temp : files) { - File fileDelete = new File(file, temp); - if (fileDelete.isDirectory()) { - purgeDirectory(fileDelete); - fileDelete.delete(); - } else { - fileDelete.delete(); - } + if (!file.isDirectory()) { + return; + } + File[] files = file.listFiles(); + if (files == null) { + return; + } + for (File target : files) { + if(target.isDirectory()) { + purgeDirectory(target); + target.delete(); + } else { + target.delete(); } } } diff --git a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java index e5c666b61..cc5d4dc36 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java @@ -50,24 +50,24 @@ public class PHPBB implements EncryptionMethod { * Encode hash */ private String _hash_encode64(String input, int count) { - String output = ""; + StringBuilder output = new StringBuilder(); int i = 0; do { int value = input.charAt(i++); - output += itoa64.charAt(value & 0x3f); + output.append(itoa64.charAt(value & 0x3f)); if (i < count) value |= input.charAt(i) << 8; - output += itoa64.charAt((value >> 6) & 0x3f); + output.append(itoa64.charAt((value >> 6) & 0x3f)); if (i++ >= count) break; if (i < count) value |= input.charAt(i) << 16; - output += itoa64.charAt((value >> 12) & 0x3f); + output.append(itoa64.charAt((value >> 12) & 0x3f)); if (i++ >= count) break; - output += itoa64.charAt((value >> 18) & 0x3f); + output.append(itoa64.charAt((value >> 18) & 0x3f)); } while (i < count); - return output; + return output.toString(); } String _hash_crypt_private(String password, String setting) { From a00deb0e0f72dc248c8cfbd872ab61e687357997 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sat, 19 Sep 2015 12:51:59 +0700 Subject: [PATCH 085/115] unregister asynchronously --- .../authme/commands/UnregisterCommand.java | 160 +++++++++--------- 1 file changed, 82 insertions(+), 78 deletions(-) diff --git a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java index b9f5cd144..7c1a4c1e1 100644 --- a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java +++ b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java @@ -1,18 +1,5 @@ package fr.xephi.authme.commands; -import java.security.NoSuchAlgorithmException; - -import org.bukkit.Location; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; @@ -26,6 +13,18 @@ import fr.xephi.authme.settings.Messages; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.TimeoutTask; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; + +import java.security.NoSuchAlgorithmException; public class UnregisterCommand implements CommandExecutor { @@ -39,8 +38,8 @@ public class UnregisterCommand implements CommandExecutor { } @Override - public boolean onCommand(CommandSender sender, Command cmnd, String label, - String[] args) { + public boolean onCommand(final CommandSender sender, Command cmnd, String label, + final String[] args) { if (!(sender instanceof Player)) { return true; } @@ -50,8 +49,8 @@ public class UnregisterCommand implements CommandExecutor { return true; } - Player player = (Player) sender; - String name = player.getName().toLowerCase(); + final Player player = (Player) sender; + final String name = player.getName().toLowerCase(); if (!PlayerCache.getInstance().isAuthenticated(name)) { m.send(player, "not_logged_in"); @@ -62,72 +61,77 @@ public class UnregisterCommand implements CommandExecutor { m.send(player, "usage_unreg"); return true; } - try { - if (PasswordSecurity.comparePasswordWithHash(args[0], PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) { - if (!plugin.database.removeAuth(name)) { - player.sendMessage("error"); - return true; - } - if (Settings.isForcedRegistrationEnabled) { - if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { - Location spawn = plugin.getSpawnLocation(player); - SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawn, false); - plugin.getServer().getPluginManager().callEvent(tpEvent); - if (!tpEvent.isCancelled()) { - player.teleport(tpEvent.getTo()); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { + @Override + public void run() { + try { + if (PasswordSecurity.comparePasswordWithHash(args[0], PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) { + if (!plugin.database.removeAuth(name)) { + player.sendMessage("error"); + return; } - } - player.getInventory().setContents(new ItemStack[36]); - player.getInventory().setArmorContents(new ItemStack[4]); - player.saveData(); - PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); - if (!Settings.getRegisteredGroup.isEmpty()) - Utils.getInstance().setGroup(player, GroupType.UNREGISTERED); - LimboCache.getInstance().addLimboPlayer(player); - int delay = Settings.getRegistrationTimeout * 20; - int interval = Settings.getWarnMessageInterval; - BukkitScheduler sched = sender.getServer().getScheduler(); - if (delay != 0) { - BukkitTask id = sched.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, name, player), delay); - LimboCache.getInstance().getLimboPlayer(name).setTimeoutTaskId(id); - } - LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.send("reg_msg"), interval))); - m.send(player, "unregistered"); - ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); - return true; - } - if (!Settings.unRegisteredGroup.isEmpty()) { - Utils.getInstance().setGroup(player, Utils.GroupType.UNREGISTERED); - } - PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); - // check if Player cache File Exist and delete it, preventing - // duplication of items - if (playerCache.doesCacheExist(player)) { - playerCache.removeCache(player); - } - if (Settings.applyBlindEffect) - player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); - m.send(player, "unregistered"); - ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); - if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { - Location spawn = plugin.getSpawnLocation(player); - SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawn, false); - plugin.getServer().getPluginManager().callEvent(tpEvent); - if (!tpEvent.isCancelled()) { - if (!tpEvent.getTo().getWorld().getChunkAt(tpEvent.getTo()).isLoaded()) { - tpEvent.getTo().getWorld().getChunkAt(tpEvent.getTo()).load(); + if (Settings.isForcedRegistrationEnabled) { + if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { + Location spawn = plugin.getSpawnLocation(player); + SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawn, false); + plugin.getServer().getPluginManager().callEvent(tpEvent); + if (!tpEvent.isCancelled()) { + player.teleport(tpEvent.getTo()); + } + } + player.getInventory().setContents(new ItemStack[36]); + player.getInventory().setArmorContents(new ItemStack[4]); + player.saveData(); + PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); + if (!Settings.getRegisteredGroup.isEmpty()) + Utils.getInstance().setGroup(player, GroupType.UNREGISTERED); + LimboCache.getInstance().addLimboPlayer(player); + int delay = Settings.getRegistrationTimeout * 20; + int interval = Settings.getWarnMessageInterval; + BukkitScheduler sched = sender.getServer().getScheduler(); + if (delay != 0) { + BukkitTask id = sched.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, name, player), delay); + LimboCache.getInstance().getLimboPlayer(name).setTimeoutTaskId(id); + } + LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.send("reg_msg"), interval))); + m.send(player, "unregistered"); + ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); + return; } - player.teleport(tpEvent.getTo()); + if (!Settings.unRegisteredGroup.isEmpty()) { + Utils.getInstance().setGroup(player, Utils.GroupType.UNREGISTERED); + } + PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); + // check if Player cache File Exist and delete it, preventing + // duplication of items + if (playerCache.doesCacheExist(player)) { + playerCache.removeCache(player); + } + if (Settings.applyBlindEffect) + player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); + m.send(player, "unregistered"); + ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); + if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { + Location spawn = plugin.getSpawnLocation(player); + SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawn, false); + plugin.getServer().getPluginManager().callEvent(tpEvent); + if (!tpEvent.isCancelled()) { + if (!tpEvent.getTo().getWorld().getChunkAt(tpEvent.getTo()).isLoaded()) { + tpEvent.getTo().getWorld().getChunkAt(tpEvent.getTo()).load(); + } + player.teleport(tpEvent.getTo()); + } + } + return; + } else { + m.send(player, "wrong_pwd"); } + } catch (NoSuchAlgorithmException ex) { + ConsoleLogger.showError(ex.getMessage()); + sender.sendMessage("Internal Error please read the server log"); } - return true; - } else { - m.send(player, "wrong_pwd"); } - } catch (NoSuchAlgorithmException ex) { - ConsoleLogger.showError(ex.getMessage()); - sender.sendMessage("Internal Error please read the server log"); - } + }); return true; } } From 4ec548cb8d548f35a70b5c57ea765d85d23f683b Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sat, 19 Sep 2015 13:27:31 +0700 Subject: [PATCH 086/115] added null check, #209 #210 --- src/main/java/fr/xephi/authme/api/NewAPI.java | 4 +- .../xephi/authme/cache/backup/JsonCache.java | 47 ++++++++++++++----- .../authme/process/join/AsyncronousJoin.java | 3 +- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index 604d9d2d7..b31f9ab28 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -34,9 +34,7 @@ public class NewAPI { /** * Hook into AuthMe - * - * @return - * + * * @return AuthMe plugin */ public static NewAPI getInstance() { diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 3203fae52..dee7b743f 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -1,6 +1,8 @@ package fr.xephi.authme.cache.backup; +import com.google.common.base.Charsets; import com.google.common.io.BaseEncoding; +import com.google.common.io.Files; import com.google.gson.*; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; @@ -18,7 +20,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.lang.reflect.Type; -import java.nio.file.Files; public class JsonCache { @@ -61,7 +62,8 @@ public class JsonCache { try { String data = gson.toJson(playerData); - Files.write(file.toPath(), data.getBytes()); + Files.touch(file); + Files.write(data, file, Charsets.UTF_8); } catch (IOException e) { e.printStackTrace(); } @@ -76,9 +78,12 @@ public class JsonCache { } File file = new File(cacheDir, path + File.separator + "cache.json"); + if (!file.exists()) { + return null; + } + try { - byte[] bytes = Files.readAllBytes(file.toPath()); - String str = new String(bytes); + String str = Files.toString(file, Charsets.UTF_8); return gson.fromJson(str, DataFileCache.class); } catch (Exception e) { e.printStackTrace(); @@ -142,17 +147,37 @@ public class JsonCache { @Override public DataFileCache deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { JsonObject jsonObject = jsonElement.getAsJsonObject(); - String group = jsonObject.get("group").getAsString(); - boolean operator = jsonObject.get("operator").getAsBoolean(); - boolean flying = jsonObject.get("flying").getAsBoolean(); + if (jsonObject == null) { + return null; + } + JsonElement e; + String group = null; + boolean operator = false; + boolean flying = false; + + if ((e = jsonObject.get("group")) != null) { + group = e.getAsString(); + } + if ((e = jsonObject.get("operator")) != null) { + operator = e.getAsBoolean(); + } + if ((e = jsonObject.get("flying")) != null) { + flying = e.getAsBoolean(); + } JsonArray arr; + ItemStack[] inv = null; + ItemStack[] armour = null; - arr = jsonObject.get("inventory").getAsJsonArray(); - ItemStack[] inv = getItems(arr); + if (jsonObject.has("inventory")) { + arr = jsonObject.get("inventory").getAsJsonArray(); + inv = getItems(arr); + } - arr = jsonObject.get("armour").getAsJsonArray(); - ItemStack[] armour = getItems(arr); + if (jsonObject.has("armour")) { + arr = jsonObject.get("armour").getAsJsonArray(); + armour = getItems(arr); + } return new DataFileCache(inv, armour, group, operator, flying); } diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index a9e7d603e..a75b91b44 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -195,7 +195,8 @@ public class AsyncronousJoin { }); } - } catch (NullPointerException ex) { + } catch (Exception ex) { + ex.printStackTrace(); } } String[] msg; From dc35d768aae4b36cf4c62f549e89b49b75e6431b Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 19 Sep 2015 20:20:46 +0200 Subject: [PATCH 087/115] add max connections setting --- src/main/java/fr/xephi/authme/Utils.java | 2 - .../fr/xephi/authme/datasource/MySQL.java | 4 +- .../fr/xephi/authme/settings/Settings.java | 130 ++++++++++-------- src/main/resources/config.yml | 2 + 4 files changed, 80 insertions(+), 58 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 645e7faf3..b0feda6bb 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -12,9 +12,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.io.File; -import java.io.IOException; import java.lang.reflect.Method; -import java.nio.file.Files; import java.util.Arrays; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 6557ebaca..8e5d4cc10 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -37,6 +37,7 @@ public class MySQL implements DataSource { private List columnOthers; private HikariDataSource ds; private String columnRealName; + private int maxConnections; public MySQL() throws ClassNotFoundException, SQLException, PoolInitializationException { this.host = Settings.getMySQLHost; @@ -60,6 +61,7 @@ public class MySQL implements DataSource { this.columnID = Settings.getMySQLColumnId; this.columnLogged = Settings.getMySQLColumnLogged; this.columnRealName = Settings.getMySQLColumnRealName; + this.maxConnections = Settings.getMySQLMaxConnections; // Set the connection arguments (and check if connection is ok) try { @@ -105,7 +107,7 @@ public class MySQL implements DataSource { config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable config.setMaxLifetime(180000); // 3 Min config.setIdleTimeout(60000); // 1 Min - config.setMaximumPoolSize(50); // 50 (including idle connections) + config.setMaximumPoolSize(maxConnections); ds = new HikariDataSource(config); ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index d57a82cf5..0b923314b 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -90,7 +90,7 @@ public final class Settings extends YamlConfiguration { getMailPort, maxLoginTry, captchaLength, saltLength, getmaxRegPerEmail, bCryptLog2Rounds, getPhpbbGroup, antiBotSensibility, antiBotDuration, delayRecall, getMaxLoginPerIp, - getMaxJoinPerIp; + getMaxJoinPerIp, getMySQLMaxConnections; protected static YamlConfiguration configFile; @@ -152,6 +152,7 @@ public final class Settings extends YamlConfiguration { isCachingEnabled = configFile.getBoolean("DataSource.caching", true); getMySQLHost = configFile.getString("DataSource.mySQLHost", "127.0.0.1"); getMySQLPort = configFile.getString("DataSource.mySQLPort", "3306"); + getMySQLMaxConnections = configFile.getInt("DataSource.mySQLMaxConections", 25); getMySQLUsername = configFile.getString("DataSource.mySQLUsername", "authme"); getMySQLPassword = configFile.getString("DataSource.mySQLPassword", "12345"); getMySQLDatabase = configFile.getString("DataSource.mySQLDatabase", "authme"); @@ -280,178 +281,197 @@ public final class Settings extends YamlConfiguration { } public void mergeConfig() { - int changes = 0; - if (contains("Xenoforo.predefinedSalt")) + boolean changes = false; + if (contains("Xenoforo.predefinedSalt")) { set("Xenoforo.predefinedSalt", null); - if (configFile.getString("settings.security.passwordHash", "SHA256").toUpperCase().equals("XFSHA1") || configFile.getString("settings.security.passwordHash", "SHA256").toUpperCase().equals("XFSHA256")) + changes = true; + } + if (configFile.getString("settings.security.passwordHash", "SHA256").toUpperCase().equals("XFSHA1") || configFile.getString("settings.security.passwordHash", "SHA256").toUpperCase().equals("XFSHA256")) { set("settings.security.passwordHash", "XENFORO"); + changes = true; + } if (!contains("Protection.enableProtection")) { set("Protection.enableProtection", false); - changes++; + changes = true; + } + if (!contains("DataSource.mySQLMaxConections")) { + set("DataSource.mySQLMaxConections", 25); + changes = true; } if (!contains("Protection.countries")) { countries = new ArrayList<>(); countries.add("US"); countries.add("GB"); set("Protection.countries", countries); - changes++; + changes = true; } if (!contains("Protection.enableAntiBot")) { set("Protection.enableAntiBot", false); - changes++; + changes = true; } if (!contains("Protection.antiBotSensibility")) { set("Protection.antiBotSensibility", 5); - changes++; + changes = true; } if (!contains("Protection.antiBotDuration")) { set("Protection.antiBotDuration", 10); - changes++; + changes = true; } if (!contains("settings.forceCommands")) { set("settings.forceCommands", new ArrayList()); - changes++; + changes = true; } if (!contains("settings.forceCommandsAsConsole")) { set("settings.forceCommandsAsConsole", new ArrayList()); - changes++; + changes = true; } if (!contains("Email.recallPlayers")) { set("Email.recallPlayers", false); - changes++; + changes = true; } if (!contains("Email.delayRecall")) { set("Email.delayRecall", 5); - changes++; + changes = true; } if (!contains("settings.useWelcomeMessage")) { set("settings.useWelcomeMessage", true); - changes++; + changes = true; } if (!contains("settings.security.unsafePasswords")) { List str = new ArrayList<>(); str.add("123456"); str.add("password"); set("settings.security.unsafePasswords", str); - changes++; + changes = true; } if (!contains("Protection.countriesBlacklist")) { countriesBlacklist = new ArrayList<>(); countriesBlacklist.add("A1"); set("Protection.countriesBlacklist", countriesBlacklist); - changes++; + changes = true; } if (!contains("settings.broadcastWelcomeMessage")) { set("settings.broadcastWelcomeMessage", false); - changes++; + changes = true; } if (!contains("settings.registration.forceKickAfterRegister")) { set("settings.registration.forceKickAfterRegister", false); - changes++; + changes = true; } if (!contains("settings.registration.forceLoginAfterRegister")) { set("settings.registration.forceLoginAfterRegister", false); - changes++; + changes = true; } if (!contains("DataSource.mySQLColumnLogged")) { set("DataSource.mySQLColumnLogged", "isLogged"); - changes++; + changes = true; } if (!contains("settings.restrictions.spawnPriority")) { set("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default"); - changes++; + changes = true; } if (!contains("settings.restrictions.maxLoginPerIp")) { set("settings.restrictions.maxLoginPerIp", 0); - changes++; + changes = true; } if (!contains("settings.restrictions.maxJoinPerIp")) { set("settings.restrictions.maxJoinPerIp", 0); - changes++; + changes = true; } if (!contains("VeryGames.enableIpCheck")) { set("VeryGames.enableIpCheck", false); - changes++; + changes = true; } - if (getString("settings.restrictions.allowedNicknameCharacters").equals("[a-zA-Z0-9_?]*")) + if (getString("settings.restrictions.allowedNicknameCharacters").equals("[a-zA-Z0-9_?]*")) { set("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*"); + changes = true; + } if (!contains("settings.delayJoinMessage")) { set("settings.delayJoinMessage", false); - changes++; + changes = true; } if (!contains("settings.restrictions.noTeleport")) { set("settings.restrictions.noTeleport", false); - changes++; + changes = true; } - if (contains("Converter.Rakamak.newPasswordHash")) + if (contains("Converter.Rakamak.newPasswordHash")) { set("Converter.Rakamak.newPasswordHash", null); + changes = true; + } if (!contains("Converter.CrazyLogin.fileName")) { set("Converter.CrazyLogin.fileName", "accounts.db"); - changes++; + changes = true; } if (!contains("settings.restrictions.allowedPasswordCharacters")) { set("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*"); - changes++; + changes = true; } if (!contains("settings.applyBlindEffect")) { set("settings.applyBlindEffect", false); - changes++; + changes = true; } if (!contains("Email.emailBlacklisted")) { set("Email.emailBlacklisted", new ArrayList()); - changes++; + changes = true; } - if (contains("Performances.useMultiThreading")) + if (contains("Performances.useMultiThreading")) { set("Performances.useMultiThreading", null); - - if (contains("Performances")) + changes = true; + } + if (contains("Performances")) { set("Performances", null); - - if (contains("Passpartu.enablePasspartu")) + changes = true; + } + if (contains("Passpartu.enablePasspartu")) { set("Passpartu.enablePasspartu", null); - - if (contains("Passpartu")) + changes = true; + } + if (contains("Passpartu")) { set("Passpartu", null); - + changes = true; + } if (!contains("Email.emailWhitelisted")) { set("Email.emailWhitelisted", new ArrayList()); - changes++; + changes = true; } if (!contains("settings.forceRegisterCommands")) { set("settings.forceRegisterCommands", new ArrayList()); - changes++; + changes = true; } if (!contains("settings.forceRegisterCommandsAsConsole")) { set("settings.forceRegisterCommandsAsConsole", new ArrayList()); - changes++; + changes = true; } if (!contains("Hooks.customAttributes")) { set("Hooks.customAttributes", false); - changes++; + changes = true; } if (!contains("Purge.removePermissions")) { set("Purge.removePermissions", false); - changes++; + changes = true; } - if (contains("Hooks.notifications")) + if (contains("Hooks.notifications")) { set("Hooks.notifications", null); - boolean useChestShop = false; - if (contains("Hooks.chestshop")) { - useChestShop = getBoolean("Hooks.chestshop"); - set("Hooks.chestshop", null); + changes = true; + } + if (contains("Hooks.chestshop")) { + if(getBoolean("Hooks.chestshop")) { + set("Hooks.legacyChestshop", true); + } + set("Hooks.chestshop", null); + changes = true; } - set("Hooks.legacyChestshop", useChestShop); if (!contains("Email.generateImage")) { set("Email.generateImage", true); - changes++; + changes = true; } if (!contains("DataSource.mySQLRealName")) { set("DataSource.mySQLRealName", "realname"); - changes++; + changes = true; } - if (changes > 0) { - plugin.getLogger().warning("Merge " + changes + " new Config Options - I'm not an error, please don't report me"); + if (changes) { + plugin.getLogger().warning("Merged new Config Options - I'm not an error, please don't report me"); plugin.getLogger().warning("Please check your config.yml file for new configs!"); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d66c5a141..b183912e8 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,6 +8,8 @@ DataSource: mySQLHost: 127.0.0.1 # Database Port mySQLPort: '3306' + # MySql Max Connections + mySQLMaxConections: 25 # Username about Database Connection Infos mySQLUsername: authme # Password about Database Connection Infos From b427d14bcb286c0406ef6115800b45064357414f Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 19 Sep 2015 22:28:55 +0200 Subject: [PATCH 088/115] Speed 0 when not logged! --- src/main/java/fr/xephi/authme/commands/AdminCommand.java | 4 ++++ src/main/java/fr/xephi/authme/commands/UnregisterCommand.java | 4 ++++ .../java/fr/xephi/authme/process/join/AsyncronousJoin.java | 4 ++++ .../authme/process/login/ProcessSyncronousPlayerLogin.java | 4 ++++ .../authme/process/logout/ProcessSyncronousPlayerLogout.java | 2 ++ .../process/register/ProcessSyncronousPasswordRegister.java | 4 ++++ 6 files changed, 22 insertions(+) diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 41c4fbfd1..569088b31 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -486,6 +486,10 @@ public class AdminCommand implements CommandExecutor { LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.send("reg_msg"), interval))); if (Settings.applyBlindEffect) target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); + if (!Settings.isMovementAllowed) { + target.setWalkSpeed(0.0f); + target.setFlySpeed(0.0f); + } m.send(target, "unregistered"); } } diff --git a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java index 7c1a4c1e1..6d8196e5f 100644 --- a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java +++ b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java @@ -109,6 +109,10 @@ public class UnregisterCommand implements CommandExecutor { } if (Settings.applyBlindEffect) player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); + if (!Settings.isMovementAllowed) { + player.setWalkSpeed(0.0f); + player.setFlySpeed(0.0f); + } m.send(player, "unregistered"); ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index a75b91b44..442fab0a1 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -235,6 +235,10 @@ public class AsyncronousJoin { player.performCommand("motd"); if (Settings.applyBlindEffect) player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); + if (!Settings.isMovementAllowed) { + player.setWalkSpeed(0.0f); + player.setFlySpeed(0.0f); + } } }); diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index 659825d74..2ad48153e 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -186,6 +186,10 @@ public class ProcessSyncronousPlayerLogin implements Runnable { if (Settings.applyBlindEffect) player.removePotionEffect(PotionEffectType.BLINDNESS); + if (!Settings.isMovementAllowed) { + player.setWalkSpeed(0.2f); + player.setFlySpeed(0.4f); + } // The Loginevent now fires (as intended) after everything is processed Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java index 4cac3864a..f78685b09 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java @@ -54,6 +54,8 @@ public class ProcessSyncronousPlayerLogout implements Runnable { if (!Settings.isMovementAllowed) { player.setAllowFlight(true); player.setFlying(true); + player.setFlySpeed(0.0f); + player.setWalkSpeed(0.0f); } // Player is now logout... Time to fire event ! Bukkit.getServer().getPluginManager().callEvent(new LogoutEvent(player)); diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java index 71d8292c6..60e1f9def 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java @@ -119,6 +119,10 @@ public class ProcessSyncronousPasswordRegister implements Runnable { } if (Settings.applyBlindEffect) player.removePotionEffect(PotionEffectType.BLINDNESS); + if (!Settings.isMovementAllowed) { + player.setWalkSpeed(0.2f); + player.setFlySpeed(0.4f); + } // The Loginevent now fires (as intended) after everything is processed Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); player.saveData(); From 53fcfb5b4343299f378f7f621add91233bdfb6f8 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sat, 19 Sep 2015 14:10:48 +0700 Subject: [PATCH 089/115] cleanup encryption --- .../authme/process/join/AsyncronousJoin.java | 30 +++++------ .../authme/security/PasswordSecurity.java | 54 +++++++++---------- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index 442fab0a1..613e43c32 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -1,17 +1,5 @@ package fr.xephi.authme.process.join; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; @@ -32,6 +20,17 @@ import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.TimeoutTask; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; public class AsyncronousJoin { @@ -62,10 +61,7 @@ public class AsyncronousJoin { } if (plugin.ess != null && Settings.disableSocialSpy) { - try { - plugin.ess.getUser(player.getName().toLowerCase()).setSocialSpyEnabled(false); - } catch (NoSuchMethodError e) { - } + plugin.ess.getUser(player).setSocialSpyEnabled(false); } final String ip = plugin.getIP(player); @@ -289,7 +285,7 @@ public class AsyncronousJoin { } private void placePlayerSafely(final Player player, - final Location spawnLoc) { + final Location spawnLoc) { Location loc = null; if (spawnLoc == null) return; diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index 3cc83cfc1..a95a848df 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -1,19 +1,18 @@ package fr.xephi.authme.security; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.HashMap; - -import org.bukkit.Bukkit; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.events.PasswordEncryptionEvent; import fr.xephi.authme.security.crypts.BCRYPT; import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.settings.Settings; +import org.bukkit.Bukkit; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.HashMap; public class PasswordSecurity { @@ -31,7 +30,7 @@ public class PasswordSecurity { } public static String getHash(HashAlgorithm alg, String password, - String playerName) throws NoSuchAlgorithmException { + String playerName) throws NoSuchAlgorithmException { EncryptionMethod method; try { if (alg != HashAlgorithm.CUSTOM) @@ -126,41 +125,39 @@ public class PasswordSecurity { } public static boolean comparePasswordWithHash(String password, String hash, - String playerName) throws NoSuchAlgorithmException { + String playerName) throws NoSuchAlgorithmException { HashAlgorithm algo = Settings.getPasswordHash; EncryptionMethod method; try { if (algo != HashAlgorithm.CUSTOM) method = (EncryptionMethod) algo.getclasse().newInstance(); - else method = null; - } catch (InstantiationException | IllegalAccessException e) { - throw new NoSuchAlgorithmException("Problem with this hash algorithm"); - } - PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName); - Bukkit.getPluginManager().callEvent(event); - method = event.getMethod(); - if (method == null) - throw new NoSuchAlgorithmException("Unknown hash algorithm"); + else + method = null; + + PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName); + Bukkit.getPluginManager().callEvent(event); + method = event.getMethod(); + + if (method == null) + throw new NoSuchAlgorithmException("Unknown hash algorithm"); - try { if (method.comparePassword(hash, password, playerName)) return true; - } catch (Exception e) { - } - if (Settings.supportOldPassword) { - try { + + if (Settings.supportOldPassword) { if (compareWithAllEncryptionMethod(password, hash, playerName)) return true; - } catch (Exception e) { } + } catch (InstantiationException | IllegalAccessException e) { + throw new NoSuchAlgorithmException("Problem with this hash algorithm"); } return false; } private static boolean compareWithAllEncryptionMethod(String password, - String hash, String playerName) throws NoSuchAlgorithmException { + String hash, String playerName) throws NoSuchAlgorithmException { for (HashAlgorithm algo : HashAlgorithm.values()) { - if (algo != HashAlgorithm.CUSTOM) + if (algo != HashAlgorithm.CUSTOM) { try { EncryptionMethod method = (EncryptionMethod) algo.getclasse().newInstance(); if (method.comparePassword(hash, password, playerName)) { @@ -173,8 +170,9 @@ public class PasswordSecurity { } return true; } - } catch (Exception e) { + } catch (Exception ignored) { } + } } return false; } From 350ab535634864a03184fd21ce4cf8f8bfb262f8 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 08:40:02 +0700 Subject: [PATCH 090/115] update base64 --- .../xephi/authme/cache/backup/JsonCache.java | 6 +- .../authme/process/join/AsyncronousJoin.java | 34 ++--- .../xephi/authme/security/crypts/BCRYPT.java | 135 +++++++----------- .../security/crypts/CryptPBKDF2Django.java | 6 +- 4 files changed, 75 insertions(+), 106 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index dee7b743f..13c1777a1 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -1,7 +1,6 @@ package fr.xephi.authme.cache.backup; import com.google.common.base.Charsets; -import com.google.common.io.BaseEncoding; import com.google.common.io.Files; import com.google.gson.*; import fr.xephi.authme.AuthMe; @@ -14,6 +13,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectOutputStream; +import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -133,7 +133,7 @@ public class JsonCache { BukkitObjectOutputStream objectOut = new BukkitObjectOutputStream(baos); objectOut.writeObject(item); objectOut.close(); - val.addProperty("item", BaseEncoding.base64().encode(baos.toByteArray())); + val.addProperty("item", Base64Coder.encodeLines(baos.toByteArray())); } catch (IOException e) { e.printStackTrace(); continue; @@ -187,7 +187,7 @@ public class JsonCache { for (int i = 0; i < arr.size(); i++) { JsonObject item = arr.get(i).getAsJsonObject(); String encoded = item.get("item").getAsString(); - byte[] decoded = BaseEncoding.base64().decode(encoded); + byte[] decoded = Base64Coder.decode(encoded); try { ByteArrayInputStream baos = new ByteArrayInputStream(decoded); BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos); diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index 613e43c32..b6362624a 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -172,27 +172,23 @@ public class AsyncronousJoin { } if (Settings.protectInventoryBeforeLogInEnabled) { - try { - LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); - ProtectInventoryEvent ev = new ProtectInventoryEvent(player, limbo.getInventory(), limbo.getArmour()); - plugin.getServer().getPluginManager().callEvent(ev); - if (ev.isCancelled()) { - if (!Settings.noConsoleSpam) - ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + " ..."); - } else { - final ItemStack[] inv = ev.getEmptyArmor(); - final ItemStack[] armor = ev.getEmptyArmor(); - sched.scheduleSyncDelayedTask(plugin, new Runnable() { + LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); + ProtectInventoryEvent ev = new ProtectInventoryEvent(player, limbo.getInventory(), limbo.getArmour()); + plugin.getServer().getPluginManager().callEvent(ev); + if (ev.isCancelled()) { + if (!Settings.noConsoleSpam) + ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + " ..."); + } else { + final ItemStack[] inv = ev.getEmptyArmor(); + final ItemStack[] armor = ev.getEmptyArmor(); + sched.scheduleSyncDelayedTask(plugin, new Runnable() { - @Override - public void run() { - plugin.api.setPlayerInventory(player, inv, armor); - } + @Override + public void run() { + plugin.api.setPlayerInventory(player, inv, armor); + } - }); - } - } catch (Exception ex) { - ex.printStackTrace(); + }); } } String[] msg; diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java index 847e99518..7f420c000 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java +++ b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java @@ -69,17 +69,17 @@ public class BCRYPT implements EncryptionMethod { private static final int BLOWFISH_NUM_ROUNDS = 16; // Initial contents of key schedule - private static final int P_orig[] = { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b }; - private static final int S_orig[] = { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 }; + private static final int P_orig[] = {0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b}; + private static final int S_orig[] = {0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6}; // bcrypt IV: "OrpheanBeholderScryDoubt" - static private final int bf_crypt_ciphertext[] = { 0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274 }; + static private final int bf_crypt_ciphertext[] = {0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274}; // Table for Base64 encoding - static private final char base64_code[] = { '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + static private final char base64_code[] = {'.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; // Table for Base64 decoding - static private final byte index_64[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1 }; + static private final byte index_64[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1}; // Expanded Blowfish key private int P[]; @@ -90,13 +90,10 @@ public class BCRYPT implements EncryptionMethod { * scheme. Note that this is *not* compatible with the standard MIME-base64 * encoding. * - * @param d - * the byte array to encode - * @param len - * the number of bytes to encode + * @param d the byte array to encode + * @param len the number of bytes to encode * @return base64-encoded string - * @exception IllegalArgumentException - * if the length is invalid + * @throws IllegalArgumentException if the length is invalid */ private static String encode_base64(byte d[], int len) throws IllegalArgumentException { @@ -134,9 +131,8 @@ public class BCRYPT implements EncryptionMethod { /** * Look up the 3 bits base64-encoded by the specified character, * range-checking againt conversion table - * - * @param x - * the base64-encoded value + * + * @param x the base64-encoded value * @return the decoded value of x */ private static byte char64(char x) { @@ -149,14 +145,11 @@ public class BCRYPT implements EncryptionMethod { * Decode a string encoded using bcrypt's base64 scheme to a byte array. * Note that this is *not* compatible with the standard MIME-base64 * encoding. - * - * @param s - * the string to decode - * @param maxolen - * the maximum number of bytes to decode + * + * @param s the string to decode + * @param maxolen the maximum number of bytes to decode * @return an array containing the decoded bytes - * @throws IllegalArgumentException - * if maxolen is invalid + * @throws IllegalArgumentException if maxolen is invalid */ private static byte[] decode_base64(String s, int maxolen) throws IllegalArgumentException { @@ -201,17 +194,15 @@ public class BCRYPT implements EncryptionMethod { /** * Blowfish encipher a single 64-bit block encoded as two 32-bit halves - * - * @param lr - * an array containing the two 32-bit half blocks - * @param off - * the position in the array of the blocks + * + * @param lr an array containing the two 32-bit half blocks + * @param off the position in the array of the blocks */ private final void encipher(int lr[], int off) { int i, n, l = lr[off], r = lr[off + 1]; l ^= P[0]; - for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) { + for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2; ) { // Feistel substitution on left word n = S[(l >> 24) & 0xff]; n += S[0x100 | ((l >> 16) & 0xff)]; @@ -232,12 +223,10 @@ public class BCRYPT implements EncryptionMethod { /** * Cycically extract a word of key material - * - * @param data - * the string to extract the data from - * @param offp - * a "pointer" (as a one-entry array) to the current offset into - * data + * + * @param data the string to extract the data from + * @param offp a "pointer" (as a one-entry array) to the current offset into + * data * @return the next word of material from data */ private static int streamtoword(byte data[], int offp[]) { @@ -264,14 +253,13 @@ public class BCRYPT implements EncryptionMethod { /** * Key the Blowfish cipher - * - * @param key - * an array containing the key + * + * @param key an array containing the key */ private void key(byte key[]) { int i; - int koffp[] = { 0 }; - int lr[] = { 0, 0 }; + int koffp[] = {0}; + int lr[] = {0, 0}; int plen = P.length, slen = S.length; for (i = 0; i < plen; i++) @@ -294,16 +282,14 @@ public class BCRYPT implements EncryptionMethod { * Perform the "enhanced key schedule" step described by Provos and Mazieres * in "A Future-Adaptable Password Scheme" * http://www.openbsd.org/papers/bcrypt-paper.ps - * - * @param data - * salt information - * @param key - * password information + * + * @param data salt information + * @param key password information */ private void ekskey(byte data[], byte key[]) { int i; - int koffp[] = { 0 }, doffp[] = { 0 }; - int lr[] = { 0, 0 }; + int koffp[] = {0}, doffp[] = {0}; + int lr[] = {0, 0}; int plen = P.length, slen = S.length; for (i = 0; i < plen; i++) @@ -328,14 +314,11 @@ public class BCRYPT implements EncryptionMethod { /** * Perform the central password hashing step in the bcrypt scheme - * - * @param password - * the password to hash - * @param salt - * the binary salt to hash with the password - * @param log_rounds - * the binary logarithm of the number of rounds of hashing to - * apply + * + * @param password the password to hash + * @param salt the binary salt to hash with the password + * @param log_rounds the binary logarithm of the number of rounds of hashing to + * apply * @return an array containing the binary hashed password */ private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) { @@ -374,11 +357,9 @@ public class BCRYPT implements EncryptionMethod { /** * Hash a password using the OpenBSD bcrypt scheme - * - * @param password - * the password to hash - * @param salt - * the salt to hash with (perhaps generated using BCrypt.gensalt) + * + * @param password the password to hash + * @param salt the salt to hash with (perhaps generated using BCrypt.gensalt) * @return the hashed password */ public static String hashpw(String password, String salt) { @@ -432,12 +413,10 @@ public class BCRYPT implements EncryptionMethod { /** * Generate a salt for use with the BCrypt.hashpw() method - * - * @param log_rounds - * the log2 of the number of rounds of hashing to apply - the - * work factor therefore increases as 2**log_rounds. - * @param random - * an instance of SecureRandom to use + * + * @param log_rounds the log2 of the number of rounds of hashing to apply - the + * work factor therefore increases as 2**log_rounds. + * @param random an instance of SecureRandom to use * @return an encoded salt value */ public static String gensalt(int log_rounds, SecureRandom random) { @@ -457,10 +436,9 @@ public class BCRYPT implements EncryptionMethod { /** * Generate a salt for use with the BCrypt.hashpw() method - * - * @param log_rounds - * the log2 of the number of rounds of hashing to apply - the - * work factor therefore increases as 2**log_rounds. + * + * @param log_rounds the log2 of the number of rounds of hashing to apply - the + * work factor therefore increases as 2**log_rounds. * @return an encoded salt value */ public static String gensalt(int log_rounds) { @@ -470,7 +448,7 @@ public class BCRYPT implements EncryptionMethod { /** * Generate a salt for use with the BCrypt.hashpw() method, selecting a * reasonable default for the number of hashing rounds to apply - * + * * @return an encoded salt value */ public static String gensalt() { @@ -479,11 +457,9 @@ public class BCRYPT implements EncryptionMethod { /** * Check that a plaintext password matches a previously hashed one - * - * @param plaintext - * the plaintext password to verify - * @param hashed - * the previously-hashed password + * + * @param plaintext the plaintext password to verify + * @param hashed the previously-hashed password * @return true if the passwords match, false otherwise */ public static boolean checkpw(String plaintext, String hashed) { @@ -494,12 +470,9 @@ public class BCRYPT implements EncryptionMethod { * Check that a text password matches a previously hashed one with the * specified number of rounds using recursion * - * @param text - * plaintext or hashed text - * @param hashed - * the previously-hashed password - * @param rounds - * number of rounds to hash the password + * @param text plaintext or hashed text + * @param hashed the previously-hashed password + * @param rounds number of rounds to hash the password * @return */ public static boolean checkpw(String text, String hashed, int rounds) { @@ -528,7 +501,7 @@ public class BCRYPT implements EncryptionMethod { @Override public boolean comparePassword(String hash, String password, - String playerName) throws NoSuchAlgorithmException { + String playerName) throws NoSuchAlgorithmException { return checkpw(password, hash); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java index fc9986649..c1e119a30 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java @@ -1,10 +1,10 @@ package fr.xephi.authme.security.crypts; -import java.security.NoSuchAlgorithmException; - import fr.xephi.authme.security.pbkdf2.PBKDF2Engine; import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters; + import javax.xml.bind.DatatypeConverter; +import java.security.NoSuchAlgorithmException; public class CryptPBKDF2Django implements EncryptionMethod { @@ -20,7 +20,7 @@ public class CryptPBKDF2Django implements EncryptionMethod { @Override public boolean comparePassword(String hash, String password, - String playerName) throws NoSuchAlgorithmException { + String playerName) throws NoSuchAlgorithmException { String[] line = hash.split("\\$"); String salt = line[2]; byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]); From b1276da4166906961591a7abca3f0713872bb44e Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 09:18:30 +0700 Subject: [PATCH 091/115] protect inventory only for registered player --- .../xephi/authme/cache/limbo/LimboCache.java | 8 ++-- .../authme/process/join/AsyncronousJoin.java | 47 +++++++++---------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index b158a8ccf..366bc60af 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -17,14 +17,14 @@ import java.util.concurrent.ConcurrentHashMap; public class LimboCache { - private volatile static LimboCache singleton = null; + private volatile static LimboCache singleton; public ConcurrentHashMap cache; private JsonCache playerData; public AuthMe plugin; private LimboCache(AuthMe plugin) { this.plugin = plugin; - this.cache = new ConcurrentHashMap(); + this.cache = new ConcurrentHashMap<>(); this.playerData = new JsonCache(plugin); } @@ -77,7 +77,7 @@ public class LimboCache { } if (Settings.isForceSurvivalModeEnabled) { - if (Settings.isResetInventoryIfCreative && player.getGameMode() == GameMode.CREATIVE) { + if (Settings.isResetInventoryIfCreative && gameMode == GameMode.CREATIVE) { ResetInventoryEvent event = new ResetInventoryEvent(player); Bukkit.getServer().getPluginManager().callEvent(event); if (!event.isCancelled()) { @@ -123,7 +123,7 @@ public class LimboCache { if (this.hasLimboPlayer(player.getName().toLowerCase())) { this.deleteLimboPlayer(player.getName().toLowerCase()); } - this.addLimboPlayer(player); + addLimboPlayer(player); } } diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index b6362624a..7099486be 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -127,11 +127,28 @@ public class AsyncronousJoin { } placePlayerSafely(player, spawnLoc); LimboCache.getInstance().updateLimboPlayer(player); - try { - DataFileCache dataFile = new DataFileCache(LimboCache.getInstance().getLimboPlayer(name).getInventory(), LimboCache.getInstance().getLimboPlayer(name).getArmour()); - playerBackup.createCache(player, dataFile); - } catch (Exception e) { - ConsoleLogger.showError("Error on creating an inventory cache for " + name + ", maybe inventory wipe in preparation..."); + DataFileCache dataFile = new DataFileCache(LimboCache.getInstance().getLimboPlayer(name).getInventory(), LimboCache.getInstance().getLimboPlayer(name).getArmour()); + playerBackup.createCache(player, dataFile); + // protect inventory + if (Settings.protectInventoryBeforeLogInEnabled) { + LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); + ProtectInventoryEvent ev = new ProtectInventoryEvent(player, limbo.getInventory(), limbo.getArmour()); + plugin.getServer().getPluginManager().callEvent(ev); + if (ev.isCancelled()) { + if (!Settings.noConsoleSpam) + ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + " ..."); + } else { + final ItemStack[] inv = ev.getEmptyArmor(); + final ItemStack[] armor = ev.getEmptyArmor(); + sched.scheduleSyncDelayedTask(plugin, new Runnable() { + + @Override + public void run() { + plugin.api.setPlayerInventory(player, inv, armor); + } + + }); + } } } else { if (Settings.isForceSurvivalModeEnabled && !Settings.forceOnlyAfterLogin) { @@ -171,26 +188,6 @@ public class AsyncronousJoin { } } - if (Settings.protectInventoryBeforeLogInEnabled) { - LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); - ProtectInventoryEvent ev = new ProtectInventoryEvent(player, limbo.getInventory(), limbo.getArmour()); - plugin.getServer().getPluginManager().callEvent(ev); - if (ev.isCancelled()) { - if (!Settings.noConsoleSpam) - ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + " ..."); - } else { - final ItemStack[] inv = ev.getEmptyArmor(); - final ItemStack[] armor = ev.getEmptyArmor(); - sched.scheduleSyncDelayedTask(plugin, new Runnable() { - - @Override - public void run() { - plugin.api.setPlayerInventory(player, inv, armor); - } - - }); - } - } String[] msg; if (Settings.emailRegistration) { msg = database.isAuthAvailable(name) ? m.send("login_msg") : m.send("reg_email_msg"); From 4288fa29b676237cc35649e27b902621bc43fbf6 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 09:26:29 +0700 Subject: [PATCH 092/115] update --- src/main/java/fr/xephi/authme/cache/backup/JsonCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 13c1777a1..b4198c48e 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -187,7 +187,7 @@ public class JsonCache { for (int i = 0; i < arr.size(); i++) { JsonObject item = arr.get(i).getAsJsonObject(); String encoded = item.get("item").getAsString(); - byte[] decoded = Base64Coder.decode(encoded); + byte[] decoded = Base64Coder.decodeLines(encoded); try { ByteArrayInputStream baos = new ByteArrayInputStream(decoded); BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos); From e1893ce85b1b2d9adcb9a4b6fa4c6ff3645f5f9e Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 11:42:41 +0700 Subject: [PATCH 093/115] ups, forgot to put inventory. --- src/main/java/fr/xephi/authme/cache/backup/JsonCache.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index b4198c48e..018e6ba20 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -106,6 +106,7 @@ public class JsonCache { contents = dataFileCache.getInventory(); arr = new JsonArray(); putItems(contents, arr); + jsonObject.add("inventory", arr); // armour contents = dataFileCache.getArmour(); From 4e275eeb1d979b7ec42ddd5e7b315b16b104701a Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 14:11:17 +0700 Subject: [PATCH 094/115] change Utils to static class. --- src/main/java/fr/xephi/authme/AuthMe.java | 5 +- src/main/java/fr/xephi/authme/Utils.java | 29 ++++------ src/main/java/fr/xephi/authme/api/API.java | 7 +-- src/main/java/fr/xephi/authme/api/NewAPI.java | 5 +- .../xephi/authme/commands/AdminCommand.java | 2 +- .../authme/commands/UnregisterCommand.java | 4 +- .../authme/listener/AuthMeBlockListener.java | 4 +- .../listener/AuthMeChestShopListener.java | 2 +- .../authme/listener/AuthMeEntityListener.java | 15 +++-- .../authme/listener/AuthMePlayerListener.java | 57 +++++++++---------- .../authme/process/join/AsyncronousJoin.java | 9 ++- .../login/ProcessSyncronousPlayerLogin.java | 4 +- .../process/logout/AsyncronousLogout.java | 3 +- .../authme/process/quit/AsyncronousQuit.java | 5 +- .../ProcessSyncronousEmailRegister.java | 2 +- .../ProcessSyncronousPasswordRegister.java | 25 ++++---- 16 files changed, 79 insertions(+), 99 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 6be444cd6..c6385f3e1 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -57,7 +57,6 @@ public class AuthMe extends JavaPlugin { private final Logger authmeLogger = Logger.getLogger("AuthMe"); public Management management; public NewAPI api; - private Utils utils = Utils.getInstance(); public SendMailSSL mail; private Settings settings; private Messages m; @@ -535,7 +534,7 @@ public class AuthMe extends JavaPlugin { // Save Player Data public void savePlayer(Player player) { - if ((utils.isNPC(player)) || (Utils.getInstance().isUnrestricted(player))) { + if ((Utils.isNPC(player)) || (Utils.isUnrestricted(player))) { return; } String name = player.getName().toLowerCase(); @@ -552,7 +551,7 @@ public class AuthMe extends JavaPlugin { if (!Settings.noTeleport) { player.teleport(limbo.getLoc()); } - this.utils.addNormal(player, limbo.getGroup()); + Utils.addNormal(player, limbo.getGroup()); player.setOp(limbo.getOperator()); limbo.getTimeoutTaskId().cancel(); LimboCache.getInstance().deleteLimboPlayer(name); diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index b0feda6bb..88b6d9d2d 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -21,16 +21,12 @@ import java.util.Iterator; public class Utils { private static boolean getOnlinePlayersIsCollection; - private String currentGroup; private static Utils singleton; private static Method getOnlinePlayers; - public final AuthMe plugin; - - public Utils(AuthMe plugin) { - this.plugin = plugin; - } + public static AuthMe plugin; static { + plugin = AuthMe.getInstance(); try { Method m = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); getOnlinePlayersIsCollection = m.getReturnType() == Collection.class; @@ -38,17 +34,18 @@ public class Utils { } } - public void setGroup(Player player, GroupType group) { + public static void setGroup(Player player, GroupType group) { setGroup(player.getName(), group); } @SuppressWarnings("deprecation") - public void setGroup(String player, GroupType group) { + public static void setGroup(String player, GroupType group) { if (!Settings.isPermissionCheckEnabled) return; if (plugin.permission == null) return; String name = player; + String currentGroup; try { World world = null; currentGroup = plugin.permission.getPrimaryGroup(world, name); @@ -88,11 +85,10 @@ public class Utils { break; } } - return; } @SuppressWarnings("deprecation") - public boolean addNormal(Player player, String group) { + public static boolean addNormal(Player player, String group) { if (!useGroupSystem()) { return false; } @@ -123,20 +119,15 @@ public class Utils { } } - public boolean isUnrestricted(Player player) { + public static boolean isUnrestricted(Player player) { return Settings.isAllowRestrictedIp && !(Settings.getUnrestrictedName == null || Settings.getUnrestrictedName.isEmpty()) && (Settings.getUnrestrictedName.contains(player.getName())); } - public static Utils getInstance() { - singleton = new Utils(AuthMe.getInstance()); - return singleton; - } - - private boolean useGroupSystem() { + private static boolean useGroupSystem() { return Settings.isPermissionCheckEnabled && !Settings.getUnloggedinGroup.isEmpty(); } - public void packCoords(double x, double y, double z, String w, + public static void packCoords(double x, double y, double z, String w, final Player pl) { World theWorld; if (w.equals("unavailableworld")) { @@ -216,7 +207,7 @@ public class Utils { return Collections.emptyList(); } - public boolean isNPC(final Entity player) { + public static boolean isNPC(final Entity player) { try { if (player.hasMetadata("NPC")) { return true; diff --git a/src/main/java/fr/xephi/authme/api/API.java b/src/main/java/fr/xephi/authme/api/API.java index 026a9577a..11eba8613 100644 --- a/src/main/java/fr/xephi/authme/api/API.java +++ b/src/main/java/fr/xephi/authme/api/API.java @@ -19,7 +19,6 @@ public class API { public static final String newline = System.getProperty("line.separator"); public static AuthMe instance; - private Utils utils = Utils.getInstance(); @Deprecated public API(AuthMe instance) { @@ -65,7 +64,7 @@ public class API { */ @Deprecated public boolean isaNPC(Player player) { - return utils.isNPC(player); + return Utils.isNPC(player); } /** @@ -75,7 +74,7 @@ public class API { */ @Deprecated public boolean isNPC(Player player) { - return utils.isNPC(player); + return Utils.isNPC(player); } /** @@ -85,7 +84,7 @@ public class API { */ @Deprecated public static boolean isUnrestricted(Player player) { - return Utils.getInstance().isUnrestricted(player); + return Utils.isUnrestricted(player); } @Deprecated diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index b31f9ab28..937a8abe3 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -22,7 +22,6 @@ public class NewAPI { public static final String newline = System.getProperty("line.separator"); public static NewAPI singleton; public AuthMe plugin; - private Utils utils = Utils.getInstance(); public NewAPI(AuthMe plugin) { this.plugin = plugin; @@ -68,7 +67,7 @@ public class NewAPI { * @return true if player is a npc */ public boolean isNPC(Player player) { - return utils.isNPC(player); + return Utils.isNPC(player); } /** @@ -77,7 +76,7 @@ public class NewAPI { * @return true if the player is unrestricted */ public boolean isUnrestricted(Player player) { - return Utils.getInstance().isUnrestricted(player); + return Utils.isUnrestricted(player); } public Location getLastLocation(Player player) { diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 569088b31..0376f12e9 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -464,7 +464,7 @@ public class AdminCommand implements CommandExecutor { @SuppressWarnings("deprecation") Player target = Bukkit.getPlayer(name); PlayerCache.getInstance().removePlayer(name); - Utils.getInstance().setGroup(name, GroupType.UNREGISTERED); + Utils.setGroup(name, GroupType.UNREGISTERED); if (target != null) { if (target.isOnline()) { if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { diff --git a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java index 6d8196e5f..ce02aee6b 100644 --- a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java +++ b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java @@ -84,7 +84,7 @@ public class UnregisterCommand implements CommandExecutor { player.saveData(); PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); if (!Settings.getRegisteredGroup.isEmpty()) - Utils.getInstance().setGroup(player, GroupType.UNREGISTERED); + Utils.setGroup(player, GroupType.UNREGISTERED); LimboCache.getInstance().addLimboPlayer(player); int delay = Settings.getRegistrationTimeout * 20; int interval = Settings.getWarnMessageInterval; @@ -99,7 +99,7 @@ public class UnregisterCommand implements CommandExecutor { return; } if (!Settings.unRegisteredGroup.isEmpty()) { - Utils.getInstance().setGroup(player, Utils.GroupType.UNREGISTERED); + Utils.setGroup(player, Utils.GroupType.UNREGISTERED); } PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); // check if Player cache File Exist and delete it, preventing diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java index d6c64582b..e6903ce34 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java @@ -28,7 +28,7 @@ public class AuthMeBlockListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } @@ -53,7 +53,7 @@ public class AuthMeBlockListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java index bafa9c4c2..3577dc341 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java @@ -28,7 +28,7 @@ public class AuthMeChestShopListener implements Listener { Player player = event.getClient(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index e1bfea52b..f85e24971 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -14,7 +14,6 @@ import org.bukkit.event.entity.*; public class AuthMeEntityListener implements Listener { public AuthMe instance; - private Utils utils = Utils.getInstance(); public AuthMeEntityListener(AuthMe instance) { this.instance = instance; @@ -28,11 +27,11 @@ public class AuthMeEntityListener implements Listener { return; } - if (Utils.getInstance().isUnrestricted((Player) entity)) { + if (Utils.isUnrestricted((Player) entity)) { return; } - if (utils.isNPC(entity)) + if (Utils.isNPC(entity)) return; Player player = (Player) entity; @@ -61,7 +60,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (utils.isNPC(entity)) + if (Utils.isNPC(entity)) return; Player player = (Player) entity; @@ -111,7 +110,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (utils.isNPC(entity)) + if (Utils.isNPC(entity)) return; Player player = (Player) entity; @@ -138,7 +137,7 @@ public class AuthMeEntityListener implements Listener { return; } - if (utils.isNPC(entity)) + if (Utils.isNPC(entity)) return; Player player = (Player) entity; @@ -167,7 +166,7 @@ public class AuthMeEntityListener implements Listener { Player player = (Player) event.getEntity(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player) || utils.isNPC(player)) + if (Utils.isUnrestricted(player) || Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName())) { @@ -191,7 +190,7 @@ public class AuthMeEntityListener implements Listener { Player player = (Player) event.getEntity(); String name = player.getName().toLowerCase(); - if (Utils.getInstance().isUnrestricted(player) || utils.isNPC(player)) + if (Utils.isUnrestricted(player) || Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName())) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 93884b283..afd1b0858 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -39,7 +39,6 @@ public class AuthMePlayerListener implements Listener { public static ConcurrentHashMap joinMessage = new ConcurrentHashMap<>(); private Messages m = Messages.getInstance(); public AuthMe plugin; - private Utils utils = Utils.getInstance(); public static ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap<>(); private List antibot = new ArrayList<>(); @@ -55,7 +54,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) + if (Utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -89,7 +88,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) + if (Utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -125,7 +124,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) + if (Utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -161,7 +160,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) + if (Utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -197,7 +196,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) + if (Utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -233,7 +232,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) + if (Utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) { @@ -270,7 +269,7 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); final String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) + if (Utils.isUnrestricted(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -305,7 +304,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isNPC(player) || utils.isUnrestricted(player)) { + if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { return; } @@ -423,7 +422,7 @@ public class AuthMePlayerListener implements Listener { public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); if (limbo != null && PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - utils.addNormal(player, limbo.getGroup()); + Utils.addNormal(player, limbo.getGroup()); LimboCache.getInstance().deleteLimboPlayer(player.getName().toLowerCase()); } } @@ -440,7 +439,7 @@ public class AuthMePlayerListener implements Listener { final String name = player.getName().toLowerCase(); boolean isAuthAvailable = plugin.database.isAuthAvailable(name); - if (utils.isNPC(player) || utils.isUnrestricted(player)) { + if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { return; } @@ -604,11 +603,11 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } - if (utils.isNPC(player)) + if (Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) { @@ -632,11 +631,11 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } - if (utils.isNPC(player)) + if (Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { @@ -663,11 +662,11 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } - if (utils.isNPC(player)) { + if (Utils.isNPC(player)) { return; } @@ -690,10 +689,10 @@ public class AuthMePlayerListener implements Listener { return; final Player player = (Player) event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } - if (utils.isNPC(player)) + if (Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { return; @@ -728,11 +727,11 @@ public class AuthMePlayerListener implements Listener { Player player = (Player) event.getWhoClicked(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } - if (utils.isNPC(player)) + if (Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { @@ -758,11 +757,11 @@ public class AuthMePlayerListener implements Listener { Player player = (Player) damager; String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } - if (utils.isNPC(player)) { + if (Utils.isNPC(player)) { return; } @@ -786,7 +785,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isNPC(player) || utils.isUnrestricted(player)) { + if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { return; } @@ -810,7 +809,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player) || utils.isNPC(player)) + if (Utils.isUnrestricted(player) || Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { @@ -833,7 +832,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } @@ -856,7 +855,7 @@ public class AuthMePlayerListener implements Listener { } Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player)) { + if (Utils.isUnrestricted(player)) { return; } if (PlayerCache.getInstance().isAuthenticated(name)) { @@ -879,7 +878,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player) || utils.isNPC(player)) + if (Utils.isUnrestricted(player) || Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) @@ -911,7 +910,7 @@ public class AuthMePlayerListener implements Listener { String name = player.getName().toLowerCase(); - if (utils.isUnrestricted(player) || utils.isNPC(player)) + if (Utils.isUnrestricted(player) || Utils.isNPC(player)) return; if (PlayerCache.getInstance().isAuthenticated(name)) diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index 7099486be..dbe71d20d 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -38,7 +38,6 @@ public class AsyncronousJoin { protected DataSource database; protected AuthMe plugin; protected String name; - private Utils utils = Utils.getInstance(); private Messages m = Messages.getInstance(); private JsonCache playerBackup; @@ -56,7 +55,7 @@ public class AsyncronousJoin { AuthMePlayerListener.gameMode.putIfAbsent(name, player.getGameMode()); BukkitScheduler sched = plugin.getServer().getScheduler(); - if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player)) { + if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { return; } @@ -163,7 +162,7 @@ public class AsyncronousJoin { }); } if (!Settings.unRegisteredGroup.isEmpty()) { - utils.setGroup(player, Utils.GroupType.UNREGISTERED); + Utils.setGroup(player, Utils.GroupType.UNREGISTERED); } if (!Settings.isForcedRegistrationEnabled) { return; @@ -205,9 +204,9 @@ public class AsyncronousJoin { if (!LimboCache.getInstance().hasLimboPlayer(name)) LimboCache.getInstance().addLimboPlayer(player); if (database.isAuthAvailable(name)) { - utils.setGroup(player, GroupType.NOTLOGGEDIN); + Utils.setGroup(player, GroupType.NOTLOGGEDIN); } else { - utils.setGroup(player, GroupType.UNREGISTERED); + Utils.setGroup(player, GroupType.UNREGISTERED); } sched.scheduleSyncDelayedTask(plugin, new Runnable() { diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index 2ad48153e..2f70bfcfc 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -63,7 +63,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { } protected void packQuitLocation() { - Utils.getInstance().packCoords(auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getWorld(), player); + Utils.packCoords(auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getWorld(), player); } protected void teleportBackFromSpawn() { @@ -166,7 +166,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { Utils.forceGM(player); // Restore Permission Group - Utils.getInstance().setGroup(player, GroupType.LOGGEDIN); + Utils.setGroup(player, GroupType.LOGGEDIN); // Cleanup no longer used temporary data LimboCache.getInstance().deleteLimboPlayer(name); diff --git a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java index 1f44b3a3e..d1f890ad4 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsyncronousLogout.java @@ -25,7 +25,6 @@ public class AsyncronousLogout { protected DataSource database; protected boolean canLogout = true; private Messages m = Messages.getInstance(); - private Utils utils = Utils.getInstance(); private JsonCache playerBackup; public AsyncronousLogout(Player player, AuthMe plugin, @@ -79,7 +78,7 @@ public class AsyncronousLogout { if (LimboCache.getInstance().hasLimboPlayer(name)) LimboCache.getInstance().deleteLimboPlayer(name); LimboCache.getInstance().addLimboPlayer(player); - utils.setGroup(player, GroupType.NOTLOGGEDIN); + Utils.setGroup(player, GroupType.NOTLOGGEDIN); if (Settings.protectInventoryBeforeLogInEnabled) { player.getInventory().clear(); // create cache file for handling lost of inventories on unlogged in diff --git a/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java index 9a05229a9..da594606b 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsyncronousQuit.java @@ -22,7 +22,6 @@ public class AsyncronousQuit { protected AuthMe plugin; protected DataSource database; protected Player player; - protected Utils utils = Utils.getInstance(); private String name; private ItemStack[] armor = null; private ItemStack[] inv = null; @@ -43,7 +42,7 @@ public class AsyncronousQuit { public void process() { if (player == null) return; - if (utils.isNPC(player) || Utils.getInstance().isUnrestricted(player)) { + if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { return; } @@ -66,7 +65,7 @@ public class AsyncronousQuit { armor = limbo.getArmour(); } if (limbo.getGroup() != null && !limbo.getGroup().equals("")) - utils.addNormal(player, limbo.getGroup()); + Utils.addNormal(player, limbo.getGroup()); needToChange = true; isOp = limbo.getOperator(); isFlying = limbo.isFlying(); diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java index 64eec84db..280daa295 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousEmailRegister.java @@ -31,7 +31,7 @@ public class ProcessSyncronousEmailRegister implements Runnable { public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); if (!Settings.getRegisteredGroup.isEmpty()) { - Utils.getInstance().setGroup(player, Utils.GroupType.REGISTERED); + Utils.setGroup(player, Utils.GroupType.REGISTERED); } m.send(player, "vb_nonActiv"); int time = Settings.getRegistrationTimeout * 20; diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java index 60e1f9def..409895d43 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java @@ -1,13 +1,5 @@ package fr.xephi.authme.process.register; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; @@ -21,6 +13,13 @@ import fr.xephi.authme.settings.Messages; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.TimeoutTask; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; public class ProcessSyncronousPasswordRegister implements Runnable { @@ -39,7 +38,7 @@ public class ProcessSyncronousPasswordRegister implements Runnable { for (String command : Settings.forceRegisterCommands) { try { player.performCommand(command.replace("%p", player.getName())); - } catch (Exception e) { + } catch (Exception ignored) { } } for (String command : Settings.forceRegisterCommandsAsConsole) { @@ -71,10 +70,8 @@ public class ProcessSyncronousPasswordRegister implements Runnable { } BukkitTask msgT = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.send("login_msg"), interval)); LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgT); - try { - if (player.isInsideVehicle()) - player.getVehicle().eject(); - } catch (NullPointerException npe) { + if (player.isInsideVehicle() && player.getVehicle() != null) { + player.getVehicle().eject(); } } @@ -108,7 +105,7 @@ public class ProcessSyncronousPasswordRegister implements Runnable { } if (!Settings.getRegisteredGroup.isEmpty()) { - Utils.getInstance().setGroup(player, Utils.GroupType.REGISTERED); + Utils.setGroup(player, Utils.GroupType.REGISTERED); } m.send(player, "registered"); if (!Settings.getmailAccount.isEmpty()) From 22638c29e5c9e08b1dcef7a64cc7bc1c688197cb Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 14:26:46 +0700 Subject: [PATCH 095/115] update logger --- .../java/fr/xephi/authme/ConsoleLogger.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index f33ff1527..befffc68b 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -8,19 +8,24 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Logger; public class ConsoleLogger { private static final Logger log = AuthMe.getInstance().getLogger(); - + private static final DateFormat df = new SimpleDateFormat("[MM-dd HH:mm:ss]"); public static void info(String message) { if (AuthMe.getInstance().isEnabled()) { log.info("[AuthMe] " + message); if (Settings.useLogging) { - writeLog("[" + DateFormat.getDateTimeInstance().format(new Date()) + "] " + message); + String dateTime; + synchronized (df) { + dateTime = df.format(new Date()); + } + writeLog(dateTime + " " + message); } } } @@ -29,7 +34,11 @@ public class ConsoleLogger { if (AuthMe.getInstance().isEnabled()) { log.warning("[AuthMe] " + message); if (Settings.useLogging) { - writeLog("[" + DateFormat.getDateTimeInstance().format(new Date()) + "] ERROR: " + message); + String dateTime; + synchronized (df) { + dateTime = df.format(new Date()); + } + writeLog(dateTime + " ERROR: " + message); } } } @@ -44,6 +53,10 @@ public class ConsoleLogger { } public static void writeStackTrace(Exception ex) { - writeLog(Throwables.getStackTraceAsString(ex)); + String dateTime; + synchronized (df) { + dateTime = df.format(new Date()); + } + writeLog(dateTime + " " + Throwables.getStackTraceAsString(ex)); } } From 314fb011051e81d1774f26006f41fc445bb73b22 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 14:46:03 +0700 Subject: [PATCH 096/115] store isAuthAvailable into local variable. improve performance when cache is not enabled. --- .../authme/process/join/AsyncronousJoin.java | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index dbe71d20d..0302e06f4 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -94,7 +94,8 @@ public class AsyncronousJoin { } } final Location spawnLoc = plugin.getSpawnLocation(player); - if (database.isAuthAvailable(name)) { + final boolean isAuthAvailable = database.isAuthAvailable(name); + if (isAuthAvailable) { if (Settings.isForceSurvivalModeEnabled && !Settings.forceOnlyAfterLogin) { sched.scheduleSyncDelayedTask(plugin, new Runnable() { @@ -170,7 +171,6 @@ public class AsyncronousJoin { if (!Settings.noTeleport) if (!needFirstspawn() && Settings.isTeleportToSpawnEnabled || (Settings.isForceSpawnLocOnJoinEnabled && Settings.getForcedWorlds.contains(player.getWorld().getName()))) { sched.scheduleSyncDelayedTask(plugin, new Runnable() { - @Override public void run() { SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawnLoc, PlayerCache.getInstance().isAuthenticated(name)); @@ -189,9 +189,9 @@ public class AsyncronousJoin { } String[] msg; if (Settings.emailRegistration) { - msg = database.isAuthAvailable(name) ? m.send("login_msg") : m.send("reg_email_msg"); + msg = isAuthAvailable ? m.send("login_msg") : m.send("reg_email_msg"); } else { - msg = database.isAuthAvailable(name) ? m.send("login_msg") : m.send("reg_msg"); + msg = isAuthAvailable ? m.send("login_msg") : m.send("reg_msg"); } int time = Settings.getRegistrationTimeout * 20; int msgInterval = Settings.getWarnMessageInterval; @@ -203,7 +203,7 @@ public class AsyncronousJoin { } if (!LimboCache.getInstance().hasLimboPlayer(name)) LimboCache.getInstance().addLimboPlayer(player); - if (database.isAuthAvailable(name)) { + if (isAuthAvailable) { Utils.setGroup(player, GroupType.NOTLOGGEDIN); } else { Utils.setGroup(player, GroupType.UNREGISTERED); @@ -230,7 +230,7 @@ public class AsyncronousJoin { } }); - if (Settings.isSessionsEnabled && database.isAuthAvailable(name) && (PlayerCache.getInstance().isAuthenticated(name) || database.isLogged(name))) { + if (Settings.isSessionsEnabled && isAuthAvailable && (PlayerCache.getInstance().isAuthenticated(name) || database.isLogged(name))) { if (plugin.sessions.containsKey(name)) plugin.sessions.get(name).cancel(); plugin.sessions.remove(name); @@ -252,28 +252,27 @@ public class AsyncronousJoin { } private boolean needFirstspawn() { - if (database.isAuthAvailable(player.getName().toLowerCase()) && player.hasPlayedBefore()) + if (player.hasPlayedBefore()) return false; - else { - if (Spawn.getInstance().getFirstSpawn() == null || Spawn.getInstance().getFirstSpawn().getWorld() == null) - return false; - FirstSpawnTeleportEvent tpEvent = new FirstSpawnTeleportEvent(player, player.getLocation(), Spawn.getInstance().getFirstSpawn()); - plugin.getServer().getPluginManager().callEvent(tpEvent); - if (!tpEvent.isCancelled()) { - if (player.isOnline() && tpEvent.getTo() != null && tpEvent.getTo().getWorld() != null) { - final Location fLoc = tpEvent.getTo(); - Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { + if (Spawn.getInstance().getFirstSpawn() == null || Spawn.getInstance().getFirstSpawn().getWorld() == null) + return false; + FirstSpawnTeleportEvent tpEvent = new FirstSpawnTeleportEvent(player, player.getLocation(), Spawn.getInstance().getFirstSpawn()); + plugin.getServer().getPluginManager().callEvent(tpEvent); + if (!tpEvent.isCancelled()) { + if (player.isOnline() && tpEvent.getTo() != null && tpEvent.getTo().getWorld() != null) { + final Location fLoc = tpEvent.getTo(); + Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { - @Override - public void run() { - player.teleport(fLoc); - } + @Override + public void run() { + player.teleport(fLoc); + } - }); - } + }); } - return true; } + return true; + } private void placePlayerSafely(final Player player, @@ -285,7 +284,7 @@ public class AsyncronousJoin { return; if (Settings.isTeleportToSpawnEnabled || (Settings.isForceSpawnLocOnJoinEnabled && Settings.getForcedWorlds.contains(player.getWorld().getName()))) return; - if (!database.isAuthAvailable(player.getName().toLowerCase()) || !player.hasPlayedBefore()) + if (!player.hasPlayedBefore()) return; Block b = player.getLocation().getBlock(); if (b.getType() == Material.PORTAL || b.getType() == Material.ENDER_PORTAL) { From ff1cc8c27dbef523fcd75e312d54023a07f13918 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 14:54:49 +0700 Subject: [PATCH 097/115] not needed, it does the same thing if event is cancelled --- .../java/fr/xephi/authme/listener/AuthMePlayerListener.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index afd1b0858..7402effeb 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -647,10 +647,6 @@ public class AuthMePlayerListener implements Listener { return; } } - if (event.getClickedBlock() != null) { - event.setUseInteractedBlock(org.bukkit.event.Event.Result.DENY); - } - event.setUseItemInHand(org.bukkit.event.Event.Result.DENY); event.setCancelled(true); } From 6babac98ebfdaa7c7bfc7c02d3f91b1faac8fb74 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 15:53:18 +0700 Subject: [PATCH 098/115] extract auth check into a method. --- .../authme/listener/AuthMePlayerListener.java | 514 +++--------------- 1 file changed, 66 insertions(+), 448 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 7402effeb..5bcad56da 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -46,24 +46,47 @@ public class AuthMePlayerListener implements Listener { this.plugin = plugin; } + private boolean checkAuth(Player player) { + if (player == null) return true; + String name = player.getName().toLowerCase(); + if (Utils.isUnrestricted(player)) { + return true; + } + if (PlayerCache.getInstance().isAuthenticated(name)) { + return true; + } + if (!plugin.database.isAuthAvailable(name)) { + if (!Settings.isForcedRegistrationEnabled) { + return true; + } + } + return false; + } + + private void handleChat(AsyncPlayerChatEvent event) { + Player player = event.getPlayer(); + if (!checkAuth(player)) { + String cmd = event.getMessage().split(" ")[0]; + if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { + event.setCancelled(true); + } + if (plugin.database.isAuthAvailable(player.getName().toLowerCase())) { + m.send(player, "login_msg"); + } else { + if (Settings.emailRegistration) { + m.send(player, "reg_email_msg"); + } else { + m.send(player, "reg_msg"); + } + } + } + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (event.getPlayer() == null) + if (checkAuth(event.getPlayer())) return; - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - if (!plugin.database.isAuthAvailable(name)) - if (!Settings.isForcedRegistrationEnabled) - return; - String msg = event.getMessage(); if (msg.equalsIgnoreCase("/worldedit cui")) return; @@ -82,240 +105,39 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) public void onPlayerNormalChat(AsyncPlayerChatEvent event) { - if (event.getPlayer() == null) - return; - - final Player player = event.getPlayer(); - final String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - String cmd = event.getMessage().split(" ")[0]; - - if (plugin.database.isAuthAvailable(name)) { - m.send(player, "login_msg"); - } else { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - if (Settings.emailRegistration) { - m.send(player, "reg_email_msg"); - return; - } else { - m.send(player, "reg_msg"); - return; - } - } - - if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { - event.setCancelled(true); - } + handleChat(event); } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) public void onPlayerHighChat(AsyncPlayerChatEvent event) { - if (event.getPlayer() == null) - return; - - final Player player = event.getPlayer(); - final String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - String cmd = event.getMessage().split(" ")[0]; - - if (plugin.database.isAuthAvailable(name)) { - m.send(player, "login_msg"); - } else { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - if (Settings.emailRegistration) { - m.send(player, "reg_email_msg"); - return; - } else { - m.send(player, "reg_msg"); - return; - } - } - - if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { - event.setCancelled(true); - } + handleChat(event); } @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlayerChat(AsyncPlayerChatEvent event) { - if (event.getPlayer() == null) - return; - - final Player player = event.getPlayer(); - final String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - String cmd = event.getMessage().split(" ")[0]; - - if (plugin.database.isAuthAvailable(name)) { - m.send(player, "login_msg"); - } else { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - if (Settings.emailRegistration) { - m.send(player, "reg_email_msg"); - return; - } else { - m.send(player, "reg_msg"); - return; - } - } - - if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { - event.setCancelled(true); - } + handleChat(event); } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerHighestChat(AsyncPlayerChatEvent event) { - if (event.getPlayer() == null) - return; - - final Player player = event.getPlayer(); - final String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - String cmd = event.getMessage().split(" ")[0]; - - if (plugin.database.isAuthAvailable(name)) { - m.send(player, "login_msg"); - } else { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - if (Settings.emailRegistration) { - m.send(player, "reg_email_msg"); - return; - } else { - m.send(player, "reg_msg"); - return; - } - } - - if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { - event.setCancelled(true); - } + handleChat(event); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerEarlyChat(final AsyncPlayerChatEvent event) { - if (event.getPlayer() == null) - return; - - final Player player = event.getPlayer(); - final String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - String cmd = event.getMessage().split(" ")[0]; - - if (plugin.database.isAuthAvailable(name)) { - m.send(player, "login_msg"); - } else { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - if (Settings.emailRegistration) { - m.send(player, "reg_email_msg"); - return; - } else { - m.send(player, "reg_msg"); - return; - } - } - - if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { - event.setCancelled(true); - } + public void onPlayerEarlyChat(AsyncPlayerChatEvent event) { + handleChat(event); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) public void onPlayerLowChat(AsyncPlayerChatEvent event) { - if (event.getPlayer() == null) - return; - - final Player player = event.getPlayer(); - final String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - String cmd = event.getMessage().split(" ")[0]; - - if (plugin.database.isAuthAvailable(name)) { - m.send(player, "login_msg"); - } else { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - if (Settings.emailRegistration) { - m.send(player, "reg_email_msg"); - } else { - m.send(player, "reg_msg"); - } - } - - if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { - event.setCancelled(true); - } + handleChat(event); } @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlayerMove(PlayerMoveEvent event) { - if (event.getPlayer() == null) { - return; - } - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { + if (checkAuth(player)) return; - } - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - if (!Settings.isForcedRegistrationEnabled) { - if (!plugin.database.isAuthAvailable(name)) - return; - } if (!Settings.isMovementAllowed) { if (!event.getFrom().getBlock().equals(event.getTo().getBlock())) @@ -375,9 +197,7 @@ public class AuthMePlayerListener implements Listener { } @EventHandler(priority = EventPriority.HIGHEST) - public void onPlayerJoin(PlayerJoinEvent e) { - final PlayerJoinEvent event = e; - + public void onPlayerJoin(final PlayerJoinEvent event) { if (event.getPlayer() == null) { return; } @@ -464,7 +284,7 @@ public class AuthMePlayerListener implements Listener { } if (Settings.isKickNonRegisteredEnabled && !Settings.antiBotInAction) { - if (!plugin.database.isAuthAvailable(name)) { + if (!isAuthAvailable) { event.setKickMessage(m.send("reg_only")[0]); event.setResult(PlayerLoginEvent.Result.KICK_OTHER); return; @@ -472,14 +292,14 @@ public class AuthMePlayerListener implements Listener { } if (Settings.antiBotInAction) { - if (!plugin.database.isAuthAvailable(name)) { + if (!isAuthAvailable) { event.setKickMessage("AntiBot service in action! You actually need to be registered!"); event.setResult(PlayerLoginEvent.Result.KICK_OTHER); return; } } - if (plugin.database.isAuthAvailable(name) && plugin.database.getType() != DataSource.DataSourceType.FILE) { + if (isAuthAvailable && plugin.database.getType() != DataSource.DataSourceType.FILE) { PlayerAuth auth = plugin.database.getAuth(name); if (auth.getRealName() != null && !auth.getRealName().isEmpty() && !auth.getRealName().equalsIgnoreCase("Player") && !auth.getRealName().equals(player.getName())) { event.setKickMessage(m.send("same_nick")[0]); @@ -575,7 +395,7 @@ public class AuthMePlayerListener implements Listener { plugin.management.performQuit(player, false); - if (plugin.database.getAuth(name) != null && !PlayerCache.getInstance().isAuthenticated(name) && Settings.enableProtection) + if (plugin.database.isAuthAvailable(name) && !PlayerCache.getInstance().isAuthenticated(name) && Settings.enableProtection) event.setQuitMessage(null); } @@ -596,108 +416,30 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerPickupItem(PlayerPickupItemEvent event) { - if (event.getPlayer() == null) { + if (checkAuth(event.getPlayer())) return; - } - - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { - return; - } - - if (Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } - event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) public void onPlayerInteract(PlayerInteractEvent event) { - if (event.getPlayer() == null) + if (checkAuth(event.getPlayer())) return; - - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { - return; - } - - if (Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } @EventHandler(priority = EventPriority.NORMAL) public void onPlayerConsumeItem(PlayerItemConsumeEvent event) { - if (event.getPlayer() == null) + if (checkAuth(event.getPlayer())) return; - - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { - return; - } - - if (Utils.isNPC(player)) { - return; - } - - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } - event.setCancelled(true); } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerInventoryOpen(InventoryOpenEvent event) { - if (event.getPlayer() == null) - return; final Player player = (Player) event.getPlayer(); - String name = player.getName().toLowerCase(); - if (Utils.isUnrestricted(player)) { + if (checkAuth(player)) return; - } - if (Utils.isNPC(player)) - return; - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); /* @@ -720,25 +462,8 @@ public class AuthMePlayerListener implements Listener { return; if (!(event.getWhoClicked() instanceof Player)) return; - Player player = (Player) event.getWhoClicked(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { + if (checkAuth((Player) event.getWhoClicked())) return; - } - - if (Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setResult(org.bukkit.event.Event.Result.DENY); event.setCancelled(true); } @@ -749,141 +474,46 @@ public class AuthMePlayerListener implements Listener { if (!(damager instanceof Player)) { return; } - - Player player = (Player) damager; - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { + if (checkAuth((Player) damager)) return; - } - - if (Utils.isNPC(player)) { - return; - } - - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - - if (!plugin.database.isAuthAvailable(name) && !Settings.isForcedRegistrationEnabled) { - return; - } event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { - if (event.getPlayer() == null) { + if (checkAuth(event.getPlayer())) return; - } - - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { - return; - } - - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerDropItem(PlayerDropItemEvent event) { - if (event.getPlayer() == null) { + if (checkAuth(event.getPlayer())) return; - } - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player) || Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerBedEnter(PlayerBedEnterEvent event) { - if (event.getPlayer() == null) { + if (checkAuth(event.getPlayer())) return; - } - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { - return; - } - - if (PlayerCache.getInstance().isAuthenticated(player.getName().toLowerCase())) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onSignChange(SignChangeEvent event) { - if (event.getPlayer() == null) { + if (checkAuth(event.getPlayer())) return; - } - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - if (Utils.isUnrestricted(player)) { - return; - } - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerRespawn(PlayerRespawnEvent event) { - if (event.getPlayer() == null) { - return; - } - Player player = event.getPlayer(); + if (checkAuth(player)) + return; String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player) || Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - if (!plugin.database.isAuthAvailable(name)) - if (!Settings.isForcedRegistrationEnabled) - return; - Location spawn = plugin.getSpawnLocation(player); if (Settings.isSaveQuitLocationEnabled && plugin.database.isAuthAvailable(name)) { final PlayerAuth auth = new PlayerAuth(name, spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getWorld().getName(), player.getName()); @@ -896,31 +526,19 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) { - if (event.getPlayer() == null) - return; - Player player = event.getPlayer(); - + if (player == null) + return; if (plugin.authmePermissible(player, "authme.bypassforcesurvival")) return; + if (checkAuth(player)) + return; String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player) || Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(name)) - return; - - if (!plugin.database.isAuthAvailable(name)) - if (!Settings.isForcedRegistrationEnabled) - return; - if (causeByAuthMe.containsKey(name)) { causeByAuthMe.remove(name); return; } - event.setCancelled(true); } } From 297e41e9bd828c0ccababb6fda60ee5f5c56c4bd Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 15:54:37 +0700 Subject: [PATCH 099/115] cleanup --- src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 5bcad56da..717022104 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -464,7 +464,6 @@ public class AuthMePlayerListener implements Listener { return; if (checkAuth((Player) event.getWhoClicked())) return; - event.setResult(org.bukkit.event.Event.Result.DENY); event.setCancelled(true); } From ec1e0527ec438349f83ba90983f5f6565523fdc8 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 15:58:16 +0700 Subject: [PATCH 100/115] sneaky plugin message --- .../authme/listener/AuthMePlayerListener.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 717022104..3c67085ce 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -1,5 +1,8 @@ package fr.xephi.authme.listener; +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.Utils; @@ -349,14 +352,9 @@ public class AuthMePlayerListener implements Listener { if (event.getResult() == PlayerLoginEvent.Result.ALLOWED) { checkAntiBotMod(player); if (Settings.bungee) { - try { - final ByteArrayOutputStream b = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(b); - out.writeUTF("IP"); - player.sendPluginMessage(plugin, "BungeeCord", b.toByteArray()); - } catch (IOException e) { - ConsoleLogger.writeStackTrace(e); - } + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("IP"); + player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); } return; } From 23e16bb7179277a6ae52d73895991ff056ea71bc Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 20 Sep 2015 12:08:24 +0200 Subject: [PATCH 101/115] Fix fly speed --- src/main/java/fr/xephi/authme/Utils.java | 1 - .../java/fr/xephi/authme/listener/AuthMePlayerListener.java | 4 ---- .../authme/process/login/ProcessSyncronousPlayerLogin.java | 2 +- .../process/register/ProcessSyncronousPasswordRegister.java | 2 +- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 88b6d9d2d..9951de5b4 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -21,7 +21,6 @@ import java.util.Iterator; public class Utils { private static boolean getOnlinePlayersIsCollection; - private static Utils singleton; private static Method getOnlinePlayers; public static AuthMe plugin; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 3c67085ce..9d53fb7c7 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -1,6 +1,5 @@ package fr.xephi.authme.listener; -import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; import fr.xephi.authme.AuthMe; @@ -27,9 +26,6 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.*; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index 2f70bfcfc..c0f05c22b 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -188,7 +188,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { player.removePotionEffect(PotionEffectType.BLINDNESS); if (!Settings.isMovementAllowed) { player.setWalkSpeed(0.2f); - player.setFlySpeed(0.4f); + player.setFlySpeed(0.1f); } // The Loginevent now fires (as intended) after everything is processed diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java index 409895d43..d5573c27f 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java @@ -118,7 +118,7 @@ public class ProcessSyncronousPasswordRegister implements Runnable { player.removePotionEffect(PotionEffectType.BLINDNESS); if (!Settings.isMovementAllowed) { player.setWalkSpeed(0.2f); - player.setFlySpeed(0.4f); + player.setFlySpeed(0.1f); } // The Loginevent now fires (as intended) after everything is processed Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); From d8267777012a23c5cb9046d39a1d99108d15d080 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 20 Sep 2015 13:41:06 +0200 Subject: [PATCH 102/115] remove speed option + config description enhancements --- .../xephi/authme/commands/AdminCommand.java | 2 +- .../authme/commands/UnregisterCommand.java | 2 +- .../login/ProcessSyncronousPlayerLogin.java | 2 +- .../logout/ProcessSyncronousPlayerLogout.java | 6 +- .../ProcessSyncronousPasswordRegister.java | 2 +- .../fr/xephi/authme/settings/Settings.java | 9 +- src/main/resources/config.yml | 97 ++++++++++--------- 7 files changed, 65 insertions(+), 55 deletions(-) diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index 0376f12e9..d3b9b6bb4 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -486,7 +486,7 @@ public class AdminCommand implements CommandExecutor { LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.send("reg_msg"), interval))); if (Settings.applyBlindEffect) target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); - if (!Settings.isMovementAllowed) { + if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { target.setWalkSpeed(0.0f); target.setFlySpeed(0.0f); } diff --git a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java index ce02aee6b..814757e1c 100644 --- a/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java +++ b/src/main/java/fr/xephi/authme/commands/UnregisterCommand.java @@ -109,7 +109,7 @@ public class UnregisterCommand implements CommandExecutor { } if (Settings.applyBlindEffect) player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); - if (!Settings.isMovementAllowed) { + if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { player.setWalkSpeed(0.0f); player.setFlySpeed(0.0f); } diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index c0f05c22b..a94375e0b 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -186,7 +186,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { if (Settings.applyBlindEffect) player.removePotionEffect(PotionEffectType.BLINDNESS); - if (!Settings.isMovementAllowed) { + if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { player.setWalkSpeed(0.2f); player.setFlySpeed(0.1f); } diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java index f78685b09..e2a96b0e7 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java @@ -54,8 +54,10 @@ public class ProcessSyncronousPlayerLogout implements Runnable { if (!Settings.isMovementAllowed) { player.setAllowFlight(true); player.setFlying(true); - player.setFlySpeed(0.0f); - player.setWalkSpeed(0.0f); + if (Settings.isRemoveSpeedEnabled) { + player.setFlySpeed(0.0f); + player.setWalkSpeed(0.0f); + } } // Player is now logout... Time to fire event ! Bukkit.getServer().getPluginManager().callEvent(new LogoutEvent(player)); diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java index d5573c27f..553e536d2 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java @@ -116,7 +116,7 @@ public class ProcessSyncronousPasswordRegister implements Runnable { } if (Settings.applyBlindEffect) player.removePotionEffect(PotionEffectType.BLINDNESS); - if (!Settings.isMovementAllowed) { + if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { player.setWalkSpeed(0.2f); player.setFlySpeed(0.1f); } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 0b923314b..f3f437be6 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -67,7 +67,7 @@ public final class Settings extends YamlConfiguration { enableProtection, enableAntiBot, recallEmail, useWelcomeMessage, broadcastWelcomeMessage, forceRegKick, forceRegLogin, checkVeryGames, delayJoinMessage, noTeleport, applyBlindEffect, - customAttributes, generateImage; + customAttributes, generateImage, isRemoveSpeedEnabled; public static String getNickRegex, getUnloggedinGroup, getMySQLHost, getMySQLPort, getMySQLUsername, getMySQLPassword, getMySQLDatabase, @@ -136,6 +136,7 @@ public final class Settings extends YamlConfiguration { isAllowRestrictedIp = configFile.getBoolean("settings.restrictions.AllowRestrictedUser", false); getRestrictedIp = configFile.getStringList("settings.restrictions.AllowedRestrictedUser"); isMovementAllowed = configFile.getBoolean("settings.restrictions.allowMovement", false); + isRemoveSpeedEnabled = configFile.getBoolean("settings.restrictions.removeSpeed", true); getMovementRadius = configFile.getInt("settings.restrictions.allowedMovementRadius", 100); getJoinPermissions = configFile.getStringList("GroupOptions.Permissions.PermissionsOnJoin"); isKickOnWrongPasswordEnabled = configFile.getBoolean("settings.restrictions.kickOnWrongPassword", false); @@ -225,7 +226,7 @@ public final class Settings extends YamlConfiguration { getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds"); banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false); doubleEmailCheck = configFile.getBoolean("settings.registration.doubleEmailCheck", false); - sessionExpireOnIpChange = configFile.getBoolean("settings.sessions.sessionExpireOnIpChange", false); + sessionExpireOnIpChange = configFile.getBoolean("settings.sessions.sessionExpireOnIpChange", true); useLogging = configFile.getBoolean("Security.console.logConsole", false); disableSocialSpy = configFile.getBoolean("Hooks.disableSocialSpy", true); bCryptLog2Rounds = configFile.getInt("ExternalBoardOptions.bCryptLog2Round", 10); @@ -294,6 +295,10 @@ public final class Settings extends YamlConfiguration { set("Protection.enableProtection", false); changes = true; } + if (!contains("settings.restrictions.removeSpeed")) { + set("settings.restrictions.removeSpeed", true); + changes = true; + } if (!contains("DataSource.mySQLMaxConections")) { set("DataSource.mySQLMaxConections", 25); changes = true; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b183912e8..19753d809 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,6 +1,7 @@ DataSource: + # What type of database do you want to use? # Can be set to: sqlite, sqlitehikari, mysql - # sqlitehikari should be more fast than normal sqlite but it's an experimental feature! + # (sqlitehikari should be more fast than normal sqlite but it's an experimental feature!) backend: sqlite # Enable database caching caching: true @@ -44,24 +45,28 @@ DataSource: mySQLRealName: realname settings: sessions: - # Do you want to enable session? When enabled - # the ip of a player will be bound to the nickname - # of the player on login. As long as neither of those - # two change players don't have to login on a reconnect + # Do you want to enable the session feature? + # If enabled, when a player authenticates successfully, + # his IP and his nickname is saved. + # The next time the player joins the server, if his IP + # is the same of the last time, and the timeout time + # hasn't expired, he will not need to authenticate. enabled: false - # After how many minutes a session should timeout? - # 0 for unlimitted sessions, use 0 at your own risk! - # consider that session will end only after timeout, and - # if player's ip is changed but the timeout treshould isent - # ended, player will kick out of sever for invalidSession! + # After how many minutes a session should expire? + # 0 for unlimited time (Very dangerous, use it at your own risk!) + # Consider that session will end only after the timeout time, and + # if the player's ip has changed but the timeout hasn't expired, + # player will be kicked out of sever due to invalidSession! timeout: 10 - # Do we need to timeout the session if the player is offline - # And try to login with an another IP Address? - sessionExpireOnIpChange: false + # Should the session expire if the player try to login with an + # another IP Address? + sessionExpireOnIpChange: true restrictions: - # Can unregistered/unlogged players chat and see chat, care , that block all commands except followers + # Can not authenticated players chat and see the chat log? + # Care that this feature blocks also all the commands not + # listed in the list below. allowChat: false - # Commands allowed when a player is unlogged + # Commands allowed when a player is not authenticated allowCommands: - /login - /register @@ -69,54 +74,52 @@ settings: - /reg - /email - /captcha - # Maximum Registration per IP default: 1 + # Max number of allowed registrations per IP (default: 1) maxRegPerIp: 1 - # Max allowed nick length + # Max allowed username length maxNicknameLength: 16 - # Player that is online arent - # kick out for "logged in from another - # Location", this options will prevent players that would exploit - # your account when you are playing + # When this setting is enabled, online players can't be kicked out + # due to "Logged in from another Location" + # This setting will prevent potetial security exploits. ForceSingleSession: true - # Teleport every time player join at World Spawn location, - # even if they loggedin successfully, - # all quit and previus location will - # overwrite with World Spawn. Different From - # "teleportUnAuthedToSpawn" - # that teleport player back to his quit or kick position, - # when he loggedin + # If enabled, every player will be teleported to the world spawnpoint + # after successful authentication. + # The quit location of the player will be overwritten. + # This is different from "teleportUnAuthedToSpawn" that teleport player + # back to his quit location after the authentication. ForceSpawnLocOnJoinEnabled: false - # This will prevent all lost of quit position, when player - # isent loggedin + # This option will save the quit location of the players. SaveQuitLocation: false - # For activate Restricted user by ip u need - # to set True this option and configure the field - # AllowedRestrctedUser as show below + # To activate the restricted user feature you need + # to enable this option and configure the + # AllowedRestrctedUser field. AllowRestrictedUser: false - # Restricted user will kick players that - # is listed below and they dont - # meet the match of username;ip - # Example playername;127.0.0.1 , if playername - # hasent 127.0.0.1 as ip address - # he will not be allowed to join the server + # The restricted user feature will kick players listed below + # if they dont match of the defined ip address. + # Example: + # AllowedRestrictedUser: + # - playername;127.0.0.1 AllowedRestrictedUser: - playername;127.0.0.1 # Should unregistered players be kicked immediatly? kickNonRegistered: false - # Should fail password players be kicked immediatly? + # Should players be kicked on wrong password? kickOnWrongPassword: false - # should not loged in players be teleported to spawn? - # On login they will be teleported back to their normal - # position + # Should not logged in players be teleported to the spawn? + # After the authentication they will be teleported back to + # their normal position. teleportUnAuthedToSpawn: false - # min allowed nick length + # Minimum allowed nick length minNicknameLength: 4 # Can unregistered players walk around? allowMovement: false - # After what time players who fail to login or register - # should be kicked. Set to 0 to disable. + # Should not authenticated players have speed = 0? + # This will reset the fly/walk speed to default value after the login. + removeSpeed: true + # After how many time players who fail to login or register + # should be kicked? Set to 0 to disable. timeout: 30 - # Regex sintax for allowed Char in player name. + # Regex sintax of allowed characters in the player name. allowedNicknameCharacters: '[a-zA-Z0-9_]*' # How far can unregistered players walk? Set to 0 # for unlimited radius From b27079026b1b1455dc395c8e40dced362023b895 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 16:06:56 +0700 Subject: [PATCH 103/115] use guava's bytestream --- .../plugin/manager/BungeeCordMessage.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/java/fr/xephi/authme/plugin/manager/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/plugin/manager/BungeeCordMessage.java index b10140775..598147384 100644 --- a/src/main/java/fr/xephi/authme/plugin/manager/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/plugin/manager/BungeeCordMessage.java @@ -1,14 +1,11 @@ package fr.xephi.authme.plugin.manager; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; - +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteStreams; +import fr.xephi.authme.AuthMe; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; -import fr.xephi.authme.AuthMe; - public class BungeeCordMessage implements PluginMessageListener { public AuthMe plugin; @@ -19,19 +16,16 @@ public class BungeeCordMessage implements PluginMessageListener { @Override public void onPluginMessageReceived(String channel, Player player, - byte[] message) { + byte[] message) { if (!channel.equals("BungeeCord")) { return; } - try { - final DataInputStream in = new DataInputStream(new ByteArrayInputStream(message)); - String subchannel = in.readUTF(); - if (subchannel.equals("IP")) { // We need only the IP channel - String ip = in.readUTF(); - plugin.realIp.put(player.getName().toLowerCase(), ip); - // Put the IP (only the ip not the port) in the hashmap - } - } catch (IOException ex) { + ByteArrayDataInput in = ByteStreams.newDataInput(message); + String subChannel = in.readUTF(); + if (subChannel.equals("IP")) { // We need only the IP channel + String ip = in.readUTF(); + // Put the IP (only the ip not the port) in the hashMap + plugin.realIp.put(player.getName().toLowerCase(), ip); } } From c94f9c5cdc800dd7f2a78ddfa44b54cd74489841 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 19:38:46 +0700 Subject: [PATCH 104/115] update to use the new vault API --- src/main/java/fr/xephi/authme/Utils.java | 51 ++++++++----------- .../xephi/authme/commands/AdminCommand.java | 2 +- .../login/ProcessSyncronousPlayerLogin.java | 23 +++------ .../ProcessSyncronousPasswordRegister.java | 8 +-- 4 files changed, 33 insertions(+), 51 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 9951de5b4..2ebb65373 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -16,7 +16,6 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; public class Utils { @@ -34,68 +33,58 @@ public class Utils { } public static void setGroup(Player player, GroupType group) { - setGroup(player.getName(), group); - } - - @SuppressWarnings("deprecation") - public static void setGroup(String player, GroupType group) { if (!Settings.isPermissionCheckEnabled) return; if (plugin.permission == null) return; - String name = player; String currentGroup; try { - World world = null; - currentGroup = plugin.permission.getPrimaryGroup(world, name); + currentGroup = plugin.permission.getPrimaryGroup(player); } catch (UnsupportedOperationException e) { ConsoleLogger.showError("Your permission plugin (" + plugin.permission.getName() + ") doesn't support the Group system... unhook!"); plugin.permission = null; return; } - World world = null; switch (group) { case UNREGISTERED: { - plugin.permission.playerRemoveGroup(world, name, currentGroup); - plugin.permission.playerAddGroup(world, name, Settings.unRegisteredGroup); + plugin.permission.playerRemoveGroup(player, currentGroup); + plugin.permission.playerAddGroup(player, Settings.unRegisteredGroup); break; } case REGISTERED: { - plugin.permission.playerRemoveGroup(world, name, currentGroup); - plugin.permission.playerAddGroup(world, name, Settings.getRegisteredGroup); + plugin.permission.playerRemoveGroup(player, currentGroup); + plugin.permission.playerAddGroup(player, Settings.getRegisteredGroup); break; } case NOTLOGGEDIN: { if (!useGroupSystem()) break; - plugin.permission.playerRemoveGroup(world, name, currentGroup); - plugin.permission.playerAddGroup(world, name, Settings.getUnloggedinGroup); + plugin.permission.playerRemoveGroup(player, currentGroup); + plugin.permission.playerAddGroup(player, Settings.getUnloggedinGroup); break; } case LOGGEDIN: { if (!useGroupSystem()) break; - LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name.toLowerCase()); + LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); if (limbo == null) break; String realGroup = limbo.getGroup(); - plugin.permission.playerRemoveGroup(world, name, currentGroup); - plugin.permission.playerAddGroup(world, name, realGroup); + plugin.permission.playerRemoveGroup(player, currentGroup); + plugin.permission.playerAddGroup(player, realGroup); break; } } } - @SuppressWarnings("deprecation") public static boolean addNormal(Player player, String group) { if (!useGroupSystem()) { return false; } if (plugin.permission == null) return false; - World world = null; try { - if (plugin.permission.playerRemoveGroup(world, player.getName().toString(), Settings.getUnloggedinGroup) && plugin.permission.playerAddGroup(world, player.getName().toString(), group)) { + if (plugin.permission.playerRemoveGroup(player, Settings.getUnloggedinGroup) && plugin.permission.playerAddGroup(player, group)) { return true; } } catch (UnsupportedOperationException e) { @@ -106,12 +95,12 @@ public class Utils { return false; } - public void hasPermOnJoin(Player player) { + // TODO: remove if not needed + @SuppressWarnings("unused") + public static void hasPermOnJoin(Player player) { if (plugin.permission == null) return; - Iterator iter = Settings.getJoinPermissions.iterator(); - while (iter.hasNext()) { - String permission = iter.next(); + for (String permission : Settings.getJoinPermissions) { if (plugin.permission.playerHas(player, permission)) { plugin.permission.playerAddTransient(player, permission); } @@ -127,7 +116,7 @@ public class Utils { } public static void packCoords(double x, double y, double z, String w, - final Player pl) { + final Player pl) { World theWorld; if (w.equals("unavailableworld")) { theWorld = pl.getWorld(); @@ -158,7 +147,7 @@ public class Utils { * Used for force player GameMode */ public static void forceGM(Player player) { - if (!AuthMe.getInstance().authmePermissible(player, "authme.bypassforcesurvival")) + if (!plugin.authmePermissible(player, "authme.bypassforcesurvival")) player.setGameMode(GameMode.SURVIVAL); } @@ -178,7 +167,7 @@ public class Utils { return; } for (File target : files) { - if(target.isDirectory()) { + if (target.isDirectory()) { purgeDirectory(target); target.delete(); } else { @@ -210,8 +199,8 @@ public class Utils { try { if (player.hasMetadata("NPC")) { return true; - } else if(plugin.combatTagPlus != null - && player instanceof Player + } else if (plugin.combatTagPlus != null + && player instanceof Player && plugin.combatTagPlus.getNpcPlayerHelper().isNpc((Player) player)) { return true; } diff --git a/src/main/java/fr/xephi/authme/commands/AdminCommand.java b/src/main/java/fr/xephi/authme/commands/AdminCommand.java index d3b9b6bb4..7a562ea50 100644 --- a/src/main/java/fr/xephi/authme/commands/AdminCommand.java +++ b/src/main/java/fr/xephi/authme/commands/AdminCommand.java @@ -464,7 +464,7 @@ public class AdminCommand implements CommandExecutor { @SuppressWarnings("deprecation") Player target = Bukkit.getPlayer(name); PlayerCache.getInstance().removePlayer(name); - Utils.setGroup(name, GroupType.UNREGISTERED); + Utils.setGroup(target, GroupType.UNREGISTERED); if (target != null) { if (target.isOnline()) { if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index a94375e0b..28f9a861b 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -103,7 +103,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable { for (String command : Settings.forceCommands) { try { player.performCommand(command.replace("%p", player.getName())); - } catch (Exception e) { + } catch (Exception ignored) { } } for (String command : Settings.forceCommandsAsConsole) { @@ -125,20 +125,13 @@ public class ProcessSyncronousPlayerLogin implements Runnable { * world inventory ! */ player.setGameMode(limbo.getGameMode()); - if (!Settings.forceOnlyAfterLogin) { - // Inventory - Make it after restore GameMode , cause we need to - // restore the - // right inventory in the right gamemode - if (Settings.protectInventoryBeforeLogInEnabled && player.hasPlayedBefore()) { - restoreInventory(); - } - } else { - // Inventory - Make it before force the survival GameMode to - // cancel all - // inventory problem - if (Settings.protectInventoryBeforeLogInEnabled && player.hasPlayedBefore()) { - restoreInventory(); - } + // Inventory - Make it after restore GameMode , cause we need to + // restore the + // right inventory in the right gamemode + if (Settings.protectInventoryBeforeLogInEnabled && player.hasPlayedBefore()) { + restoreInventory(); + } + if (Settings.forceOnlyAfterLogin) { player.setGameMode(GameMode.SURVIVAL); } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java index 553e536d2..5a7a13532 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncronousPasswordRegister.java @@ -120,8 +120,8 @@ public class ProcessSyncronousPasswordRegister implements Runnable { player.setWalkSpeed(0.2f); player.setFlySpeed(0.1f); } - // The Loginevent now fires (as intended) after everything is processed - Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); + // The LoginEvent now fires (as intended) after everything is processed + plugin.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); player.saveData(); if (!Settings.noConsoleSpam) @@ -133,7 +133,7 @@ public class ProcessSyncronousPasswordRegister implements Runnable { return; } - // Request Login after Registation + // Request Login after Registration if (Settings.forceRegLogin) { forceLogin(player); return; @@ -143,7 +143,7 @@ public class ProcessSyncronousPasswordRegister implements Runnable { if (Settings.useWelcomeMessage) if (Settings.broadcastWelcomeMessage) { for (String s : Settings.welcomeMsg) { - Bukkit.getServer().broadcastMessage(plugin.replaceAllInfos(s, player)); + plugin.getServer().broadcastMessage(plugin.replaceAllInfos(s, player)); } } else { for (String s : Settings.welcomeMsg) { From 14f187c32dbf393508b36fb0720f1d87afe11166 Mon Sep 17 00:00:00 2001 From: DNx Date: Sun, 20 Sep 2015 20:15:36 +0700 Subject: [PATCH 105/115] start working on modules --- src/main/java/fr/xephi/authme/AuthMe.java | 27 +++++++++++++------ .../java/fr/xephi/authme/modules/Module.java | 24 +++++++---------- .../xephi/authme/modules/ModuleManager.java | 20 +++++++++++--- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index c6385f3e1..0cf325976 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -15,6 +15,7 @@ import fr.xephi.authme.converter.Converter; import fr.xephi.authme.converter.ForceFlatToSqlite; import fr.xephi.authme.datasource.*; import fr.xephi.authme.listener.*; +import fr.xephi.authme.modules.ModuleManager; import fr.xephi.authme.plugin.manager.BungeeCordMessage; import fr.xephi.authme.plugin.manager.EssSpawn; import fr.xephi.authme.process.Management; @@ -24,7 +25,6 @@ import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; import net.milkbowl.vault.permission.Permission; import net.minelink.ctplus.CombatTagPlus; - import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -64,15 +64,22 @@ public class AuthMe extends JavaPlugin { public DataSource database; private JsonCache playerBackup; public OtherAccounts otherAccounts; - public Permission permission; - public Essentials ess; public Location essentialsSpawn; - public MultiverseCore multiverse; public LookupService lookupService; - public CombatTagPlus combatTagPlus = null; public boolean legacyChestShop = false; public boolean antibotMod = false; public boolean delayedAntiBot = true; + + // Hooks TODO: move into modules + public Permission permission; + public Essentials ess; + public MultiverseCore multiverse; + public CombatTagPlus combatTagPlus; + + // Manager + private ModuleManager moduleManager; + + // TODO: Create Manager for fields below public ConcurrentHashMap sessions = new ConcurrentHashMap<>(); public ConcurrentHashMap captcha = new ConcurrentHashMap<>(); public ConcurrentHashMap cap = new ConcurrentHashMap<>(); @@ -101,6 +108,9 @@ public class AuthMe extends JavaPlugin { authme = this; // TODO: split the plugin in more modules + moduleManager = new ModuleManager(this); + int loaded = moduleManager.loadModules(); + // TODO: remove vault as hard dependency PluginManager pm = server.getPluginManager(); @@ -312,16 +322,17 @@ public class AuthMe extends JavaPlugin { // Do backup on stop if enabled if (Settings.isBackupActivated && Settings.isBackupOnStop) { - Boolean Backup = new PerformBackup(this).doBackup(); + boolean Backup = new PerformBackup(this).doBackup(); if (Backup) ConsoleLogger.info("Backup performed correctly."); else ConsoleLogger.showError("Error while performing the backup!"); } + // Unload modules + moduleManager.unloadModules(); + // Disabled correctly ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!"); - - authme = null; } // Stop/unload the server/plugin as defined in the configuration diff --git a/src/main/java/fr/xephi/authme/modules/Module.java b/src/main/java/fr/xephi/authme/modules/Module.java index 6011097af..ab30e5ef9 100644 --- a/src/main/java/fr/xephi/authme/modules/Module.java +++ b/src/main/java/fr/xephi/authme/modules/Module.java @@ -1,28 +1,24 @@ package fr.xephi.authme.modules; -import fr.xephi.authme.AuthMe; +public abstract class Module { -public interface Module { - - public String getName(); - - public AuthMe getInstanceOfAuthMe(); - - public Module getInstance(); - - public enum ModuleType { + enum ModuleType { MANAGER, MYSQL, REDIS, ACTIONS, CONVERTERS, EMAILS, - CUSTOM; + CUSTOM } - public ModuleType getType(); + public abstract String getName(); - public boolean load(); + public abstract ModuleType getType(); - public boolean unload(); + public void load() { + } + + public void unload() { + } } diff --git a/src/main/java/fr/xephi/authme/modules/ModuleManager.java b/src/main/java/fr/xephi/authme/modules/ModuleManager.java index f3c7df3c4..32d4d1fa6 100644 --- a/src/main/java/fr/xephi/authme/modules/ModuleManager.java +++ b/src/main/java/fr/xephi/authme/modules/ModuleManager.java @@ -10,6 +10,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; +import java.util.Iterator; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -111,10 +112,23 @@ public class ModuleManager { return count; } + public void unloadModule(String name) { + Iterator it = modules.iterator(); + while (it.hasNext()) { + Module m = it.next(); + if (m.getName().equalsIgnoreCase(name)) { + m.unload(); + it.remove(); + return; + } + } + } + public void unloadModules() { - for (Module m : modules) { - m.unload(); - modules.remove(m); + Iterator it = modules.iterator(); + while (it.hasNext()) { + it.next().unload(); + it.remove(); } } From 2cea7387c986211ccc5034c88e9ed2443dec15b5 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 21:25:29 +0700 Subject: [PATCH 106/115] set all listeners to use checkAuth method. --- src/main/java/fr/xephi/authme/Utils.java | 18 +++ .../authme/listener/AuthMeBlockListener.java | 43 +------ .../listener/AuthMeChestShopListener.java | 20 +-- .../authme/listener/AuthMeEntityListener.java | 115 +++--------------- .../authme/listener/AuthMePlayerListener.java | 49 +++----- 5 files changed, 52 insertions(+), 193 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 2ebb65373..9540e448e 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -1,5 +1,6 @@ package fr.xephi.authme; +import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.events.AuthMeTeleportEvent; @@ -107,6 +108,23 @@ public class Utils { } } + // TODO: Move to a Manager + public static boolean checkAuth(Player player) { + if (player == null || Utils.isUnrestricted(player)) { + return true; + } + String name = player.getName().toLowerCase(); + if (PlayerCache.getInstance().isAuthenticated(name)) { + return true; + } + if (!plugin.database.isAuthAvailable(name)) { + if (!Settings.isForcedRegistrationEnabled) { + return true; + } + } + return false; + } + public static boolean isUnrestricted(Player player) { return Settings.isAllowRestrictedIp && !(Settings.getUnrestrictedName == null || Settings.getUnrestrictedName.isEmpty()) && (Settings.getUnrestrictedName.contains(player.getName())); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java index e6903ce34..ca5f68d31 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java @@ -2,9 +2,6 @@ package fr.xephi.authme.listener; import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.settings.Settings; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; @@ -21,51 +18,15 @@ public class AuthMeBlockListener implements Listener { @EventHandler(ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent event) { - if (event.getPlayer() == null) { + if (Utils.checkAuth(event.getPlayer())) return; - } - - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { - return; - } - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } @EventHandler(ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { - if (event.getPlayer() == null) { + if (Utils.checkAuth(event.getPlayer())) return; - } - - Player player = event.getPlayer(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { - return; - } - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java index 3577dc341..cf551a638 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java @@ -21,26 +21,8 @@ public class AuthMeChestShopListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPreTransaction(PreTransactionEvent event) { - if (event.getClient() == null) { + if (Utils.checkAuth(event.getClient())) return; - } - - Player player = event.getClient(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player)) { - return; - } - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(TransactionOutcome.OTHER); } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index f85e24971..109fe83d9 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -2,8 +2,6 @@ package fr.xephi.authme.listener; import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.settings.Settings; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -22,30 +20,15 @@ public class AuthMeEntityListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onEntityDamage(EntityDamageEvent event) { Entity entity = event.getEntity(); - - if (!(entity instanceof Player)) { + if (entity == null || !(entity instanceof Player)) { return; } - if (Utils.isUnrestricted((Player) entity)) { - return; - } - - if (Utils.isNPC(entity)) - return; - Player player = (Player) entity; - String name = player.getName().toLowerCase(); - - if (PlayerCache.getInstance().isAuthenticated(name)) { + if (Utils.checkAuth(player)) { return; } - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } player.setFireTicks(0); event.setDamage(0.0); event.setCancelled(true); @@ -53,28 +36,15 @@ public class AuthMeEntityListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onEntityTarget(EntityTargetEvent event) { - if (event.getTarget() == null) - return; Entity entity = event.getTarget(); - if (!(entity instanceof Player)) { + if (entity == null || !(entity instanceof Player)) { return; } - if (Utils.isNPC(entity)) - return; - - Player player = (Player) entity; - String name = player.getName().toLowerCase(); - - if (PlayerCache.getInstance().isAuthenticated(name)) { + if (Utils.checkAuth((Player) entity)) { return; } - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setTarget(null); event.setCancelled(true); } @@ -82,75 +52,40 @@ public class AuthMeEntityListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onDmg(EntityDamageByEntityEvent event) { Entity entity = event.getDamager(); - if (entity == null || !(entity instanceof Player)) { return; } - Player player = (Player) entity; - String name = player.getName().toLowerCase(); - - if (PlayerCache.getInstance().isAuthenticated(name)) { + if (Utils.checkAuth((Player) entity)) { return; } - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } - event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onFoodLevelChange(FoodLevelChangeEvent event) { Entity entity = event.getEntity(); - if (!(entity instanceof Player)) { + if (entity == null || !(entity instanceof Player)) { return; } - if (Utils.isNPC(entity)) + if (Utils.checkAuth((Player) entity)) { return; - - Player player = (Player) entity; - String name = player.getName().toLowerCase(); - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } } event.setCancelled(true); - } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void entityRegainHealthEvent(EntityRegainHealthEvent event) { Entity entity = event.getEntity(); - if (!(entity instanceof Player)) { + if (entity == null || !(entity instanceof Player)) { return; } - if (Utils.isNPC(entity)) + if (Utils.checkAuth((Player) entity)) { return; - - Player player = (Player) entity; - String name = player.getName().toLowerCase(); - - if (PlayerCache.getInstance().isAuthenticated(name)) { - return; - } - - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } } event.setAmount(0.0); @@ -159,49 +94,29 @@ public class AuthMeEntityListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onEntityInteract(EntityInteractEvent event) { - if (!(event.getEntity() instanceof Player)) { + Entity entity = event.getEntity(); + if (entity == null || !(entity instanceof Player)) { return; } - Player player = (Player) event.getEntity(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player) || Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(player.getName())) { + if (Utils.checkAuth((Player) entity)) { return; } - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onLowestEntityInteract(EntityInteractEvent event) { - if (!(event.getEntity() instanceof Player)) { + Entity entity = event.getEntity(); + if (entity == null || !(entity instanceof Player)) { return; } - Player player = (Player) event.getEntity(); - String name = player.getName().toLowerCase(); - - if (Utils.isUnrestricted(player) || Utils.isNPC(player)) - return; - - if (PlayerCache.getInstance().isAuthenticated(player.getName())) { + if (Utils.checkAuth((Player) entity)) { return; } - if (!instance.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return; - } - } event.setCancelled(true); } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 9d53fb7c7..390154e52 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -45,26 +45,9 @@ public class AuthMePlayerListener implements Listener { this.plugin = plugin; } - private boolean checkAuth(Player player) { - if (player == null) return true; - String name = player.getName().toLowerCase(); - if (Utils.isUnrestricted(player)) { - return true; - } - if (PlayerCache.getInstance().isAuthenticated(name)) { - return true; - } - if (!plugin.database.isAuthAvailable(name)) { - if (!Settings.isForcedRegistrationEnabled) { - return true; - } - } - return false; - } - private void handleChat(AsyncPlayerChatEvent event) { Player player = event.getPlayer(); - if (!checkAuth(player)) { + if (!Utils.checkAuth(player)) { String cmd = event.getMessage().split(" ")[0]; if (!Settings.isChatAllowed && !(Settings.allowCommands.contains(cmd))) { event.setCancelled(true); @@ -83,7 +66,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; String msg = event.getMessage(); @@ -135,7 +118,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); - if (checkAuth(player)) + if (Utils.checkAuth(player)) return; if (!Settings.isMovementAllowed) { @@ -410,21 +393,21 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerPickupItem(PlayerPickupItemEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } - @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerInteract(PlayerInteractEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } @EventHandler(priority = EventPriority.NORMAL) public void onPlayerConsumeItem(PlayerItemConsumeEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } @@ -432,7 +415,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerInventoryOpen(InventoryOpenEvent event) { final Player player = (Player) event.getPlayer(); - if (checkAuth(player)) + if (Utils.checkAuth(player)) return; event.setCancelled(true); @@ -456,7 +439,7 @@ public class AuthMePlayerListener implements Listener { return; if (!(event.getWhoClicked() instanceof Player)) return; - if (checkAuth((Player) event.getWhoClicked())) + if (Utils.checkAuth((Player) event.getWhoClicked())) return; event.setCancelled(true); } @@ -467,7 +450,7 @@ public class AuthMePlayerListener implements Listener { if (!(damager instanceof Player)) { return; } - if (checkAuth((Player) damager)) + if (Utils.checkAuth((Player) damager)) return; event.setCancelled(true); @@ -475,28 +458,28 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerDropItem(PlayerDropItemEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerBedEnter(PlayerBedEnterEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onSignChange(SignChangeEvent event) { - if (checkAuth(event.getPlayer())) + if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } @@ -504,7 +487,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerRespawn(PlayerRespawnEvent event) { Player player = event.getPlayer(); - if (checkAuth(player)) + if (Utils.checkAuth(player)) return; String name = player.getName().toLowerCase(); Location spawn = plugin.getSpawnLocation(player); @@ -524,7 +507,7 @@ public class AuthMePlayerListener implements Listener { return; if (plugin.authmePermissible(player, "authme.bypassforcesurvival")) return; - if (checkAuth(player)) + if (Utils.checkAuth(player)) return; String name = player.getName().toLowerCase(); From 878ab70c2fcaba170a546558fc674cb2a880825e Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 21:50:39 +0700 Subject: [PATCH 107/115] move GeoIP function into Utils --- src/main/java/fr/xephi/authme/AuthMe.java | 52 +-------------- src/main/java/fr/xephi/authme/Utils.java | 65 ++++++++++++++++++- .../authme/listener/AuthMePlayerListener.java | 4 +- .../authme/listener/AuthMeServerListener.java | 5 +- 4 files changed, 71 insertions(+), 55 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 0cf325976..737299d4f 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -175,7 +175,7 @@ public class AuthMe extends JavaPlugin { } // Download GeoIp.dat file - downloadGeoIp(); + Utils.checkGeoIP(); // Load MailApi if needed if (!Settings.getmailAccount.isEmpty() && !Settings.getmailPassword.isEmpty()) { @@ -673,54 +673,6 @@ public class AuthMe extends JavaPlugin { return player.getWorld().getSpawnLocation(); } - // Download GeoIp data - public void downloadGeoIp() { - ConsoleLogger.info("[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com"); - File file = new File(getDataFolder(), "GeoIP.dat"); - try { - if (file.exists()) { - if (lookupService == null) { - lookupService = new LookupService(file); - } - } else { - String url = "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"; - URL downloadUrl = new URL(url); - URLConnection conn = downloadUrl.openConnection(); - conn.setConnectTimeout(10000); - conn.connect(); - InputStream input = conn.getInputStream(); - if (url.endsWith(".gz")) { - input = new GZIPInputStream(input); - } - OutputStream output = new FileOutputStream(file); - byte[] buffer = new byte[2048]; - int length = input.read(buffer); - while (length >= 0) { - output.write(buffer, 0, length); - length = input.read(buffer); - } - output.close(); - input.close(); - } - } catch (Exception e) { - ConsoleLogger.writeStackTrace(e); - } - } - - public String getCountryCode(String ip) { - if (lookupService != null) { - return lookupService.getCountry(ip).getCode(); - } - return "--"; - } - - public String getCountryName(String ip) { - if (lookupService != null) { - return lookupService.getCountry(ip).getName(); - } - return "N/A"; - } - public void switchAntiBotMod(boolean mode) { this.antibotMod = mode; Settings.switchAntiBotMod(mode); @@ -759,7 +711,7 @@ public class AuthMe extends JavaPlugin { message = message.replace("{WORLD}", player.getWorld().getName()); message = message.replace("{SERVER}", server.getServerName()); message = message.replace("{VERSION}", server.getBukkitVersion()); - message = message.replace("{COUNTRY}", this.getCountryName(getIP(player))); + message = message.replace("{COUNTRY}", Utils.getCountryName(getIP(player))); return message; } diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index 9540e448e..bdd156ff2 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -1,5 +1,6 @@ package fr.xephi.authme; +import com.maxmind.geoip.LookupService; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; @@ -13,19 +14,28 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLConnection; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.zip.GZIPInputStream; public class Utils { + public static AuthMe plugin; + private static boolean getOnlinePlayersIsCollection; private static Method getOnlinePlayers; - public static AuthMe plugin; + private static LookupService lookupService; static { plugin = AuthMe.getInstance(); + checkGeoIP(); try { Method m = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); getOnlinePlayersIsCollection = m.getReturnType() == Collection.class; @@ -33,6 +43,59 @@ public class Utils { } } + // Check and Download GeoIP data if not exist + public static boolean checkGeoIP() { + if (lookupService != null) { + return true; + } + ConsoleLogger.info("[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com"); + File file = new File(Settings.PLUGIN_FOLDER, "GeoIP.dat"); + try { + if (file.exists()) { + if (lookupService == null) { + lookupService = new LookupService(file); + return true; + } + } + String url = "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"; + URL downloadUrl = new URL(url); + URLConnection conn = downloadUrl.openConnection(); + conn.setConnectTimeout(10000); + conn.connect(); + InputStream input = conn.getInputStream(); + if (conn.getURL().toString().endsWith(".gz")) { + input = new GZIPInputStream(input); + } + OutputStream output = new FileOutputStream(file); + byte[] buffer = new byte[2048]; + int length = input.read(buffer); + while (length >= 0) { + output.write(buffer, 0, length); + length = input.read(buffer); + } + output.close(); + input.close(); + } catch (Exception e) { + ConsoleLogger.writeStackTrace(e); + return false; + } + return checkGeoIP(); + } + + public static String getCountryCode(String ip) { + if (checkGeoIP()) { + return lookupService.getCountry(ip).getCode(); + } + return "--"; + } + + public static String getCountryName(String ip) { + if (checkGeoIP()) { + return lookupService.getCountry(ip).getName(); + } + return "N/A"; + } + public static void setGroup(Player player, GroupType group) { if (!Settings.isPermissionCheckEnabled) return; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 390154e52..b7723522e 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -249,7 +249,7 @@ public class AuthMePlayerListener implements Listener { return; if (!Settings.countriesBlacklist.isEmpty()) { - String code = plugin.getCountryCode(event.getAddress().getHostAddress()); + String code = Utils.getCountryCode(event.getAddress().getHostAddress()); if (((code == null) || (Settings.countriesBlacklist.contains(code) && !isAuthAvailable)) && !plugin.authmePermissible(player, "authme.bypassantibot")) { event.setKickMessage(m.send("country_banned")[0]); event.setResult(PlayerLoginEvent.Result.KICK_OTHER); @@ -257,7 +257,7 @@ public class AuthMePlayerListener implements Listener { } } if (Settings.enableProtection && !Settings.countries.isEmpty()) { - String code = plugin.getCountryCode(event.getAddress().getHostAddress()); + String code = Utils.getCountryCode(event.getAddress().getHostAddress()); if (((code == null) || (!Settings.countries.contains(code) && !isAuthAvailable)) && !plugin.authmePermissible(player, "authme.bypassantibot")) { event.setKickMessage(m.send("country_banned")[0]); event.setResult(PlayerLoginEvent.Result.KICK_OTHER); diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index 8e7960210..d13e87383 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -2,6 +2,7 @@ package fr.xephi.authme.listener; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.Utils; import fr.xephi.authme.settings.Messages; import fr.xephi.authme.settings.Settings; import org.bukkit.event.EventHandler; @@ -27,10 +28,10 @@ public class AuthMeServerListener implements Listener { if (Settings.countries.isEmpty()) return; if (!Settings.countriesBlacklist.isEmpty()) { - if (Settings.countriesBlacklist.contains(plugin.getCountryCode(event.getAddress().getHostAddress()))) + if (Settings.countriesBlacklist.contains(Utils.getCountryCode(event.getAddress().getHostAddress()))) event.setMotd(m.send("country_banned")[0]); } - if (Settings.countries.contains(plugin.getCountryCode(event.getAddress().getHostAddress()))) { + if (Settings.countries.contains(Utils.getCountryCode(event.getAddress().getHostAddress()))) { event.setMotd(plugin.getServer().getMotd()); } else { event.setMotd(m.send("country_banned")[0]); From 4b67cf961ccc8980e3e468140d8e2d8e65b7f078 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 20 Sep 2015 17:21:49 +0200 Subject: [PATCH 108/115] fix speed remover --- src/main/java/fr/xephi/authme/AuthMe.java | 1 - .../java/fr/xephi/authme/listener/AuthMeChestShopListener.java | 3 --- .../java/fr/xephi/authme/process/join/AsyncronousJoin.java | 2 +- .../authme/process/logout/ProcessSyncronousPlayerLogout.java | 2 +- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 737299d4f..170e6d7dc 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -47,7 +47,6 @@ import java.util.Date; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; -import java.util.zip.GZIPInputStream; public class AuthMe extends JavaPlugin { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java index cf551a638..476f25866 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeChestShopListener.java @@ -4,9 +4,6 @@ import com.Acrobot.ChestShop.Events.PreTransactionEvent; import com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome; import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.settings.Settings; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; diff --git a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java index 0302e06f4..4df4928e7 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsyncronousJoin.java @@ -223,7 +223,7 @@ public class AsyncronousJoin { player.performCommand("motd"); if (Settings.applyBlindEffect) player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); - if (!Settings.isMovementAllowed) { + if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { player.setWalkSpeed(0.0f); player.setFlySpeed(0.0f); } diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java index e2a96b0e7..e9efd847c 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java @@ -54,7 +54,7 @@ public class ProcessSyncronousPlayerLogout implements Runnable { if (!Settings.isMovementAllowed) { player.setAllowFlight(true); player.setFlying(true); - if (Settings.isRemoveSpeedEnabled) { + if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { player.setFlySpeed(0.0f); player.setWalkSpeed(0.0f); } From 5247b5aa2c391e302f85f2088b73311a54af1449 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 22:55:44 +0700 Subject: [PATCH 109/115] fix cache folder not removed --- src/main/java/fr/xephi/authme/cache/backup/JsonCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 018e6ba20..760def963 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -209,7 +209,7 @@ public class JsonCache { } catch (Exception | Error e) { path = player.getName().toLowerCase(); } - File file = new File(cacheDir, path + File.separator + "cache.json"); + File file = new File(cacheDir, path); if (file.exists()) { Utils.purgeDirectory(file); if (!file.delete()) { From accd209e84fe37af30f9afd17aee6d466571d134 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 22:58:54 +0700 Subject: [PATCH 110/115] add null check for vehicle --- .../process/logout/ProcessSyncronousPlayerLogout.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java index e9efd847c..96ea7e1f6 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java @@ -43,11 +43,8 @@ public class ProcessSyncronousPlayerLogout implements Runnable { } BukkitTask msgT = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.send("login_msg"), interval)); LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgT); - try { - if (player.isInsideVehicle()) - player.getVehicle().eject(); - } catch (NullPointerException npe) { - } + if (player.isInsideVehicle() && player.getVehicle() != null) + player.getVehicle().eject(); if (Settings.applyBlindEffect) player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); player.setOp(false); From b9dce03af52dc8a855237df9bb32cad7b2c189a7 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 20 Sep 2015 23:17:03 +0700 Subject: [PATCH 111/115] add ProjectileLaunch listener. --- .../authme/listener/AuthMeEntityListener.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 109fe83d9..7ace12c93 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -8,6 +8,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.*; +import org.bukkit.event.player.PlayerEggThrowEvent; public class AuthMeEntityListener implements Listener { @@ -119,4 +120,18 @@ public class AuthMeEntityListener implements Listener { event.setCancelled(true); } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onProjectileLaunch(ProjectileLaunchEvent event) { + Entity entity = (Entity) event.getEntity().getShooter(); + if (entity == null || !(entity instanceof Player)) { + return; + } + + if (Utils.checkAuth((Player) entity)) { + return; + } + + event.setCancelled(true); + } } From 490f9406c3eb0f3be9d157aaf20b487b627ce589 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 21 Sep 2015 00:15:05 +0700 Subject: [PATCH 112/115] added durability fix --- src/main/java/fr/xephi/authme/Utils.java | 16 ++++++++++ .../authme/listener/AuthMeBlockListener.java | 7 ++++- .../authme/listener/AuthMeEntityListener.java | 29 +++++++++++++++++-- .../authme/listener/AuthMePlayerListener.java | 29 +++++++++++++++++-- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index bdd156ff2..be103fa84 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -12,6 +12,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.io.File; import java.io.FileOutputStream; @@ -290,4 +291,19 @@ public class Utils { return false; } } + + public static void fixDurability(final ItemStack item) { + if (item == null || item.getType().getMaxDurability() == 0) + return; + final short old = item.getDurability(); + plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable() { + @Override + public void run() { + int diff = old - item.getDurability(); + if (diff != 0) { + item.setDurability((short) (item.getDurability() + diff)); + } + } + }, 1); + } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java index ca5f68d31..58a056830 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java @@ -2,10 +2,12 @@ package fr.xephi.authme.listener; import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; public class AuthMeBlockListener implements Listener { @@ -25,8 +27,11 @@ public class AuthMeBlockListener implements Listener { @EventHandler(ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { - if (Utils.checkAuth(event.getPlayer())) + Player player = event.getPlayer(); + if (player == null || Utils.checkAuth(player)) { return; + } + Utils.fixDurability(player.getItemInHand()); event.setCancelled(true); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 7ace12c93..ae8385881 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -8,7 +8,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.*; -import org.bukkit.event.player.PlayerEggThrowEvent; +import org.bukkit.inventory.ItemStack; public class AuthMeEntityListener implements Listener { @@ -29,7 +29,11 @@ public class AuthMeEntityListener implements Listener { if (Utils.checkAuth(player)) { return; } - + for (ItemStack item : player.getInventory().getArmorContents()) { + if (item != null) { + Utils.fixDurability(item); + } + } player.setFireTicks(0); event.setDamage(0.0); event.setCancelled(true); @@ -57,10 +61,12 @@ public class AuthMeEntityListener implements Listener { return; } - if (Utils.checkAuth((Player) entity)) { + Player player = (Player) entity; + if (Utils.checkAuth(player)) { return; } + Utils.fixDurability(player.getItemInHand()); event.setCancelled(true); } @@ -134,4 +140,21 @@ public class AuthMeEntityListener implements Listener { event.setCancelled(true); } + + @EventHandler + public void onShoot(EntityShootBowEvent event) { + Entity entity = event.getEntity(); + if (entity == null || !(entity instanceof Player)) { + return; + } + + Player player = (Player) entity; + if (Utils.checkAuth(player)) { + return; + } + + Utils.fixDurability(player.getItemInHand()); + event.setCancelled(true); + } + } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index b7723522e..ccb11a286 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -20,6 +20,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.inventory.InventoryClickEvent; @@ -400,8 +401,14 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerInteract(PlayerInteractEvent event) { - if (Utils.checkAuth(event.getPlayer())) + Player player = event.getPlayer(); + if (player == null || Utils.checkAuth(player)) return; + + if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Utils.fixDurability(player.getItemInHand()); + } + event.setCancelled(true); } @@ -487,7 +494,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerRespawn(PlayerRespawnEvent event) { Player player = event.getPlayer(); - if (Utils.checkAuth(player)) + if (player == null || Utils.checkAuth(player)) return; String name = player.getName().toLowerCase(); Location spawn = plugin.getSpawnLocation(player); @@ -517,4 +524,22 @@ public class AuthMePlayerListener implements Listener { } event.setCancelled(true); } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerShear(PlayerShearEntityEvent event) { + Player player = event.getPlayer(); + if (player == null || Utils.checkAuth(player)) + return; + Utils.fixDurability(player.getItemInHand()); + event.setCancelled(true); + } + + @EventHandler + public void onPlayerFish(PlayerFishEvent event) { + Player player = event.getPlayer(); + if (player == null || Utils.checkAuth(player)) + return; + Utils.fixDurability(player.getItemInHand()); + event.setCancelled(true); + } } From 365e23d863a0a706fa6994385fa746e901f21f3f Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 21 Sep 2015 00:44:40 +0700 Subject: [PATCH 113/115] show the name, not displayname --- src/main/java/fr/xephi/authme/Utils.java | 15 --------------- .../authme/listener/AuthMeEntityListener.java | 8 -------- .../authme/listener/AuthMePlayerListener.java | 8 -------- .../logout/ProcessSyncronousPlayerLogout.java | 2 +- 4 files changed, 1 insertion(+), 32 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index be103fa84..c814fd679 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -291,19 +291,4 @@ public class Utils { return false; } } - - public static void fixDurability(final ItemStack item) { - if (item == null || item.getType().getMaxDurability() == 0) - return; - final short old = item.getDurability(); - plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable() { - @Override - public void run() { - int diff = old - item.getDurability(); - if (diff != 0) { - item.setDurability((short) (item.getDurability() + diff)); - } - } - }, 1); - } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index ae8385881..46c924b9e 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -8,7 +8,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.*; -import org.bukkit.inventory.ItemStack; public class AuthMeEntityListener implements Listener { @@ -29,11 +28,6 @@ public class AuthMeEntityListener implements Listener { if (Utils.checkAuth(player)) { return; } - for (ItemStack item : player.getInventory().getArmorContents()) { - if (item != null) { - Utils.fixDurability(item); - } - } player.setFireTicks(0); event.setDamage(0.0); event.setCancelled(true); @@ -66,7 +60,6 @@ public class AuthMeEntityListener implements Listener { return; } - Utils.fixDurability(player.getItemInHand()); event.setCancelled(true); } @@ -153,7 +146,6 @@ public class AuthMeEntityListener implements Listener { return; } - Utils.fixDurability(player.getItemInHand()); event.setCancelled(true); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index ccb11a286..c275e9b8c 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -20,7 +20,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.inventory.InventoryClickEvent; @@ -404,11 +403,6 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); if (player == null || Utils.checkAuth(player)) return; - - if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Utils.fixDurability(player.getItemInHand()); - } - event.setCancelled(true); } @@ -530,7 +524,6 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); if (player == null || Utils.checkAuth(player)) return; - Utils.fixDurability(player.getItemInHand()); event.setCancelled(true); } @@ -539,7 +532,6 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); if (player == null || Utils.checkAuth(player)) return; - Utils.fixDurability(player.getItemInHand()); event.setCancelled(true); } } diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java index 96ea7e1f6..7c1992016 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java @@ -59,7 +59,7 @@ public class ProcessSyncronousPlayerLogout implements Runnable { // Player is now logout... Time to fire event ! Bukkit.getServer().getPluginManager().callEvent(new LogoutEvent(player)); m.send(player, "logout"); - ConsoleLogger.info(player.getDisplayName() + " logged out"); + ConsoleLogger.info(player.getName() + " logged out"); } } From dfe1074f657b029988e95c10b64da251430c6c8f Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 21 Sep 2015 00:45:37 +0700 Subject: [PATCH 114/115] revert fixdurability task. not necessary --- src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java index 58a056830..678fbca2b 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java @@ -7,7 +7,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.inventory.ItemStack; public class AuthMeBlockListener implements Listener { @@ -31,7 +30,6 @@ public class AuthMeBlockListener implements Listener { if (player == null || Utils.checkAuth(player)) { return; } - Utils.fixDurability(player.getItemInHand()); event.setCancelled(true); } From 837da9a0fa03e9c7a29c7d5e9c2c13676fe39b4a Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 21 Sep 2015 01:16:04 +0700 Subject: [PATCH 115/115] disabling protectInventory should be okay now --- src/main/java/fr/xephi/authme/Utils.java | 1 - .../authme/listener/AuthMeEntityListener.java | 11 +++++--- .../authme/listener/AuthMePlayerListener.java | 27 +++++++++++++++---- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/main/java/fr/xephi/authme/Utils.java b/src/main/java/fr/xephi/authme/Utils.java index c814fd679..bdd156ff2 100644 --- a/src/main/java/fr/xephi/authme/Utils.java +++ b/src/main/java/fr/xephi/authme/Utils.java @@ -12,7 +12,6 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; import java.io.File; import java.io.FileOutputStream; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 46c924b9e..da4b43ea2 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -4,6 +4,7 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.Utils; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -122,12 +123,16 @@ public class AuthMeEntityListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onProjectileLaunch(ProjectileLaunchEvent event) { - Entity entity = (Entity) event.getEntity().getShooter(); - if (entity == null || !(entity instanceof Player)) { + Projectile projectile = event.getEntity(); + if (projectile == null) + return; + + Entity shooter = (Entity) projectile.getShooter(); + if (shooter == null || !(shooter instanceof Player)) { return; } - if (Utils.checkAuth((Player) entity)) { + if (Utils.checkAuth((Player) shooter)) { return; } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index c275e9b8c..882ddcbde 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -406,14 +406,14 @@ public class AuthMePlayerListener implements Listener { event.setCancelled(true); } - @EventHandler(priority = EventPriority.NORMAL) + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) public void onPlayerConsumeItem(PlayerItemConsumeEvent event) { if (Utils.checkAuth(event.getPlayer())) return; event.setCancelled(true); } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerInventoryOpen(InventoryOpenEvent event) { final Player player = (Player) event.getPlayer(); if (Utils.checkAuth(player)) @@ -459,7 +459,16 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { - if (Utils.checkAuth(event.getPlayer())) + Player player = event.getPlayer(); + if (player == null || Utils.checkAuth(player)) + return; + event.setCancelled(true); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) { + Player player = event.getPlayer(); + if (player == null || Utils.checkAuth(player)) return; event.setCancelled(true); } @@ -519,7 +528,7 @@ public class AuthMePlayerListener implements Listener { event.setCancelled(true); } - @EventHandler(priority = EventPriority.NORMAL) + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) public void onPlayerShear(PlayerShearEntityEvent event) { Player player = event.getPlayer(); if (player == null || Utils.checkAuth(player)) @@ -527,11 +536,19 @@ public class AuthMePlayerListener implements Listener { event.setCancelled(true); } - @EventHandler + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) public void onPlayerFish(PlayerFishEvent event) { Player player = event.getPlayer(); if (player == null || Utils.checkAuth(player)) return; event.setCancelled(true); } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) + public void onPlayerEditBook(PlayerEditBookEvent event) { + Player player = event.getPlayer(); + if (player == null || Utils.checkAuth(player)) + return; + event.setCancelled(true); + } }

{O+` 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υuH<9|^0jzN~S*|u<{ZQFKM+O}=mHY#n~wr$(C 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 diff --git a/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom b/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom deleted file mode 100644 index 4479ed0f2..000000000 --- a/localrepo/com/zaxxer/HikariCP-Log4j/2.4.2-SNAPSHOT/HikariCP-Log4J-2.4.2-SNAPSHOT.pom +++ /dev/null @@ -1,443 +0,0 @@ - - 4.0.0 - - com.zaxxer - HikariCP-Log4j - 2.4.2-SNAPSHOT - bundle - - HikariCP-Log4J - Ultimate JDBC Connection Pool [Log4j Version] - https://github.com/brettwooldridge/HikariCP - - - Zaxxer.com - https://github.com/brettwooldridge - - - - scm:git:git@github.com:brettwooldridge/HikariCP.git - scm:git:git@github.com:brettwooldridge/HikariCP.git - git@github.com:brettwooldridge/HikariCP.git - HEAD - - - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - - - Brett Wooldridge - brett.wooldridge@gmail.com - - - - - UTF-8 - 4.3.9.Final - 3.18.2-GA - 0.11.4.1 - 3.1.2 - 1.10.19 - 4.5.0 - 2.4.1 - 1.7.12 - 2.5.3 - 5.0.0 - 2.3 - - - - org.sonatype.oss - oss-parent - 7 - - - - - org.slf4j - slf4j-api - ${slf4j.version} - compile - - - org.apache.logging.log4j - log4j-slf4j-impl - ${log4j.version} - compile - true - - - - org.apache.logging.log4j - log4j-core - ${log4j.version} - compile - true - - - org.mockito - mockito-all - ${mockito.version} - test - - - org.javassist - javassist - ${javassist.version} - true - - - org.hibernate - hibernate-core - ${hibernate.version} - provided - true - - - io.dropwizard.metrics - metrics-core - ${metrics.version} - provided - true - - - io.dropwizard.metrics - metrics-healthchecks - ${metrics.version} - provided - true - - - simple-jndi - simple-jndi - ${jndi.version} - test - - - - - javax.inject - javax.inject - 1 - test - - - org.apache.felix - org.apache.felix.framework - ${felix.version} - test - - - org.ops4j.pax.exam - pax-exam-container-native - ${pax.exam.version} - test - - - org.ops4j.pax.exam - pax-exam-junit4 - ${pax.exam.version} - test - - - org.ops4j.pax.exam - pax-exam-link-mvn - ${pax.exam.version} - test - - - org.ops4j.pax.url - pax-url-aether - ${pax.url.version} - test - - - org.ops4j.pax.url - pax-url-reference - ${pax.url.version} - test - - - - - ${project.name}-${project.version} - - - - org.codehaus.mojo - exec-maven-plugin - 1.4.0 - - - compile - - - java - - - - - com.zaxxer.hikari.proxy.JavassistProxyFactory - - - - - org.jacoco - jacoco-maven-plugin - 0.7.4.201502262128 - - - - pre-unit-test - - prepare-agent - - - - ${project.build.directory}/coverage-reports/jacoco.exec - - surefireArgLine - - **/com/zaxxer/hikari/proxy/** - **/com/zaxxer/hikari/metrics/** - - - - - - post-unit-test - test - - report - - - - ${project.build.directory}/coverage-reports/jacoco.exec - - ${project.reporting.outputDirectory}/jacoco - - **/com/zaxxer/hikari/proxy/** - **/com/zaxxer/hikari/metrics/** - - - - - - - - org.apache.felix - maven-bundle-plugin - ${felix.bundle.plugin.version} - true - - - HikariCP - - com.zaxxer.hikari, - com.zaxxer.hikari.hibernate, - com.zaxxer.hikari.metrics - - com.zaxxer.hikari.* - <_exportcontents> - com.zaxxer.hikari.pool, - com.zaxxer.hikari.util, - com.zaxxer.hikari.proxy - - - javax.management, - javax.naming, - javax.naming.spi, - javax.sql, - javax.sql.rowset, - javax.sql.rowset.serial, - javax.sql.rowset.spi, - com.codahale.metrics;resolution:=optional, - com.codahale.metrics.health;resolution:=optional, - org.slf4j;version="[1.6,2)", - org.hibernate;resolution:=optional, - org.hibernate.cfg;resolution:=optional, - org.hibernate.engine.jdbc.connections.spi;resolution:=optional, - org.hibernate.service;resolution:=optional, - org.hibernate.service.spi;resolution:=optional - - ${project.groupId}.${project.artifactId} - * - - - - - - - manifest - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - true - - 1.7 - 1.7 - - - - - org.apache.maven.plugins - maven-release-plugin - 2.5 - - true - HikariCP-@{project.version} - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.18.1 - - - ${surefireArgLine} - - ${skip.unit.tests} - - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - true - - - - attach-sources - - jar - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - public - - true - 1024m - - - - bundle-sources - package - - jar - - - - - - - - - - - coverage - - - - org.eluder.coveralls - coveralls-maven-plugin - 3.1.0 - - - coveralls - verify - - jacoco - - false - - - - - - - - - release-sign-artifacts - - - performRelease - true - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - - - - - felix - - true - - pax.exam.framework - felix - - - - felix - none - - - - org.apache.felix - org.apache.felix.framework - ${felix.version} - test - - - - - diff --git a/pom.xml b/pom.xml index 390d04eeb..a924c7f50 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,14 @@ *.yml + + ./messages/ + false + ${basedir}/src/main/resources/messages/ + + *.yml + + @@ -74,12 +82,13 @@ - com.maxmind.geoip:* - javax.mail:* - com.sun.mail:* - com.comphenix.attribute:* - org.mcstats.*:* - com.zaxxer:* + org.slf4j:slf4j-api + org.apache.logging.log4j:log4j-slf4j-impl + com.zaxxer:HikariCP + com.maxmind.geoip:geoip-api + com.sun.mail:javax.mail + com.comphenix.attribute:AttributeStorage + org.mcstats.bukkit:metrics @@ -163,10 +172,10 @@ http://repo.mcstats.org/content/repositories/snapshots/ - + - local-repo - file://${basedir}/localrepo + hikaricp-log4j-releases + http://nexus-sgdc3.rhcloud.com/nexus/content/repositories/hikaricp-log4j-releases/ @@ -175,37 +184,11 @@ - - - org.slf4j - slf4j-api - 1.7.12 - compile - - - org.apache.logging.log4j - log4j-slf4j-impl - 2.0.3 - compile - - - org.apache.logging.log4j - log4j-api - ${log4j.version} - compile - true - - + com.zaxxer - HikariCP-Log4j - 2.4.2-SNAPSHOT + HikariCP-Log4J + 2.4.1 compile @@ -219,7 +202,7 @@ - + org.xerial sqlite-jdbc @@ -227,7 +210,13 @@ compile - + + + javax.mail + javax.mail-api + 1.5.4 + compile + com.sun.mail javax.mail diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 8f9db6d85..472a29e89 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -134,10 +134,13 @@ public class DataManager { playerFile.delete(); i++; } else { - playerFile = new File(plugin.ess.getDataFolder() + File.separator + "userdata" + File.separator + Bukkit.getOfflinePlayer(name).getUniqueId() + ".yml"); - if (playerFile.exists()) { - playerFile.delete(); - i++; + try { + playerFile = new File(plugin.ess.getDataFolder() + File.separator + "userdata" + File.separator + Bukkit.getOfflinePlayer(name).getUniqueId() + ".yml"); + if (playerFile.exists()) { + playerFile.delete(); + i++; + } + } catch (Exception e) { // Don't do nothing if the method getUniqueId() isn't avariable ( MC version < 1.7.5 ) } } } catch (Exception e) { diff --git a/src/main/java/fr/xephi/authme/settings/Messages.java b/src/main/java/fr/xephi/authme/settings/Messages.java index 75db7b7ce..1845d739d 100644 --- a/src/main/java/fr/xephi/authme/settings/Messages.java +++ b/src/main/java/fr/xephi/authme/settings/Messages.java @@ -1,12 +1,9 @@ package fr.xephi.authme.settings; import java.io.File; -import java.io.InputStream; - import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.YamlConfiguration; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; public class Messages extends CustomConfiguration { @@ -29,13 +26,11 @@ public class Messages extends CustomConfiguration { * @param filename * The filename to open */ - @SuppressWarnings("deprecation") public final void loadDefaults(File file) { - InputStream stream = AuthMe.getInstance().getResource(file.getName()); - if (stream == null) - return; - - setDefaults(YamlConfiguration.loadConfiguration(stream)); + if(file.isFile()){ + setDefaults(YamlConfiguration.loadConfiguration(file)); + } + return; } /** diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 54dcf2c10..41fbaff71 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -28,7 +28,7 @@ public final class Settings extends YamlConfiguration { public static String PLUGIN_FOLDER = "." + File.separator + "plugins" + File.separator + "AuthMe"; public static final String CACHE_FOLDER = Settings.PLUGIN_FOLDER + File.separator + "cache"; public static final String AUTH_FILE = Settings.PLUGIN_FOLDER + File.separator + "auths.db"; - public static final String MESSAGE_FILE = Settings.PLUGIN_FOLDER + File.separator + "messages"; + public static final String MESSAGE_FILE = Settings.PLUGIN_FOLDER + File.separator + "messages" + File.separator + "messages"; public static final String SETTINGS_FILE = Settings.PLUGIN_FOLDER + File.separator + "config.yml"; public static List allowCommands = null; public static List getJoinPermissions = null; diff --git a/src/main/resources/messages_bg.yml b/src/main/resources/messages/messages_bg.yml similarity index 100% rename from src/main/resources/messages_bg.yml rename to src/main/resources/messages/messages_bg.yml diff --git a/src/main/resources/messages_br.yml b/src/main/resources/messages/messages_br.yml similarity index 100% rename from src/main/resources/messages_br.yml rename to src/main/resources/messages/messages_br.yml diff --git a/src/main/resources/messages_cz.yml b/src/main/resources/messages/messages_cz.yml similarity index 100% rename from src/main/resources/messages_cz.yml rename to src/main/resources/messages/messages_cz.yml diff --git a/src/main/resources/messages_de.yml b/src/main/resources/messages/messages_de.yml similarity index 100% rename from src/main/resources/messages_de.yml rename to src/main/resources/messages/messages_de.yml diff --git a/src/main/resources/messages_en.yml b/src/main/resources/messages/messages_en.yml similarity index 100% rename from src/main/resources/messages_en.yml rename to src/main/resources/messages/messages_en.yml diff --git a/src/main/resources/messages_es.yml b/src/main/resources/messages/messages_es.yml similarity index 100% rename from src/main/resources/messages_es.yml rename to src/main/resources/messages/messages_es.yml diff --git a/src/main/resources/messages_eu.yml b/src/main/resources/messages/messages_eu.yml similarity index 100% rename from src/main/resources/messages_eu.yml rename to src/main/resources/messages/messages_eu.yml diff --git a/src/main/resources/messages_fi.yml b/src/main/resources/messages/messages_fi.yml similarity index 100% rename from src/main/resources/messages_fi.yml rename to src/main/resources/messages/messages_fi.yml diff --git a/src/main/resources/messages_fr.yml b/src/main/resources/messages/messages_fr.yml similarity index 100% rename from src/main/resources/messages_fr.yml rename to src/main/resources/messages/messages_fr.yml diff --git a/src/main/resources/messages_gl.yml b/src/main/resources/messages/messages_gl.yml similarity index 100% rename from src/main/resources/messages_gl.yml rename to src/main/resources/messages/messages_gl.yml diff --git a/src/main/resources/messages_hu.yml b/src/main/resources/messages/messages_hu.yml similarity index 100% rename from src/main/resources/messages_hu.yml rename to src/main/resources/messages/messages_hu.yml diff --git a/src/main/resources/messages_it.yml b/src/main/resources/messages/messages_it.yml similarity index 100% rename from src/main/resources/messages_it.yml rename to src/main/resources/messages/messages_it.yml diff --git a/src/main/resources/messages_ko.yml b/src/main/resources/messages/messages_ko.yml similarity index 100% rename from src/main/resources/messages_ko.yml rename to src/main/resources/messages/messages_ko.yml diff --git a/src/main/resources/messages_lt.yml b/src/main/resources/messages/messages_lt.yml similarity index 100% rename from src/main/resources/messages_lt.yml rename to src/main/resources/messages/messages_lt.yml diff --git a/src/main/resources/messages_nl.yml b/src/main/resources/messages/messages_nl.yml similarity index 100% rename from src/main/resources/messages_nl.yml rename to src/main/resources/messages/messages_nl.yml diff --git a/src/main/resources/messages_pl.yml b/src/main/resources/messages/messages_pl.yml similarity index 100% rename from src/main/resources/messages_pl.yml rename to src/main/resources/messages/messages_pl.yml diff --git a/src/main/resources/messages_pt.yml b/src/main/resources/messages/messages_pt.yml similarity index 100% rename from src/main/resources/messages_pt.yml rename to src/main/resources/messages/messages_pt.yml diff --git a/src/main/resources/messages_ru.yml b/src/main/resources/messages/messages_ru.yml similarity index 98% rename from src/main/resources/messages_ru.yml rename to src/main/resources/messages/messages_ru.yml index 536dc4797..4a6a2bf16 100644 --- a/src/main/resources/messages_ru.yml +++ b/src/main/resources/messages/messages_ru.yml @@ -1,58 +1,58 @@ -unknown_user: '&fПользователь не найден в Базе Данных' -unsafe_spawn: '&eВаше раÑположение перед выходом было опаÑным - вы перенеÑены на Ñпавн' -not_logged_in: '&cÐ’Ñ‹ еще не вошли!' -reg_voluntarily: '&aЧтобы зарегиÑтрироватьÑÑ Ð²Ð²ÐµÐ´Ð¸Ñ‚Ðµ: &5/reg ПÐРОЛЬ ПОВТОР_ПÐРОЛЯ' -usage_log: '&eСинтакÑиÑ: &d/l ПÐРОЛЬ &eили &d/login ПÐРОЛЬ' -wrong_pwd: '&4Ðеправильный пароль!' -unregistered: '&6Ð’Ñ‹ уÑпешно удалили Ñвой аккаунт!' -reg_disabled: '&4РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°' -valid_session: '&aСеÑÑÐ¸Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°' -login: '&2Ð’Ñ‹ уÑпешно вошли!' -vb_nonActiv: '&6Ваш аккаунт еще не активирован! Проверьте вашу почту!' -user_regged: '&4Такой игрок уже зарегиÑтрирован' -usage_reg: '&4ИÑпользование: &5/reg ПÐРОЛЬ ПОВТОР_ПÐРОЛЯ' -max_reg: '&4Ð’Ñ‹ превыÑили Ð¼Ð°ÐºÑ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтво региÑтраций на ваш IP' -no_perm: '&4ÐедоÑтаточно прав' -error: '&4Произошла ошибка. СвÑжитеÑÑŒ Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратором' -login_msg: '&4ÐвторизациÑ: &5/l ПÐРОЛЬ' -reg_msg: '&4РегиÑтрациÑ: &5/reg ПÐРОЛЬ ПОВТОР_ПÐРОЛЯ' -password_error_nick: '&fÐ’Ñ‹ не можете иÑпользовать ваш ник в роли паролÑ' -password_error_unsafe: '&fÐ’Ñ‹ не можете иÑпользовать небезопаÑный пароль' -reg_email_msg: '&4РегиÑтрациÑ: &5/reg EMAIL ПОВТОР_EMAIL' -usage_unreg: '&4ИÑпользование: &5/unregister ПÐРОЛЬ' -pwd_changed: '&2Пароль изменен!' -user_unknown: '&4Такой игрок не зарегиÑтрирован' -password_error: '&4Пароль не Ñовпадает' -invalid_session: '&4СеÑÑÐ¸Ñ Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð°. ДождитеÑÑŒ, пока она закончитÑÑ' -reg_only: '&4Только Ð´Ð»Ñ Ð·Ð°Ñ€ÐµÐ³Ð¸Ñтрированных! ПоÑетите http://Ñайт_Ñервера.com/register/ Ð´Ð»Ñ Ñ€ÐµÐ³Ð¸Ñтрации' -logged_in: '&4Ð’Ñ‹ уже авторизированы!' -logout: '&2Ð’Ñ‹ уÑпешно вышли' -same_nick: '&4Такой игрок уже играет на Ñервере' -registered: '&2УÑÐ¿ÐµÑˆÐ½Ð°Ñ Ñ€ÐµÐ³Ð¸ÑтрациÑ!' -pass_len: '&4Твой пароль либо Ñлишком длинный, либо Ñлишком короткий' -reload: '&6ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¸ база данных перезагружены' -timeout: '&4Ð’Ñ€ÐµÐ¼Ñ Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ð¸ иÑтекло' -usage_changepassword: '&4ИÑпользование: &5/changepassword СТÐРЫЙ_ПÐРОЛЬ ÐОВЫЙ_ПÐРОЛЬ' -name_len: '&4Ваш логин Ñлишком длинный или Ñлишком короткий' -regex: '&4Ваш логин Ñодержит запрещенные Ñимволы. Разрешенные Ñимволы: REG_EX' -add_email: '&4Добавьте Ñвой email: &5/email add Ð’ÐШ_EMAIL Ð’ÐШ_EMAIL' -bad_database_email: '&4[AuthMe] Команда &5/email&4 доÑтупна только при работе Ñ MySQL или SQLite. ОбратититеÑÑŒ к админиÑтрации Ñервера' -recovery_email: '&4Забыли пароль? ИÑпользуйте &5/email recovery Ð’ÐШ_EMAIL' -usage_captcha: '&4Ð’Ñ‹ должны ввеÑти код, иÑпользуйте: &5/captcha ' -wrong_captcha: '&4Ðеверный код, иÑпользуйте: &5/captcha THE_CAPTCHA' -valid_captcha: '&2Ð’Ñ‹ уÑпешно ввели код!' -kick_forvip: '&6VIP игрок зашел на переполненный Ñервер!' -kick_fullserver: '&4Сервер переполнен!' -usage_email_add: '&4ИÑпользование: &5/email add Ð’ÐШ_EMAIL ПОВТОР_EMAIL' -usage_email_change: '&4ИÑпользование: &5/email change СТÐРЫЙ_EMAIL ÐОВЫЙ_EMAIL' -usage_email_recovery: '&4ИÑпользование: /email recovery EMAIL' -new_email_invalid: '[AuthMe] ÐедейÑтвительный новый email!' -old_email_invalid: '[AuthMe] ÐедейÑтвительный Ñтарый email!' -email_invalid: '[AuthMe] ÐедейÑтвительный email' -email_added: '[AuthMe] Email добавлен!' -email_confirm: '[AuthMe] Подтвердите ваш Email!' -email_changed: '[AuthMe] Email изменен!' -email_send: '[AuthMe] ПиÑьмо Ñ Ð¸Ð½ÑтрукциÑми Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð¾ отправлено на ваш Email!' -country_banned: 'Вход Ñ IP-адреÑов вашей Ñтраны воÑпрещен на Ñтом Ñервере' -antibot_auto_enabled: '[AuthMe] AntiBot-режим автоматичеÑки включен из-за большого количеÑтва входов!' -antibot_auto_disabled: '[AuthMe] AntiBot-режим автоматичÑки отключен поÑле %m мин. ÐадеюÑÑŒ атака закончилаÑÑŒ' +unknown_user: '&fПользователь не найден в Базе Данных' +unsafe_spawn: '&eВаше раÑположение перед выходом было опаÑным - вы перенеÑены на Ñпавн' +not_logged_in: '&cÐ’Ñ‹ еще не вошли!' +reg_voluntarily: '&aЧтобы зарегиÑтрироватьÑÑ Ð²Ð²ÐµÐ´Ð¸Ñ‚Ðµ: &5/reg ПÐРОЛЬ ПОВТОР_ПÐРОЛЯ' +usage_log: '&eСинтакÑиÑ: &d/l ПÐРОЛЬ &eили &d/login ПÐРОЛЬ' +wrong_pwd: '&4Ðеправильный пароль!' +unregistered: '&6Ð’Ñ‹ уÑпешно удалили Ñвой аккаунт!' +reg_disabled: '&4РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°' +valid_session: '&aСеÑÑÐ¸Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°' +login: '&2Ð’Ñ‹ уÑпешно вошли!' +vb_nonActiv: '&6Ваш аккаунт еще не активирован! Проверьте вашу почту!' +user_regged: '&4Такой игрок уже зарегиÑтрирован' +usage_reg: '&4ИÑпользование: &5/reg ПÐРОЛЬ ПОВТОР_ПÐРОЛЯ' +max_reg: '&4Ð’Ñ‹ превыÑили Ð¼Ð°ÐºÑ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтво региÑтраций на ваш IP' +no_perm: '&4ÐедоÑтаточно прав' +error: '&4Произошла ошибка. СвÑжитеÑÑŒ Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратором' +login_msg: '&4ÐвторизациÑ: &5/l ПÐРОЛЬ' +reg_msg: '&4РегиÑтрациÑ: &5/reg ПÐРОЛЬ ПОВТОР_ПÐРОЛЯ' +password_error_nick: '&fÐ’Ñ‹ не можете иÑпользовать ваш ник в роли паролÑ' +password_error_unsafe: '&fÐ’Ñ‹ не можете иÑпользовать небезопаÑный пароль' +reg_email_msg: '&4РегиÑтрациÑ: &5/reg EMAIL ПОВТОР_EMAIL' +usage_unreg: '&4ИÑпользование: &5/unregister ПÐРОЛЬ' +pwd_changed: '&2Пароль изменен!' +user_unknown: '&4Такой игрок не зарегиÑтрирован' +password_error: '&4Пароль не Ñовпадает' +invalid_session: '&4СеÑÑÐ¸Ñ Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð°. ДождитеÑÑŒ, пока она закончитÑÑ' +reg_only: '&4Только Ð´Ð»Ñ Ð·Ð°Ñ€ÐµÐ³Ð¸Ñтрированных! ПоÑетите http://Ñайт_Ñервера.com/register/ Ð´Ð»Ñ Ñ€ÐµÐ³Ð¸Ñтрации' +logged_in: '&4Ð’Ñ‹ уже авторизированы!' +logout: '&2Ð’Ñ‹ уÑпешно вышли' +same_nick: '&4Такой игрок уже играет на Ñервере' +registered: '&2УÑÐ¿ÐµÑˆÐ½Ð°Ñ Ñ€ÐµÐ³Ð¸ÑтрациÑ!' +pass_len: '&4Твой пароль либо Ñлишком длинный, либо Ñлишком короткий' +reload: '&6ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¸ база данных перезагружены' +timeout: '&4Ð’Ñ€ÐµÐ¼Ñ Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ð¸ иÑтекло' +usage_changepassword: '&4ИÑпользование: &5/changepassword СТÐРЫЙ_ПÐРОЛЬ ÐОВЫЙ_ПÐРОЛЬ' +name_len: '&4Ваш логин Ñлишком длинный или Ñлишком короткий' +regex: '&4Ваш логин Ñодержит запрещенные Ñимволы. Разрешенные Ñимволы: REG_EX' +add_email: '&4Добавьте Ñвой email: &5/email add Ð’ÐШ_EMAIL Ð’ÐШ_EMAIL' +bad_database_email: '&4[AuthMe] Команда &5/email&4 доÑтупна только при работе Ñ MySQL или SQLite. ОбратититеÑÑŒ к админиÑтрации Ñервера' +recovery_email: '&4Забыли пароль? ИÑпользуйте &5/email recovery Ð’ÐШ_EMAIL' +usage_captcha: '&4Ð’Ñ‹ должны ввеÑти код, иÑпользуйте: &5/captcha ' +wrong_captcha: '&4Ðеверный код, иÑпользуйте: &5/captcha THE_CAPTCHA' +valid_captcha: '&2Ð’Ñ‹ уÑпешно ввели код!' +kick_forvip: '&6VIP игрок зашел на переполненный Ñервер!' +kick_fullserver: '&4Сервер переполнен!' +usage_email_add: '&4ИÑпользование: &5/email add Ð’ÐШ_EMAIL ПОВТОР_EMAIL' +usage_email_change: '&4ИÑпользование: &5/email change СТÐРЫЙ_EMAIL ÐОВЫЙ_EMAIL' +usage_email_recovery: '&4ИÑпользование: /email recovery EMAIL' +new_email_invalid: '[AuthMe] ÐедейÑтвительный новый email!' +old_email_invalid: '[AuthMe] ÐедейÑтвительный Ñтарый email!' +email_invalid: '[AuthMe] ÐедейÑтвительный email' +email_added: '[AuthMe] Email добавлен!' +email_confirm: '[AuthMe] Подтвердите ваш Email!' +email_changed: '[AuthMe] Email изменен!' +email_send: '[AuthMe] ПиÑьмо Ñ Ð¸Ð½ÑтрукциÑми Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð¾ отправлено на ваш Email!' +country_banned: 'Вход Ñ IP-адреÑов вашей Ñтраны воÑпрещен на Ñтом Ñервере' +antibot_auto_enabled: '[AuthMe] AntiBot-режим автоматичеÑки включен из-за большого количеÑтва входов!' +antibot_auto_disabled: '[AuthMe] AntiBot-режим автоматичÑки отключен поÑле %m мин. ÐадеюÑÑŒ атака закончилаÑÑŒ' diff --git a/src/main/resources/messages_sk.yml b/src/main/resources/messages/messages_sk.yml similarity index 100% rename from src/main/resources/messages_sk.yml rename to src/main/resources/messages/messages_sk.yml diff --git a/src/main/resources/messages_tr.yml b/src/main/resources/messages/messages_tr.yml similarity index 100% rename from src/main/resources/messages_tr.yml rename to src/main/resources/messages/messages_tr.yml diff --git a/src/main/resources/messages_uk.yml b/src/main/resources/messages/messages_uk.yml similarity index 100% rename from src/main/resources/messages_uk.yml rename to src/main/resources/messages/messages_uk.yml diff --git a/src/main/resources/messages_vn.yml b/src/main/resources/messages/messages_vn.yml similarity index 98% rename from src/main/resources/messages_vn.yml rename to src/main/resources/messages/messages_vn.yml index 56efede94..1722385a1 100644 --- a/src/main/resources/messages_vn.yml +++ b/src/main/resources/messages/messages_vn.yml @@ -1,59 +1,59 @@ -unknown_user: '&fNgÆ°á»i chÆ¡i không tồn tại trong cÆ¡ sở dữ liệu' -unsafe_spawn: '&fNÆ¡i thoát server của bạn không an toàn, Ä‘ang dịch chuyển bạn tá»›i Ä‘iểm spawn của server' -not_logged_in: '&cChÆ°a đăng nhập!' -reg_voluntarily: '&fBạn có thể đăng kí tài khoản vá»›i lệnh - "/register mật-khẩu nhập-lại-mật-khẩu"' -usage_log: '&eSá»­ dụng: /login password' -wrong_pwd: '&cSai mật khẩu' -unregistered: '&cHuá»· đăng kí thành công!' -reg_disabled: '&cHệ thống đăng kí đã bị vô hiệu' -valid_session: '&cPhiên đăng nhập còn tồn tại, bạn không cần nhập mật khẩu' -login: '&cÄăng nhập thành công!' -vb_nonActiv: '&fTài khoản của bạn chÆ°a được kích hoạt, kiểm tra email!' -user_regged: '&cTên đăng nhập này đã được đăng kí' -usage_reg: '&eSá»­ dụng: /register mật-khẩu nhập-lại-mật-khẩu' -max_reg: '&fSố lượng tài khoản ở IP của bạn trong server này đã quá giá»›i hạn cho phép' -no_perm: '&cKhông có quyá»n' -error: '&fCó lá»—i xảy ra; Báo lại cho ngÆ°á»i Ä‘iá»u hành server' -login_msg: '&cÄăng nhập vá»›i lệnh "/login mật-khẩu"' -reg_msg: '&cÄăng kí tài khoản vá»›i lệnh "/register mật-khẩu nhập-lại-mật-khẩu"' -reg_email_msg: '&cÄăng kí email cho tài khoản vá»›i lệnh "/register "' -usage_unreg: '&eSá»­ dụng: /unregister mật-khẩu' -pwd_changed: '&cÄã đổi mật khẩu!' -user_unknown: '&cTài khoản này chÆ°a được đăng kí' -password_error: '&fMật khẩu không khá»›p' -unvalid_session: '&fPhiên đăng nhập không hồi đáp, vui lòng chá» phiên đăng nhập kết thúc' -reg_only: '&fChỉ cho phép ngÆ°á»i đã đăng kí! Hãy vào trang http://web-của.bạn/ để đăng kí' -logged_in: '&cÄã đăng nhập!' -logout: '&cThoát đăng nhập thành công' -same_nick: '&fTài khoản Ä‘ang được ngÆ°á»i khác sá»­ dụng trong server' -registered: '&cÄăng kí thành công!' -pass_len: '&fMật khẩu của bạn quá ngắn hoặc quá dài' -reload: '&fThiết lập và dữ liệu đã được nạp lại' -timeout: '&fQuá thá»i gian đăng nhập' -usage_changepassword: '&eSá»­ dụng: /changepassword mật-khẩu-cÅ© mật-khẩu-má»›i' -name_len: '&cTên đăng nhập của bạn quá ngắn hoặc quá dài' -regex: '&cTên đăng nhập của bạn có chứa kí tá»± đặc biệt không được cho phép. Các kí tá»± hợp lệ: REG_EX' -add_email: '&cVui lòng thêm địa chỉ email cho tài khoản vá»›i lệnh: /email add email-của-bạn nhập-lại-email-của-bạn' -bad_database_email: '[AuthMe] Lệnh /email chỉ hoạt Ä‘á»™ng vá»›i cÆ¡ sở dữ liệu MySQL và SQLite, - hãy liên hệ Ä‘iá»u hành viên của server' -recovery_email: '&cQuên mật khẩu? Hãy dùng lệnh /email recovery ' -usage_captcha: '&cBạn cần nhập mã xác nhận: /captcha ' -wrong_captcha: '&cSai mã xác nhận, nhập lại: /captcha ' -valid_captcha: '&aMã xác nhận hợp lệ!' -kick_forvip: '&cNgÆ°á»i chÆ¡i VIP đã vào server hiện Ä‘ang full!' -kick_fullserver: '&cXin lá»—i, hiện tại server không còn trống slot để bạn có thể vào!' -usage_email_add: '&eSá»­ dụng: /email add ' -usage_email_change: '&eSá»­ dụng: /email change ' -usage_email_recovery: '&eSá»­ dụng: /email recovery ' -new_email_invalid: '[AuthMe] Äịa chỉ email má»›i không hợp lệ!' -old_email_invalid: '[AuthMe] Äịa chỉ email cÅ© không hợp lệ!' -email_invalid: '[AuthMe] Sai địa chỉ email' -email_added: '[AuthMe] Äã thêm địa chỉ email !' -email_confirm: '[AuthMe] Xác nhận email !' -email_changed: '[AuthMe] Äã thay đổi email !' -email_send: '[AuthMe] Äã gá»­i email khôi phục mật khẩu tá»›i bạn !' -country_banned: 'Rất tiếc, quốc gia của bạn không được phép gia nhập server' -antibot_auto_enabled: '[AuthMe] AntiBot đã được kích hoạt vì lượng ngÆ°á»i chÆ¡i kết nối vượt quá giá»›i hạn!' -antibot_auto_disabled: '[AuthMe] AntiBot tá»± huá»· kích hoạt sau %m phút, +unknown_user: '&fNgÆ°á»i chÆ¡i không tồn tại trong cÆ¡ sở dữ liệu' +unsafe_spawn: '&fNÆ¡i thoát server của bạn không an toàn, Ä‘ang dịch chuyển bạn tá»›i Ä‘iểm spawn của server' +not_logged_in: '&cChÆ°a đăng nhập!' +reg_voluntarily: '&fBạn có thể đăng kí tài khoản vá»›i lệnh + "/register mật-khẩu nhập-lại-mật-khẩu"' +usage_log: '&eSá»­ dụng: /login password' +wrong_pwd: '&cSai mật khẩu' +unregistered: '&cHuá»· đăng kí thành công!' +reg_disabled: '&cHệ thống đăng kí đã bị vô hiệu' +valid_session: '&cPhiên đăng nhập còn tồn tại, bạn không cần nhập mật khẩu' +login: '&cÄăng nhập thành công!' +vb_nonActiv: '&fTài khoản của bạn chÆ°a được kích hoạt, kiểm tra email!' +user_regged: '&cTên đăng nhập này đã được đăng kí' +usage_reg: '&eSá»­ dụng: /register mật-khẩu nhập-lại-mật-khẩu' +max_reg: '&fSố lượng tài khoản ở IP của bạn trong server này đã quá giá»›i hạn cho phép' +no_perm: '&cKhông có quyá»n' +error: '&fCó lá»—i xảy ra; Báo lại cho ngÆ°á»i Ä‘iá»u hành server' +login_msg: '&cÄăng nhập vá»›i lệnh "/login mật-khẩu"' +reg_msg: '&cÄăng kí tài khoản vá»›i lệnh "/register mật-khẩu nhập-lại-mật-khẩu"' +reg_email_msg: '&cÄăng kí email cho tài khoản vá»›i lệnh "/register "' +usage_unreg: '&eSá»­ dụng: /unregister mật-khẩu' +pwd_changed: '&cÄã đổi mật khẩu!' +user_unknown: '&cTài khoản này chÆ°a được đăng kí' +password_error: '&fMật khẩu không khá»›p' +unvalid_session: '&fPhiên đăng nhập không hồi đáp, vui lòng chá» phiên đăng nhập kết thúc' +reg_only: '&fChỉ cho phép ngÆ°á»i đã đăng kí! Hãy vào trang http://web-của.bạn/ để đăng kí' +logged_in: '&cÄã đăng nhập!' +logout: '&cThoát đăng nhập thành công' +same_nick: '&fTài khoản Ä‘ang được ngÆ°á»i khác sá»­ dụng trong server' +registered: '&cÄăng kí thành công!' +pass_len: '&fMật khẩu của bạn quá ngắn hoặc quá dài' +reload: '&fThiết lập và dữ liệu đã được nạp lại' +timeout: '&fQuá thá»i gian đăng nhập' +usage_changepassword: '&eSá»­ dụng: /changepassword mật-khẩu-cÅ© mật-khẩu-má»›i' +name_len: '&cTên đăng nhập của bạn quá ngắn hoặc quá dài' +regex: '&cTên đăng nhập của bạn có chứa kí tá»± đặc biệt không được cho phép. Các kí tá»± hợp lệ: REG_EX' +add_email: '&cVui lòng thêm địa chỉ email cho tài khoản vá»›i lệnh: /email add email-của-bạn nhập-lại-email-của-bạn' +bad_database_email: '[AuthMe] Lệnh /email chỉ hoạt Ä‘á»™ng vá»›i cÆ¡ sở dữ liệu MySQL và SQLite, + hãy liên hệ Ä‘iá»u hành viên của server' +recovery_email: '&cQuên mật khẩu? Hãy dùng lệnh /email recovery ' +usage_captcha: '&cBạn cần nhập mã xác nhận: /captcha ' +wrong_captcha: '&cSai mã xác nhận, nhập lại: /captcha ' +valid_captcha: '&aMã xác nhận hợp lệ!' +kick_forvip: '&cNgÆ°á»i chÆ¡i VIP đã vào server hiện Ä‘ang full!' +kick_fullserver: '&cXin lá»—i, hiện tại server không còn trống slot để bạn có thể vào!' +usage_email_add: '&eSá»­ dụng: /email add ' +usage_email_change: '&eSá»­ dụng: /email change ' +usage_email_recovery: '&eSá»­ dụng: /email recovery ' +new_email_invalid: '[AuthMe] Äịa chỉ email má»›i không hợp lệ!' +old_email_invalid: '[AuthMe] Äịa chỉ email cÅ© không hợp lệ!' +email_invalid: '[AuthMe] Sai địa chỉ email' +email_added: '[AuthMe] Äã thêm địa chỉ email !' +email_confirm: '[AuthMe] Xác nhận email !' +email_changed: '[AuthMe] Äã thay đổi email !' +email_send: '[AuthMe] Äã gá»­i email khôi phục mật khẩu tá»›i bạn !' +country_banned: 'Rất tiếc, quốc gia của bạn không được phép gia nhập server' +antibot_auto_enabled: '[AuthMe] AntiBot đã được kích hoạt vì lượng ngÆ°á»i chÆ¡i kết nối vượt quá giá»›i hạn!' +antibot_auto_disabled: '[AuthMe] AntiBot tá»± huá»· kích hoạt sau %m phút, hi vá»ng lượng kết nối sẽ giảm bá»›t' \ No newline at end of file diff --git a/src/main/resources/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml similarity index 100% rename from src/main/resources/messages_zhcn.yml rename to src/main/resources/messages/messages_zhcn.yml diff --git a/src/main/resources/messages_zhhk.yml b/src/main/resources/messages/messages_zhhk.yml similarity index 98% rename from src/main/resources/messages_zhhk.yml rename to src/main/resources/messages/messages_zhhk.yml index 173fb46cc..d66f1003c 100644 --- a/src/main/resources/messages_zhhk.yml +++ b/src/main/resources/messages/messages_zhhk.yml @@ -1,61 +1,61 @@ -# Translator: uSoc_lifehome (http://lifeho.me) # -# Translator: WaterXCubic ¤ô¤è¶ô # -# -------------------------------------------- # -unknown_user: '&8[&6¥Î¤á¨t²Î&8] &f¥Î¤á¸ê®Æ¨Ã¤£¦s¦b©ó¸ê®Æ®w¤¤¡C' -unsafe_spawn: '&8[&6¥Î¤á¨t²Î&8] &f§Aªºµn¥X¦ì¸m¤£¦w¥þ¡A²{¦b±N¶Ç°e§A¨ì­«¥ÍÂI¡C' -not_logged_in: '&8[&6¥Î¤á¨t²Î&8] &c§AÁÙ¨S¦³µn¤J ¡I' -reg_voluntarily: '&8[&6¥Î¤á¨t²Î&8] &f§A¥i¥H¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' -usage_log: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /login <±K½X> ¡n' -wrong_pwd: '&8[&6¥Î¤á¨t²Î&8] &c§A¿é¤J¤F¿ù»~ªº±K½X¡C' -unregistered: '&8[&6¥Î¤á¨t²Î&8] &c§A¤w¦¨¥\¨ú®ø·|­ûµù¥U°O¿ý¡C' -reg_disabled: '&8[&6¥Î¤á¨t²Î&8] &c¥»¦øªA¾¹¤w°±¤î·sª±®aµù¥U¡C' -valid_session: '&8[&6¥Î¤á¨t²Î&8] &b¶Ù ¡I §Ú°O±o§A¡AÅwªï¦^¨Ó¡ã' -login: '&8[&6¥Î¤á¨t²Î&8] &c§A¦¨¥\ªºµn¤J¤F¡C' -password_error_nick: '&f§A¤£¥i¥H¨Ï¥Î§Aªº¦W¦r¬°±K½X!' -password_error_unsafe: '&f§A¤£¥i¥H¨Ï¥Î¤£¦w¥þªº±K½X' -vb_nonActiv: '&8[&6¥Î¤á¨t²Î&8] &f§Aªº±b¤áÁÙ¨S¦³¸g¹L¹q¶lÅçÃÒ ¡I' -user_regged: '&8[&6¥Î¤á¨t²Î&8] &c¦¹¥Î¤á¦W¤w¸gµù¥U¹L¤F¡C' -usage_reg: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' -max_reg: '&8[&6¥Î¤á¨t²Î&8] &f§AªºIP¦a§}¤w¹F¨ìµù¥U¼Æ¤W­­¡C' -no_perm: '&8[&6¥Î¤á¨t²Î&8] &b§A¥i¥H¨ì CraftingHK ª±®a¦Ê¬ì¤¤¬d¬Ý»¡©ú¤å¥ó¡C' -error: '&8[&6¥Î¤á¨t²Î&8] &fµo¥Í¿ù»~¡A½Ð»PºÞ²z­ûÁpµ¸¡C' -login_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Ó«ü¥O¨Óµn¤J¡G ¡m /login <±K½X> ¡n' -reg_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' -reg_email_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <¹q¶l> <­«Âйq¶l> ¡n' -usage_unreg: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /unregister <±K½X> ¡n' -pwd_changed: '&8[&6¥Î¤á¨t²Î&8] &c§A¦¨¥\ªº§ó´«¤F§Aªº±K½X ¡I' -user_unknown: '&8[&6¥Î¤á¨t²Î&8] &c¦¹¥Î¤á¦W¨S¦³¤wµn°O¸ê®Æ¡C' -password_error: '&8[&6¥Î¤á¨t²Î&8] &f±K½X¤£²Å¦X¡C' -invalid_session: '&8[&6¥Î¤á¨t²Î&8] &fµn¤J¶¥¬q¸ê®Æ¤w·lÃa¡A½Ðµ¥«Ýµn¤J¶¥¬qµ²§ô¡C' -reg_only: '&8[&6¥Î¤á¨t²Î&8] &f­­¤wµù¥U·|­û¡A½Ð¥ý¨ì https://www.example.com/ µù¥U¡C' -logged_in: '&8[&6¥Î¤á¨t²Î&8] &c§A¤w¸gµn¤J¹L¤F¡C' -logout: '&8[&6¥Î¤á¨t²Î&8] &b§A¦¨¥\ªºµn¥X¤F¡C' -same_nick: '&8[&6¥Î¤á¨t²Î&8] &f¦P¦Wª±®a¤w¦b¹Cª±¡C' -registered: '&8[&6¥Î¤á¨t²Î&8] &b§A¦¨¥\ªºµù¥U¤F¡C' -pass_len: '&8[&6¥Î¤á¨t²Î&8] &f§Aªº±K½X¨Ã¤£²Å¦X³W©wªø«×¡C' -reload: '&8[&6¥Î¤á¨t²Î&8] &bµn¤J¨t²Î³]©w¤Î¸ê®Æ®w­«·s¸ü¤J§¹²¦¡C' -timeout: '&8[&6¥Î¤á¨t²Î&8] &fµn¤J¹O®É¡C' -usage_changepassword: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /changepassword <±K½X> <·s±K½X> ¡n' -name_len: '&8[&6¥Î¤á¨t²Î&8] &c§Aªº¥Î¤á¦W¤£²Å¦X³W©wªø«×¡C' -regex: '&8[&6¥Î¤á¨t²Î&8] &c§Aªº¥Î¤á¦W§t¦³¤£®e³\¤§¦r²Å¡C¥H¤U¬°­ã³\¤§¦r¥À¡G REG_EX' -add_email: '&8[&6¥Î¤á¨t²Î&8] &b½Ð¬°§Aªº±b¤á¥ß§Y²K¥[¹q¶l¦a§}¡G ¡m /email add <¹q¶l¦a§}> <­«Âйq¶l¦a§}> ¡n' -bad_database_email: '&8[&6¥Î¤á¨t²Î&8] ¦¹«ü¥O¥u¾A¥Î©ó¨Ï¥ÎMySQL©ÎSQLite¤§¦øªA¾¹¡C' -recovery_email: '&8[&6¥Î¤á¨t²Î&8] &c§Ñ°O±K½X ¡H ½Ð¨Ï¥Î³o­Óªº«ü¥O¨Ó§ó·s±K½X¡G ¡m /email recovery <¹q¶l¦a§}> ¡n' -usage_captcha: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /captcha ¡n' -wrong_captcha: '&8[&6¥Î¤á¨t²Î&8] &c§A¿é¤J¤F¿ù»~ªºÅçÃÒ½X¡A½Ð¨Ï¥Î ¡m /captcha <ÅçÃÒ½X> ¡n ¦A¦¸¿é¤J¡C' -valid_captcha: '&8[&6¥Î¤á¨t²Î&8] &c§A©Ò¿é¤JªºÅçÃÒ½X¬OµL®Äªº ¡I' -kick_forvip: '&c¦]¬°¦³VIPª±®aµn¤J¤F¦øªA¾¹¡C' -kick_fullserver: '&c©êºp¡I ¦]¬°¦øªA¾¹º¡¤H¤F¡A©Ò¥H§A¥Ø«e¥¼¯àµn¤J¦øªA¾¹¡C' -usage_email_add: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email add <¹q¶l> <­«Âйq¶l> ¡n' -usage_email_change: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email change <¹q¶l> <·s¹q¶l> ¡n' -usage_email_recovery: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email recovery <¹q¶l> ¡n' -new_email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªº·s¹q¶l¦a§}¨Ã¤£¥¿½T¡C' -old_email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªºÂ¹q¶l¦a§}¨Ã¤£¥¿½T¡C' -email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªº¹q¶l¦a§}¨Ã¤£¥¿½T¡C' -email_added: '&8[&6¥Î¤á¨t²Î&8] ¤w¥[¤J§Aªº¹q¶l¦a§}°O¿ý¡C' -email_confirm: '&8[&6¥Î¤á¨t²Î&8] ½Ð­«Âпé¤J§Aªº¹q¶l¦a§}¡C' -email_changed: '&8[&6¥Î¤á¨t²Î&8] §Aªº¹q¶l¦a§}°O¿ý¤w§ó§ï¡C' -email_send: '&8[&6¥Î¤á¨t²Î&8] §Ñ°O±K½X«H¥ó¤w±H¥X¡A½Ð¬d¦¬¡C' -country_banned: '&8[&6¥Î¤á¨t²Î&8] ¥»¦øªA¾¹¤w°±¤î¹ï§Aªº°ê®a´£¨Ñ¹CÀ¸ªA°È¡C' -antibot_auto_enabled: '&8[&6¥Î¤á¨t²Î&8] ¨¾¤î¾÷±ñ¤Hµ{§Ç¤w¦]À³²{®É¤j¶q¤£´M±`ªº³s½u¦Ó±Ò¥Î¡C' -antibot_auto_disabled: '&8[&6¥Î¤á¨t²Î&8] ¨¾¤î¾÷±ñ¤Hµ{§ÇÀˬd¨ì¤£¥¿±`³s±µ¼Æ¤w´î¤Ö¡A¨Ã©ó %m ¤ÀÄÁ«á°±¤î¹B§@¡C' +# Translator: uSoc_lifehome (http://lifeho.me) # +# Translator: WaterXCubic ¤ô¤è¶ô # +# -------------------------------------------- # +unknown_user: '&8[&6¥Î¤á¨t²Î&8] &f¥Î¤á¸ê®Æ¨Ã¤£¦s¦b©ó¸ê®Æ®w¤¤¡C' +unsafe_spawn: '&8[&6¥Î¤á¨t²Î&8] &f§Aªºµn¥X¦ì¸m¤£¦w¥þ¡A²{¦b±N¶Ç°e§A¨ì­«¥ÍÂI¡C' +not_logged_in: '&8[&6¥Î¤á¨t²Î&8] &c§AÁÙ¨S¦³µn¤J ¡I' +reg_voluntarily: '&8[&6¥Î¤á¨t²Î&8] &f§A¥i¥H¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' +usage_log: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /login <±K½X> ¡n' +wrong_pwd: '&8[&6¥Î¤á¨t²Î&8] &c§A¿é¤J¤F¿ù»~ªº±K½X¡C' +unregistered: '&8[&6¥Î¤á¨t²Î&8] &c§A¤w¦¨¥\¨ú®ø·|­ûµù¥U°O¿ý¡C' +reg_disabled: '&8[&6¥Î¤á¨t²Î&8] &c¥»¦øªA¾¹¤w°±¤î·sª±®aµù¥U¡C' +valid_session: '&8[&6¥Î¤á¨t²Î&8] &b¶Ù ¡I §Ú°O±o§A¡AÅwªï¦^¨Ó¡ã' +login: '&8[&6¥Î¤á¨t²Î&8] &c§A¦¨¥\ªºµn¤J¤F¡C' +password_error_nick: '&f§A¤£¥i¥H¨Ï¥Î§Aªº¦W¦r¬°±K½X!' +password_error_unsafe: '&f§A¤£¥i¥H¨Ï¥Î¤£¦w¥þªº±K½X' +vb_nonActiv: '&8[&6¥Î¤á¨t²Î&8] &f§Aªº±b¤áÁÙ¨S¦³¸g¹L¹q¶lÅçÃÒ ¡I' +user_regged: '&8[&6¥Î¤á¨t²Î&8] &c¦¹¥Î¤á¦W¤w¸gµù¥U¹L¤F¡C' +usage_reg: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' +max_reg: '&8[&6¥Î¤á¨t²Î&8] &f§AªºIP¦a§}¤w¹F¨ìµù¥U¼Æ¤W­­¡C' +no_perm: '&8[&6¥Î¤á¨t²Î&8] &b§A¥i¥H¨ì CraftingHK ª±®a¦Ê¬ì¤¤¬d¬Ý»¡©ú¤å¥ó¡C' +error: '&8[&6¥Î¤á¨t²Î&8] &fµo¥Í¿ù»~¡A½Ð»PºÞ²z­ûÁpµ¸¡C' +login_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Ó«ü¥O¨Óµn¤J¡G ¡m /login <±K½X> ¡n' +reg_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <±K½X> <­«ÂбK½X> ¡n' +reg_email_msg: '&8[&6¥Î¤á¨t²Î&8] &c½Ð¨Ï¥Î³o­Óªº«ü¥O¨Óµù¥U¡G ¡m /register <¹q¶l> <­«Âйq¶l> ¡n' +usage_unreg: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /unregister <±K½X> ¡n' +pwd_changed: '&8[&6¥Î¤á¨t²Î&8] &c§A¦¨¥\ªº§ó´«¤F§Aªº±K½X ¡I' +user_unknown: '&8[&6¥Î¤á¨t²Î&8] &c¦¹¥Î¤á¦W¨S¦³¤wµn°O¸ê®Æ¡C' +password_error: '&8[&6¥Î¤á¨t²Î&8] &f±K½X¤£²Å¦X¡C' +invalid_session: '&8[&6¥Î¤á¨t²Î&8] &fµn¤J¶¥¬q¸ê®Æ¤w·lÃa¡A½Ðµ¥«Ýµn¤J¶¥¬qµ²§ô¡C' +reg_only: '&8[&6¥Î¤á¨t²Î&8] &f­­¤wµù¥U·|­û¡A½Ð¥ý¨ì https://www.example.com/ µù¥U¡C' +logged_in: '&8[&6¥Î¤á¨t²Î&8] &c§A¤w¸gµn¤J¹L¤F¡C' +logout: '&8[&6¥Î¤á¨t²Î&8] &b§A¦¨¥\ªºµn¥X¤F¡C' +same_nick: '&8[&6¥Î¤á¨t²Î&8] &f¦P¦Wª±®a¤w¦b¹Cª±¡C' +registered: '&8[&6¥Î¤á¨t²Î&8] &b§A¦¨¥\ªºµù¥U¤F¡C' +pass_len: '&8[&6¥Î¤á¨t²Î&8] &f§Aªº±K½X¨Ã¤£²Å¦X³W©wªø«×¡C' +reload: '&8[&6¥Î¤á¨t²Î&8] &bµn¤J¨t²Î³]©w¤Î¸ê®Æ®w­«·s¸ü¤J§¹²¦¡C' +timeout: '&8[&6¥Î¤á¨t²Î&8] &fµn¤J¹O®É¡C' +usage_changepassword: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /changepassword <±K½X> <·s±K½X> ¡n' +name_len: '&8[&6¥Î¤á¨t²Î&8] &c§Aªº¥Î¤á¦W¤£²Å¦X³W©wªø«×¡C' +regex: '&8[&6¥Î¤á¨t²Î&8] &c§Aªº¥Î¤á¦W§t¦³¤£®e³\¤§¦r²Å¡C¥H¤U¬°­ã³\¤§¦r¥À¡G REG_EX' +add_email: '&8[&6¥Î¤á¨t²Î&8] &b½Ð¬°§Aªº±b¤á¥ß§Y²K¥[¹q¶l¦a§}¡G ¡m /email add <¹q¶l¦a§}> <­«Âйq¶l¦a§}> ¡n' +bad_database_email: '&8[&6¥Î¤á¨t²Î&8] ¦¹«ü¥O¥u¾A¥Î©ó¨Ï¥ÎMySQL©ÎSQLite¤§¦øªA¾¹¡C' +recovery_email: '&8[&6¥Î¤á¨t²Î&8] &c§Ñ°O±K½X ¡H ½Ð¨Ï¥Î³o­Óªº«ü¥O¨Ó§ó·s±K½X¡G ¡m /email recovery <¹q¶l¦a§}> ¡n' +usage_captcha: '&8[&6¥Î¤á¨t²Î&8] &c¥Îªk¡G ¡m /captcha ¡n' +wrong_captcha: '&8[&6¥Î¤á¨t²Î&8] &c§A¿é¤J¤F¿ù»~ªºÅçÃÒ½X¡A½Ð¨Ï¥Î ¡m /captcha <ÅçÃÒ½X> ¡n ¦A¦¸¿é¤J¡C' +valid_captcha: '&8[&6¥Î¤á¨t²Î&8] &c§A©Ò¿é¤JªºÅçÃÒ½X¬OµL®Äªº ¡I' +kick_forvip: '&c¦]¬°¦³VIPª±®aµn¤J¤F¦øªA¾¹¡C' +kick_fullserver: '&c©êºp¡I ¦]¬°¦øªA¾¹º¡¤H¤F¡A©Ò¥H§A¥Ø«e¥¼¯àµn¤J¦øªA¾¹¡C' +usage_email_add: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email add <¹q¶l> <­«Âйq¶l> ¡n' +usage_email_change: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email change <¹q¶l> <·s¹q¶l> ¡n' +usage_email_recovery: '&8[&6¥Î¤á¨t²Î&8] &f¥Îªk¡G ¡m /email recovery <¹q¶l> ¡n' +new_email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªº·s¹q¶l¦a§}¨Ã¤£¥¿½T¡C' +old_email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªºÂ¹q¶l¦a§}¨Ã¤£¥¿½T¡C' +email_invalid: '&8[&6¥Î¤á¨t²Î&8] §A©Ò¶ñ¼gªº¹q¶l¦a§}¨Ã¤£¥¿½T¡C' +email_added: '&8[&6¥Î¤á¨t²Î&8] ¤w¥[¤J§Aªº¹q¶l¦a§}°O¿ý¡C' +email_confirm: '&8[&6¥Î¤á¨t²Î&8] ½Ð­«Âпé¤J§Aªº¹q¶l¦a§}¡C' +email_changed: '&8[&6¥Î¤á¨t²Î&8] §Aªº¹q¶l¦a§}°O¿ý¤w§ó§ï¡C' +email_send: '&8[&6¥Î¤á¨t²Î&8] §Ñ°O±K½X«H¥ó¤w±H¥X¡A½Ð¬d¦¬¡C' +country_banned: '&8[&6¥Î¤á¨t²Î&8] ¥»¦øªA¾¹¤w°±¤î¹ï§Aªº°ê®a´£¨Ñ¹CÀ¸ªA°È¡C' +antibot_auto_enabled: '&8[&6¥Î¤á¨t²Î&8] ¨¾¤î¾÷±ñ¤Hµ{§Ç¤w¦]À³²{®É¤j¶q¤£´M±`ªº³s½u¦Ó±Ò¥Î¡C' +antibot_auto_disabled: '&8[&6¥Î¤á¨t²Î&8] ¨¾¤î¾÷±ñ¤Hµ{§ÇÀˬd¨ì¤£¥¿±`³s±µ¼Æ¤w´î¤Ö¡A¨Ã©ó %m ¤ÀÄÁ«á°±¤î¹B§@¡C' diff --git a/src/main/resources/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml similarity index 98% rename from src/main/resources/messages_zhtw.yml rename to src/main/resources/messages/messages_zhtw.yml index 6668976e2..5091f8414 100644 --- a/src/main/resources/messages_zhtw.yml +++ b/src/main/resources/messages/messages_zhtw.yml @@ -1,62 +1,62 @@ -# Translator: MineWolf50 -# Last Time Edit : 2015 / 7 / 14 , A.M.10:14 -# = = = = = = = = = = = = = = = = = = = = = = = # -unknown_user: "&bã€AuthMe】&6沒有在資料庫內找到該玩家。" -unsafe_spawn: '&bã€AuthMe】&6你登出的地點ä¸å®‰å…¨ï¼Œå·²å‚³é€ä½ åˆ°å®‰å…¨çš„地點。' -not_logged_in: '&bã€AuthMe】&6你還沒有登入!' -reg_voluntarily: '&bã€AuthMe】&6使用 &c"/register <密碼> <確èªå¯†ç¢¼>" &6來註冊你的暱稱' -usage_log: '&bã€AuthMe】&6用法: &c"/login <密碼>"' -wrong_pwd: '&bã€AuthMe】&6密碼錯誤!' -unregistered: '&bã€AuthMe】&6你已經æˆåŠŸå–消註冊。' -reg_disabled: '&bã€AuthMe】&6已關閉註冊功能' -password_error_nick: '&bã€AuthMe】&6ä½ ä¸å¯ä»¥ç”¨ä½ çš„ ID ( å稱 ) 來當作密碼 !' -password_error_unsafe: '&bã€AuthMe】&6ä½ ä¸å¯ä»¥ä½¿ç”¨é€™å€‹ä¸å®‰å…¨çš„密碼' -valid_session: '&bã€AuthMe】&6你已經æˆåŠŸç™»å…¥!' -login: '&bã€AuthMe】&6密碼正確,你已æˆåŠŸç™»å…¥!' -vb_nonActiv: '&bã€AuthMe】&6你的帳號還沒有經éŽé©—è­‰! 檢查看看你的電å­ä¿¡ç®± (Email) å§!' -user_regged: '&bã€AuthMe】&6這個帳號已經被註冊éŽäº†!' -usage_reg: '&bã€AuthMe】&6用法: &c"/register <密碼> <確èªå¯†ç¢¼>"' -max_reg: '&bã€AuthMe】&6ä½ çš„ IP ä½ç½®æ‰€è¨»å†Šçš„帳號數é‡å·²ç¶“é”到最大。' -no_perm: '&bã€AuthMe】&6你沒有使用該指令的權é™ã€‚' -error: '&bã€AuthMe】&6發生錯誤,請è¯ç¹«ç®¡ç†å“¡' -login_msg: '&bã€AuthMe】&6請使用 &c"/login <密碼>" &6來登入。' -reg_msg: '&bã€AuthMe】&6請使用 "&c/register <密碼> <確èªå¯†ç¢¼>" 來註冊。' -reg_email_msg: '&bã€AuthMe】&6請使用 &c"/register <é‡è¤‡Email>" 來註冊' -usage_unreg: '&bã€AuthMe】&6用法: &c"/unregister <密碼>"' -pwd_changed: '&bã€AuthMe】&6密碼變更æˆåŠŸ!' -user_unknown: '&bã€AuthMe】&6這個帳號還沒有註冊éŽ' -password_error: '&bã€AuthMe】&6兩次輸入的密碼ä¸ä¸€è‡´!' -invalid_session: '&bã€AuthMe】&6憑證日期ä¸ç›¸ç¬¦!' -reg_only: '&bã€AuthMe】&6請到下列網站 :「 http://example.com 〠進行註冊' -logged_in: '&bã€AuthMe】&6你已經登入了!' -logout: '&bã€AuthMe】&6ä½ å·²æˆåŠŸç™»å‡º' -same_nick: '&bã€AuthMe】&6有åŒæ¨£å¸³è™Ÿçš„玩家在線上!' -registered: '&bã€AuthMe】&6ä½ å·²æˆåŠŸè¨»å†Š' -pass_len: '&bã€AuthMe】&6你的密碼 超éŽæœ€å¤§å­—數 / å°æ–¼æœ€å°å­—數' -reload: '&bã€AuthMe】&6å·²é‡æ–°è®€å–設定檔åŠè³‡æ–™åº«' -timeout: '&bã€AuthMe】&6超éŽç™»å…¥æ™‚間,請ç¨å¾Œå†è©¦ä¸€æ¬¡' -usage_changepassword: '&bã€AuthMe】&6用法: &c"/changepassword <舊密碼> <新密碼>"' -name_len: '&bã€AuthMe】&6你的暱稱 太長 / 太短 了!' -regex: '&bã€AuthMe】&6暱稱裡包å«ä¸èƒ½ä½¿ç”¨çš„字符' -add_email: '&bã€AuthMe】&6請使用 &c"/email add <ä½ çš„Email> <å†æ¬¡è¼¸å…¥ä½ çš„Email>" &6來添加 Email' -bad_database_email: '&bã€AuthMe】&6此指令åªé©ç”¨æ–¼æœ‰ä½¿ç”¨MySQLå’ŒSQLite的伺æœå™¨ã€‚' -recovery_email: '&bã€AuthMe】&6忘記密碼了嗎? 使用 &c"/email recovery <ä½ çš„Email>"' -usage_captcha: '&bã€AuthMe】&6請用 &c"/captcha " &6來輸入你的驗證碼' -wrong_captcha: '&bã€AuthMe】&6錯誤的驗證碼' -valid_captcha: '&bã€AuthMe】&6驗證碼無效!' -kick_forvip: '&bã€AuthMe】&6你已經被請出。&c原因 : 有 VIP 玩家登入伺æœå™¨' -kick_fullserver: '&bã€AuthMe】&6伺æœå™¨å·²ç¶“滿了,請等等å†è©¦ä¸€æ¬¡' -usage_email_add: '&bã€AuthMe】&6用法: &c"/email add <ä½ çš„Email> <é‡è¤‡Email>"' -usage_email_change: '&bã€AuthMe】&6用法: &c"/email change <舊的Email> <æ–°çš„Email>"' -usage_email_recovery: '&bã€AuthMe】&6用法: &c"/email recovery <ä½ çš„Email>"' -new_email_invalid: '&bã€AuthMe】&6æ–°çš„Email無效!' -old_email_invalid: '&bã€AuthMe】&6舊的Email無效!' -email_invalid: '&bã€AuthMe】&6無效的Email!' -email_added: '&bã€AuthMe】&6已添加Email!' -email_confirm: '&bã€AuthMe】&6請驗證你的Email!' -email_changed: '&bã€AuthMe】&6Email已變更!' -email_send: '&bã€AuthMe】&6已經é€å‡ºé‡è¨­å¯†ç¢¼è¦æ±‚至你的Email , 請查收。' -email_exists: '&bã€AuthMe】&6這個帳戶已經有設定電å­éƒµä»¶äº†' -country_banned: '&bã€AuthMe】&6你所在的地å€ç„¡æ³•é€²å…¥æ­¤ä¼ºæœå™¨' -antibot_auto_enabled: '&bã€AuthMe】&6AntiBotMod已自動啟用!' +# Translator: MineWolf50 +# Last Time Edit : 2015 / 7 / 14 , A.M.10:14 +# = = = = = = = = = = = = = = = = = = = = = = = # +unknown_user: "&bã€AuthMe】&6沒有在資料庫內找到該玩家。" +unsafe_spawn: '&bã€AuthMe】&6你登出的地點ä¸å®‰å…¨ï¼Œå·²å‚³é€ä½ åˆ°å®‰å…¨çš„地點。' +not_logged_in: '&bã€AuthMe】&6你還沒有登入!' +reg_voluntarily: '&bã€AuthMe】&6使用 &c"/register <密碼> <確èªå¯†ç¢¼>" &6來註冊你的暱稱' +usage_log: '&bã€AuthMe】&6用法: &c"/login <密碼>"' +wrong_pwd: '&bã€AuthMe】&6密碼錯誤!' +unregistered: '&bã€AuthMe】&6你已經æˆåŠŸå–消註冊。' +reg_disabled: '&bã€AuthMe】&6已關閉註冊功能' +password_error_nick: '&bã€AuthMe】&6ä½ ä¸å¯ä»¥ç”¨ä½ çš„ ID ( å稱 ) 來當作密碼 !' +password_error_unsafe: '&bã€AuthMe】&6ä½ ä¸å¯ä»¥ä½¿ç”¨é€™å€‹ä¸å®‰å…¨çš„密碼' +valid_session: '&bã€AuthMe】&6你已經æˆåŠŸç™»å…¥!' +login: '&bã€AuthMe】&6密碼正確,你已æˆåŠŸç™»å…¥!' +vb_nonActiv: '&bã€AuthMe】&6你的帳號還沒有經éŽé©—è­‰! 檢查看看你的電å­ä¿¡ç®± (Email) å§!' +user_regged: '&bã€AuthMe】&6這個帳號已經被註冊éŽäº†!' +usage_reg: '&bã€AuthMe】&6用法: &c"/register <密碼> <確èªå¯†ç¢¼>"' +max_reg: '&bã€AuthMe】&6ä½ çš„ IP ä½ç½®æ‰€è¨»å†Šçš„帳號數é‡å·²ç¶“é”到最大。' +no_perm: '&bã€AuthMe】&6你沒有使用該指令的權é™ã€‚' +error: '&bã€AuthMe】&6發生錯誤,請è¯ç¹«ç®¡ç†å“¡' +login_msg: '&bã€AuthMe】&6請使用 &c"/login <密碼>" &6來登入。' +reg_msg: '&bã€AuthMe】&6請使用 "&c/register <密碼> <確èªå¯†ç¢¼>" 來註冊。' +reg_email_msg: '&bã€AuthMe】&6請使用 &c"/register <é‡è¤‡Email>" 來註冊' +usage_unreg: '&bã€AuthMe】&6用法: &c"/unregister <密碼>"' +pwd_changed: '&bã€AuthMe】&6密碼變更æˆåŠŸ!' +user_unknown: '&bã€AuthMe】&6這個帳號還沒有註冊éŽ' +password_error: '&bã€AuthMe】&6兩次輸入的密碼ä¸ä¸€è‡´!' +invalid_session: '&bã€AuthMe】&6憑證日期ä¸ç›¸ç¬¦!' +reg_only: '&bã€AuthMe】&6請到下列網站 :「 http://example.com 〠進行註冊' +logged_in: '&bã€AuthMe】&6你已經登入了!' +logout: '&bã€AuthMe】&6ä½ å·²æˆåŠŸç™»å‡º' +same_nick: '&bã€AuthMe】&6有åŒæ¨£å¸³è™Ÿçš„玩家在線上!' +registered: '&bã€AuthMe】&6ä½ å·²æˆåŠŸè¨»å†Š' +pass_len: '&bã€AuthMe】&6你的密碼 超éŽæœ€å¤§å­—數 / å°æ–¼æœ€å°å­—數' +reload: '&bã€AuthMe】&6å·²é‡æ–°è®€å–設定檔åŠè³‡æ–™åº«' +timeout: '&bã€AuthMe】&6超éŽç™»å…¥æ™‚間,請ç¨å¾Œå†è©¦ä¸€æ¬¡' +usage_changepassword: '&bã€AuthMe】&6用法: &c"/changepassword <舊密碼> <新密碼>"' +name_len: '&bã€AuthMe】&6你的暱稱 太長 / 太短 了!' +regex: '&bã€AuthMe】&6暱稱裡包å«ä¸èƒ½ä½¿ç”¨çš„字符' +add_email: '&bã€AuthMe】&6請使用 &c"/email add <ä½ çš„Email> <å†æ¬¡è¼¸å…¥ä½ çš„Email>" &6來添加 Email' +bad_database_email: '&bã€AuthMe】&6此指令åªé©ç”¨æ–¼æœ‰ä½¿ç”¨MySQLå’ŒSQLite的伺æœå™¨ã€‚' +recovery_email: '&bã€AuthMe】&6忘記密碼了嗎? 使用 &c"/email recovery <ä½ çš„Email>"' +usage_captcha: '&bã€AuthMe】&6請用 &c"/captcha " &6來輸入你的驗證碼' +wrong_captcha: '&bã€AuthMe】&6錯誤的驗證碼' +valid_captcha: '&bã€AuthMe】&6驗證碼無效!' +kick_forvip: '&bã€AuthMe】&6你已經被請出。&c原因 : 有 VIP 玩家登入伺æœå™¨' +kick_fullserver: '&bã€AuthMe】&6伺æœå™¨å·²ç¶“滿了,請等等å†è©¦ä¸€æ¬¡' +usage_email_add: '&bã€AuthMe】&6用法: &c"/email add <ä½ çš„Email> <é‡è¤‡Email>"' +usage_email_change: '&bã€AuthMe】&6用法: &c"/email change <舊的Email> <æ–°çš„Email>"' +usage_email_recovery: '&bã€AuthMe】&6用法: &c"/email recovery <ä½ çš„Email>"' +new_email_invalid: '&bã€AuthMe】&6æ–°çš„Email無效!' +old_email_invalid: '&bã€AuthMe】&6舊的Email無效!' +email_invalid: '&bã€AuthMe】&6無效的Email!' +email_added: '&bã€AuthMe】&6已添加Email!' +email_confirm: '&bã€AuthMe】&6請驗證你的Email!' +email_changed: '&bã€AuthMe】&6Email已變更!' +email_send: '&bã€AuthMe】&6已經é€å‡ºé‡è¨­å¯†ç¢¼è¦æ±‚至你的Email , 請查收。' +email_exists: '&bã€AuthMe】&6這個帳戶已經有設定電å­éƒµä»¶äº†' +country_banned: '&bã€AuthMe】&6你所在的地å€ç„¡æ³•é€²å…¥æ­¤ä¼ºæœå™¨' +antibot_auto_enabled: '&bã€AuthMe】&6AntiBotMod已自動啟用!' antibot_auto_disabled: '&bã€AuthMe】&6AntiBotMod將會於 &c%m &6分é˜å¾Œè‡ªå‹•é—œé–‰' \ No newline at end of file From d13f8fc512245c674cf9d3445c47b2577ef83195 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 5 Sep 2015 00:50:08 +0200 Subject: [PATCH 008/115] Fix build xD --- pom.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index a924c7f50..e13f330ef 100644 --- a/pom.xml +++ b/pom.xml @@ -82,9 +82,7 @@ - org.slf4j:slf4j-api - org.apache.logging.log4j:log4j-slf4j-impl - com.zaxxer:HikariCP + com.zaxxer:HikariCP-Log4J com.maxmind.geoip:geoip-api com.sun.mail:javax.mail com.comphenix.attribute:AttributeStorage From 78d6b9cc6baa1631ebc58e3cc9f359b12b6116b7 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 5 Sep 2015 12:40:36 +0200 Subject: [PATCH 009/115] Ok, it's too complex to use the log4j implementation xD --- pom.xml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index e13f330ef..cecb3117f 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,8 @@ - com.zaxxer:HikariCP-Log4J + com.zaxxer:HikariCP + org.slf4j:slf4j-simple com.maxmind.geoip:geoip-api com.sun.mail:javax.mail com.comphenix.attribute:AttributeStorage @@ -172,8 +173,8 @@ - hikaricp-log4j-releases - http://nexus-sgdc3.rhcloud.com/nexus/content/repositories/hikaricp-log4j-releases/ + hikaricp-log4j-releases + http://nexus-sgdc3.rhcloud.com/nexus/content/repositories/hikaricp-log4j-releases/ @@ -185,19 +186,9 @@ com.zaxxer - HikariCP-Log4J + HikariCP 2.4.1 compile - - - org.slf4j - slf4j-api - - - org.apache.logging.log4j - log4j-core - - From 3926faeb35c4379591bdf17a4b682720b547f6c1 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 6 Sep 2015 13:51:35 +0200 Subject: [PATCH 010/115] Fix Hikari timeouts --- pom.xml | 5 +++++ src/main/java/fr/xephi/authme/datasource/MySQL.java | 6 +++--- src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index cecb3117f..7182eff48 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,11 @@ http://dev.bukkit.org/bukkit-plugins/authme-reloaded/ + + AuthMe-Team + https://github.com/AuthMe-Team + + scm:git:https://github.com/Xephi/AuthMeReloaded.git scm:git:git@github.com:Xephi/AuthMeReloaded.git diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 73f730ad6..24e37dbcd 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -138,9 +138,9 @@ public class MySQL implements DataSource { config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); config.addDataSourceProperty("autoReconnect", false); config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable - config.setMaxLifetime(60000); // 60 Sec - config.setIdleTimeout(45000); // 45 Sec - config.setMaximumPoolSize(50); // 50 Connections (including idle connections) + config.setMaxLifetime(180000); // 3 Min + config.setIdleTimeout(60000); // 1 Min + config.setMaximumPoolSize(50); // 50 (including idle connections) ds = new HikariDataSource(config); ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); } diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java index 767a5da7d..2b6ea3869 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite_HIKARI.java @@ -126,9 +126,9 @@ public class SQLite_HIKARI implements DataSource { config.setJdbcUrl("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable config.setConnectionTestQuery("SELECT 1"); - config.setMaxLifetime(60000); // 60 Sec - config.setIdleTimeout(45000); // 45 Sec - config.setMaximumPoolSize(50); // 50 Connections (including idle connections) + config.setMaxLifetime(180000); // 3 Min + config.setIdleTimeout(60000); // 1 Min + config.setMaximumPoolSize(50); // 50 (including idle connections) ds = new HikariDataSource(config); ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); } From 7f9d641fe3d6814a49869fa7044c22edaa846ee2 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 6 Sep 2015 14:16:57 +0200 Subject: [PATCH 011/115] Fix hikari logger --- pom.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pom.xml b/pom.xml index 7182eff48..b34222f3e 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,7 @@ com.zaxxer:HikariCP org.slf4j:slf4j-simple + org.slf4j:slf4j-api com.maxmind.geoip:geoip-api com.sun.mail:javax.mail com.comphenix.attribute:AttributeStorage @@ -195,6 +196,18 @@ 2.4.1 compile + + org.slf4j + slf4j-api + 1.7.12 + compile + + + org.slf4j + slf4j-simple + 1.7.12 + compile + From 200ff01cd9d8e2931cba7c620d6ce379273599f3 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 6 Sep 2015 22:24:23 +0700 Subject: [PATCH 012/115] never return null, just throw exception. --- src/main/java/fr/xephi/authme/AuthMe.java | 7 ++- .../java/fr/xephi/authme/ConsoleLogger.java | 7 ++- .../xephi/authme/datasource/DataSource.java | 5 +-- .../fr/xephi/authme/datasource/MySQL.java | 43 ++++++++----------- 4 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 131991dcf..9f7834abf 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -626,9 +626,8 @@ public class AuthMe extends JavaPlugin { if (multiverse != null && Settings.multiverse) { try { return multiverse.getMVWorldManager().getMVWorld(world).getSpawnLocation(); - } catch (NullPointerException npe) { - } catch (ClassCastException cce) { - } catch (NoClassDefFoundError ncdfe) { + } catch (Exception e) { + e.printStackTrace(); } } return null; @@ -792,7 +791,7 @@ public class AuthMe extends JavaPlugin { /** * Get Player real IP through VeryGames method * - * @param Player + * @param player * player */ @Deprecated diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index 3a73ab5c1..010b66192 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -1,5 +1,8 @@ package fr.xephi.authme; +import fr.xephi.authme.settings.Settings; +import org.bukkit.Bukkit; + import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; @@ -8,10 +11,6 @@ import java.text.DateFormat; import java.util.Calendar; import java.util.logging.Logger; -import org.bukkit.Bukkit; - -import fr.xephi.authme.settings.Settings; - public class ConsoleLogger { private static final Logger log = Logger.getLogger("AuthMe"); diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index ef445dc4c..41dc8923d 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -1,13 +1,12 @@ package fr.xephi.authme.datasource; -import java.util.List; - import fr.xephi.authme.cache.auth.PlayerAuth; +import java.util.List; + public interface DataSource { public enum DataSourceType { - MYSQL, FILE, SQLITE diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 24e37dbcd..15e5eb8e2 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -1,24 +1,18 @@ package fr.xephi.authme.datasource; -import java.sql.Blob; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; - import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.pool.PoolInitializationException; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.settings.Settings; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + public class MySQL implements DataSource { private String host; @@ -43,6 +37,7 @@ public class MySQL implements DataSource { private List columnOthers; private HikariDataSource ds; private String columnRealName; + private Connection connection; public MySQL() throws ClassNotFoundException, SQLException, PoolInitializationException { this.host = Settings.getMySQLHost; @@ -135,35 +130,30 @@ public class MySQL implements DataSource { config.setPassword(this.password); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); - config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); config.addDataSourceProperty("autoReconnect", false); config.setInitializationFailFast(true); // Don't start the plugin if the database is unavariable config.setMaxLifetime(180000); // 3 Min config.setIdleTimeout(60000); // 1 Min - config.setMaximumPoolSize(50); // 50 (including idle connections) + config.setMaximumPoolSize(50); // 50 (including idle connections) ds = new HikariDataSource(config); ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); } private synchronized void reloadArguments() throws ClassNotFoundException, IllegalArgumentException { - if (ds != null){ + if (ds != null) { ds.close(); } setConnectionArguments(); ConsoleLogger.info("Hikari ConnectionPool arguments reloaded!"); } - private synchronized Connection getConnection() { - Connection con = null; - while(con == null){ - try { - con = ds.getConnection(); - } catch (SQLException ce) { - return null; - } + private synchronized Connection getConnection() throws SQLException { + if (connection == null || connection.isClosed()) { + connection = ds.getConnection(); } - return con; + return connection; } private synchronized void setupConnection() throws SQLException { @@ -268,7 +258,8 @@ public class MySQL implements DataSource { if (!columnSalt.isEmpty()) { if (!columnGroup.isEmpty()) pAuth = new PlayerAuth(rs.getString(columnName).toLowerCase(), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - else pAuth = new PlayerAuth(rs.getString(columnName).toLowerCase(), rs.getString(columnPassword), rs.getString(columnSalt), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); + else + pAuth = new PlayerAuth(rs.getString(columnName).toLowerCase(), rs.getString(columnPassword), rs.getString(columnSalt), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } else { pAuth = new PlayerAuth(rs.getString(columnName).toLowerCase(), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } @@ -1047,7 +1038,8 @@ public class MySQL implements DataSource { if (!columnSalt.isEmpty()) { if (!columnGroup.isEmpty()) pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - else pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); + else + pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } else { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } @@ -1098,7 +1090,8 @@ public class MySQL implements DataSource { if (!columnSalt.isEmpty()) { if (!columnGroup.isEmpty()) pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - else pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); + else + pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } else { pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); } From 495dd35b4848f1585858b62e3b2711d3f9dbb22d Mon Sep 17 00:00:00 2001 From: DmitryRendov Date: Sun, 6 Sep 2015 20:28:25 +0000 Subject: [PATCH 013/115] Updated PBKDF2 hasher to support Django 1.7+ --- .../xephi/authme/security/crypts/CryptPBKDF2.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java index e6fb9bc50..426b36ee0 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java @@ -4,17 +4,18 @@ import java.security.NoSuchAlgorithmException; import fr.xephi.authme.security.pbkdf2.PBKDF2Engine; import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters; +import javax.xml.bind.DatatypeConverter; public class CryptPBKDF2 implements EncryptionMethod { @Override public String getHash(String password, String salt, String name) throws NoSuchAlgorithmException { - String result = "pbkdf2_sha256$10000$" + salt + "$"; - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000); + String result = "pbkdf2_sha256$15000$" + salt + "$"; + PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000); PBKDF2Engine engine = new PBKDF2Engine(params); - - return result + String.valueOf(engine.deriveKey(password, 64)); + + return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32))); } @Override @@ -22,8 +23,8 @@ public class CryptPBKDF2 implements EncryptionMethod { String playerName) throws NoSuchAlgorithmException { String[] line = hash.split("\\$"); String salt = line[2]; - String derivedKey = line[3]; - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000, derivedKey.getBytes()); + byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]); + PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000, derivedKey); PBKDF2Engine engine = new PBKDF2Engine(params); return engine.verifyKey(password); } From 7c2649abf51ed388805d89b4b2541454a27c4189 Mon Sep 17 00:00:00 2001 From: DmitryRendov Date: Sun, 6 Sep 2015 20:32:58 +0000 Subject: [PATCH 014/115] Fix --- src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java index 426b36ee0..7e672ea79 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java @@ -14,7 +14,7 @@ public class CryptPBKDF2 implements EncryptionMethod { String result = "pbkdf2_sha256$15000$" + salt + "$"; PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000); PBKDF2Engine engine = new PBKDF2Engine(params); - + return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32))); } From 8ec497a5e832459161426be79850fbee77552203 Mon Sep 17 00:00:00 2001 From: "Gabriele C." Date: Mon, 7 Sep 2015 13:25:40 +0200 Subject: [PATCH 015/115] Update AuthMe.java --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 7a817213a..5e6e2cc07 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -308,7 +308,7 @@ public class AuthMe extends JavaPlugin { // Sponsor message ConsoleLogger.info("AuthMe hooks perfectly with the VERYGAMES server hosting!"); - ConsoleLogger.info("AuthMe builds are available on jenkins, thanks to our sponsor GameHosting.it - leader in Italy in Game Server Provider"); + ConsoleLogger.info("Development builds are available on our jenkins, thanks to our sponsor GameHosting.it - leader in Italy as Game Server Provider"); ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!"); } From 0bab99b2fdf2fd92a21429fcc3e0d8cd2ac94480 Mon Sep 17 00:00:00 2001 From: "Gabriele C." Date: Mon, 7 Sep 2015 13:29:22 +0200 Subject: [PATCH 016/115] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02e6a9d36..3f12a0cc4 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ EUR: