cleared = database.autoPurgeDatabase(until);
- if (CollectionUtils.isEmpty(cleared)) {
- return;
- }
-
- ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!");
- ConsoleLogger.info("Purging user accounts...");
- new PurgeTask(plugin, Bukkit.getConsoleSender(), cleared, true, Bukkit.getOfflinePlayers())
- .runTaskTimer(plugin, 0, 1);
- }
-
- // Return the spawn location of a player
- @Deprecated
- public Location getSpawnLocation(Player player) {
- return spawnLoader.getSpawnLocation(player);
- }
-
- private void scheduleRecallEmailTask() {
- if (!newSettings.getProperty(RECALL_PLAYERS)) {
- return;
- }
- Bukkit.getScheduler().runTaskTimerAsynchronously(this, new Runnable() {
- @Override
- public void run() {
- for (PlayerAuth auth : database.getLoggedPlayers()) {
- String email = auth.getEmail();
- if (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email)) {
- Player player = bukkitService.getPlayerExact(auth.getRealName());
- if (player != null) {
- messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
- }
- }
- }
- }
- }, 1, 1200 * newSettings.getProperty(EmailSettings.DELAY_RECALL));
- }
-
public String replaceAllInfo(String message, Player player) {
String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size());
String ipAddress = Utils.getPlayerIp(player);
@@ -695,15 +359,15 @@ public class AuthMe extends JavaPlugin {
.replace("{ONLINE}", playersOnline)
.replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers()))
.replace("{IP}", ipAddress)
- .replace("{LOGINS}", Integer.toString(PlayerCache.getInstance().getLogged()))
+ .replace("{LOGINS}", Integer.toString(playerCache.getLogged()))
.replace("{WORLD}", player.getWorld().getName())
.replace("{SERVER}", server.getServerName())
.replace("{VERSION}", server.getBukkitVersion())
- .replace("{COUNTRY}", GeoLiteAPI.getCountryName(ipAddress));
+ // TODO: We should cache info like this, maybe with a class that extends Player?
+ .replace("{COUNTRY}", geoLiteApi.getCountryName(ipAddress));
}
-
/**
* Handle Bukkit commands.
*
@@ -726,67 +390,4 @@ public class AuthMe extends JavaPlugin {
// Handle the command
return commandHandler.processCommand(sender, commandLabel, args);
}
-
- public void notifyAutoPurgeEnd() {
- this.autoPurging = false;
- }
-
-
- // -------------
- // Service getters (deprecated)
- // Use @Inject fields instead
- // -------------
- /**
- * @return NewSetting
- * @deprecated should be used in API classes only (temporarily)
- */
- @Deprecated
- public NewSetting getSettings() {
- return newSettings;
- }
-
- /**
- * @return permission manager
- * @deprecated should be used in API classes only (temporarily)
- */
- @Deprecated
- public PermissionsManager getPermissionsManager() {
- return this.permsMan;
- }
-
- /**
- * @return process manager
- * @deprecated should be used in API classes only (temporarily)
- */
- @Deprecated
- public Management getManagement() {
- return management;
- }
-
- /**
- * @return the datasource
- * @deprecated should be used in API classes only (temporarily)
- */
- @Deprecated
- public DataSource getDataSource() {
- return database;
- }
-
- /**
- * @return password manager
- * @deprecated should be used in API classes only (temporarily)
- */
- @Deprecated
- public PasswordSecurity getPasswordSecurity() {
- return passwordSecurity;
- }
-
- /**
- * @return plugin hooks
- * @deprecated should be used in API classes only (temporarily)
- */
- @Deprecated
- public PluginHooks getPluginHooks() {
- return pluginHooks;
- }
}
diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java
index 284a7442..b0167459 100644
--- a/src/main/java/fr/xephi/authme/ConsoleLogger.java
+++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java
@@ -1,7 +1,9 @@
package fr.xephi.authme;
import com.google.common.base.Throwables;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.output.LogLevel;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.StringUtils;
@@ -11,7 +13,6 @@ import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
-import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -22,7 +23,7 @@ public final class ConsoleLogger {
private static final String NEW_LINE = System.getProperty("line.separator");
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
private static Logger logger;
- private static boolean enableDebug = false;
+ private static LogLevel logLevel = LogLevel.INFO;
private static boolean useLogging = false;
private static File logFile;
private static FileWriter fileWriter;
@@ -30,17 +31,36 @@ public final class ConsoleLogger {
private ConsoleLogger() {
}
+ // --------
+ // Configurations
+ // --------
+
+ /**
+ * Set the logger to use.
+ *
+ * @param logger The logger
+ */
public static void setLogger(Logger logger) {
ConsoleLogger.logger = logger;
}
+ /**
+ * Set the file to log to if enabled.
+ *
+ * @param logFile The log file
+ */
public static void setLogFile(File logFile) {
ConsoleLogger.logFile = logFile;
}
- public static void setLoggingOptions(NewSetting settings) {
+ /**
+ * Load the required settings.
+ *
+ * @param settings The settings instance
+ */
+ public static void setLoggingOptions(Settings settings) {
+ ConsoleLogger.logLevel = settings.getProperty(PluginSettings.LOG_LEVEL);
ConsoleLogger.useLogging = settings.getProperty(SecuritySettings.USE_LOGGING);
- ConsoleLogger.enableDebug = !settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE);
if (useLogging) {
if (fileWriter == null) {
try {
@@ -54,86 +74,81 @@ public final class ConsoleLogger {
}
}
+
+ // --------
+ // Logging methods
+ // --------
+
/**
- * Print an info message.
+ * Log a WARN message.
*
- * @param message String
+ * @param message The message to log
+ */
+ public static void warning(String message) {
+ logger.warning(message);
+ writeLog("[WARN] " + message);
+ }
+
+ /**
+ * Log an INFO message.
+ *
+ * @param message The message to log
*/
public static void info(String message) {
logger.info(message);
- if (useLogging) {
- writeLog(message);
- }
-
+ writeLog("[INFO] " + message);
}
+ /**
+ * Log a FINE message if enabled.
+ *
+ * Implementation note: this logs a message on INFO level because
+ * levels below INFO are disabled by Bukkit/Spigot.
+ *
+ * @param message The message to log
+ */
+ public static void fine(String message) {
+ if (logLevel.includes(LogLevel.FINE)) {
+ logger.info(message);
+ writeLog("[FINE] " + message);
+ }
+ }
+
+ /**
+ * Log a DEBUG message if enabled.
+ *
+ * Implementation note: this logs a message on INFO level and prefixes it with "DEBUG" because
+ * levels below INFO are disabled by Bukkit/Spigot.
+ *
+ * @param message The message to log
+ */
public static void debug(String message) {
- if (enableDebug) {
- //creating and filling an exception is a expensive call
- //TODO #419 20160601: ->so it should be removed as soon #419 is fixed
- //logger.isLoggable does not work because the plugin logger is always ALL
- logger.log(Level.FINE, message + ' ' + Thread.currentThread().getName(), new Exception());
-
- if (useLogging) {
- writeLog("Debug: " + Thread.currentThread().getName() + ':' + message);
- }
+ if (logLevel.includes(LogLevel.DEBUG)) {
+ logger.info("Debug: " + message);
+ writeLog("[DEBUG] " + message);
}
}
/**
- * Print an error message.
- *
- * @param message String
- */
- public static void showError(String message) {
- logger.warning(message);
- if (useLogging) {
- writeLog("ERROR: " + message);
- }
- }
-
- /**
- * Write a message into the log file with a TimeStamp.
- *
- * @param message String
- */
- private static void writeLog(String message) {
- String dateTime;
- synchronized (DATE_FORMAT) {
- dateTime = DATE_FORMAT.format(new Date());
- }
- try {
- fileWriter.write(dateTime);
- fileWriter.write(": ");
- fileWriter.write(message);
- fileWriter.write(NEW_LINE);
- fileWriter.flush();
- } catch (IOException ignored) {
- }
- }
-
- /**
- * Write a StackTrace into the log.
- *
- * @param th The Throwable whose stack trace should be logged
- */
- public static void writeStackTrace(Throwable th) {
- if (useLogging) {
- writeLog(Throwables.getStackTraceAsString(th));
- }
- }
-
- /**
- * Logs a Throwable with the provided message and saves the stack trace to the log file.
+ * Log a Throwable with the provided message on WARNING level
+ * and save the stack trace to the log file.
*
* @param message The message to accompany the exception
* @param th The Throwable to log
*/
public static void logException(String message, Throwable th) {
- showError(message + " " + StringUtils.formatException(th));
- writeStackTrace(th);
+ warning(message + " " + StringUtils.formatException(th));
+ writeLog(Throwables.getStackTraceAsString(th));
}
+
+ // --------
+ // Helpers
+ // --------
+
+ /**
+ * Close all file handles.
+ */
public static void close() {
if (fileWriter != null) {
try {
@@ -144,4 +159,26 @@ public final class ConsoleLogger {
}
}
}
+
+ /**
+ * Write a message into the log file with a TimeStamp if enabled.
+ *
+ * @param message The message to write to the log
+ */
+ private static void writeLog(String message) {
+ if (useLogging) {
+ String dateTime;
+ synchronized (DATE_FORMAT) {
+ dateTime = DATE_FORMAT.format(new Date());
+ }
+ try {
+ fileWriter.write(dateTime);
+ fileWriter.write(": ");
+ fileWriter.write(message);
+ fileWriter.write(NEW_LINE);
+ fileWriter.flush();
+ } catch (IOException ignored) {
+ }
+ }
+ }
}
diff --git a/src/main/java/fr/xephi/authme/PerformBackup.java b/src/main/java/fr/xephi/authme/PerformBackup.java
index 4106001f..79f1bf9f 100644
--- a/src/main/java/fr/xephi/authme/PerformBackup.java
+++ b/src/main/java/fr/xephi/authme/PerformBackup.java
@@ -1,7 +1,7 @@
package fr.xephi.authme;
import fr.xephi.authme.datasource.DataSourceType;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.BackupSettings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.util.StringUtils;
@@ -30,7 +30,7 @@ public class PerformBackup {
private final String tblname;
private final String path;
private final File dataFolder;
- private final NewSetting settings;
+ private final Settings settings;
/**
* Constructor for PerformBackup.
@@ -38,7 +38,7 @@ public class PerformBackup {
* @param instance AuthMe
* @param settings The plugin settings
*/
- public PerformBackup(AuthMe instance, NewSetting settings) {
+ public PerformBackup(AuthMe instance, Settings settings) {
this.dataFolder = instance.getDataFolder();
this.settings = settings;
this.dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
@@ -60,7 +60,7 @@ public class PerformBackup {
if (!settings.getProperty(BackupSettings.ENABLED)) {
// Print a warning if the backup was requested via command or by another plugin
if (cause == BackupCause.COMMAND || cause == BackupCause.OTHER) {
- ConsoleLogger.showError("Can't perform a Backup: disabled in configuration. Cause of the Backup: "
+ ConsoleLogger.warning("Can't perform a Backup: disabled in configuration. Cause of the Backup: "
+ cause.name());
}
return;
@@ -76,7 +76,7 @@ public class PerformBackup {
if (doBackup()) {
ConsoleLogger.info("A backup has been performed successfully. Cause of the Backup: " + cause.name());
} else {
- ConsoleLogger.showError("Error while performing a backup! Cause of the Backup: " + cause.name());
+ ConsoleLogger.warning("Error while performing a backup! Cause of the Backup: " + cause.name());
}
}
@@ -90,7 +90,7 @@ public class PerformBackup {
case SQLITE:
return fileBackup(dbName + ".db");
default:
- ConsoleLogger.showError("Unknown data source type '" + dataSourceType + "' for backup");
+ ConsoleLogger.warning("Unknown data source type '" + dataSourceType + "' for backup");
}
return false;
@@ -113,7 +113,7 @@ public class PerformBackup {
ConsoleLogger.info("Backup created successfully.");
return true;
} else {
- ConsoleLogger.showError("Could not create the backup! (Windows)");
+ ConsoleLogger.warning("Could not create the backup! (Windows)");
}
} catch (IOException | InterruptedException e) {
ConsoleLogger.logException("Error during Windows backup:", e);
@@ -128,7 +128,7 @@ public class PerformBackup {
ConsoleLogger.info("Backup created successfully.");
return true;
} else {
- ConsoleLogger.showError("Could not create the backup!");
+ ConsoleLogger.warning("Could not create the backup!");
}
} catch (IOException | InterruptedException e) {
ConsoleLogger.logException("Error during backup:", e);
@@ -147,8 +147,7 @@ public class PerformBackup {
copy("plugins" + File.separator + "AuthMe" + File.separator + backend, path + ".db");
return true;
} catch (IOException ex) {
- ConsoleLogger.showError("Encountered an error during file backup: " + StringUtils.formatException(ex));
- ConsoleLogger.writeStackTrace(ex);
+ ConsoleLogger.logException("Encountered an error during file backup:", ex);
}
return false;
}
@@ -166,7 +165,7 @@ public class PerformBackup {
if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) {
return true;
} else {
- ConsoleLogger.showError("Mysql Windows Path is incorrect. Please check it");
+ ConsoleLogger.warning("Mysql Windows Path is incorrect. Please check it");
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 ca75cee1..8757bcd5 100644
--- a/src/main/java/fr/xephi/authme/api/API.java
+++ b/src/main/java/fr/xephi/authme/api/API.java
@@ -4,10 +4,11 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
-import fr.xephi.authme.util.Utils;
+import fr.xephi.authme.util.ValidationService;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -27,19 +28,21 @@ public class API {
private static DataSource dataSource;
private static PasswordSecurity passwordSecurity;
private static Management management;
+ private static PluginHooks pluginHooks;
+ private static ValidationService validationService;
- /**
- * Constructor for the deprecated API.
- *
- * @param instance AuthMe
+ /*
+ * Constructor.
*/
- @Deprecated
@Inject
- API(AuthMe instance, DataSource dataSource, PasswordSecurity passwordSecurity, Management management) {
+ API(AuthMe instance, DataSource dataSource, PasswordSecurity passwordSecurity, Management management,
+ PluginHooks pluginHooks, ValidationService validationService) {
API.instance = instance;
API.dataSource = dataSource;
API.passwordSecurity = passwordSecurity;
API.management = management;
+ API.pluginHooks = pluginHooks;
+ API.validationService = validationService;
}
/**
@@ -47,7 +50,6 @@ public class API {
*
* @return AuthMe instance
*/
- @Deprecated
public static AuthMe hookAuthMe() {
if (instance != null) {
return instance;
@@ -66,7 +68,6 @@ public class API {
* @param player The player to verify
* @return true if the player is authenticated
*/
- @Deprecated
public static boolean isAuthenticated(Player player) {
return PlayerCache.getInstance().isAuthenticated(player.getName());
}
@@ -77,12 +78,10 @@ public class API {
* @param player The player to verify
* @return true if the player is unrestricted
*/
- @Deprecated
public static boolean isUnrestricted(Player player) {
- return Utils.isUnrestricted(player);
+ return validationService.isUnrestricted(player.getName());
}
- @Deprecated
public static Location getLastLocation(Player player) {
try {
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase());
@@ -99,7 +98,6 @@ public class API {
}
}
- @Deprecated
public static void setPlayerInventory(Player player, ItemStack[] content,
ItemStack[] armor) {
try {
@@ -115,7 +113,6 @@ public class API {
* @param playerName The player name to verify
* @return true if player is registered
*/
- @Deprecated
public static boolean isRegistered(String playerName) {
String player = playerName.toLowerCase();
return dataSource.isAuthAvailable(player);
@@ -128,7 +125,6 @@ public class API {
* @param passwordToCheck The password to check
* @return true if the password is correct, false otherwise
*/
- @Deprecated
public static boolean checkPassword(String playerName, String passwordToCheck) {
return isRegistered(playerName) && passwordSecurity.comparePassword(passwordToCheck, playerName);
}
@@ -140,7 +136,6 @@ public class API {
* @param password The password
* @return true if the player was registered correctly
*/
- @Deprecated
public static boolean registerPlayer(String playerName, String password) {
String name = playerName.toLowerCase();
HashedPassword hashedPassword = passwordSecurity.computeHash(password, name);
@@ -161,12 +156,10 @@ public class API {
*
* @param player The player to log in
*/
- @Deprecated
public static void forceLogin(Player player) {
management.performLogin(player, "dontneed", true);
}
- @Deprecated
public AuthMe getPlugin() {
return instance;
}
@@ -177,9 +170,8 @@ public class API {
* @param player The player to verify
* @return true if player is an npc
*/
- @Deprecated
public boolean isNPC(Player player) {
- return instance.getPluginHooks().isNpc(player);
+ return pluginHooks.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 5e0063e9..6b87cb53 100644
--- a/src/main/java/fr/xephi/authme/api/NewAPI.java
+++ b/src/main/java/fr/xephi/authme/api/NewAPI.java
@@ -3,12 +3,15 @@ package fr.xephi.authme.api;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
+import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.hooks.PluginHooks;
+import fr.xephi.authme.process.Management;
+import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
-import fr.xephi.authme.util.Utils;
+import fr.xephi.authme.util.ValidationService;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
import javax.inject.Inject;
@@ -22,34 +25,41 @@ public class NewAPI {
public static NewAPI singleton;
public final AuthMe plugin;
+ private final PluginHooks pluginHooks;
+ private final DataSource dataSource;
+ private final PasswordSecurity passwordSecurity;
+ private final Management management;
+ private final ValidationService validationService;
+ private final PlayerCache playerCache;
- /**
+ /*
* Constructor for NewAPI.
- *
- * @param plugin The AuthMe plugin instance
*/
@Inject
- public NewAPI(AuthMe plugin) {
+ NewAPI(AuthMe plugin, PluginHooks pluginHooks, DataSource dataSource, PasswordSecurity passwordSecurity,
+ Management management, ValidationService validationService, PlayerCache playerCache) {
this.plugin = plugin;
+ this.pluginHooks = pluginHooks;
+ this.dataSource = dataSource;
+ this.passwordSecurity = passwordSecurity;
+ this.management = management;
+ this.validationService = validationService;
+ this.playerCache = playerCache;
+ NewAPI.singleton = this;
}
/**
* Get the API object for AuthMe.
*
- * @return The API object, or null if the AuthMe plugin instance could not be retrieved
- * from the server environment
+ * @return The API object, or null if the AuthMe plugin is not enabled or not fully initialized yet
*/
public static NewAPI getInstance() {
if (singleton != null) {
return singleton;
}
- Plugin p = Bukkit.getServer().getPluginManager().getPlugin("AuthMe");
- if (p == null || !(p instanceof AuthMe)) {
- return null;
- }
- AuthMe authme = (AuthMe) p;
- singleton = new NewAPI(authme);
- return singleton;
+ // NewAPI is initialized in AuthMe#onEnable -> if singleton is null,
+ // it means AuthMe isn't initialized (yet)
+ return null;
}
/**
@@ -78,7 +88,7 @@ public class NewAPI {
* @return true if the player is authenticated
*/
public boolean isAuthenticated(Player player) {
- return PlayerCache.getInstance().isAuthenticated(player.getName());
+ return playerCache.isAuthenticated(player.getName());
}
/**
@@ -88,7 +98,7 @@ public class NewAPI {
* @return true if the player is an npc
*/
public boolean isNPC(Player player) {
- return plugin.getPluginHooks().isNpc(player);
+ return pluginHooks.isNpc(player);
}
/**
@@ -100,17 +110,17 @@ public class NewAPI {
* @see fr.xephi.authme.settings.properties.RestrictionSettings#UNRESTRICTED_NAMES
*/
public boolean isUnrestricted(Player player) {
- return Utils.isUnrestricted(player);
+ return validationService.isUnrestricted(player.getName());
}
/**
- * Get the last location of a player.
+ * Get the last location of an online player.
*
* @param player The player to process
* @return Location The location of the player
*/
public Location getLastLocation(Player player) {
- PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName());
+ PlayerAuth auth = playerCache.getAuth(player.getName());
if (auth != null) {
return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
}
@@ -125,7 +135,7 @@ public class NewAPI {
*/
public boolean isRegistered(String playerName) {
String player = playerName.toLowerCase();
- return plugin.getDataSource().isAuthAvailable(player);
+ return dataSource.isAuthAvailable(player);
}
/**
@@ -136,7 +146,7 @@ public class NewAPI {
* @return true if the password is correct, false otherwise
*/
public boolean checkPassword(String playerName, String passwordToCheck) {
- return isRegistered(playerName) && plugin.getPasswordSecurity().comparePassword(passwordToCheck, playerName);
+ return passwordSecurity.comparePassword(passwordToCheck, playerName);
}
/**
@@ -149,7 +159,7 @@ public class NewAPI {
*/
public boolean registerPlayer(String playerName, String password) {
String name = playerName.toLowerCase();
- HashedPassword result = plugin.getPasswordSecurity().computeHash(password, name);
+ HashedPassword result = passwordSecurity.computeHash(password, name);
if (isRegistered(name)) {
return false;
}
@@ -158,7 +168,7 @@ public class NewAPI {
.password(result)
.realName(playerName)
.build();
- return plugin.getDataSource().saveAuth(auth);
+ return dataSource.saveAuth(auth);
}
/**
@@ -167,7 +177,7 @@ public class NewAPI {
* @param player The player to log in
*/
public void forceLogin(Player player) {
- plugin.getManagement().performLogin(player, "dontneed", true);
+ management.performLogin(player, "dontneed", true);
}
/**
@@ -176,7 +186,7 @@ public class NewAPI {
* @param player The player to log out
*/
public void forceLogout(Player player) {
- plugin.getManagement().performLogout(player);
+ management.performLogout(player);
}
/**
@@ -187,7 +197,7 @@ public class NewAPI {
* @param autoLogin Should the player be authenticated automatically after the registration?
*/
public void forceRegister(Player player, String password, boolean autoLogin) {
- plugin.getManagement().performRegister(player, password, null, autoLogin);
+ management.performRegister(player, password, null, autoLogin);
}
/**
@@ -206,6 +216,6 @@ public class NewAPI {
* @param player The player to unregister
*/
public void forceUnregister(Player player) {
- plugin.getManagement().performUnregister(player, "", true);
+ management.performUnregisterByAdmin(null, player.getName(), player);
}
}
diff --git a/src/main/java/fr/xephi/authme/cache/CaptchaManager.java b/src/main/java/fr/xephi/authme/cache/CaptchaManager.java
index ec7deca9..f37637df 100644
--- a/src/main/java/fr/xephi/authme/cache/CaptchaManager.java
+++ b/src/main/java/fr/xephi/authme/cache/CaptchaManager.java
@@ -2,7 +2,7 @@ package fr.xephi.authme.cache;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.security.RandomString;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import javax.inject.Inject;
@@ -21,10 +21,10 @@ public class CaptchaManager implements SettingsDependent {
private int captchaLength;
@Inject
- CaptchaManager(NewSetting settings) {
+ CaptchaManager(Settings settings) {
this.playerCounts = new ConcurrentHashMap<>();
this.captchaCodes = new ConcurrentHashMap<>();
- loadSettings(settings);
+ reload(settings);
}
/**
@@ -123,7 +123,7 @@ public class CaptchaManager implements SettingsDependent {
}
@Override
- public void loadSettings(NewSetting settings) {
+ public void reload(Settings settings) {
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
diff --git a/src/main/java/fr/xephi/authme/cache/SessionManager.java b/src/main/java/fr/xephi/authme/cache/SessionManager.java
new file mode 100644
index 00000000..95b6d8db
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/cache/SessionManager.java
@@ -0,0 +1,96 @@
+package fr.xephi.authme.cache;
+
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.initialization.HasCleanup;
+import fr.xephi.authme.initialization.SettingsDependent;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.PluginSettings;
+
+import javax.inject.Inject;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages sessions, allowing players to be automatically logged in if they join again
+ * within a configurable amount of time.
+ */
+public class SessionManager implements SettingsDependent, HasCleanup {
+
+ private static final int MINUTE_IN_MILLIS = 60_000;
+ // Player -> expiration of session in milliseconds
+ private final Map sessions = new ConcurrentHashMap<>();
+
+ private boolean enabled;
+ private int timeoutInMinutes;
+
+ @Inject
+ SessionManager(Settings settings) {
+ reload(settings);
+ }
+
+ /**
+ * Check if a session is available for the given player.
+ *
+ * @param name The name to check.
+ * @return True if a session is found.
+ */
+ public boolean hasSession(String name) {
+ if (enabled) {
+ Long timeout = sessions.get(name.toLowerCase());
+ if (timeout != null) {
+ return System.currentTimeMillis() <= timeout;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add a player session to the cache.
+ *
+ * @param name The name of the player.
+ */
+ public void addSession(String name) {
+ if (enabled) {
+ long timeout = System.currentTimeMillis() + timeoutInMinutes * MINUTE_IN_MILLIS;
+ sessions.put(name.toLowerCase(), timeout);
+ }
+ }
+
+ /**
+ * Remove a player's session from the cache.
+ *
+ * @param name The name of the player.
+ */
+ public void removeSession(String name) {
+ this.sessions.remove(name.toLowerCase());
+ }
+
+ @Override
+ public void reload(Settings settings) {
+ timeoutInMinutes = settings.getProperty(PluginSettings.SESSIONS_TIMEOUT);
+ boolean oldEnabled = enabled;
+ enabled = timeoutInMinutes > 0 && settings.getProperty(PluginSettings.SESSIONS_ENABLED);
+
+ // With this reload, the sessions feature has just been disabled, so clear all stored sessions
+ if (oldEnabled && !enabled) {
+ sessions.clear();
+ ConsoleLogger.fine("Sessions disabled: cleared all sessions");
+ }
+ }
+
+ @Override
+ public void performCleanup() {
+ if (!enabled) {
+ return;
+ }
+ final long currentTime = System.currentTimeMillis();
+ Iterator> iterator = sessions.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = iterator.next();
+ if (entry.getValue() < currentTime) {
+ iterator.remove();
+ }
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/cache/TempbanManager.java b/src/main/java/fr/xephi/authme/cache/TempbanManager.java
index 0a55353c..c5f0ee6f 100644
--- a/src/main/java/fr/xephi/authme/cache/TempbanManager.java
+++ b/src/main/java/fr/xephi/authme/cache/TempbanManager.java
@@ -3,7 +3,7 @@ package fr.xephi.authme.cache;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.Utils;
@@ -30,11 +30,11 @@ public class TempbanManager implements SettingsDependent {
private int length;
@Inject
- TempbanManager(BukkitService bukkitService, Messages messages, NewSetting settings) {
+ TempbanManager(BukkitService bukkitService, Messages messages, Settings settings) {
this.ipLoginFailureCounts = new ConcurrentHashMap<>();
this.bukkitService = bukkitService;
this.messages = messages;
- loadSettings(settings);
+ reload(settings);
}
/**
@@ -108,7 +108,7 @@ public class TempbanManager implements SettingsDependent {
}
@Override
- public void loadSettings(NewSetting settings) {
+ public void reload(Settings settings) {
this.isEnabled = settings.getProperty(SecuritySettings.TEMPBAN_ON_MAX_LOGINS);
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TEMPBAN);
this.length = settings.getProperty(SecuritySettings.TEMPBAN_LENGTH);
diff --git a/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java b/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java
index 9bc57e20..cdbe0c00 100644
--- a/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java
+++ b/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java
@@ -85,6 +85,13 @@ public class PlayerAuth {
return groupId;
}
+ public void setQuitLocation(Location location) {
+ x = location.getBlockX();
+ y = location.getBlockY();
+ z = location.getBlockZ();
+ world = location.getWorld().getName();
+ }
+
public double getQuitLocX() {
return x;
}
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 9914ee3f..b1352833 100644
--- a/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java
+++ b/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java
@@ -1,10 +1,10 @@
package fr.xephi.authme.cache.auth;
-import fr.xephi.authme.ConsoleLogger;
import java.util.concurrent.ConcurrentHashMap;
/**
+ * Used to manage player's Authenticated status
*/
public class PlayerCache {
@@ -34,7 +34,6 @@ public class PlayerCache {
* @param auth PlayerAuth
*/
public void addPlayer(PlayerAuth auth) {
- ConsoleLogger.debug("ADDED PLAYER TO CACHE " + auth.getNickname());
cache.put(auth.getNickname().toLowerCase(), auth);
}
@@ -44,7 +43,6 @@ public class PlayerCache {
* @param auth PlayerAuth
*/
public void updatePlayer(PlayerAuth auth) {
- ConsoleLogger.debug("UPDATE PLAYER " + auth.getNickname());
cache.put(auth.getNickname(), auth);
}
@@ -54,16 +52,15 @@ public class PlayerCache {
* @param user String
*/
public void removePlayer(String user) {
- ConsoleLogger.debug("REMOVE PLAYER " + user);
cache.remove(user.toLowerCase());
}
/**
- * Method isAuthenticated.
+ * get player's authenticated status.
*
- * @param user String
+ * @param user player's name
*
- * @return boolean
+ * @return true if player is logged in, false otherwise.
*/
public boolean isAuthenticated(String user) {
return cache.containsKey(user.toLowerCase());
diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java
deleted file mode 100644
index d9735491..00000000
--- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package fr.xephi.authme.cache.backup;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.Files;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import org.bukkit.entity.Player;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Type;
-
-public class JsonCache {
-
- private final Gson gson;
- private final File cacheDir;
-
- public JsonCache() {
- cacheDir = new File(AuthMe.getInstance().getDataFolder(), "cache");
- if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
- ConsoleLogger.showError("Failed to create cache directory.");
- }
- gson = new GsonBuilder()
- .registerTypeAdapter(PlayerData.class, new PlayerDataSerializer())
- .registerTypeAdapter(PlayerData.class, new PlayerDataDeserializer())
- .setPrettyPrinting()
- .create();
- }
-
- public PlayerData readCache(Player player) {
- String name = player.getName().toLowerCase();
- File file = new File(cacheDir, name + File.separator + "cache.json");
- if (!file.exists()) {
- return null;
- }
-
- try {
- String str = Files.toString(file, Charsets.UTF_8);
- return gson.fromJson(str, PlayerData.class);
- } catch (IOException e) {
- ConsoleLogger.writeStackTrace(e);
- return null;
- }
- }
-
- public void removeCache(Player player) {
- String name = player.getName().toLowerCase();
- File file = new File(cacheDir, name);
- if (file.exists()) {
- purgeDirectory(file);
- if (!file.delete()) {
- ConsoleLogger.showError("Failed to remove" + player.getName() + "cache.");
- }
- }
- }
-
- public boolean doesCacheExist(Player player) {
- String name = player.getName().toLowerCase();
- File file = new File(cacheDir, name + File.separator + "cache.json");
- return file.exists();
- }
-
- private class PlayerDataDeserializer implements JsonDeserializer {
- @Override
- public PlayerData deserialize(JsonElement jsonElement, Type type,
- JsonDeserializationContext context) {
- JsonObject jsonObject = jsonElement.getAsJsonObject();
- if (jsonObject == null) {
- return null;
- }
- String group = null;
- boolean operator = false;
- boolean fly = false;
-
- JsonElement e;
- if ((e = jsonObject.get("group")) != null) {
- group = e.getAsString();
- }
- if ((e = jsonObject.get("operator")) != null) {
- operator = e.getAsBoolean();
- }
- if ((e = jsonObject.get("fly")) != null) {
- fly = e.getAsBoolean();
- }
-
- return new PlayerData(group, operator, fly);
- }
- }
-
- private class PlayerDataSerializer implements JsonSerializer {
- @Override
- public JsonElement serialize(PlayerData playerData, Type type,
- JsonSerializationContext context) {
- JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("group", playerData.getGroup());
- jsonObject.addProperty("operator", playerData.getOperator());
- jsonObject.addProperty("fly", playerData.isFlyEnabled());
- return jsonObject;
- }
- }
-
- /**
- * Delete a given directory and all its content.
- *
- * @param directory The directory to remove
- */
- private static void purgeDirectory(File directory) {
- if (!directory.isDirectory()) {
- return;
- }
- File[] files = directory.listFiles();
- if (files == null) {
- return;
- }
- for (File target : files) {
- if (target.isDirectory()) {
- purgeDirectory(target);
- }
- target.delete();
- }
- }
-
-}
diff --git a/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java b/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java
deleted file mode 100644
index a41b8aa9..00000000
--- a/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package fr.xephi.authme.cache.backup;
-
-public class PlayerData {
-
- private final String group;
- private final boolean operator;
- private final boolean flyEnabled;
-
- public PlayerData(String group, boolean operator, boolean flyEnabled) {
- this.group = group;
- this.operator = operator;
- this.flyEnabled = flyEnabled;
- }
-
- public String getGroup() {
- return group;
- }
-
- public boolean getOperator() {
- return operator;
- }
-
- public boolean isFlyEnabled() {
- return flyEnabled;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/cache/backup/PlayerDataStorage.java b/src/main/java/fr/xephi/authme/cache/backup/PlayerDataStorage.java
new file mode 100644
index 00000000..73c96e21
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/cache/backup/PlayerDataStorage.java
@@ -0,0 +1,214 @@
+package fr.xephi.authme.cache.backup;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.cache.limbo.PlayerData;
+import fr.xephi.authme.initialization.DataFolder;
+import fr.xephi.authme.permission.PermissionsManager;
+import fr.xephi.authme.settings.SpawnLoader;
+import fr.xephi.authme.util.BukkitService;
+import fr.xephi.authme.util.FileUtils;
+import fr.xephi.authme.util.Utils;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Type;
+
+/**
+ * Class used to store player's data (OP, flying, speed, position) to disk.
+ */
+public class PlayerDataStorage {
+
+ private final Gson gson;
+ private final File cacheDir;
+ private PermissionsManager permissionsManager;
+ private SpawnLoader spawnLoader;
+ private BukkitService bukkitService;
+
+ @Inject
+ PlayerDataStorage(@DataFolder File dataFolder, PermissionsManager permsMan,
+ SpawnLoader spawnLoader, BukkitService bukkitService) {
+ this.permissionsManager = permsMan;
+ this.spawnLoader = spawnLoader;
+ this.bukkitService = bukkitService;
+
+ cacheDir = new File(dataFolder, "playerdata");
+ if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
+ ConsoleLogger.warning("Failed to create userdata directory.");
+ }
+ gson = new GsonBuilder()
+ .registerTypeAdapter(PlayerData.class, new PlayerDataSerializer())
+ .registerTypeAdapter(PlayerData.class, new PlayerDataDeserializer())
+ .setPrettyPrinting()
+ .create();
+ }
+
+ /**
+ * Read and construct new PlayerData from existing player data.
+ *
+ * @param player player to read
+ *
+ * @return PlayerData object if the data is exist, null otherwise.
+ */
+ public PlayerData readData(Player player) {
+ String id = Utils.getUUIDorName(player);
+ File file = new File(cacheDir, id + File.separator + "data.json");
+ if (!file.exists()) {
+ return null;
+ }
+
+ try {
+ String str = Files.toString(file, Charsets.UTF_8);
+ return gson.fromJson(str, PlayerData.class);
+ } catch (IOException e) {
+ ConsoleLogger.logException("Could not read player data on disk for '" + player.getName() + "'", e);
+ return null;
+ }
+ }
+
+ /**
+ * Save player data (OP, flying, location, etc) to disk.
+ *
+ * @param player player to save
+ */
+ public void saveData(Player player) {
+ String id = Utils.getUUIDorName(player);
+ Location location = spawnLoader.getPlayerLocationOrSpawn(player);
+ String group = "";
+ if (permissionsManager.hasGroupSupport()) {
+ group = permissionsManager.getPrimaryGroup(player);
+ }
+ boolean operator = player.isOp();
+ boolean canFly = player.getAllowFlight();
+ float walkSpeed = player.getWalkSpeed();
+ float flySpeed = player.getFlySpeed();
+ PlayerData playerData = new PlayerData(location, operator, group, canFly, walkSpeed, flySpeed);
+ try {
+ File file = new File(cacheDir, id + File.separator + "data.json");
+ Files.createParentDirs(file);
+ Files.touch(file);
+ Files.write(gson.toJson(playerData), file, Charsets.UTF_8);
+ } catch (IOException e) {
+ ConsoleLogger.logException("Failed to write " + player.getName() + " data.", e);
+ }
+ }
+
+ /**
+ * Remove player data, this will delete
+ * "playerdata/<uuid or name>/" folder from disk.
+ *
+ * @param player player to remove
+ */
+ public void removeData(Player player) {
+ String id = Utils.getUUIDorName(player);
+ File file = new File(cacheDir, id);
+ if (file.exists()) {
+ FileUtils.purgeDirectory(file);
+ if (!file.delete()) {
+ ConsoleLogger.warning("Failed to remove " + player.getName() + " cache.");
+ }
+ }
+ }
+
+ /**
+ * Use to check is player data is exist.
+ *
+ * @param player player to check
+ *
+ * @return true if data exist, false otherwise.
+ */
+ public boolean hasData(Player player) {
+ String id = Utils.getUUIDorName(player);
+ File file = new File(cacheDir, id + File.separator + "data.json");
+ return file.exists();
+ }
+
+ private class PlayerDataDeserializer implements JsonDeserializer {
+ @Override
+ public PlayerData deserialize(JsonElement jsonElement, Type type,
+ JsonDeserializationContext context) {
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ if (jsonObject == null) {
+ return null;
+ }
+
+ Location loc = null;
+ String group = "";
+ boolean operator = false;
+ boolean canFly = false;
+ float walkSpeed = 0.2f;
+ float flySpeed = 0.2f;
+
+ JsonElement e;
+ if ((e = jsonObject.getAsJsonObject("location")) != null) {
+ JsonObject obj = e.getAsJsonObject();
+ World world = bukkitService.getWorld(obj.get("world").getAsString());
+ if (world != null) {
+ double x = obj.get("x").getAsDouble();
+ double y = obj.get("y").getAsDouble();
+ double z = obj.get("z").getAsDouble();
+ float yaw = obj.get("yaw").getAsFloat();
+ float pitch = obj.get("pitch").getAsFloat();
+ loc = new Location(world, x, y, z, yaw, pitch);
+ }
+ }
+ if ((e = jsonObject.get("group")) != null) {
+ group = e.getAsString();
+ }
+ if ((e = jsonObject.get("operator")) != null) {
+ operator = e.getAsBoolean();
+ }
+ if ((e = jsonObject.get("can-fly")) != null) {
+ canFly = e.getAsBoolean();
+ }
+ if ((e = jsonObject.get("walk-speed")) != null) {
+ walkSpeed = e.getAsFloat();
+ }
+ if ((e = jsonObject.get("fly-speed")) != null) {
+ flySpeed = e.getAsFloat();
+ }
+
+ return new PlayerData(loc, operator, group, canFly, walkSpeed, flySpeed);
+ }
+ }
+
+ private class PlayerDataSerializer implements JsonSerializer {
+ @Override
+ public JsonElement serialize(PlayerData playerData, Type type,
+ JsonSerializationContext context) {
+ JsonObject obj = new JsonObject();
+ obj.addProperty("group", playerData.getGroup());
+
+ Location loc = playerData.getLocation();
+ JsonObject obj2 = new JsonObject();
+ obj2.addProperty("world", loc.getWorld().getName());
+ obj2.addProperty("x", loc.getX());
+ obj2.addProperty("y", loc.getY());
+ obj2.addProperty("z", loc.getZ());
+ obj2.addProperty("yaw", loc.getYaw());
+ obj2.addProperty("pitch", loc.getPitch());
+ obj.add("location", obj2);
+
+ obj.addProperty("operator", playerData.isOperator());
+ obj.addProperty("can-fly", playerData.isCanFly());
+ obj.addProperty("walk-speed", playerData.getWalkSpeed());
+ obj.addProperty("fly-speed", playerData.getFlySpeed());
+ return obj;
+ }
+ }
+
+
+}
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 97670a88..a49408b0 100644
--- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java
+++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java
@@ -1,111 +1,164 @@
package fr.xephi.authme.cache.limbo;
-import fr.xephi.authme.cache.backup.JsonCache;
-import fr.xephi.authme.cache.backup.PlayerData;
+import fr.xephi.authme.cache.backup.PlayerDataStorage;
import fr.xephi.authme.permission.PermissionsManager;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader;
+import fr.xephi.authme.settings.properties.PluginSettings;
+import fr.xephi.authme.util.StringUtils;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import javax.inject.Inject;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkNotNull;
/**
- * Manages all {@link LimboPlayer} instances.
+ * Manages all {@link PlayerData} instances.
*/
public class LimboCache {
- private final ConcurrentHashMap cache = new ConcurrentHashMap<>();
- private final JsonCache jsonCache = new JsonCache();
+ private final Map cache = new ConcurrentHashMap<>();
- @Inject
+ private PlayerDataStorage playerDataStorage;
+ private Settings settings;
private PermissionsManager permissionsManager;
- @Inject
private SpawnLoader spawnLoader;
@Inject
- LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader) {
+ LimboCache(Settings settings, PermissionsManager permissionsManager,
+ SpawnLoader spawnLoader, PlayerDataStorage playerDataStorage) {
+ this.settings = settings;
this.permissionsManager = permissionsManager;
this.spawnLoader = spawnLoader;
+ this.playerDataStorage = playerDataStorage;
}
/**
- * Add a limbo player.
+ * Load player data if exist, otherwise current player's data will be stored.
*
* @param player Player instance to add.
*/
- public void addLimboPlayer(Player player) {
+ public void addPlayerData(Player player) {
String name = player.getName().toLowerCase();
- Location location = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation();
+ Location location = spawnLoader.getPlayerLocationOrSpawn(player);
boolean operator = player.isOp();
boolean flyEnabled = player.getAllowFlight();
+ float walkSpeed = player.getWalkSpeed();
+ float flySpeed = player.getFlySpeed();
String playerGroup = "";
if (permissionsManager.hasGroupSupport()) {
playerGroup = permissionsManager.getPrimaryGroup(player);
}
- if (jsonCache.doesCacheExist(player)) {
- PlayerData cache = jsonCache.readCache(player);
+ if (playerDataStorage.hasData(player)) {
+ PlayerData cache = playerDataStorage.readData(player);
if (cache != null) {
+ location = cache.getLocation();
playerGroup = cache.getGroup();
- operator = cache.getOperator();
- flyEnabled = cache.isFlyEnabled();
+ operator = cache.isOperator();
+ flyEnabled = cache.isCanFly();
+ walkSpeed = cache.getWalkSpeed();
+ flySpeed = cache.getFlySpeed();
}
+ } else {
+ playerDataStorage.saveData(player);
}
-
- cache.put(name, new LimboPlayer(name, location, operator, playerGroup, flyEnabled));
+ cache.put(name, new PlayerData(location, operator, playerGroup, flyEnabled, walkSpeed, flySpeed));
}
/**
- * Method deleteLimboPlayer.
+ * Restore player's data to player if exist.
*
- * @param name String
+ * @param player Player instance to restore
*/
- public void deleteLimboPlayer(String name) {
- checkNotNull(name);
- name = name.toLowerCase();
- LimboPlayer cachedPlayer = cache.remove(name);
+ public void restoreData(Player player) {
+ String lowerName = player.getName().toLowerCase();
+ if (cache.containsKey(lowerName)) {
+ PlayerData data = cache.get(lowerName);
+ player.setOp(data.isOperator());
+ player.setAllowFlight(data.isCanFly());
+ float walkSpeed = data.getWalkSpeed();
+ float flySpeed = data.getFlySpeed();
+ // Reset the speed value if it was 0
+ if(walkSpeed == 0f) {
+ walkSpeed = 0.2f;
+ }
+ if(flySpeed == 0f) {
+ flySpeed = 0.2f;
+ }
+ player.setWalkSpeed(walkSpeed);
+ player.setFlySpeed(flySpeed);
+ restoreGroup(player, data.getGroup());
+ data.clearTasks();
+ }
+ }
+
+ /**
+ * Remove PlayerData from cache and disk.
+ *
+ * @param player Player player to remove.
+ */
+ public void deletePlayerData(Player player) {
+ removeFromCache(player);
+ playerDataStorage.removeData(player);
+ }
+
+ /**
+ * Remove PlayerData from cache.
+ *
+ * @param player player to remove.
+ */
+ public void removeFromCache(Player player) {
+ String name = player.getName().toLowerCase();
+ PlayerData cachedPlayer = cache.remove(name);
if (cachedPlayer != null) {
cachedPlayer.clearTasks();
}
}
/**
- * Method getLimboPlayer.
+ * Method getPlayerData.
*
* @param name String
*
- * @return LimboPlayer
+ * @return PlayerData
*/
- public LimboPlayer getLimboPlayer(String name) {
+ public PlayerData getPlayerData(String name) {
checkNotNull(name);
return cache.get(name.toLowerCase());
}
/**
- * Method hasLimboPlayer.
+ * Method hasPlayerData.
*
* @param name String
*
* @return boolean
*/
- public boolean hasLimboPlayer(String name) {
+ public boolean hasPlayerData(String name) {
checkNotNull(name);
return cache.containsKey(name.toLowerCase());
}
/**
- * Method updateLimboPlayer.
+ * Method updatePlayerData.
*
* @param player Player
*/
- public void updateLimboPlayer(Player player) {
+ public void updatePlayerData(Player player) {
checkNotNull(player);
- deleteLimboPlayer(player.getName().toLowerCase());
- addLimboPlayer(player);
+ removeFromCache(player);
+ addPlayerData(player);
}
+ private void restoreGroup(Player player, String group) {
+ if (!StringUtils.isEmpty(group) && permissionsManager.hasGroupSupport()
+ && settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
+ permissionsManager.setGroup(player, group);
+ }
+ }
}
diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java b/src/main/java/fr/xephi/authme/cache/limbo/PlayerData.java
similarity index 79%
rename from src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java
rename to src/main/java/fr/xephi/authme/cache/limbo/PlayerData.java
index 6295bbb7..36e641fd 100644
--- a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java
+++ b/src/main/java/fr/xephi/authme/cache/limbo/PlayerData.java
@@ -7,32 +7,25 @@ import org.bukkit.scheduler.BukkitTask;
* Represents a player which is not logged in and keeps track of certain states (like OP status, flying)
* which may be revoked from the player until he has logged in or registered.
*/
-public class LimboPlayer {
+public class PlayerData {
- private final String name;
- private final boolean fly;
- private Location loc = null;
+ private final boolean canFly;
+ private final boolean operator;
+ private final String group;
+ private final Location loc;
+ private final float walkSpeed;
+ private final float flySpeed;
private BukkitTask timeoutTask = null;
private BukkitTask messageTask = null;
- private boolean operator = false;
- private String group;
- public LimboPlayer(String name, Location loc, boolean operator,
- String group, boolean fly) {
- this.name = name;
+ public PlayerData(Location loc, boolean operator,
+ String group, boolean fly, float walkSpeed, float flySpeed) {
this.loc = loc;
this.operator = operator;
this.group = group;
- this.fly = fly;
- }
-
- /**
- * Return the name of the player.
- *
- * @return The player's name
- */
- public String getName() {
- return name;
+ this.canFly = fly;
+ this.walkSpeed = walkSpeed;
+ this.flySpeed = flySpeed;
}
/**
@@ -40,7 +33,7 @@ public class LimboPlayer {
*
* @return The player's location
*/
- public Location getLoc() {
+ public Location getLocation() {
return loc;
}
@@ -62,8 +55,16 @@ public class LimboPlayer {
return group;
}
- public boolean isFly() {
- return fly;
+ public boolean isCanFly() {
+ return canFly;
+ }
+
+ public float getWalkSpeed() {
+ return walkSpeed;
+ }
+
+ public float getFlySpeed() {
+ return flySpeed;
}
/**
diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java
index da5299e2..743b01e8 100644
--- a/src/main/java/fr/xephi/authme/command/CommandHandler.java
+++ b/src/main/java/fr/xephi/authme/command/CommandHandler.java
@@ -1,8 +1,8 @@
package fr.xephi.authme.command;
+import ch.jalu.injector.Injector;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.help.HelpProvider;
-import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor;
@@ -37,12 +37,12 @@ public class CommandHandler {
private Map, ExecutableCommand> commands = new HashMap<>();
@Inject
- public CommandHandler(AuthMeServiceInitializer initializer, CommandMapper commandMapper,
+ public CommandHandler(Injector injector, CommandMapper commandMapper,
PermissionsManager permissionsManager, HelpProvider helpProvider) {
this.commandMapper = commandMapper;
this.permissionsManager = permissionsManager;
this.helpProvider = helpProvider;
- initializeCommands(initializer, commandMapper.getCommandClasses());
+ initializeCommands(injector, commandMapper.getCommandClasses());
}
/**
@@ -90,12 +90,13 @@ public class CommandHandler {
/**
* Initialize all required ExecutableCommand objects.
*
+ * @param injector the injector
* @param commandClasses the classes to instantiate
*/
- private void initializeCommands(AuthMeServiceInitializer initializer,
+ private void initializeCommands(Injector injector,
Set> commandClasses) {
for (Class extends ExecutableCommand> clazz : commandClasses) {
- commands.put(clazz, initializer.newInstance(clazz));
+ commands.put(clazz, injector.newInstance(clazz));
}
}
diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java
index 5efe79e8..567bcb30 100644
--- a/src/main/java/fr/xephi/authme/command/CommandService.java
+++ b/src/main/java/fr/xephi/authme/command/CommandService.java
@@ -2,7 +2,7 @@ package fr.xephi.authme.command;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
@@ -18,7 +18,7 @@ public class CommandService {
@Inject
private Messages messages;
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private ValidationService validationService;
@@ -53,6 +53,16 @@ public class CommandService {
return messages.retrieve(key);
}
+ /**
+ * Retrieve a message as a single String by its message key.
+ *
+ * @param key The message to retrieve
+ * @return The message
+ */
+ public String retrieveSingle(MessageKey key) {
+ return messages.retrieveSingle(key);
+ }
+
/**
* Retrieve the given property's value.
*
@@ -69,7 +79,7 @@ public class CommandService {
*
* @return The settings manager
*/
- public NewSetting getSettings() {
+ public Settings getSettings() {
return settings;
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java
index 729a4b4e..d55e84ac 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java
@@ -75,7 +75,7 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
if (dataSource.updatePassword(auth)) {
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
- ConsoleLogger.info(playerNameLowerCase + "'s password changed");
+ ConsoleLogger.info(sender.getName() + " changed password of " + playerNameLowerCase);
} else {
commandService.send(sender, MessageKey.ERROR);
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
index e18c9dc4..a4a06486 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
@@ -1,6 +1,8 @@
package fr.xephi.authme.command.executable.authme;
+import ch.jalu.injector.Injector;
import com.google.common.annotations.VisibleForTesting;
+import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.converter.Converter;
@@ -10,7 +12,6 @@ import fr.xephi.authme.converter.RoyalAuthConverter;
import fr.xephi.authme.converter.SqliteToSql;
import fr.xephi.authme.converter.vAuthConverter;
import fr.xephi.authme.converter.xAuthConverter;
-import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.command.CommandSender;
@@ -30,7 +31,7 @@ public class ConverterCommand implements ExecutableCommand {
private BukkitService bukkitService;
@Inject
- private AuthMeServiceInitializer initializer;
+ private Injector injector;
@Override
public void executeCommand(final CommandSender sender, List arguments) {
@@ -45,13 +46,17 @@ public class ConverterCommand implements ExecutableCommand {
}
// Get the proper converter instance
- final Converter converter = initializer.newInstance(jobType.getConverterClass());
+ final Converter converter = injector.newInstance(jobType.getConverterClass());
// Run the convert job
bukkitService.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
- converter.execute(sender);
+ try {
+ converter.execute(sender);
+ } catch (Exception e) {
+ ConsoleLogger.logException("Error during conversion:", e);
+ }
}
});
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java
index c80a790d..b4e9e545 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java
@@ -1,11 +1,8 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.ExecutableCommand;
-import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.task.PurgeTask;
+import fr.xephi.authme.task.purge.PurgeService;
import fr.xephi.authme.util.BukkitService;
-import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
@@ -21,10 +18,7 @@ import java.util.Set;
public class PurgeBannedPlayersCommand implements ExecutableCommand {
@Inject
- private DataSource dataSource;
-
- @Inject
- private AuthMe plugin;
+ private PurgeService purgeService;
@Inject
private BukkitService bukkitService;
@@ -32,18 +26,12 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand {
@Override
public void executeCommand(CommandSender sender, List arguments) {
// Get the list of banned players
- Set namedBanned = new HashSet<>();
Set bannedPlayers = bukkitService.getBannedPlayers();
+ Set namedBanned = new HashSet<>(bannedPlayers.size());
for (OfflinePlayer offlinePlayer : bannedPlayers) {
namedBanned.add(offlinePlayer.getName().toLowerCase());
}
- //todo: note this should may run async because it may executes a SQL-Query
- // Purge the banned players
- dataSource.purgeBanned(namedBanned);
-
- // Show a status message
- sender.sendMessage(ChatColor.GOLD + "Purging user accounts...");
- new PurgeTask(plugin, sender, namedBanned, bannedPlayers).runTaskTimer(plugin, 0, 1);
+ purgeService.purgePlayers(sender, namedBanned, bannedPlayers.toArray(new OfflinePlayer[bannedPlayers.size()]));
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java
index 73e8e7c0..21552d81 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java
@@ -1,16 +1,13 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.ExecutableCommand;
-import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.task.PurgeTask;
+import fr.xephi.authme.task.purge.PurgeService;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.Calendar;
import java.util.List;
-import java.util.Set;
/**
* Command for purging the data of players which have not been since for a given number
@@ -21,10 +18,7 @@ public class PurgeCommand implements ExecutableCommand {
private static final int MINIMUM_LAST_SEEN_DAYS = 30;
@Inject
- private DataSource dataSource;
-
- @Inject
- private AuthMe plugin;
+ private PurgeService purgeService;
@Override
public void executeCommand(CommandSender sender, List arguments) {
@@ -52,13 +46,7 @@ public class PurgeCommand implements ExecutableCommand {
calendar.add(Calendar.DATE, -days);
long until = calendar.getTimeInMillis();
- //todo: note this should may run async because it may executes a SQL-Query
- // Purge the data, get the purged values
- Set purged = dataSource.autoPurgeDatabase(until);
-
- // Show a status message
- sender.sendMessage(ChatColor.GOLD + "Deleted " + purged.size() + " user accounts");
- sender.sendMessage(ChatColor.GOLD + "Purging user accounts...");
- new PurgeTask(plugin, sender, purged).runTaskTimer(plugin, 0, 1);
+ // Run the purge
+ purgeService.runPurge(sender, until);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java
index a4931e96..325eb4c0 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java
@@ -2,6 +2,7 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
@@ -37,6 +38,9 @@ public class RegisterAdminCommand implements ExecutableCommand {
@Inject
private ValidationService validationService;
+ @Inject
+ private LimboCache limboCache;
+
@Override
public void executeCommand(final CommandSender sender, List arguments) {
// Get the player name and password
@@ -79,7 +83,8 @@ public class RegisterAdminCommand implements ExecutableCommand {
bukkitService.scheduleSyncDelayedTask(new Runnable() {
@Override
public void run() {
- player.kickPlayer("An admin just registered you, please log in again");
+ limboCache.restoreData(player);
+ player.kickPlayer(commandService.retrieveSingle(MessageKey.KICK_FOR_ADMIN_REGISTER));
}
});
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java
index 73534902..e6b8009f 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java
@@ -1,17 +1,20 @@
package fr.xephi.authme.command.executable.authme;
+import ch.jalu.injector.Injector;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.initialization.AuthMeServiceInitializer;
+import fr.xephi.authme.initialization.Reloadable;
+import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.output.MessageKey;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
+import java.util.Collection;
import java.util.List;
/**
@@ -23,10 +26,10 @@ public class ReloadCommand implements ExecutableCommand {
private AuthMe plugin;
@Inject
- private AuthMeServiceInitializer initializer;
+ private Injector injector;
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private DataSource dataSource;
@@ -44,7 +47,7 @@ public class ReloadCommand implements ExecutableCommand {
ConsoleLogger.info("Note: cannot change database type during /authme reload");
sender.sendMessage("Note: cannot change database type during /authme reload");
}
- initializer.performReloadOnServices();
+ performReloadOnServices();
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} catch (Exception e) {
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
@@ -52,4 +55,16 @@ public class ReloadCommand implements ExecutableCommand {
plugin.stopOrUnload();
}
}
+
+ private void performReloadOnServices() {
+ Collection reloadables = injector.retrieveAllOfType(Reloadable.class);
+ for (Reloadable reloadable : reloadables) {
+ reloadable.reload();
+ }
+
+ Collection settingsDependents = injector.retrieveAllOfType(SettingsDependent.class);
+ for (SettingsDependent dependent : settingsDependents) {
+ dependent.reload(settings);
+ }
+ }
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
index 2e746f0d..eaf14b6b 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
@@ -1,29 +1,17 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.cache.auth.PlayerCache;
-import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
-import fr.xephi.authme.permission.AuthGroupHandler;
-import fr.xephi.authme.permission.AuthGroupType;
-import fr.xephi.authme.settings.properties.RegistrationSettings;
-import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.task.LimboPlayerTaskManager;
+import fr.xephi.authme.process.Management;
import fr.xephi.authme.util.BukkitService;
-import fr.xephi.authme.util.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
import java.util.List;
-import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
-
/**
* Admin command to unregister a player.
*/
@@ -35,74 +23,27 @@ public class UnregisterAdminCommand implements ExecutableCommand {
@Inject
private CommandService commandService;
- @Inject
- private PlayerCache playerCache;
-
@Inject
private BukkitService bukkitService;
@Inject
- private LimboCache limboCache;
-
- @Inject
- private LimboPlayerTaskManager limboPlayerTaskManager;
-
- @Inject
- private AuthGroupHandler authGroupHandler;
+ private Management management;
+ UnregisterAdminCommand() {
+ }
@Override
public void executeCommand(final CommandSender sender, List arguments) {
- // Get the player name
String playerName = arguments.get(0);
- String playerNameLowerCase = playerName.toLowerCase();
- // Make sure the user is valid
- if (!dataSource.isAuthAvailable(playerNameLowerCase)) {
+ // Make sure the user exists
+ if (!dataSource.isAuthAvailable(playerName)) {
commandService.send(sender, MessageKey.UNKNOWN_USER);
return;
}
- // Remove the player
- if (!dataSource.removeAuth(playerNameLowerCase)) {
- commandService.send(sender, MessageKey.ERROR);
- return;
- }
-
- // Unregister the player
- Player target = bukkitService.getPlayerExact(playerNameLowerCase);
- playerCache.removePlayer(playerNameLowerCase);
- authGroupHandler.setGroup(target, AuthGroupType.UNREGISTERED);
- if (target != null && target.isOnline()) {
- if (commandService.getProperty(RegistrationSettings.FORCE)) {
- applyUnregisteredEffectsAndTasks(target);
- }
- commandService.send(target, MessageKey.UNREGISTERED_SUCCESS);
- }
-
- // Show a status message
- commandService.send(sender, MessageKey.UNREGISTERED_SUCCESS);
- ConsoleLogger.info(sender.getName() + " unregistered " + playerName);
- }
-
- /**
- * When registration is forced, applies the configured "unregistered effects" to the player as he
- * would encounter when joining the server before logging on - reminder task to log in,
- * timeout kick, blindness.
- *
- * @param target the player that was unregistered
- */
- private void applyUnregisteredEffectsAndTasks(Player target) {
- // TODO #765: Remove use of Utils method and behave according to settings
- Utils.teleportToSpawn(target);
-
- limboCache.addLimboPlayer(target);
- limboPlayerTaskManager.registerTimeoutTask(target);
- limboPlayerTaskManager.registerMessageTask(target.getName(), false);
-
- final int timeout = commandService.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
- if (commandService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
- target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
- }
+ // Get the player from the server and perform unregister
+ Player target = bukkitService.getPlayerExact(playerName);
+ management.performUnregisterByAdmin(sender, playerName, target);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java
index a7e6575e..86437dd7 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java
@@ -31,11 +31,13 @@ public class VersionCommand implements ExecutableCommand {
+ " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")");
sender.sendMessage(ChatColor.GOLD + "Developers:");
Collection extends Player> onlinePlayers = bukkitService.getOnlinePlayers();
- printDeveloper(sender, "Xephi", "xephi59", "Lead Developer", onlinePlayers);
+ printDeveloper(sender, "Alexandre Vanhecke", "xephi59", "Original Author", onlinePlayers);
+ printDeveloper(sender, "Lucas J.", "ljacqu", "Main Developer", onlinePlayers);
+ printDeveloper(sender, "Gnat008", "gnat008", "Developer", onlinePlayers);
printDeveloper(sender, "DNx5", "DNx5", "Developer", onlinePlayers);
printDeveloper(sender, "games647", "games647", "Developer", onlinePlayers);
printDeveloper(sender, "Tim Visee", "timvisee", "Developer", onlinePlayers);
- printDeveloper(sender, "Sgdc3", "sgdc3", "Project manager, Contributor", onlinePlayers);
+ printDeveloper(sender, "Gabriele C.", "sgdc3", "Project manager, Contributor", onlinePlayers);
sender.sendMessage(ChatColor.GOLD + "Website: " + ChatColor.WHITE +
"http://dev.bukkit.org/bukkit-plugins/authme-reloaded/");
sender.sendMessage(ChatColor.GOLD + "License: " + ChatColor.WHITE + "GNU GPL v3.0"
diff --git a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java
index 68377390..0fdbf607 100644
--- a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java
@@ -47,7 +47,6 @@ public class ChangePasswordCommand extends PlayerCommand {
return;
}
- // TODO ljacqu 20160117: Call async task via Management
management.performPasswordChange(player, oldPassword, newPassword);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java
index fac517ea..8965c96f 100644
--- a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java
@@ -1,18 +1,17 @@
package fr.xephi.authme.command.executable.email;
-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.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.properties.EmailSettings;
-import fr.xephi.authme.util.StringUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -33,53 +32,39 @@ public class RecoverEmailCommand extends PlayerCommand {
private PlayerCache playerCache;
@Inject
- // TODO #655: Remove injected AuthMe instance once Authme#mail is encapsulated
- private AuthMe plugin;
+ private SendMailSSL sendMailSsl;
@Override
public void runCommand(Player player, List arguments) {
final String playerMail = arguments.get(0);
final String playerName = player.getName();
- if (plugin.mail == null) {
- ConsoleLogger.showError("Mail API is not set");
- commandService.send(player, MessageKey.ERROR);
+ if (!sendMailSsl.hasAllInformation()) {
+ ConsoleLogger.warning("Mail API is not set");
+ commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
return;
}
- if (dataSource.isAuthAvailable(playerName)) {
- if (PlayerCache.getInstance().isAuthenticated(playerName)) {
- commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
- return;
- }
-
- String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH));
- HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName);
- PlayerAuth auth;
- if (playerCache.isAuthenticated(playerName)) {
- auth = playerCache.getAuth(playerName);
- } else if (dataSource.isAuthAvailable(playerName)) {
- auth = dataSource.getAuth(playerName);
- } else {
- commandService.send(player, MessageKey.UNKNOWN_USER);
- return;
- }
- if (StringUtils.isEmpty(commandService.getProperty(EmailSettings.MAIL_ACCOUNT))) {
- ConsoleLogger.showError("No mail account set in settings");
- commandService.send(player, MessageKey.ERROR);
- return;
- }
-
- if (!playerMail.equalsIgnoreCase(auth.getEmail()) || "your@email.com".equalsIgnoreCase(playerMail)
- || "your@email.com".equalsIgnoreCase(auth.getEmail())) {
- commandService.send(player, MessageKey.INVALID_EMAIL);
- return;
- }
- auth.setPassword(hashNew);
- dataSource.updatePassword(auth);
- plugin.mail.main(auth, thePass);
- commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
- } else {
- commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
+ if (playerCache.isAuthenticated(playerName)) {
+ commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
+ return;
}
+
+ PlayerAuth auth = dataSource.getAuth(playerName);
+ if (auth == null) {
+ commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
+ return;
+ }
+
+ if (!playerMail.equalsIgnoreCase(auth.getEmail()) || "your@email.com".equalsIgnoreCase(auth.getEmail())) {
+ commandService.send(player, MessageKey.INVALID_EMAIL);
+ return;
+ }
+
+ String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH));
+ HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName);
+ auth.setPassword(hashNew);
+ dataSource.updatePassword(auth);
+ sendMailSsl.sendPasswordMail(auth, thePass);
+ commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java
index ed9f9eef..0e3f055b 100644
--- a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java
@@ -3,6 +3,7 @@ package fr.xephi.authme.command.executable.register;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
+import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.HashAlgorithm;
@@ -27,6 +28,9 @@ public class RegisterCommand extends PlayerCommand {
@Inject
private CommandService commandService;
+ @Inject
+ private SendMailSSL sendMailSsl;
+
@Override
public void runCommand(Player player, List arguments) {
if (commandService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
@@ -63,11 +67,10 @@ public class RegisterCommand extends PlayerCommand {
}
private void handleEmailRegistration(Player player, List arguments) {
- if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) {
- player.sendMessage("Cannot register: no email address is set for the server. "
- + "Please contact an administrator");
- ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email is set "
- + "to send emails from. Please add one in your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
+ if (!sendMailSsl.hasAllInformation()) {
+ commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
+ ConsoleLogger.warning("Cannot register player '" + player.getName() + "': no email or password is set "
+ + "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
return;
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java
index 720b136e..8526e4a1 100644
--- a/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java
@@ -10,6 +10,9 @@ import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List;
+/**
+ * Command for a player to unregister himself.
+ */
public class UnregisterCommand extends PlayerCommand {
@Inject
@@ -24,15 +27,15 @@ public class UnregisterCommand extends PlayerCommand {
@Override
public void runCommand(Player player, List arguments) {
String playerPass = arguments.get(0);
- final String playerNameLowerCase = player.getName().toLowerCase();
+ final String playerName = player.getName();
// Make sure the player is authenticated
- if (!playerCache.isAuthenticated(playerNameLowerCase)) {
+ if (!playerCache.isAuthenticated(playerName)) {
commandService.send(player, MessageKey.NOT_LOGGED_IN);
return;
}
// Unregister the player
- management.performUnregister(player, playerPass, false);
+ management.performUnregister(player, playerPass);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
index 4e07639d..ebe8c0cb 100644
--- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
+++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
@@ -10,7 +10,7 @@ import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -48,9 +48,9 @@ public class HelpProvider implements SettingsDependent {
private String helpHeader;
@Inject
- HelpProvider(PermissionsManager permissionsManager, NewSetting settings) {
+ HelpProvider(PermissionsManager permissionsManager, Settings settings) {
this.permissionsManager = permissionsManager;
- loadSettings(settings);
+ reload(settings);
}
private List printHelp(CommandSender sender, FoundCommandResult result, int options) {
@@ -102,7 +102,7 @@ public class HelpProvider implements SettingsDependent {
}
@Override
- public void loadSettings(NewSetting settings) {
+ public void reload(Settings settings) {
helpHeader = settings.getProperty(PluginSettings.HELP_HEADER);
}
diff --git a/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java b/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java
index 5a8c547a..50cb43c1 100644
--- a/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java
+++ b/src/main/java/fr/xephi/authme/converter/CrazyLoginConverter.java
@@ -4,7 +4,7 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.DataFolder;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.ConverterSettings;
import org.bukkit.command.CommandSender;
@@ -20,11 +20,11 @@ import java.io.IOException;
public class CrazyLoginConverter implements Converter {
private final DataSource database;
- private final NewSetting settings;
+ private final Settings settings;
private final File dataFolder;
@Inject
- CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings) {
+ CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings) {
this.dataFolder = dataFolder;
this.database = dataSource;
this.settings = settings;
@@ -61,7 +61,7 @@ public class CrazyLoginConverter implements Converter {
}
ConsoleLogger.info("CrazyLogin database has been imported correctly");
} catch (IOException ex) {
- ConsoleLogger.showError("Can't open the crazylogin database file! Does it exist?");
+ ConsoleLogger.warning("Can't open the crazylogin database file! Does it exist?");
ConsoleLogger.logException("Encountered", ex);
}
}
diff --git a/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java b/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java
index 82b2540d..64f89b7e 100644
--- a/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java
+++ b/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java
@@ -43,7 +43,7 @@ public class ForceFlatToSqlite {
}
if (!skippedPlayers.isEmpty()) {
- ConsoleLogger.showError("Warning: skipped conversion for players which were already in SQLite: "
+ ConsoleLogger.warning("Warning: skipped conversion for players which were already in SQLite: "
+ StringUtils.join(", ", skippedPlayers));
}
ConsoleLogger.info("Database successfully converted from " + source.getClass().getSimpleName()
diff --git a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java
index e568bb8b..9cf6749f 100644
--- a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java
+++ b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java
@@ -6,7 +6,7 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.ConverterSettings;
import org.bukkit.command.CommandSender;
@@ -24,12 +24,12 @@ import java.util.Map.Entry;
public class RakamakConverter implements Converter {
private final DataSource database;
- private final NewSetting settings;
+ private final Settings settings;
private final File pluginFolder;
private final PasswordSecurity passwordSecurity;
@Inject
- RakamakConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings,
+ RakamakConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings,
PasswordSecurity passwordSecurity) {
this.database = dataSource;
this.settings = settings;
@@ -82,15 +82,14 @@ public class RakamakConverter implements Converter {
.realName(playerName)
.ip(ip)
.password(psw)
- .lastLogin(System.currentTimeMillis())
+ .lastLogin(0)
.build();
database.saveAuth(auth);
}
ConsoleLogger.info("Rakamak database has been imported correctly");
sender.sendMessage("Rakamak database has been imported correctly");
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
- sender.sendMessage("Can't open the rakamak database file! Does it exist?");
+ ConsoleLogger.logException("Can't open the rakamak database file! Does it exist?", ex);
}
}
}
diff --git a/src/main/java/fr/xephi/authme/converter/SqliteToSql.java b/src/main/java/fr/xephi/authme/converter/SqliteToSql.java
index 61168480..dbb127f5 100644
--- a/src/main/java/fr/xephi/authme/converter/SqliteToSql.java
+++ b/src/main/java/fr/xephi/authme/converter/SqliteToSql.java
@@ -7,19 +7,19 @@ import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.datasource.SQLite;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
public class SqliteToSql implements Converter {
- private final NewSetting settings;
+ private final Settings settings;
private final DataSource dataSource;
private final Messages messages;
@Inject
- SqliteToSql(NewSetting settings, DataSource dataSource, Messages messages) {
+ SqliteToSql(Settings settings, DataSource dataSource, Messages messages) {
this.settings = settings;
this.dataSource = dataSource;
this.messages = messages;
diff --git a/src/main/java/fr/xephi/authme/converter/vAuthConverter.java b/src/main/java/fr/xephi/authme/converter/vAuthConverter.java
index 7c6f3ea5..9c116f02 100644
--- a/src/main/java/fr/xephi/authme/converter/vAuthConverter.java
+++ b/src/main/java/fr/xephi/authme/converter/vAuthConverter.java
@@ -1,28 +1,77 @@
package fr.xephi.authme.converter;
-import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.initialization.DataFolder;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.util.Scanner;
+import java.util.UUID;
+
+import static fr.xephi.authme.util.StringUtils.makePath;
public class vAuthConverter implements Converter {
- private final AuthMe plugin;
+ private final DataSource dataSource;
+ private final File vAuthPasswordsFile;
@Inject
- vAuthConverter(AuthMe plugin) {
- this.plugin = plugin;
+ vAuthConverter(@DataFolder File dataFolder, DataSource dataSource) {
+ vAuthPasswordsFile = new File(dataFolder.getParent(), makePath("vAuth", "passwords.yml"));
+ this.dataSource = dataSource;
}
@Override
public void execute(CommandSender sender) {
- try {
- new vAuthFileReader(plugin).convert();
- } catch (Exception e) {
- sender.sendMessage(e.getMessage());
- ConsoleLogger.showError(e.getMessage());
+ try (Scanner scanner = new Scanner(vAuthPasswordsFile)) {
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ String name = line.split(": ")[0];
+ String password = line.split(": ")[1];
+ PlayerAuth auth;
+ if (isUuidInstance(password)) {
+ String pname;
+ try {
+ pname = Bukkit.getOfflinePlayer(UUID.fromString(name)).getName();
+ } catch (Exception | NoSuchMethodError e) {
+ pname = getName(UUID.fromString(name));
+ }
+ if (pname == null)
+ continue;
+ auth = PlayerAuth.builder()
+ .name(pname.toLowerCase())
+ .realName(pname)
+ .password(password, null).build();
+ } else {
+ auth = PlayerAuth.builder()
+ .name(name.toLowerCase())
+ .realName(name)
+ .password(password, null).build();
+ }
+ dataSource.saveAuth(auth);
+ }
+ } catch (IOException e) {
+ ConsoleLogger.logException("Error while trying to import some vAuth data", e);
}
}
+ private static boolean isUuidInstance(String s) {
+ return s.length() > 8 && s.charAt(8) == '-';
+ }
+
+ private String getName(UUID uuid) {
+ for (OfflinePlayer op : Bukkit.getOfflinePlayers()) {
+ if (op.getUniqueId().compareTo(uuid) == 0) {
+ return op.getName();
+ }
+ }
+ return null;
+ }
+
}
diff --git a/src/main/java/fr/xephi/authme/converter/vAuthFileReader.java b/src/main/java/fr/xephi/authme/converter/vAuthFileReader.java
deleted file mode 100644
index 4c5b3b4f..00000000
--- a/src/main/java/fr/xephi/authme/converter/vAuthFileReader.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package fr.xephi.authme.converter;
-
-import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.cache.auth.PlayerAuth;
-import fr.xephi.authme.datasource.DataSource;
-import org.bukkit.Bukkit;
-import org.bukkit.OfflinePlayer;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Scanner;
-import java.util.UUID;
-
-import static fr.xephi.authme.util.StringUtils.makePath;
-
-class vAuthFileReader {
-
- private final AuthMe plugin;
- private final DataSource database;
-
- /**
- * Constructor for vAuthFileReader.
- *
- * @param plugin AuthMe
- */
- public vAuthFileReader(AuthMe plugin) {
- this.plugin = plugin;
- this.database = plugin.getDataSource();
- }
-
- public void convert() {
- final File file = new File(plugin.getDataFolder().getParent(), makePath("vAuth", "passwords.yml"));
- Scanner scanner;
- try {
- scanner = new Scanner(file);
- while (scanner.hasNextLine()) {
- String line = scanner.nextLine();
- String name = line.split(": ")[0];
- String password = line.split(": ")[1];
- PlayerAuth auth;
- if (isUuidInstance(password)) {
- String pname;
- try {
- pname = Bukkit.getOfflinePlayer(UUID.fromString(name)).getName();
- } catch (Exception | NoSuchMethodError e) {
- pname = getName(UUID.fromString(name));
- }
- if (pname == null)
- continue;
- auth = PlayerAuth.builder()
- .name(pname.toLowerCase())
- .realName(pname)
- .password(password, null).build();
- } else {
- auth = PlayerAuth.builder()
- .name(name.toLowerCase())
- .realName(name)
- .password(password, null).build();
- }
- database.saveAuth(auth);
- }
- scanner.close();
- } catch (IOException e) {
- ConsoleLogger.logException("Error while trying to import some vAuth data", e);
- }
-
- }
-
- private static boolean isUuidInstance(String s) {
- return s.length() > 8 && s.charAt(8) == '-';
- }
-
- private String getName(UUID uuid) {
- for (OfflinePlayer op : Bukkit.getOfflinePlayers()) {
- if (op.getUniqueId().compareTo(uuid) == 0) {
- return op.getName();
- }
- }
- return null;
- }
-
-}
diff --git a/src/main/java/fr/xephi/authme/converter/xAuthConverter.java b/src/main/java/fr/xephi/authme/converter/xAuthConverter.java
index 6fdddbf7..37dfc9fe 100644
--- a/src/main/java/fr/xephi/authme/converter/xAuthConverter.java
+++ b/src/main/java/fr/xephi/authme/converter/xAuthConverter.java
@@ -1,28 +1,146 @@
package fr.xephi.authme.converter;
-import fr.xephi.authme.AuthMe;
+import de.luricos.bukkit.xAuth.database.DatabaseTables;
+import de.luricos.bukkit.xAuth.utils.xAuthLog;
+import de.luricos.bukkit.xAuth.xAuth;
+import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.initialization.DataFolder;
+import fr.xephi.authme.util.CollectionUtils;
import org.bukkit.command.CommandSender;
+import org.bukkit.plugin.PluginManager;
import javax.inject.Inject;
+import java.io.File;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static fr.xephi.authme.util.StringUtils.makePath;
public class xAuthConverter implements Converter {
- private final AuthMe plugin;
-
@Inject
- xAuthConverter(AuthMe plugin) {
- this.plugin = plugin;
+ @DataFolder
+ private File dataFolder;
+ @Inject
+ private DataSource database;
+ @Inject
+ private PluginManager pluginManager;
+
+ xAuthConverter() {
}
@Override
public void execute(CommandSender sender) {
try {
Class.forName("de.luricos.bukkit.xAuth.xAuth");
- xAuthToFlat converter = new xAuthToFlat(plugin, sender);
- converter.convert();
+ convert(sender);
} catch (ClassNotFoundException ce) {
sender.sendMessage("xAuth has not been found, please put xAuth.jar in your plugin folder and restart!");
}
}
+ private void convert(CommandSender sender) {
+ if (pluginManager.getPlugin("xAuth") == null) {
+ sender.sendMessage("[AuthMe] xAuth plugin not found");
+ return;
+ }
+ // TODO ljacqu 20160702: xAuthDb is not used except for the existence check -- is this intended?
+ File xAuthDb = new File(dataFolder.getParent(), makePath("xAuth", "xAuth.h2.db"));
+ if (!xAuthDb.exists()) {
+ sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data...");
+ }
+ List players = getXAuthPlayers();
+ if (CollectionUtils.isEmpty(players)) {
+ sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players");
+ return;
+ }
+ sender.sendMessage("[AuthMe] Starting import...");
+
+ for (int id : players) {
+ String pl = getIdPlayer(id);
+ String psw = getPassword(id);
+ if (psw != null && !psw.isEmpty() && pl != null) {
+ PlayerAuth auth = PlayerAuth.builder()
+ .name(pl.toLowerCase())
+ .realName(pl)
+ .password(psw, null).build();
+ database.saveAuth(auth);
+ }
+ }
+ sender.sendMessage("[AuthMe] Successfully converted from xAuth database");
+ }
+
+ private String getIdPlayer(int id) {
+ String realPass = "";
+ Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ String sql = String.format("SELECT `playername` FROM `%s` WHERE `id` = ?",
+ xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
+ ps = conn.prepareStatement(sql);
+ ps.setInt(1, id);
+ rs = ps.executeQuery();
+ if (!rs.next())
+ return null;
+ realPass = rs.getString("playername").toLowerCase();
+ } catch (SQLException e) {
+ xAuthLog.severe("Failed to retrieve name for account: " + id, e);
+ return null;
+ } finally {
+ xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
+ }
+ return realPass;
+ }
+
+ private List getXAuthPlayers() {
+ List xP = new ArrayList<>();
+ Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ String sql = String.format("SELECT * FROM `%s`",
+ xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
+ ps = conn.prepareStatement(sql);
+ rs = ps.executeQuery();
+ while (rs.next()) {
+ xP.add(rs.getInt("id"));
+ }
+ } catch (SQLException e) {
+ xAuthLog.severe("Cannot import xAuthPlayers", e);
+ return new ArrayList<>();
+ } finally {
+ xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
+ }
+ return xP;
+ }
+
+ private String getPassword(int accountId) {
+ String realPass = "";
+ Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?",
+ xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
+ ps = conn.prepareStatement(sql);
+ ps.setInt(1, accountId);
+ rs = ps.executeQuery();
+ if (!rs.next())
+ return null;
+ realPass = rs.getString("password");
+ } catch (SQLException e) {
+ xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e);
+ return null;
+ } finally {
+ xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
+ }
+ return realPass;
+ }
+
}
diff --git a/src/main/java/fr/xephi/authme/converter/xAuthToFlat.java b/src/main/java/fr/xephi/authme/converter/xAuthToFlat.java
deleted file mode 100644
index 34ec2a5e..00000000
--- a/src/main/java/fr/xephi/authme/converter/xAuthToFlat.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package fr.xephi.authme.converter;
-
-import de.luricos.bukkit.xAuth.database.DatabaseTables;
-import de.luricos.bukkit.xAuth.utils.xAuthLog;
-import de.luricos.bukkit.xAuth.xAuth;
-import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.cache.auth.PlayerAuth;
-import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.util.CollectionUtils;
-import org.bukkit.command.CommandSender;
-
-import java.io.File;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-
-class xAuthToFlat {
-
- private final AuthMe instance;
- private final DataSource database;
- private final CommandSender sender;
-
- public xAuthToFlat(AuthMe instance, CommandSender sender) {
- this.instance = instance;
- this.database = instance.getDataSource();
- this.sender = sender;
- }
-
- public boolean convert() {
- if (instance.getServer().getPluginManager().getPlugin("xAuth") == null) {
- sender.sendMessage("[AuthMe] xAuth plugin not found");
- return false;
- }
- File xAuthDb = new File(instance.getDataFolder().getParent(), "xAuth" + File.separator + "xAuth.h2.db");
- if (!xAuthDb.exists()) {
- sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data...");
- }
- List players = getXAuthPlayers();
- if (CollectionUtils.isEmpty(players)) {
- sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players");
- return false;
- }
- sender.sendMessage("[AuthMe] Starting import...");
- try {
- for (int id : players) {
- String pl = getIdPlayer(id);
- String psw = getPassword(id);
- if (psw != null && !psw.isEmpty() && pl != null) {
- PlayerAuth auth = PlayerAuth.builder()
- .name(pl.toLowerCase())
- .realName(pl)
- .password(psw, null).build();
- database.saveAuth(auth);
- }
- }
- sender.sendMessage("[AuthMe] Successfully converted from xAuth database");
- } catch (Exception e) {
- sender.sendMessage("[AuthMe] An error has occurred while importing the xAuth database."
- + " The import may have succeeded partially.");
- ConsoleLogger.logException("Error during xAuth database import", e);
- }
- return true;
- }
-
- private String getIdPlayer(int id) {
- String realPass = "";
- Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
- PreparedStatement ps = null;
- ResultSet rs = null;
- try {
- String sql = String.format("SELECT `playername` FROM `%s` WHERE `id` = ?",
- xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
- ps = conn.prepareStatement(sql);
- ps.setInt(1, id);
- rs = ps.executeQuery();
- if (!rs.next())
- return null;
- realPass = rs.getString("playername").toLowerCase();
- } catch (SQLException e) {
- xAuthLog.severe("Failed to retrieve name for account: " + id, e);
- return null;
- } finally {
- xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
- }
- return realPass;
- }
-
- private List getXAuthPlayers() {
- List xP = new ArrayList<>();
- Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
- PreparedStatement ps = null;
- ResultSet rs = null;
- try {
- String sql = String.format("SELECT * FROM `%s`",
- xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
- ps = conn.prepareStatement(sql);
- rs = ps.executeQuery();
- while (rs.next()) {
- xP.add(rs.getInt("id"));
- }
- } catch (SQLException e) {
- xAuthLog.severe("Cannot import xAuthPlayers", e);
- return new ArrayList<>();
- } finally {
- xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
- }
- return xP;
- }
-
- private String getPassword(int accountId) {
- String realPass = "";
- Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
- PreparedStatement ps = null;
- ResultSet rs = null;
- try {
- String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?",
- xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
- ps = conn.prepareStatement(sql);
- ps.setInt(1, accountId);
- rs = ps.executeQuery();
- if (!rs.next())
- return null;
- realPass = rs.getString("password");
- } catch (SQLException e) {
- xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e);
- return null;
- } finally {
- xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
- }
- return realPass;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
index 12d45d20..a79cb580 100644
--- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
@@ -15,6 +15,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
@@ -54,7 +55,6 @@ public class CacheDataSource implements DataSource {
return executorService.submit(new Callable>() {
@Override
public Optional call() {
- ConsoleLogger.debug("REFRESH " + key);
return load(key);
}
});
@@ -139,13 +139,8 @@ public class CacheDataSource implements DataSource {
}
@Override
- public Set autoPurgeDatabase(long until) {
- Set cleared = source.autoPurgeDatabase(until);
- for (String name : cleared) {
- cachedAuths.invalidate(name);
- }
-
- return cleared;
+ public Set getRecordsToPurge(long until) {
+ return source.getRecordsToPurge(until);
}
@Override
@@ -160,14 +155,14 @@ public class CacheDataSource implements DataSource {
@Override
public void close() {
- source.close();
- cachedAuths.invalidateAll();
executorService.shutdown();
try {
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
- ConsoleLogger.writeStackTrace(e);
+ ConsoleLogger.logException("Could not close executor service:", e);
}
+ cachedAuths.invalidateAll();
+ source.close();
}
@Override
@@ -190,8 +185,8 @@ public class CacheDataSource implements DataSource {
}
@Override
- public void purgeBanned(final Set banned) {
- source.purgeBanned(banned);
+ public void purgeRecords(final Collection banned) {
+ source.purgeRecords(banned);
cachedAuths.invalidateAll(banned);
}
@@ -235,15 +230,6 @@ public class CacheDataSource implements DataSource {
return result;
}
- @Override
- public boolean updateIp(String user, String ip) {
- boolean result = source.updateIp(user, ip);
- if (result) {
- cachedAuths.refresh(user);
- }
- return result;
- }
-
@Override
public List getAllAuths() {
return source.getAllAuths();
diff --git a/src/main/java/fr/xephi/authme/datasource/Columns.java b/src/main/java/fr/xephi/authme/datasource/Columns.java
index adef938b..b6d732cd 100644
--- a/src/main/java/fr/xephi/authme/datasource/Columns.java
+++ b/src/main/java/fr/xephi/authme/datasource/Columns.java
@@ -1,6 +1,6 @@
package fr.xephi.authme.datasource;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
/**
@@ -23,7 +23,7 @@ public final class Columns {
public final String ID;
public final String IS_LOGGED;
- public Columns(NewSetting settings) {
+ public Columns(Settings settings) {
NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME);
REAL_NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_REALNAME);
PASSWORD = settings.getProperty(DatabaseSettings.MYSQL_COL_PASSWORD);
diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java
index dd80bc76..5b25fde4 100644
--- a/src/main/java/fr/xephi/authme/datasource/DataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java
@@ -4,6 +4,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.security.crypts.HashedPassword;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -70,13 +71,19 @@ public interface DataSource extends Reloadable {
boolean updatePassword(String user, HashedPassword password);
/**
- * Purge all records in the database whose last login was longer ago than
- * the given time.
+ * Get all records in the database whose last login was before the given time.
*
* @param until The minimum last login
- * @return The account names that have been removed
+ * @return The account names selected to purge
*/
- Set autoPurgeDatabase(long until);
+ Set getRecordsToPurge(long until);
+
+ /**
+ * Purge the given players from the database.
+ *
+ * @param toPurge The players to purge
+ */
+ void purgeRecords(Collection toPurge);
/**
* Remove a user record from the database.
@@ -123,13 +130,6 @@ public interface DataSource extends Reloadable {
*/
void close();
- /**
- * Purge all given players, i.e. delete all players whose name is in the list.
- *
- * @param banned the list of players to delete
- */
- void purgeBanned(Set banned);
-
/**
* Return the data source type.
*
@@ -187,15 +187,6 @@ public interface DataSource extends Reloadable {
*/
boolean updateRealName(String user, String realName);
- /**
- * Update a player's IP address.
- *
- * @param user The name of the user (lowercase)
- * @param ip The IP address to save
- * @return True upon success, false upon failure
- */
- boolean updateIp(String user, String ip);
-
/**
* Return all players of the database.
*
diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
index fa9d291e..f3f18014 100644
--- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java
+++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
@@ -1,12 +1,9 @@
package fr.xephi.authme.datasource;
-import com.google.common.annotations.VisibleForTesting;
-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.crypts.HashedPassword;
-import fr.xephi.authme.settings.Settings;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -17,6 +14,7 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -41,27 +39,11 @@ public class FlatFile implements DataSource {
*/
private final File source;
- public FlatFile() {
- AuthMe instance = AuthMe.getInstance();
-
- source = new File(instance.getDataFolder(), "auths.db");
- try {
- source.createNewFile();
- } catch (IOException e) {
- ConsoleLogger.logException("Cannot open flatfile", e);
- if (Settings.isStopEnabled) {
- ConsoleLogger.showError("Can't use FLAT FILE... SHUTDOWN...");
- instance.getServer().shutdown();
- }
- if (!Settings.isStopEnabled) {
- instance.getServer().getPluginManager().disablePlugin(instance);
- }
- }
- }
-
- @VisibleForTesting
- public FlatFile(File source) {
+ public FlatFile(File source) throws IOException {
this.source = source;
+ if (!source.exists() && !source.createNewFile()) {
+ throw new IOException("Could not create file '" + source.getPath() + "'");
+ }
}
@Override
@@ -82,7 +64,7 @@ public class FlatFile implements DataSource {
}
}
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
silentClose(br);
@@ -109,7 +91,7 @@ public class FlatFile implements DataSource {
bw = new BufferedWriter(new FileWriter(source, true));
bw.write(auth.getNickname() + ":" + auth.getPassword().getHash() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
silentClose(bw);
@@ -145,7 +127,7 @@ public class FlatFile implements DataSource {
}
}
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
silentClose(br);
@@ -179,7 +161,7 @@ public class FlatFile implements DataSource {
}
}
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
silentClose(br);
@@ -216,7 +198,7 @@ public class FlatFile implements DataSource {
}
}
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
silentClose(br);
@@ -229,11 +211,10 @@ public class FlatFile implements DataSource {
}
@Override
- public Set autoPurgeDatabase(long until) {
+ public Set getRecordsToPurge(long until) {
BufferedReader br = null;
- BufferedWriter bw = null;
- ArrayList lines = new ArrayList<>();
- Set cleared = new HashSet<>();
+ Set list = new HashSet<>();
+
try {
br = new BufferedReader(new FileReader(source));
String line;
@@ -241,25 +222,24 @@ public class FlatFile implements DataSource {
String[] args = line.split(":");
if (args.length >= 4) {
if (Long.parseLong(args[3]) >= until) {
- lines.add(line);
+ list.add(args[0]);
continue;
}
}
- cleared.add(args[0]);
- }
- bw = new BufferedWriter(new FileWriter(source));
- for (String l : lines) {
- bw.write(l + "\n");
}
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return cleared;
+ ConsoleLogger.warning(ex.getMessage());
+ return list;
} finally {
silentClose(br);
- silentClose(bw);
}
- return cleared;
+ return list;
+ }
+
+ @Override
+ public void purgeRecords(Collection toPurge) {
+ throw new UnsupportedOperationException("Flat file no longer supported");
}
@Override
@@ -284,7 +264,7 @@ public class FlatFile implements DataSource {
bw.write(l + "\n");
}
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
silentClose(br);
@@ -306,7 +286,7 @@ public class FlatFile implements DataSource {
}
}
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return null;
} finally {
silentClose(br);
@@ -339,10 +319,10 @@ public class FlatFile implements DataSource {
}
}
} catch (FileNotFoundException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
if (br != null) {
@@ -374,10 +354,10 @@ public class FlatFile implements DataSource {
}
return countIp;
} catch (FileNotFoundException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return new ArrayList<>();
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return new ArrayList<>();
} finally {
if (br != null) {
@@ -404,7 +384,7 @@ public class FlatFile implements DataSource {
}
return countEmail;
} catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
} finally {
if (br != null) {
try {
@@ -416,37 +396,6 @@ public class FlatFile implements DataSource {
return 0;
}
- @Override
- public void purgeBanned(Set banned) {
- BufferedReader br = null;
- BufferedWriter bw = null;
- ArrayList lines = new ArrayList<>();
- try {
- br = new BufferedReader(new FileReader(source));
- String line;
- while ((line = br.readLine()) != null) {
- String[] args = line.split(":");
- try {
- if (banned.contains(args[0])) {
- lines.add(line);
- }
- } catch (NullPointerException | ArrayIndexOutOfBoundsException ignored) {
- }
- }
- bw = new BufferedWriter(new FileWriter(source));
- for (String l : lines) {
- bw.write(l + "\n");
- }
-
- } catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
-
- } finally {
- silentClose(br);
- silentClose(bw);
- }
- }
-
@Override
public DataSourceType getType() {
return DataSourceType.FILE;
@@ -479,7 +428,7 @@ public class FlatFile implements DataSource {
result++;
}
} catch (Exception ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return result;
} finally {
silentClose(br);
@@ -492,11 +441,6 @@ public class FlatFile implements DataSource {
throw new UnsupportedOperationException("Flat file no longer supported");
}
- @Override
- public boolean updateIp(String user, String ip) {
- throw new UnsupportedOperationException("Flat file no longer supported");
- }
-
@Override
public List getAllAuths() {
BufferedReader br = null;
diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java
index 94e43e00..661e3fad 100644
--- a/src/main/java/fr/xephi/authme/datasource/MySQL.java
+++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java
@@ -3,13 +3,11 @@ package fr.xephi.authme.datasource;
import com.google.common.annotations.VisibleForTesting;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
-
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.XFBCRYPT;
-import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
@@ -25,72 +23,65 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MySQL implements DataSource {
- private final String host;
- private final String port;
- private final String username;
- private final String password;
- private final String database;
- private final String tableName;
- private final List columnOthers;
- private final Columns col;
- private final HashAlgorithm hashAlgorithm;
+ private String host;
+ private String port;
+ private String username;
+ private String password;
+ private String database;
+ private String tableName;
+ private List columnOthers;
+ private Columns col;
+ private HashAlgorithm hashAlgorithm;
private HikariDataSource ds;
- private final String phpBbPrefix;
- private final int phpBbGroup;
- private final String wordpressPrefix;
+ private String phpBbPrefix;
+ private int phpBbGroup;
+ private String wordpressPrefix;
- public MySQL(NewSetting settings) throws ClassNotFoundException, SQLException, PoolInitializationException {
- this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
- this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT);
- this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
- this.password = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD);
- this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
- this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
- this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS);
- this.col = new Columns(settings);
- this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
- this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
- this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
- this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
+ public MySQL(Settings settings) throws ClassNotFoundException, SQLException, PoolInitializationException {
+ setParameters(settings);
// Set the connection arguments (and check if connection is ok)
try {
this.setConnectionArguments();
} 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!");
- throw new IllegalArgumentException(e);
+ ConsoleLogger.warning("Invalid database arguments! Please check your configuration!");
+ ConsoleLogger.warning("If this error persists, please report it to the developer!");
}
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!");
- throw new PoolInitializationException(e);
+ ConsoleLogger.warning("Can't initialize database connection! Please check your configuration!");
+ ConsoleLogger.warning("If this error persists, please report it to the developer!");
}
- ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer!");
+ ConsoleLogger.warning("Can't use the Hikari Connection Pool! Please, report this error to the developer!");
throw e;
}
// Initialize the database
try {
- this.setupConnection();
+ checkTablesAndColumns();
} catch (SQLException e) {
- 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!");
+ close();
+ ConsoleLogger.logException("Can't initialize the MySQL database:", e);
+ ConsoleLogger.warning("Please check your database settings in the config.yml file!");
throw e;
}
}
@VisibleForTesting
- MySQL(NewSetting settings, HikariDataSource hikariDataSource) {
+ MySQL(Settings settings, HikariDataSource hikariDataSource) {
+ ds = hikariDataSource;
+ setParameters(settings);
+ }
+
+ private void setParameters(Settings settings) {
this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT);
this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
@@ -103,7 +94,6 @@ public class MySQL implements DataSource {
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
- ds = hikariDataSource;
}
private void setConnectionArguments() throws RuntimeException {
@@ -147,118 +137,83 @@ public class MySQL implements DataSource {
return ds.getConnection();
}
- private void setupConnection() throws SQLException {
- try (Connection con = getConnection()) {
- Statement st = con.createStatement();
- DatabaseMetaData md = con.getMetaData();
- // Create table if not exists.
+ private void checkTablesAndColumns() throws SQLException {
+ try (Connection con = getConnection(); Statement st = con.createStatement()) {
+ // Create table with ID column if it doesn't exist
String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " ("
- + col.ID + " INTEGER AUTO_INCREMENT,"
- + col.NAME + " VARCHAR(255) NOT NULL UNIQUE,"
- + col.REAL_NAME + " VARCHAR(255) NOT NULL,"
- + col.PASSWORD + " VARCHAR(255) NOT NULL,"
- + col.IP + " VARCHAR(40) NOT NULL DEFAULT '127.0.0.1',"
- + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0,"
- + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0',"
- + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0',"
- + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0',"
- + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "',"
- + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com',"
- + col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0',"
- + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + ")"
- + ");";
+ + col.ID + " MEDIUMINT(8) UNSIGNED AUTO_INCREMENT,"
+ + "PRIMARY KEY (" + col.ID + ")"
+ + ") CHARACTER SET = utf8;";
st.executeUpdate(sql);
- ResultSet rs = md.getColumns(null, null, tableName, col.NAME);
- if (!rs.next()) {
+ DatabaseMetaData md = con.getMetaData();
+ if (isColumnMissing(md, col.NAME)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.NAME + " VARCHAR(255) NOT NULL UNIQUE AFTER " + col.ID + ";");
}
- rs.close();
- rs = md.getColumns(null, null, tableName, col.REAL_NAME);
- if (!rs.next()) {
+ if (isColumnMissing(md, col.REAL_NAME)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL AFTER " + col.NAME + ";");
}
- rs.close();
- rs = md.getColumns(null, null, tableName, col.PASSWORD);
- if (!rs.next()) {
+ if (isColumnMissing(md, col.PASSWORD)) {
st.executeUpdate("ALTER TABLE " + tableName
- + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;");
- }
- rs.close();
-
- if (!col.SALT.isEmpty()) {
- rs = md.getColumns(null, null, tableName, col.SALT);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName
- + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
- }
- rs.close();
+ + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;");
}
- rs = md.getColumns(null, null, tableName, col.IP);
- if (!rs.next()) {
+ if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) {
+ st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
+ }
+
+ if (isColumnMissing(md, col.IP)) {
st.executeUpdate("ALTER TABLE " + tableName
- + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;");
+ + " ADD COLUMN " + col.IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;");
}
- rs.close();
- rs = md.getColumns(null, null, tableName, col.LAST_LOGIN);
- if (!rs.next()) {
+ if (isColumnMissing(md, col.LAST_LOGIN)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0;");
} else {
- migrateLastLoginColumnToBigInt(con, rs);
+ migrateLastLoginColumn(con, md);
}
- rs.close();
- rs = md.getColumns(null, null, tableName, col.LASTLOC_X);
- if (!rs.next()) {
+ if (isColumnMissing(md, col.LASTLOC_X)) {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LAST_LOGIN + " , ADD "
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_X + " , ADD "
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_Y);
- }
- rs.close();
-
- rs = md.getColumns(null, null, tableName, col.LASTLOC_X);
- if (rs.next()) {
+ } else {
st.executeUpdate("ALTER TABLE " + tableName + " MODIFY "
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY "
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY "
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';");
}
- rs.close();
- rs = md.getColumns(null, null, tableName, col.LASTLOC_WORLD);
- if (!rs.next()) {
+ if (isColumnMissing(md, col.LASTLOC_WORLD)) {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
+ col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world' AFTER " + col.LASTLOC_Z);
}
- rs.close();
- rs = md.getColumns(null, null, tableName, col.EMAIL);
- if (!rs.next()) {
+ if (isColumnMissing(md, col.EMAIL)) {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
+ col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com' AFTER " + col.LASTLOC_WORLD);
}
- rs.close();
- rs = md.getColumns(null, null, tableName, col.IS_LOGGED);
- if (!rs.next()) {
+ if (isColumnMissing(md, col.IS_LOGGED)) {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
+ col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.EMAIL);
}
- rs.close();
-
- st.close();
}
ConsoleLogger.info("MySQL setup finished");
}
+ private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException {
+ try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) {
+ return !rs.next();
+ }
+ }
+
@Override
public boolean isAuthAvailable(String user) {
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
@@ -613,21 +568,18 @@ public class MySQL implements DataSource {
}
@Override
- public Set autoPurgeDatabase(long until) {
+ public Set getRecordsToPurge(long until) {
Set list = new HashSet<>();
+
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
- String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
try (Connection con = getConnection();
- PreparedStatement selectPst = con.prepareStatement(select);
- PreparedStatement deletePst = con.prepareStatement(delete)) {
+ PreparedStatement selectPst = con.prepareStatement(select)) {
selectPst.setLong(1, until);
try (ResultSet rs = selectPst.executeQuery()) {
while (rs.next()) {
list.add(rs.getString(col.NAME));
}
}
- deletePst.setLong(1, until);
- deletePst.executeUpdate();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -742,11 +694,11 @@ public class MySQL implements DataSource {
}
@Override
- public void purgeBanned(Set banned) {
+ public void purgeRecords(Collection toPurge) {
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
- for (String name : banned) {
- pst.setString(1, name);
+ for (String name : toPurge) {
+ pst.setString(1, name.toLowerCase());
pst.executeUpdate();
}
} catch (SQLException ex) {
@@ -839,20 +791,6 @@ public class MySQL implements DataSource {
return false;
}
- @Override
- public boolean updateIp(String user, String ip) {
- String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
- try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
- pst.setString(1, ip);
- pst.setString(2, user);
- pst.executeUpdate();
- return true;
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- return false;
- }
-
@Override
public List getAllAuths() {
List auths = new ArrayList<>();
@@ -933,40 +871,82 @@ public class MySQL implements DataSource {
}
/**
- * Check if the lastlogin column is of type timestamp and, if so, revert it to the bigint format.
+ * Checks if the last login column has a type that needs to be migrated.
*
- * @param con Connection to the database
- * @param rs ResultSet containing meta data for the lastlogin column
+ * @param con connection to the database
+ * @param metaData lastlogin column meta data
+ * @throws SQLException
*/
- private void migrateLastLoginColumnToBigInt(Connection con, ResultSet rs) throws SQLException {
- final int columnType = rs.getInt("DATA_TYPE");
- if (columnType == Types.TIMESTAMP) {
- ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint");
- final String lastLoginOld = col.LAST_LOGIN + "_old";
-
- // Rename lastlogin to lastlogin_old
- String sql = String.format("ALTER TABLE %s CHANGE COLUMN %s %s BIGINT",
- tableName, col.LAST_LOGIN, lastLoginOld);
- PreparedStatement pst = con.prepareStatement(sql);
- pst.execute();
-
- // Create lastlogin column
- sql = String.format("ALTER TABLE %s ADD COLUMN %s "
- + "BIGINT NOT NULL DEFAULT 0 AFTER %s",
- tableName, col.LAST_LOGIN, col.IP);
- con.prepareStatement(sql).execute();
-
- // Set values of lastlogin based on lastlogin_old
- sql = String.format("UPDATE %s SET %s = UNIX_TIMESTAMP(%s)",
- tableName, col.LAST_LOGIN, lastLoginOld);
- con.prepareStatement(sql).execute();
-
- // Drop lastlogin_old
- sql = String.format("ALTER TABLE %s DROP COLUMN %s",
- tableName, lastLoginOld);
- con.prepareStatement(sql).execute();
- ConsoleLogger.info("Finished migration of lastlogin (timestamp to bigint)");
+ private void migrateLastLoginColumn(Connection con, DatabaseMetaData metaData) throws SQLException {
+ final int columnType;
+ try (ResultSet rs = metaData.getColumns(null, null, tableName, col.LAST_LOGIN)) {
+ if (!rs.next()) {
+ ConsoleLogger.warning("Could not get LAST_LOGIN meta data. This should never happen!");
+ return;
+ }
+ columnType = rs.getInt("DATA_TYPE");
}
+
+ if (columnType == Types.TIMESTAMP) {
+ migrateLastLoginColumnFromTimestamp(con);
+ } else if (columnType == Types.INTEGER) {
+ migrateLastLoginColumnFromInt(con);
+ }
+ }
+
+ /**
+ * Performs conversion of lastlogin column from timestamp type to bigint.
+ *
+ * @param con connection to the database
+ */
+ private void migrateLastLoginColumnFromTimestamp(Connection con) throws SQLException {
+ ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint");
+ final String lastLoginOld = col.LAST_LOGIN + "_old";
+
+ // Rename lastlogin to lastlogin_old
+ String sql = String.format("ALTER TABLE %s CHANGE COLUMN %s %s BIGINT",
+ tableName, col.LAST_LOGIN, lastLoginOld);
+ PreparedStatement pst = con.prepareStatement(sql);
+ pst.execute();
+
+ // Create lastlogin column
+ sql = String.format("ALTER TABLE %s ADD COLUMN %s "
+ + "BIGINT NOT NULL DEFAULT 0 AFTER %s",
+ tableName, col.LAST_LOGIN, col.IP);
+ con.prepareStatement(sql).execute();
+
+ // Set values of lastlogin based on lastlogin_old
+ sql = String.format("UPDATE %s SET %s = UNIX_TIMESTAMP(%s) * 1000",
+ tableName, col.LAST_LOGIN, lastLoginOld);
+ con.prepareStatement(sql).execute();
+
+ // Drop lastlogin_old
+ sql = String.format("ALTER TABLE %s DROP COLUMN %s",
+ tableName, lastLoginOld);
+ con.prepareStatement(sql).execute();
+ ConsoleLogger.info("Finished migration of lastlogin (timestamp to bigint)");
+ }
+
+ /**
+ * Performs conversion of lastlogin column from int to bigint.
+ *
+ * @param con connection to the database
+ */
+ private void migrateLastLoginColumnFromInt(Connection con) throws SQLException {
+ // Change from int to bigint
+ ConsoleLogger.info("Migrating lastlogin column from int to bigint");
+ String sql = String.format("ALTER TABLE %s MODIFY %s BIGINT;", tableName, col.LAST_LOGIN);
+ con.prepareStatement(sql).execute();
+
+ // Migrate timestamps in seconds format to milliseconds format if they are plausible
+ int rangeStart = 1262304000; // timestamp for 2010-01-01
+ int rangeEnd = 1514678400; // timestamp for 2017-12-31
+ sql = String.format("UPDATE %s SET %s = %s * 1000 WHERE %s > %d AND %s < %d;",
+ tableName, col.LAST_LOGIN, col.LAST_LOGIN, col.LAST_LOGIN, rangeStart, col.LAST_LOGIN, rangeEnd);
+ int changedRows = con.prepareStatement(sql).executeUpdate();
+
+ ConsoleLogger.warning("You may have entries with invalid timestamps. Please check your data "
+ + "before purging. " + changedRows + " rows were migrated from seconds to milliseconds.");
}
private static void logSqlException(SQLException e) {
diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java
index 8072d58f..8aae94c5 100644
--- a/src/main/java/fr/xephi/authme/datasource/SQLite.java
+++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java
@@ -1,26 +1,26 @@
package fr.xephi.authme.datasource;
+import com.google.common.annotations.VisibleForTesting;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.security.crypts.HashedPassword;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.DatabaseSettings;
+import fr.xephi.authme.util.StringUtils;
+
import java.sql.Connection;
+import java.sql.DatabaseMetaData;
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.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import com.google.common.annotations.VisibleForTesting;
-
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.cache.auth.PlayerAuth;
-import fr.xephi.authme.security.crypts.HashedPassword;
-import fr.xephi.authme.settings.NewSetting;
-import fr.xephi.authme.settings.Settings;
-import fr.xephi.authme.settings.properties.DatabaseSettings;
-import fr.xephi.authme.util.StringUtils;
-
/**
*/
public class SQLite implements DataSource {
@@ -38,7 +38,7 @@ public class SQLite implements DataSource {
* @throws ClassNotFoundException if no driver could be found for the datasource
* @throws SQLException when initialization of a SQL datasource failed
*/
- public SQLite(NewSetting settings) throws ClassNotFoundException, SQLException {
+ public SQLite(Settings settings) throws ClassNotFoundException, SQLException {
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
this.col = new Columns(settings);
@@ -53,7 +53,7 @@ public class SQLite implements DataSource {
}
@VisibleForTesting
- SQLite(NewSetting settings, Connection connection) {
+ SQLite(Settings settings, Connection connection) {
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
this.col = new Columns(settings);
@@ -70,67 +70,73 @@ public class SQLite implements DataSource {
this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db");
}
- private void setup() throws SQLException {
- Statement st = null;
- ResultSet rs = null;
- try {
- st = con.createStatement();
- st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" + col.ID + " INTEGER AUTO_INCREMENT," + col.NAME + " VARCHAR(255) NOT NULL UNIQUE," + col.PASSWORD + " VARCHAR(255) NOT NULL," + col.IP + " VARCHAR(40) NOT NULL," + col.LAST_LOGIN + " BIGINT," + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com'," + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));");
- rs = con.getMetaData().getColumns(null, null, tableName, col.PASSWORD);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;");
+ @VisibleForTesting
+ protected void setup() throws SQLException {
+ try (Statement st = con.createStatement()) {
+ // Note: cannot add unique fields later on in SQLite, so we add it on initialization
+ st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " ("
+ + col.ID + " INTEGER AUTO_INCREMENT, "
+ + col.NAME + " VARCHAR(255) NOT NULL UNIQUE, "
+ + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));");
+
+ DatabaseMetaData md = con.getMetaData();
+
+ if (isColumnMissing(md, col.REAL_NAME)) {
+ st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
+ + col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';");
}
- rs.close();
- if (!col.SALT.isEmpty()) {
- rs = con.getMetaData().getColumns(null, null, tableName, col.SALT);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
- }
- rs.close();
+
+ if (isColumnMissing(md, col.PASSWORD)) {
+ st.executeUpdate("ALTER TABLE " + tableName
+ + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL DEFAULT '';");
}
- rs = con.getMetaData().getColumns(null, null, tableName, col.IP);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;");
+
+ if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) {
+ st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
}
- rs.close();
- rs = con.getMetaData().getColumns(null, null, tableName, col.LAST_LOGIN);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP DEFAULT current_timestamp;");
+
+ if (isColumnMissing(md, col.IP)) {
+ st.executeUpdate("ALTER TABLE " + tableName
+ + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL DEFAULT '';");
}
- rs.close();
- rs = con.getMetaData().getColumns(null, null, tableName, col.LASTLOC_X);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0';");
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0';");
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';");
+
+ if (isColumnMissing(md, col.LAST_LOGIN)) {
+ st.executeUpdate("ALTER TABLE " + tableName
+ + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP;");
}
- rs.close();
- rs = con.getMetaData().getColumns(null, null, tableName, col.LASTLOC_WORLD);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';");
+
+ if (isColumnMissing(md, col.LASTLOC_X)) {
+ st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X
+ + " DOUBLE NOT NULL DEFAULT '0.0';");
+ st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Y
+ + " DOUBLE NOT NULL DEFAULT '0.0';");
+ st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Z
+ + " DOUBLE NOT NULL DEFAULT '0.0';");
}
- rs.close();
- rs = con.getMetaData().getColumns(null, null, tableName, col.EMAIL);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';");
+
+ if (isColumnMissing(md, col.LASTLOC_WORLD)) {
+ st.executeUpdate("ALTER TABLE " + tableName
+ + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';");
}
- rs.close();
- rs = con.getMetaData().getColumns(null, null, tableName, col.IS_LOGGED);
- if (!rs.next()) {
+
+ if (isColumnMissing(md, col.EMAIL)) {
+ st.executeUpdate("ALTER TABLE " + tableName
+ + " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';");
+ }
+
+ if (isColumnMissing(md, col.IS_LOGGED)) {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IS_LOGGED + " INT DEFAULT '0';");
}
- rs.close();
- rs = con.getMetaData().getColumns(null, null, tableName, col.REAL_NAME);
- if (!rs.next()) {
- st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';");
- }
- } finally {
- close(rs);
- close(st);
}
ConsoleLogger.info("SQLite Setup finished");
}
+ private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException {
+ try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) {
+ return !rs.next();
+ }
+ }
+
@Override
public void reload() {
close(con);
@@ -147,12 +153,12 @@ public class SQLite implements DataSource {
PreparedStatement pst = null;
ResultSet rs = null;
try {
- pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);");
+ pst = con.prepareStatement("SELECT 1 FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);");
pst.setString(1, user);
rs = pst.executeQuery();
return rs.next();
} catch (SQLException ex) {
- ConsoleLogger.showError(ex.getMessage());
+ ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
close(rs);
@@ -207,7 +213,7 @@ public class SQLite implements DataSource {
HashedPassword password = auth.getPassword();
if (col.SALT.isEmpty()) {
if (!StringUtils.isEmpty(auth.getPassword().getSalt())) {
- ConsoleLogger.showError("Warning! Detected hashed password with separate salt but the salt column "
+ ConsoleLogger.warning("Warning! Detected hashed password with separate salt but the salt column "
+ "is not set in the config!");
}
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD +
@@ -293,20 +299,17 @@ public class SQLite implements DataSource {
}
@Override
- public Set autoPurgeDatabase(long until) {
+ public Set getRecordsToPurge(long until) {
Set list = new HashSet<>();
+
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
- String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
- try (PreparedStatement selectPst = con.prepareStatement(select);
- PreparedStatement deletePst = con.prepareStatement(delete)) {
+ try (PreparedStatement selectPst = con.prepareStatement(select)) {
selectPst.setLong(1, until);
try (ResultSet rs = selectPst.executeQuery()) {
while (rs.next()) {
list.add(rs.getString(col.NAME));
}
}
- deletePst.setLong(1, until);
- deletePst.executeUpdate();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -314,6 +317,19 @@ public class SQLite implements DataSource {
return list;
}
+ @Override
+ public void purgeRecords(Collection toPurge) {
+ String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
+ try (PreparedStatement deletePst = con.prepareStatement(delete)) {
+ for (String name : toPurge) {
+ deletePst.setString(1, name.toLowerCase());
+ deletePst.executeUpdate();
+ }
+ } catch (SQLException ex) {
+ logSqlException(ex);
+ }
+ }
+
@Override
public boolean removeAuth(String user) {
PreparedStatement pst = null;
@@ -443,19 +459,6 @@ public class SQLite implements DataSource {
return 0;
}
- @Override
- public void purgeBanned(Set banned) {
- String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
- try (PreparedStatement pst = con.prepareStatement(sql)) {
- for (String name : banned) {
- pst.setString(1, name);
- pst.executeUpdate();
- }
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- }
-
@Override
public DataSourceType getType() {
return DataSourceType.SQLITE;
@@ -553,20 +556,6 @@ public class SQLite implements DataSource {
return false;
}
- @Override
- public boolean updateIp(String user, String ip) {
- String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
- try (PreparedStatement pst = con.prepareStatement(sql)) {
- pst.setString(1, ip);
- pst.setString(2, user);
- pst.executeUpdate();
- return true;
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- return false;
- }
-
@Override
public List getAllAuths() {
List auths = new ArrayList<>();
diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java
index 47e7d17d..7b736aad 100644
--- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java
+++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java
@@ -2,21 +2,17 @@ package fr.xephi.authme.hooks;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
-
-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.datasource.DataSource;
import fr.xephi.authme.security.crypts.HashedPassword;
-import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import javax.inject.Inject;
-
public class BungeeCordMessage implements PluginMessageListener {
@Inject
@@ -28,9 +24,6 @@ public class BungeeCordMessage implements PluginMessageListener {
@Inject
private PlayerCache playerCache;
- @Inject
- private AuthMe plugin;
-
BungeeCordMessage() { }
@@ -56,26 +49,13 @@ public class BungeeCordMessage implements PluginMessageListener {
if ("login".equals(act)) {
playerCache.updatePlayer(auth);
dataSource.setLogged(name);
- //START 03062016 sgdc3: should fix #731 but we need to recode this mess
- if (plugin.sessions.containsKey(name)) {
- plugin.sessions.get(name).cancel();
- plugin.sessions.remove(name);
- }
- //END
-
- if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info("Player " + auth.getNickname() + " has logged in from one of your server!");
- }
+ ConsoleLogger.fine("Player " + auth.getNickname() + " has logged in from one of your server!");
} else if ("logout".equals(act)) {
playerCache.removePlayer(name);
dataSource.setUnlogged(name);
- if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info("Player " + auth.getNickname() + " has logged out from one of your server!");
- }
+ ConsoleLogger.fine("Player " + auth.getNickname() + " has logged out from one of your server!");
} else if ("register".equals(act)) {
- if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info("Player " + auth.getNickname() + " has registered out from one of your server!");
- }
+ ConsoleLogger.fine("Player " + auth.getNickname() + " has registered out from one of your server!");
} else if ("changepassword".equals(act)) {
final String password = args[2];
final String salt = args.length >= 4 ? args[3] : null;
diff --git a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java
index 76f8e034..f3a066e1 100644
--- a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java
+++ b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java
@@ -1,5 +1,6 @@
package fr.xephi.authme.hooks;
+import ch.jalu.injector.annotations.NoFieldScan;
import com.earth2me.essentials.Essentials;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
@@ -17,6 +18,7 @@ import java.io.File;
/**
* Hooks into third-party plugins and allows to perform actions on them.
*/
+@NoFieldScan
public class PluginHooks {
private final PluginManager pluginManager;
diff --git a/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java
deleted file mode 100644
index 29e5adcf..00000000
--- a/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java
+++ /dev/null
@@ -1,324 +0,0 @@
-package fr.xephi.authme.initialization;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import fr.xephi.authme.settings.NewSetting;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Provider;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Dependency injector of AuthMe: initializes and injects services and tasks.
- *
- * Only constructor and field injection are supported, indicated with the JSR330
- * {@link javax.inject.Inject @Inject} annotation.
- *
- * {@link PostConstruct @PostConstruct} methods are recognized and invoked upon
- * instantiation. Note that the parent classes are not scanned for such methods.
- */
-public class AuthMeServiceInitializer {
-
- private final Set ALLOWED_PACKAGES;
- private final Map, Object> objects;
-
- /**
- * Constructor.
- *
- * @param allowedPackages list of allowed packages. Only classes whose package
- * starts with any of the given entries will be instantiated
- */
- public AuthMeServiceInitializer(String... allowedPackages) {
- ALLOWED_PACKAGES = ImmutableSet.copyOf(allowedPackages);
- objects = new HashMap<>();
- objects.put(getClass(), this);
- }
-
- /**
- * Retrieves or instantiates an object of the given type.
- *
- * @param clazz the class to retrieve the value for
- * @param the class' type
- * @return object of the class' type
- */
- public T get(Class clazz) {
- return get(clazz, new HashSet>());
- }
-
- /**
- * Register an object with a custom class (supertype). Use this for example to specify a
- * concrete implementation of an interface or an abstract class.
- *
- * @param clazz the class to register the object for
- * @param object the object
- * @param the class' type
- */
- public void register(Class super T> clazz, T object) {
- if (objects.containsKey(clazz)) {
- throw new IllegalStateException("There is already an object present for " + clazz);
- }
- Preconditions.checkNotNull(object);
- objects.put(clazz, object);
- }
-
- /**
- * Associate an annotation with a value.
- *
- * @param annotation the annotation
- * @param value the value
- */
- public void provide(Class extends Annotation> annotation, Object value) {
- if (objects.containsKey(annotation)) {
- throw new IllegalStateException("Annotation @" + annotation.getClass().getSimpleName()
- + " already registered");
- }
- Preconditions.checkNotNull(value);
- objects.put(annotation, value);
- }
-
- /**
- * Creates a new instance of the given class and does not keep track of it afterwards,
- * unlike {@link #get(Class)} (singleton scope).
- *
- * @param clazz the class to instantiate
- * @param the class' type
- * @return new instance of class T
- */
- public T newInstance(Class clazz) {
- return instantiate(clazz, new HashSet>());
- }
-
- /**
- * Returns an instance of the given class if available. This simply returns the instance if present and
- * otherwise {@code null}. Calling this method will not instantiate anything.
- *
- * @param clazz the class to retrieve the instance for
- * @param the class' type
- * @return instance or null if none available
- */
- public T getIfAvailable(Class clazz) {
- if (Annotation.class.isAssignableFrom(clazz)) {
- throw new UnsupportedOperationException("Annotations may not be retrieved in this way!");
- }
- return clazz.cast(objects.get(clazz));
- }
-
- /**
- * Returns an instance of the given class by retrieving it or by instantiating it if not yet present.
- *
- * @param clazz the class to retrieve a value for
- * @param traversedClasses the list of traversed classes
- * @param the class' type
- * @return instance or associated value (for annotations)
- */
- private T get(Class clazz, Set> traversedClasses) {
- if (Annotation.class.isAssignableFrom(clazz)) {
- throw new UnsupportedOperationException("Cannot retrieve annotated elements in this way!");
- } else if (objects.containsKey(clazz)) {
- return clazz.cast(objects.get(clazz));
- }
-
- // First time we come across clazz, need to instantiate it. Validate that we can do so
- validatePackage(clazz);
- validateInstantiable(clazz);
-
- // Add the clazz to the list of traversed classes in a new Set, so each path we take has its own Set.
- traversedClasses = new HashSet<>(traversedClasses);
- traversedClasses.add(clazz);
- T object = instantiate(clazz, traversedClasses);
- storeObject(object);
- return object;
- }
-
- /**
- * Performs a reload on all applicable instances which are registered.
- * Requires that the {@link NewSetting settings} instance be registered.
- *
- * Note that the order in which these classes are reloaded is not guaranteed.
- */
- public void performReloadOnServices() {
- NewSetting settings = (NewSetting) objects.get(NewSetting.class);
- if (settings == null) {
- throw new IllegalStateException("Settings instance is null");
- }
- for (Object object : objects.values()) {
- if (object instanceof Reloadable) {
- ((Reloadable) object).reload();
- } else if (object instanceof SettingsDependent) {
- ((SettingsDependent) object).loadSettings(settings);
- }
- }
- }
-
- /**
- * Instantiates the given class by locating its @Inject elements and retrieving
- * or instantiating the required instances.
- *
- * @param clazz the class to instantiate
- * @param traversedClasses collection of classes already traversed
- * @param the class' type
- * @return the instantiated object
- */
- private T instantiate(Class clazz, Set> traversedClasses) {
- Injection injection = firstNotNull(
- ConstructorInjection.provide(clazz), FieldInjection.provide(clazz), InstantiationFallback.provide(clazz));
- if (injection == null) {
- throw new IllegalStateException("Did not find injection method for " + clazz + ". Make sure you have "
- + "a constructor with @Inject or fields with @Inject. Fields with @Inject require "
- + "the default constructor");
- }
-
- validateInjectionHasNoCircularDependencies(injection.getDependencies(), traversedClasses);
- Object[] dependencies = resolveDependencies(injection, traversedClasses);
- T object = injection.instantiateWith(dependencies);
- executePostConstructMethod(object);
- return object;
- }
-
- /**
- * Resolves the dependencies for the given class instantiation, i.e. returns a collection that satisfy
- * the class' dependencies by retrieving elements or instantiating them where necessary.
- *
- * @param injection the injection parameters
- * @param traversedClasses collection of traversed classes
- * @return array with the parameters to use in the constructor
- */
- private Object[] resolveDependencies(Injection> injection, Set> traversedClasses) {
- Class>[] dependencies = injection.getDependencies();
- Class>[] annotations = injection.getDependencyAnnotations();
- Object[] values = new Object[dependencies.length];
- for (int i = 0; i < dependencies.length; ++i) {
- if (annotations[i] == null) {
- values[i] = get(dependencies[i], traversedClasses);
- } else {
- Object value = objects.get(annotations[i]);
- if (value == null) {
- throw new IllegalStateException("Value for field with @" + annotations[i].getSimpleName()
- + " must be registered beforehand");
- }
- values[i] = value;
- }
- }
- return values;
- }
-
- /**
- * Stores the given object with its class as key. Throws an exception if the key already has
- * a value associated to it.
- *
- * @param object the object to store
- */
- private void storeObject(Object object) {
- if (objects.containsKey(object.getClass())) {
- throw new IllegalStateException("There is already an object present for " + object.getClass());
- }
- Preconditions.checkNotNull(object);
- objects.put(object.getClass(), object);
- }
-
- /**
- * Validates that none of the dependencies' types are present in the given collection
- * of traversed classes. This prevents circular dependencies.
- *
- * @param dependencies the dependencies of the class
- * @param traversedClasses the collection of traversed classes
- */
- private static void validateInjectionHasNoCircularDependencies(Class>[] dependencies,
- Set> traversedClasses) {
- for (Class> clazz : dependencies) {
- if (traversedClasses.contains(clazz)) {
- throw new IllegalStateException("Found cyclic dependency - already traversed '" + clazz
- + "' (full traversal list: " + traversedClasses + ")");
- }
- }
- }
-
- /**
- * Validates the package of a parameter type to ensure that it is part of the allowed packages.
- * This ensures that we don't try to instantiate things that are beyond our reach in case some
- * external parameter type has not been registered.
- *
- * @param clazz the class to validate
- */
- private void validatePackage(Class> clazz) {
- if (clazz.getPackage() == null) {
- throw new IllegalStateException("Primitive types must be provided explicitly (or use an annotation).");
- }
- String packageName = clazz.getPackage().getName();
- for (String allowedPackage : ALLOWED_PACKAGES) {
- if (packageName.startsWith(allowedPackage)) {
- return;
- }
- }
- throw new IllegalStateException("Class " + clazz + " with package " + packageName + " is outside of the "
- + "allowed packages. It must be provided explicitly or the package must be passed to the constructor.");
- }
-
- /**
- * Executes an object's method annotated with {@link PostConstruct} if present.
- * Throws an exception if there are multiple such methods, or if the method is static.
- *
- * @param object the object to execute the post construct method for
- */
- private static void executePostConstructMethod(Object object) {
- Method postConstructMethod = getAndValidatePostConstructMethod(object.getClass());
- if (postConstructMethod != null) {
- try {
- postConstructMethod.setAccessible(true);
- postConstructMethod.invoke(object);
- } catch (IllegalAccessException | InvocationTargetException e) {
- throw new UnsupportedOperationException("Error executing @PostConstruct method", e);
- }
- }
- }
-
- private static void validateInstantiable(Class> clazz) {
- if (clazz.isEnum() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
- throw new IllegalStateException("Class " + clazz.getSimpleName() + " cannot be instantiated");
- }
- }
-
- /**
- * Validate and locate the given class' post construct method. Returns {@code null} if none present.
- *
- * @param clazz the class to search
- * @return post construct method, or null
- */
- private static Method getAndValidatePostConstructMethod(Class> clazz) {
- Method postConstructMethod = null;
- for (Method method : clazz.getDeclaredMethods()) {
- if (method.isAnnotationPresent(PostConstruct.class)) {
- if (postConstructMethod != null) {
- throw new IllegalStateException("Multiple methods with @PostConstruct on " + clazz);
- } else if (method.getParameterTypes().length > 0 || Modifier.isStatic(method.getModifiers())) {
- throw new IllegalStateException("@PostConstruct method may not be static or have any parameters. "
- + "Invalid method in " + clazz);
- } else if (method.getReturnType() != void.class) {
- throw new IllegalStateException("@PostConstruct method must have return type void. "
- + "Offending class: " + clazz);
- } else {
- postConstructMethod = method;
- }
- }
- }
- return postConstructMethod;
- }
-
- @SafeVarargs
- private static Injection firstNotNull(Provider extends Injection>... providers) {
- for (Provider extends Injection> provider : providers) {
- Injection object = provider.get();
- if (object != null) {
- return object;
- }
- }
- return null;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java
deleted file mode 100644
index 74ea28b2..00000000
--- a/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package fr.xephi.authme.initialization;
-
-import com.google.common.base.Preconditions;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Functionality for constructor injection.
- */
-public class ConstructorInjection implements Injection {
-
- private final Constructor constructor;
-
- private ConstructorInjection(Constructor constructor) {
- this.constructor = constructor;
- }
-
- @Override
- public Class>[] getDependencies() {
- return constructor.getParameterTypes();
- }
-
- @Override
- public Class>[] getDependencyAnnotations() {
- Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
- Class>[] annotations = new Class>[parameterAnnotations.length];
- for (int i = 0; i < parameterAnnotations.length; ++i) {
- annotations[i] = parameterAnnotations[i].length > 0
- ? parameterAnnotations[i][0].annotationType()
- : null;
- }
- return annotations;
- }
-
- @Override
- public T instantiateWith(Object... values) {
- validateNoNullValues(values);
- try {
- return constructor.newInstance(values);
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- throw new UnsupportedOperationException(e);
- }
- }
-
- public static Provider> provide(final Class clazz) {
- return new Provider>() {
- @Override
- public ConstructorInjection get() {
- Constructor constructor = getInjectionConstructor(clazz);
- return constructor == null ? null : new ConstructorInjection<>(constructor);
- }
- };
- }
-
-
- /**
- * Gets the first found constructor annotated with {@link Inject} of the given class
- * and marks it as accessible.
- *
- * @param clazz the class to process
- * @param the class' type
- * @return injection constructor for the class, null if not applicable
- */
- @SuppressWarnings("unchecked")
- private static Constructor getInjectionConstructor(Class clazz) {
- Constructor>[] constructors = clazz.getDeclaredConstructors();
- for (Constructor> constructor : constructors) {
- if (constructor.isAnnotationPresent(Inject.class)) {
- constructor.setAccessible(true);
- return (Constructor) constructor;
- }
- }
- return null;
- }
-
- private static void validateNoNullValues(Object[] array) {
- for (Object entry : array) {
- Preconditions.checkNotNull(entry);
- }
- }
-
-}
diff --git a/src/main/java/fr/xephi/authme/initialization/FieldInjection.java b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java
deleted file mode 100644
index c74e7c27..00000000
--- a/src/main/java/fr/xephi/authme/initialization/FieldInjection.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package fr.xephi.authme.initialization;
-
-import com.google.common.base.Preconditions;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Functionality for field injection.
- */
-public class FieldInjection implements Injection {
-
- private final Field[] fields;
- private final Constructor defaultConstructor;
-
- private FieldInjection(Constructor defaultConstructor, Collection fields) {
- this.fields = fields.toArray(new Field[fields.size()]);
- this.defaultConstructor = defaultConstructor;
- }
-
- @Override
- public Class>[] getDependencies() {
- Class>[] types = new Class>[fields.length];
- for (int i = 0; i < fields.length; ++i) {
- types[i] = fields[i].getType();
- }
- return types;
- }
-
- @Override
- public Class>[] getDependencyAnnotations() {
- Class>[] annotations = new Class>[fields.length];
- for (int i = 0; i < fields.length; ++i) {
- annotations[i] = getFirstNonInjectAnnotation(fields[i]);
- }
- return annotations;
- }
-
- @Override
- public T instantiateWith(Object... values) {
- Preconditions.checkArgument(values.length == fields.length,
- "The number of values must be equal to the number of fields");
-
- T instance;
- try {
- instance = defaultConstructor.newInstance();
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- throw new UnsupportedOperationException(e);
- }
-
- for (int i = 0; i < fields.length; ++i) {
- try {
- Preconditions.checkNotNull(values[i]);
- fields[i].set(instance, values[i]);
- } catch (IllegalAccessException e) {
- throw new UnsupportedOperationException(e);
- }
- }
- return instance;
- }
-
- /**
- * Returns a provider for a {@code FieldInjection} instance, i.e. a provides an object
- * with which field injection can be performed on the given class if applicable. The provided
- * value is {@code null} if field injection cannot be applied to the class.
- *
- * @param clazz the class to provide field injection for
- * @param the class' type
- * @return field injection provider for the given class, or null if not applicable
- */
- public static Provider> provide(final Class clazz) {
- return new Provider>() {
- @Override
- public FieldInjection get() {
- Constructor constructor = getDefaultConstructor(clazz);
- if (constructor == null) {
- return null;
- }
- List fields = getInjectionFields(clazz);
- return fields.isEmpty() ? null : new FieldInjection<>(constructor, fields);
- }
- };
- }
-
- private static List getInjectionFields(Class> clazz) {
- List fields = new ArrayList<>();
- for (Field field : clazz.getDeclaredFields()) {
- if (field.isAnnotationPresent(Inject.class)) {
- if (Modifier.isStatic(field.getModifiers())) {
- throw new IllegalStateException(String.format("Field '%s' in class '%s' is static but "
- + "annotated with @Inject", field.getName(), clazz.getSimpleName()));
- }
- field.setAccessible(true);
- fields.add(field);
- }
- }
- return fields;
- }
-
- private static Class> getFirstNonInjectAnnotation(Field field) {
- for (Annotation annotation : field.getAnnotations()) {
- if (annotation.annotationType() != Inject.class) {
- return annotation.annotationType();
- }
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- private static Constructor getDefaultConstructor(Class clazz) {
- try {
- Constructor> defaultConstructor = clazz.getDeclaredConstructor();
- defaultConstructor.setAccessible(true);
- return (Constructor) defaultConstructor;
- } catch (NoSuchMethodException ignore) {
- // no default constructor available
- }
- return null;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/initialization/HasCleanup.java b/src/main/java/fr/xephi/authme/initialization/HasCleanup.java
new file mode 100644
index 00000000..db047d84
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/HasCleanup.java
@@ -0,0 +1,14 @@
+package fr.xephi.authme.initialization;
+
+/**
+ * Common interface for types which have data that becomes outdated
+ * and that can be cleaned up periodically.
+ */
+public interface HasCleanup {
+
+ /**
+ * Performs the cleanup action.
+ */
+ void performCleanup();
+
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/Initializer.java b/src/main/java/fr/xephi/authme/initialization/Initializer.java
new file mode 100644
index 00000000..a6d5a58e
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/Initializer.java
@@ -0,0 +1,171 @@
+package fr.xephi.authme.initialization;
+
+import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.datasource.CacheDataSource;
+import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.datasource.DataSourceType;
+import fr.xephi.authme.datasource.FlatFile;
+import fr.xephi.authme.datasource.MySQL;
+import fr.xephi.authme.datasource.SQLite;
+import fr.xephi.authme.output.ConsoleFilter;
+import fr.xephi.authme.output.Log4JFilter;
+import fr.xephi.authme.output.MessageKey;
+import fr.xephi.authme.output.Messages;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.SettingsMigrationService;
+import fr.xephi.authme.settings.properties.DatabaseSettings;
+import fr.xephi.authme.settings.properties.EmailSettings;
+import fr.xephi.authme.settings.properties.SecuritySettings;
+import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
+import fr.xephi.authme.settings.propertymap.PropertyMap;
+import fr.xephi.authme.util.BukkitService;
+import fr.xephi.authme.util.FileUtils;
+import fr.xephi.authme.util.MigrationService;
+import fr.xephi.authme.util.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.io.File;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.logging.Logger;
+
+import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
+import static fr.xephi.authme.util.BukkitService.TICKS_PER_MINUTE;
+
+/**
+ * Initializes various services.
+ */
+public class Initializer {
+
+ private static final String FLATFILE_FILENAME = "auths.db";
+ private static final int SQLITE_MAX_SIZE = 4000;
+
+ private AuthMe authMe;
+ private BukkitService bukkitService;
+
+ public Initializer(AuthMe authMe, BukkitService bukkitService) {
+ this.authMe = authMe;
+ this.bukkitService = bukkitService;
+ }
+
+ /**
+ * Loads the plugin's settings.
+ *
+ * @return The settings instance, or null if it could not be constructed
+ */
+ public Settings createSettings() throws Exception {
+ File configFile = new File(authMe.getDataFolder(), "config.yml");
+ PropertyMap properties = SettingsFieldRetriever.getAllPropertyFields();
+ SettingsMigrationService migrationService = new SettingsMigrationService();
+ if (FileUtils.copyFileFromResource(configFile, "config.yml")) {
+ return new Settings(configFile, authMe.getDataFolder(), properties, migrationService);
+ }
+ throw new Exception("Could not copy config.yml from JAR to plugin folder");
+ }
+
+ /**
+ * Sets up the data source.
+ *
+ * @param settings the settings
+ * @throws ClassNotFoundException if no driver could be found for the datasource
+ * @throws SQLException when initialization of a SQL datasource failed
+ * @throws IOException if flat file cannot be read
+ */
+ public DataSource setupDatabase(Settings settings) throws ClassNotFoundException, SQLException, IOException {
+ DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
+ DataSource dataSource;
+ switch (dataSourceType) {
+ case FILE:
+ File source = new File(authMe.getDataFolder(), FLATFILE_FILENAME);
+ dataSource = new FlatFile(source);
+ break;
+ case MYSQL:
+ dataSource = new MySQL(settings);
+ break;
+ case SQLITE:
+ dataSource = new SQLite(settings);
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'");
+ }
+
+ DataSource convertedSource = MigrationService.convertFlatfileToSqlite(settings, dataSource);
+ dataSource = convertedSource == null ? dataSource : convertedSource;
+
+ if (settings.getProperty(DatabaseSettings.USE_CACHING)) {
+ dataSource = new CacheDataSource(dataSource);
+ }
+ if (DataSourceType.SQLITE.equals(dataSourceType)) {
+ checkDataSourceSize(dataSource);
+ }
+ return dataSource;
+ }
+
+ private void checkDataSourceSize(final DataSource dataSource) {
+ bukkitService.runTaskAsynchronously(new Runnable() {
+ @Override
+ public void run() {
+ int accounts = dataSource.getAccountsRegistered();
+ if (accounts >= SQLITE_MAX_SIZE) {
+ ConsoleLogger.warning("YOU'RE USING THE SQLITE DATABASE WITH "
+ + accounts + "+ ACCOUNTS; FOR BETTER PERFORMANCE, PLEASE UPGRADE TO MYSQL!!");
+ }
+ }
+ });
+ }
+
+ /**
+ * Sets up the console filter if enabled.
+ *
+ * @param settings the settings
+ * @param logger the plugin logger
+ */
+ public void setupConsoleFilter(Settings settings, Logger logger) {
+ if (!settings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) {
+ return;
+ }
+ // Try to set the log4j filter
+ try {
+ Class.forName("org.apache.logging.log4j.core.filter.AbstractFilter");
+ setLog4JFilter();
+ } catch (ClassNotFoundException | NoClassDefFoundError e) {
+ // log4j is not available
+ ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled");
+ ConsoleFilter filter = new ConsoleFilter();
+ logger.setFilter(filter);
+ Bukkit.getLogger().setFilter(filter);
+ Logger.getLogger("Minecraft").setFilter(filter);
+ }
+ }
+
+ // Set the console filter to remove the passwords
+ private static void setLog4JFilter() {
+ org.apache.logging.log4j.core.Logger logger;
+ logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger();
+ logger.addFilter(new Log4JFilter());
+ }
+
+ public void scheduleRecallEmailTask(Settings settings, final DataSource dataSource, final Messages messages) {
+ if (!settings.getProperty(RECALL_PLAYERS)) {
+ return;
+ }
+ bukkitService.runTaskTimerAsynchronously(new Runnable() {
+ @Override
+ public void run() {
+ for (PlayerAuth auth : dataSource.getLoggedPlayers()) {
+ String email = auth.getEmail();
+ if (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email)) {
+ Player player = bukkitService.getPlayerExact(auth.getRealName());
+ if (player != null) {
+ messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
+ }
+ }
+ }
+ }
+ }, 1, TICKS_PER_MINUTE * settings.getProperty(EmailSettings.DELAY_RECALL));
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/Injection.java b/src/main/java/fr/xephi/authme/initialization/Injection.java
deleted file mode 100644
index 65acf796..00000000
--- a/src/main/java/fr/xephi/authme/initialization/Injection.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package fr.xephi.authme.initialization;
-
-/**
- * Common interface for all injection methods.
- *
- * @param the type of the concerned object
- */
-public interface Injection {
-
- /**
- * Returns the dependencies that must be provided to instantiate the given item.
- *
- * @return list of dependencies
- * @see #instantiateWith
- */
- Class>[] getDependencies();
-
- /**
- * Returns the annotation on each dependency if available. The indices of this
- * array correspond to the ones of {@link #getDependencies()}. If no annotation
- * is available, {@code null} is stored. If multiple annotations are present, only
- * one is stored (no guarantee on which one).
- *
- * @return annotation for each dependency
- */
- Class>[] getDependencyAnnotations();
-
- /**
- * Creates a new instance with the given values as dependencies. The given values
- * must correspond to {@link #getDependencies()} in size, order and type.
- *
- * @param values the values to set for the dependencies
- * @return resulting object
- */
- T instantiateWith(Object... values);
-}
diff --git a/src/main/java/fr/xephi/authme/initialization/InstantiationFallback.java b/src/main/java/fr/xephi/authme/initialization/InstantiationFallback.java
deleted file mode 100644
index 7a1c0849..00000000
--- a/src/main/java/fr/xephi/authme/initialization/InstantiationFallback.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package fr.xephi.authme.initialization;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Fallback instantiation method for classes with an accessible no-args constructor
- * and no elements whatsoever annotated with {@link Inject} or {@link PostConstruct}.
- */
-public class InstantiationFallback implements Injection {
-
- private final Constructor constructor;
-
- private InstantiationFallback(Constructor constructor) {
- this.constructor = constructor;
- }
-
- @Override
- public Class>[] getDependencies() {
- return new Class>[0];
- }
-
- @Override
- public Class>[] getDependencyAnnotations() {
- return new Class>[0];
- }
-
- @Override
- public T instantiateWith(Object... values) {
- if (values == null || values.length > 0) {
- throw new UnsupportedOperationException("Instantiation fallback cannot have parameters");
- }
- try {
- return constructor.newInstance();
- } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
- throw new UnsupportedOperationException(e);
- }
- }
-
- /**
- * Returns an instantiation fallback if the class is applicable.
- *
- * @param clazz the class
- * @param the class' type
- * @return instantiation fallback provider for the given class, or null if not applicable
- */
- public static Provider> provide(final Class clazz) {
- return new Provider>() {
- @Override
- public InstantiationFallback get() {
- Constructor noArgsConstructor = getNoArgsConstructor(clazz);
- // Return fallback only if we have no args constructor and no @Inject annotation anywhere
- if (noArgsConstructor != null
- && !isInjectionAnnotationPresent(clazz.getDeclaredConstructors())
- && !isInjectionAnnotationPresent(clazz.getDeclaredFields())
- && !isInjectionAnnotationPresent(clazz.getDeclaredMethods())) {
- return new InstantiationFallback<>(noArgsConstructor);
- }
- return null;
- }
- };
- }
-
- private static Constructor getNoArgsConstructor(Class clazz) {
- try {
- // Note ljacqu 20160504: getConstructor(), unlike getDeclaredConstructor(), only considers public members
- return clazz.getConstructor();
- } catch (NoSuchMethodException e) {
- return null;
- }
- }
-
- private static boolean isInjectionAnnotationPresent(A[] accessibles) {
- for (A accessible : accessibles) {
- if (accessible.isAnnotationPresent(Inject.class) || accessible.isAnnotationPresent(PostConstruct.class)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java b/src/main/java/fr/xephi/authme/initialization/MetricsManager.java
similarity index 82%
rename from src/main/java/fr/xephi/authme/initialization/MetricsStarter.java
rename to src/main/java/fr/xephi/authme/initialization/MetricsManager.java
index 4a163f98..e22e742e 100644
--- a/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java
+++ b/src/main/java/fr/xephi/authme/initialization/MetricsManager.java
@@ -2,7 +2,7 @@ package fr.xephi.authme.initialization;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import org.mcstats.Metrics;
@@ -10,12 +10,12 @@ import org.mcstats.Metrics.Graph;
import java.io.IOException;
-public class MetricsStarter {
+public class MetricsManager {
- private MetricsStarter() {
+ private MetricsManager() {
}
- public static void setupMetrics(AuthMe plugin, NewSetting settings) {
+ public static void sendMetrics(AuthMe plugin, Settings settings) {
try {
final Metrics metrics = new Metrics(plugin);
@@ -41,7 +41,7 @@ public class MetricsStarter {
metrics.start();
} catch (IOException e) {
// Failed to submit the metrics data
- ConsoleLogger.logException("Can't start Metrics! The plugin will work anyway...", e);
+ ConsoleLogger.logException("Can't send Metrics data! The plugin will work anyway...", e);
}
}
}
diff --git a/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java b/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java
new file mode 100644
index 00000000..852f5380
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java
@@ -0,0 +1,85 @@
+package fr.xephi.authme.initialization;
+
+import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.cache.auth.PlayerCache;
+import fr.xephi.authme.cache.backup.PlayerDataStorage;
+import fr.xephi.authme.cache.limbo.LimboCache;
+import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.hooks.PluginHooks;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.SpawnLoader;
+import fr.xephi.authme.settings.properties.RestrictionSettings;
+import fr.xephi.authme.util.BukkitService;
+import fr.xephi.authme.util.ValidationService;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+
+import javax.inject.Inject;
+
+/**
+ * Saves all players' data when the plugin shuts down.
+ */
+public class OnShutdownPlayerSaver {
+
+ @Inject
+ private BukkitService bukkitService;
+ @Inject
+ private Settings settings;
+ @Inject
+ private ValidationService validationService;
+ @Inject
+ private LimboCache limboCache;
+ @Inject
+ private DataSource dataSource;
+ @Inject
+ private PlayerDataStorage playerDataStorage;
+ @Inject
+ private SpawnLoader spawnLoader;
+ @Inject
+ private PluginHooks pluginHooks;
+ @Inject
+ private PlayerCache playerCache;
+
+ OnShutdownPlayerSaver() {
+ }
+
+ /**
+ * Saves the data of all online players.
+ */
+ public void saveAllPlayers() {
+ for (Player player : bukkitService.getOnlinePlayers()) {
+ savePlayer(player);
+ }
+ }
+
+ private void savePlayer(Player player) {
+ final String name = player.getName().toLowerCase();
+ if (pluginHooks.isNpc(player) || validationService.isUnrestricted(name)) {
+ return;
+ }
+ if (limboCache.hasPlayerData(name)) {
+ limboCache.restoreData(player);
+ limboCache.removeFromCache(player);
+ } else {
+ saveLoggedinPlayer(player);
+ }
+ playerCache.removePlayer(name);
+ }
+
+ private void saveLoggedinPlayer(Player player) {
+ if (settings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) {
+ Location loc = spawnLoader.getPlayerLocationOrSpawn(player);
+ final PlayerAuth auth = PlayerAuth.builder()
+ .name(player.getName().toLowerCase())
+ .realName(player.getName())
+ .location(loc).build();
+ dataSource.updateQuitLoc(auth);
+ }
+ if (settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)
+ && !settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
+ if (!playerDataStorage.hasData(player)) {
+ playerDataStorage.saveData(player);
+ }
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java b/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java
index f891b170..487f70d5 100644
--- a/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java
+++ b/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java
@@ -1,6 +1,6 @@
package fr.xephi.authme.initialization;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
/**
* Interface for classes that keep a local copy of certain settings.
@@ -8,9 +8,9 @@ import fr.xephi.authme.settings.NewSetting;
public interface SettingsDependent {
/**
- * Loads the needed settings.
+ * Performs a reload with the provided settings instance.
*
* @param settings the settings instance
*/
- void loadSettings(NewSetting settings);
+ void reload(Settings settings);
}
diff --git a/src/main/java/fr/xephi/authme/initialization/TaskCloser.java b/src/main/java/fr/xephi/authme/initialization/TaskCloser.java
new file mode 100644
index 00000000..d4119f92
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/TaskCloser.java
@@ -0,0 +1,88 @@
+package fr.xephi.authme.initialization;
+
+import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.datasource.DataSource;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.scheduler.BukkitWorker;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Waits for asynchronous tasks to complete before closing the data source
+ * so the plugin can shut down properly.
+ */
+public class TaskCloser implements Runnable {
+
+ private final BukkitScheduler scheduler;
+ private final Logger logger;
+ private final AuthMe plugin;
+ private final DataSource dataSource;
+
+ /**
+ * Constructor.
+ *
+ * @param plugin the plugin instance
+ * @param dataSource the data source (nullable)
+ */
+ public TaskCloser(AuthMe plugin, DataSource dataSource) {
+ this.scheduler = plugin.getServer().getScheduler();
+ this.logger = plugin.getLogger();
+ this.plugin = plugin;
+ this.dataSource = dataSource;
+ }
+
+ @Override
+ public void run() {
+ List pendingTasks = getPendingTasks();
+ logger.log(Level.INFO, "Waiting for {0} tasks to finish", pendingTasks.size());
+ int progress = 0;
+
+ //one minute + some time checking the running state
+ int tries = 60;
+ while (!pendingTasks.isEmpty()) {
+ if (tries <= 0) {
+ logger.log(Level.INFO, "Async tasks times out after to many tries {0}", pendingTasks);
+ break;
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ignored) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+
+ for (Iterator iterator = pendingTasks.iterator(); iterator.hasNext(); ) {
+ int taskId = iterator.next();
+ if (!scheduler.isCurrentlyRunning(taskId)) {
+ iterator.remove();
+ progress++;
+ logger.log(Level.INFO, "Progress: {0} / {1}", new Object[]{progress, pendingTasks.size()});
+ }
+ }
+
+ tries--;
+ }
+
+ if (dataSource != null) {
+ dataSource.close();
+ }
+ }
+
+ private List getPendingTasks() {
+ List pendingTasks = new ArrayList<>();
+ //returns only the async tasks
+ for (BukkitWorker pendingTask : scheduler.getActiveWorkers()) {
+ if (pendingTask.getOwner().equals(plugin)
+ //it's not a periodic task
+ && !scheduler.isQueued(pendingTask.getTaskId())) {
+ pendingTasks.add(pendingTask.getTaskId());
+ }
+ }
+ return pendingTasks;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
deleted file mode 100644
index 17b4a60a..00000000
--- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package fr.xephi.authme.listener;
-
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.ProtocolLibrary;
-import com.comphenix.protocol.ProtocolManager;
-import com.comphenix.protocol.events.ListenerPriority;
-import com.comphenix.protocol.events.PacketAdapter;
-import com.comphenix.protocol.events.PacketContainer;
-import com.comphenix.protocol.events.PacketEvent;
-import com.comphenix.protocol.reflect.FieldAccessException;
-import com.comphenix.protocol.utility.MinecraftVersion;
-import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
-import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
-import com.comphenix.protocol.wrappers.PlayerInfoData;
-import com.comphenix.protocol.wrappers.WrappedChatComponent;
-import com.comphenix.protocol.wrappers.WrappedGameProfile;
-import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.cache.auth.PlayerCache;
-import fr.xephi.authme.util.BukkitService;
-import org.bukkit.entity.Player;
-
-import javax.inject.Inject;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.logging.Level;
-
-public class AuthMeTablistPacketAdapter extends PacketAdapter {
-
- private final BukkitService bukkitService;
-
- @Inject
- public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) {
- super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO);
- this.bukkitService = bukkitService;
- }
-
- @Override
- public void onPacketSending(PacketEvent event) {
- if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
- //this hides the tablist for the new joining players. Already playing users will see the new player
- try {
- if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
- event.setCancelled(true);
- }
- } catch (FieldAccessException e) {
- ConsoleLogger.logException("Couldn't access field", e);
- }
- }
- }
-
- public void sendTablist(Player receiver) {
- WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(receiver);
-
- ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
- NativeGameMode gamemode = NativeGameMode.fromBukkit(receiver.getGameMode());
-
- WrappedChatComponent displayName = WrappedChatComponent.fromText(receiver.getDisplayName());
- PlayerInfoData playerInfoData = new PlayerInfoData(gameProfile, 0, gamemode, displayName);
-
- //add info containing the skin data
- PacketContainer addInfo = protocolManager.createPacket(PacketType.Play.Server.PLAYER_INFO);
- addInfo.getPlayerInfoAction().write(0, PlayerInfoAction.ADD_PLAYER);
- addInfo.getPlayerInfoDataLists().write(0, Arrays.asList(playerInfoData));
-
- try {
- //adds the skin
- protocolManager.sendServerPacket(receiver, addInfo);
- } catch (InvocationTargetException ex) {
- plugin.getLogger().log(Level.SEVERE, "Exception sending instant skin change packet", ex);
- }
-
- //triggers an update for others player to see them
- for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
- if (onlinePlayer.equals(receiver) || !receiver.canSee(onlinePlayer)) {
- continue;
- }
-
- //removes the entity and display them
- receiver.hidePlayer(onlinePlayer);
- receiver.showPlayer(onlinePlayer);
- }
- }
-
- public void register() {
- if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
- ProtocolLibrary.getProtocolManager().addPacketListener(this);
- } else {
- ConsoleLogger.info("The hideTablist feature is not compatible with your minecraft version");
- ConsoleLogger.info("It requires 1.8+. Disabling the hideTablist feature...");
- }
- }
-
- public void unregister() {
- ProtocolLibrary.getProtocolManager().removePacketListener(this);
- }
-}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java b/src/main/java/fr/xephi/authme/listener/BlockListener.java
similarity index 92%
rename from src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java
rename to src/main/java/fr/xephi/authme/listener/BlockListener.java
index 7fe23dd9..64ef09ea 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeBlockListener.java
+++ b/src/main/java/fr/xephi/authme/listener/BlockListener.java
@@ -7,7 +7,7 @@ import org.bukkit.event.block.BlockPlaceEvent;
import javax.inject.Inject;
-public class AuthMeBlockListener implements Listener {
+public class BlockListener implements Listener {
@Inject
private ListenerService listenerService;
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/EntityListener.java
similarity index 93%
rename from src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java
rename to src/main/java/fr/xephi/authme/listener/EntityListener.java
index ce8afa40..649f5153 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java
+++ b/src/main/java/fr/xephi/authme/listener/EntityListener.java
@@ -1,6 +1,7 @@
package fr.xephi.authme.listener;
import fr.xephi.authme.ConsoleLogger;
+
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
@@ -20,14 +21,14 @@ import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-public class AuthMeEntityListener implements Listener {
+public class EntityListener implements Listener {
private final ListenerService listenerService;
private Method getShooter;
private boolean shooterIsLivingEntity;
@Inject
- AuthMeEntityListener(ListenerService listenerService) {
+ EntityListener(ListenerService listenerService) {
this.listenerService = listenerService;
try {
getShooter = Projectile.class.getDeclaredMethod("getShooter");
@@ -39,7 +40,7 @@ public class AuthMeEntityListener implements Listener {
// Note #360: npc status can be used to bypass security!!!
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
- public void onEntityDamage(EntityDamageEvent event) {
+ public void onDamage(EntityDamageEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.getEntity().setFireTicks(0);
event.setDamage(0);
@@ -48,16 +49,16 @@ public class AuthMeEntityListener implements Listener {
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
- public void onEntityTarget(EntityTargetEvent event) {
- if (listenerService.shouldCancelEvent(event)) {
- event.setTarget(null);
+ public void onAttack(EntityDamageByEntityEvent event) {
+ if (listenerService.shouldCancelEvent(event.getDamager())) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
- public void onDamage(EntityDamageByEntityEvent event) {
+ public void onEntityTarget(EntityTargetEvent event) {
if (listenerService.shouldCancelEvent(event)) {
+ event.setTarget(null);
event.setCancelled(true);
}
}
diff --git a/src/main/java/fr/xephi/authme/listener/FailedVerificationException.java b/src/main/java/fr/xephi/authme/listener/FailedVerificationException.java
index 31957cdb..b189fd07 100644
--- a/src/main/java/fr/xephi/authme/listener/FailedVerificationException.java
+++ b/src/main/java/fr/xephi/authme/listener/FailedVerificationException.java
@@ -6,9 +6,9 @@ import fr.xephi.authme.util.StringUtils;
/**
* Exception thrown when a verification has failed.
*/
-@SuppressWarnings("serial")
public class FailedVerificationException extends Exception {
+ private static final long serialVersionUID = 3903242223297960699L;
private final MessageKey reason;
private final String[] args;
diff --git a/src/main/java/fr/xephi/authme/listener/ListenerService.java b/src/main/java/fr/xephi/authme/listener/ListenerService.java
index c5de1bc3..6c09bd2e 100644
--- a/src/main/java/fr/xephi/authme/listener/ListenerService.java
+++ b/src/main/java/fr/xephi/authme/listener/ListenerService.java
@@ -4,17 +4,15 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.initialization.SettingsDependent;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
-import fr.xephi.authme.settings.properties.RestrictionSettings;
+import fr.xephi.authme.util.ValidationService;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.player.PlayerEvent;
import javax.inject.Inject;
-import java.util.HashSet;
-import java.util.Set;
/**
* Service class for the AuthMe listeners to determine whether an event should be canceled.
@@ -24,16 +22,18 @@ class ListenerService implements SettingsDependent {
private final DataSource dataSource;
private final PluginHooks pluginHooks;
private final PlayerCache playerCache;
+ private final ValidationService validationService;
private boolean isRegistrationForced;
- private Set unrestrictedNames;
@Inject
- ListenerService(NewSetting settings, DataSource dataSource, PluginHooks pluginHooks, PlayerCache playerCache) {
+ ListenerService(Settings settings, DataSource dataSource, PluginHooks pluginHooks,
+ PlayerCache playerCache, ValidationService validationService) {
this.dataSource = dataSource;
this.pluginHooks = pluginHooks;
this.playerCache = playerCache;
- loadSettings(settings);
+ this.validationService = validationService;
+ reload(settings);
}
/**
@@ -44,10 +44,19 @@ class ListenerService implements SettingsDependent {
*/
public boolean shouldCancelEvent(EntityEvent event) {
Entity entity = event.getEntity();
+ return shouldCancelEvent(entity);
+ }
+
+ /**
+ * Returns, based on the entity associated with the event, whether or not the event should be canceled.
+ *
+ * @param entity the player entity to verify
+ * @return true if the associated event should be canceled, false otherwise
+ */
+ public boolean shouldCancelEvent(Entity entity) {
if (entity == null || !(entity instanceof Player)) {
return false;
}
-
Player player = (Player) entity;
return shouldCancelEvent(player);
}
@@ -74,10 +83,8 @@ class ListenerService implements SettingsDependent {
}
@Override
- public void loadSettings(NewSetting settings) {
+ public void reload(Settings settings) {
isRegistrationForced = settings.getProperty(RegistrationSettings.FORCE);
- // Keep unrestricted names as Set for more efficient contains()
- unrestrictedNames = new HashSet<>(settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES));
}
/**
@@ -88,7 +95,7 @@ class ListenerService implements SettingsDependent {
* @return true if the player may play, false otherwise
*/
private boolean checkAuth(String name) {
- if (isUnrestricted(name) || playerCache.isAuthenticated(name)) {
+ if (validationService.isUnrestricted(name) || playerCache.isAuthenticated(name)) {
return true;
}
if (!isRegistrationForced && !dataSource.isAuthAvailable(name)) {
@@ -96,14 +103,4 @@ class ListenerService implements SettingsDependent {
}
return false;
}
-
- /**
- * Checks if the name is unrestricted according to the configured settings.
- *
- * @param name the name to verify
- * @return true if unrestricted, false otherwise
- */
- private boolean isUnrestricted(String name) {
- return unrestrictedNames.contains(name.toLowerCase());
- }
}
diff --git a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java
index 297e74c6..745a1908 100644
--- a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java
+++ b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java
@@ -9,12 +9,13 @@ import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.ProtectionSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.StringUtils;
+import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.Server;
import org.bukkit.entity.Player;
@@ -31,7 +32,7 @@ import java.util.regex.Pattern;
class OnJoinVerifier implements Reloadable {
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private DataSource dataSource;
@Inject
@@ -56,13 +57,7 @@ class OnJoinVerifier implements Reloadable {
@Override
public void reload() {
String nickRegEx = settings.getProperty(RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS);
- try {
- nicknamePattern = Pattern.compile(nickRegEx);
- } catch (Exception e) {
- nicknamePattern = Pattern.compile(".*?");
- ConsoleLogger.showError("Nickname pattern is not a valid regular expression! "
- + "Fallback to allowing all nicknames");
- }
+ nicknamePattern = Utils.safePatternCompile(nickRegEx);
}
/**
@@ -73,7 +68,7 @@ class OnJoinVerifier implements Reloadable {
*/
public void checkAntibot(String playerName, boolean isAuthAvailable) throws FailedVerificationException {
if (antiBot.getAntiBotStatus() == AntiBot.AntiBotStatus.ACTIVE && !isAuthAvailable) {
- antiBot.antibotKicked.addIfAbsent(playerName);
+ antiBot.addPlayerKick(playerName);
throw new FailedVerificationException(MessageKey.KICK_ANTIBOT);
}
}
@@ -162,15 +157,15 @@ class OnJoinVerifier implements Reloadable {
}
/**
- * Checks that the player's country is admitted if he is not registered.
+ * Checks that the player's country is admitted.
*
* @param isAuthAvailable whether or not the user is registered
- * @param event the login event of the player
+ * @param playerIp the ip address of the player
*/
public void checkPlayerCountry(boolean isAuthAvailable,
- PlayerLoginEvent event) throws FailedVerificationException {
- if (!isAuthAvailable && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
- String playerIp = event.getAddress().getHostAddress();
+ String playerIp) throws FailedVerificationException {
+ if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED))
+ && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
if (!validationService.isCountryAdmitted(playerIp)) {
throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR);
}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/PlayerListener.java
similarity index 82%
rename from src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
rename to src/main/java/fr/xephi/authme/listener/PlayerListener.java
index 84fff695..c498e6ec 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
+++ b/src/main/java/fr/xephi/authme/listener/PlayerListener.java
@@ -6,13 +6,14 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.process.Management;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.BukkitService;
-import fr.xephi.authme.util.Utils;
+import fr.xephi.authme.util.TeleportationService;
+import fr.xephi.authme.util.ValidationService;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -23,7 +24,6 @@ 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;
@@ -51,12 +51,12 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAU
/**
* Listener class for player events.
*/
-public class AuthMePlayerListener implements Listener {
+public class PlayerListener implements Listener {
public static final ConcurrentHashMap joinMessage = new ConcurrentHashMap<>();
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private Messages m;
@Inject
@@ -73,6 +73,10 @@ public class AuthMePlayerListener implements Listener {
private OnJoinVerifier onJoinVerifier;
@Inject
private ListenerService listenerService;
+ @Inject
+ private TeleportationService teleportationService;
+ @Inject
+ private ValidationService validationService;
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
@@ -141,10 +145,6 @@ public class AuthMePlayerListener implements Listener {
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
// "cancel" the event
event.setTo(event.getFrom());
- if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) {
- player.setFlySpeed(0.0f);
- player.setWalkSpeed(0.0f);
- }
return;
}
@@ -189,47 +189,24 @@ public class AuthMePlayerListener implements Listener {
}
}
- @EventHandler(priority = EventPriority.LOW)
+ @EventHandler(priority = EventPriority.NORMAL)
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
- if (player != null) {
- // Schedule login task so works after the prelogin
- // (Fix found by Koolaid5000)
- bukkitService.runTask(new Runnable() {
- @Override
- public void run() {
- management.performJoin(player);
- }
- });
- }
+ teleportationService.teleportNewPlayerToFirstSpawn(player);
+ management.performJoin(player);
}
- // Note ljacqu 20160528: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
- // e.g. CraftBukkit does not. So we need to run crucial things in onPlayerLogin, too
- @EventHandler(priority = EventPriority.HIGHEST)
- public void onPreLogin(AsyncPlayerPreLoginEvent event) {
- final String name = event.getName().toLowerCase();
- final boolean isAuthAvailable = dataSource.isAuthAvailable(event.getName());
+ // Note #831: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
+ // e.g. CraftBukkit does not fire it. So we need to run crucial things with PlayerLoginEvent.
+ // Single session feature can be implemented for Spigot and CraftBukkit by canceling a kick
+ // event caused by "logged in from another location". The nicer way, but only for Spigot, would be
+ // to check in the AsyncPlayerPreLoginEvent. To support all servers, we use the less nice way.
- try {
- // Potential performance improvement: make checkAntiBot not require `isAuthAvailable` info and use
- // "checkKickNonRegistered" as last -> no need to query the DB before checking antibot / name
- onJoinVerifier.checkAntibot(name, isAuthAvailable);
- onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
- onJoinVerifier.checkIsValidName(name);
- // Note #760: Single session must be checked here - checking with PlayerLoginEvent is too late and
- // the first connection will have been kicked. This means this feature doesn't work on CraftBukkit.
- onJoinVerifier.checkSingleSession(name);
- } catch (FailedVerificationException e) {
- event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
- event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
- }
- }
-
- @EventHandler(priority = EventPriority.HIGHEST)
+ @EventHandler(priority = EventPriority.LOW)
public void onPlayerLogin(PlayerLoginEvent event) {
final Player player = event.getPlayer();
- if (Utils.isUnrestricted(player)) {
+ final String name = player.getName();
+ if (validationService.isUnrestricted(name)) {
return;
} else if (onJoinVerifier.refusePlayerForFullServer(event)) {
return;
@@ -237,16 +214,20 @@ public class AuthMePlayerListener implements Listener {
return;
}
- final String name = player.getName().toLowerCase();
- final PlayerAuth auth = dataSource.getAuth(player.getName());
- final boolean isAuthAvailable = (auth != null);
-
try {
- onJoinVerifier.checkAntibot(name, isAuthAvailable);
- onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
+ // Fast stuff
+ onJoinVerifier.checkSingleSession(name);
onJoinVerifier.checkIsValidName(name);
+
+ // Get the auth later as this may cause the single session check to fail
+ // Slow stuff
+ final PlayerAuth auth = dataSource.getAuth(name);
+ final boolean isAuthAvailable = (auth != null);
+ final String lowerName = name.toLowerCase();
+ onJoinVerifier.checkAntibot(lowerName, isAuthAvailable);
+ onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
onJoinVerifier.checkNameCasing(player, auth);
- onJoinVerifier.checkPlayerCountry(isAuthAvailable, event);
+ onJoinVerifier.checkPlayerCountry(isAuthAvailable, event.getAddress().getHostAddress());
} catch (FailedVerificationException e) {
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
@@ -254,6 +235,7 @@ public class AuthMePlayerListener implements Listener {
}
antiBot.handlePlayerJoin(player);
+ teleportationService.teleportOnJoin(player);
}
@EventHandler(priority = EventPriority.HIGHEST)
@@ -262,21 +244,32 @@ public class AuthMePlayerListener implements Listener {
if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) {
event.setQuitMessage(null);
+ } else if (settings.getProperty(RegistrationSettings.REMOVE_UNLOGGED_LEAVE_MESSAGE)) {
+ if(listenerService.shouldCancelEvent(event)) {
+ event.setQuitMessage(null);
+ }
}
- if (antiBot.antibotKicked.contains(player.getName())) {
+ if (antiBot.wasPlayerKicked(player.getName())) {
return;
}
- management.performQuit(player, false);
+ management.performQuit(player);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerKick(PlayerKickEvent event) {
- Player player = event.getPlayer();
+ // Note #831: Especially for offline CraftBukkit, we need to catch players being kicked because of
+ // "logged in from another location" and to cancel their kick
+ if (settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)
+ && event.getReason().contains("You logged in from another location")) {
+ event.setCancelled(true);
+ return;
+ }
- if (!antiBot.antibotKicked.contains(player.getName())) {
- management.performQuit(player, true);
+ final Player player = event.getPlayer();
+ if (!antiBot.wasPlayerKicked(player.getName())) {
+ management.performQuit(player);
}
}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener16.java b/src/main/java/fr/xephi/authme/listener/PlayerListener16.java
similarity index 91%
rename from src/main/java/fr/xephi/authme/listener/AuthMePlayerListener16.java
rename to src/main/java/fr/xephi/authme/listener/PlayerListener16.java
index 871757f4..0fe16756 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener16.java
+++ b/src/main/java/fr/xephi/authme/listener/PlayerListener16.java
@@ -10,7 +10,7 @@ import javax.inject.Inject;
/**
* Listener of player events for events introduced in Minecraft 1.6.
*/
-public class AuthMePlayerListener16 implements Listener {
+public class PlayerListener16 implements Listener {
@Inject
private ListenerService listenerService;
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener18.java b/src/main/java/fr/xephi/authme/listener/PlayerListener18.java
similarity index 91%
rename from src/main/java/fr/xephi/authme/listener/AuthMePlayerListener18.java
rename to src/main/java/fr/xephi/authme/listener/PlayerListener18.java
index b6cbf2a7..891a9b94 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener18.java
+++ b/src/main/java/fr/xephi/authme/listener/PlayerListener18.java
@@ -10,7 +10,7 @@ import javax.inject.Inject;
/**
* Listener of player events for events introduced in Minecraft 1.8.
*/
-public class AuthMePlayerListener18 implements Listener {
+public class PlayerListener18 implements Listener {
@Inject
private ListenerService listenerService;
diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListener19.java b/src/main/java/fr/xephi/authme/listener/PlayerListener19.java
new file mode 100644
index 00000000..ce2febe0
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/listener/PlayerListener19.java
@@ -0,0 +1,25 @@
+package fr.xephi.authme.listener;
+
+import javax.inject.Inject;
+
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerSwapHandItemsEvent;
+
+/**
+ * Listener of player events for events introduced in Minecraft 1.9.
+ */
+public class PlayerListener19 implements Listener {
+
+ @Inject
+ private ListenerService listenerService;
+
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
+ public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
+ if (listenerService.shouldCancelEvent(event)) {
+ event.setCancelled(true);
+ }
+ }
+
+}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/ServerListener.java
similarity index 66%
rename from src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
rename to src/main/java/fr/xephi/authme/listener/ServerListener.java
index b627ed6d..e3cbb813 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
+++ b/src/main/java/fr/xephi/authme/listener/ServerListener.java
@@ -1,53 +1,30 @@
package fr.xephi.authme.listener;
-import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.hooks.PluginHooks;
-import fr.xephi.authme.output.MessageKey;
-import fr.xephi.authme.output.Messages;
+import fr.xephi.authme.listener.protocollib.ProtocolLibService;
import fr.xephi.authme.permission.PermissionsManager;
-import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.SpawnLoader;
-import fr.xephi.authme.settings.properties.ProtectionSettings;
-import fr.xephi.authme.util.ValidationService;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
-import org.bukkit.event.server.ServerListPingEvent;
-
import javax.inject.Inject;
/**
*/
-public class AuthMeServerListener implements Listener {
+public class ServerListener implements Listener {
- @Inject
- private AuthMe plugin;
- @Inject
- private Messages messages;
- @Inject
- private NewSetting settings;
@Inject
private PluginHooks pluginHooks;
@Inject
private SpawnLoader spawnLoader;
@Inject
- private ValidationService validationService;
+ private ProtocolLibService protocolLibService;
@Inject
private PermissionsManager permissionsManager;
- @EventHandler(priority = EventPriority.HIGHEST)
- public void onServerPing(ServerListPingEvent event) {
- if (settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
- String playerIp = event.getAddress().getHostAddress();
- if (!validationService.isCountryAdmitted(playerIp)) {
- event.setMotd(messages.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR));
- }
- }
- }
-
@EventHandler(priority = EventPriority.HIGHEST)
public void onPluginDisable(PluginDisableEvent event) {
// Make sure the plugin instance isn't null
@@ -72,13 +49,9 @@ public class AuthMeServerListener implements Listener {
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
spawnLoader.unloadEssentialsSpawn();
ConsoleLogger.info("EssentialsSpawn has been disabled: unhooking");
- }
-
- if (pluginName.equalsIgnoreCase("ProtocolLib")) {
- plugin.inventoryProtector = null;
- plugin.tablistHider = null;
- plugin.tabComplete = null;
- ConsoleLogger.showError("ProtocolLib has been disabled, unhook packet inventory protection!");
+ } else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
+ protocolLibService.disable();
+ ConsoleLogger.warning("ProtocolLib has been disabled, unhooking packet adapters!");
}
}
@@ -102,10 +75,8 @@ public class AuthMeServerListener implements Listener {
pluginHooks.tryHookToCombatPlus();
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
spawnLoader.loadEssentialsSpawn();
- }
-
- if (pluginName.equalsIgnoreCase("ProtocolLib")) {
- plugin.checkProtocolLib();
+ } else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
+ protocolLibService.setup();
}
}
}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/InventoryPacketAdapter.java
similarity index 51%
rename from src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java
rename to src/main/java/fr/xephi/authme/listener/protocollib/InventoryPacketAdapter.java
index c6bb0967..1813ae1d 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java
+++ b/src/main/java/fr/xephi/authme/listener/protocollib/InventoryPacketAdapter.java
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package fr.xephi.authme.listener;
+package fr.xephi.authme.listener.protocollib;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
@@ -22,24 +22,16 @@ import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
-
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache;
-import fr.xephi.authme.settings.Settings;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.logging.Level;
-
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.PlayerInventory;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.logging.Level;
-import org.apache.commons.lang.reflect.MethodUtils;
-
-public class AuthMeInventoryPacketAdapter extends PacketAdapter {
+class InventoryPacketAdapter extends PacketAdapter {
private static final int PLAYER_INVENTORY = 0;
// http://wiki.vg/Inventory#Inventory (0-4 crafting, 5-8 armor, 9-35 main inventory, 36-44 hotbar, 45 off hand)
@@ -48,12 +40,8 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
private static final int ARMOR_SIZE = 4;
private static final int MAIN_SIZE = 27;
private static final int HOTBAR_SIZE = 9;
- private static final int OFF_HAND_POSITION = 45;
- private final boolean offHandSupported = MethodUtils
- .getAccessibleMethod(PlayerInventory.class, "getItemInOffHand", new Class[]{}) != null;
-
- public AuthMeInventoryPacketAdapter(AuthMe plugin) {
+ public InventoryPacketAdapter(AuthMe plugin) {
super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS);
}
@@ -63,8 +51,7 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
PacketContainer packet = packetEvent.getPacket();
byte windowId = packet.getIntegers().read(0).byteValue();
- if (windowId == PLAYER_INVENTORY && Settings.protectInventoryBeforeLogInEnabled
- && !PlayerCache.getInstance().isAuthenticated(player.getName())) {
+ if (windowId == PLAYER_INVENTORY && !PlayerCache.getInstance().isAuthenticated(player.getName())) {
packetEvent.setCancelled(true);
}
}
@@ -77,52 +64,6 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
ProtocolLibrary.getProtocolManager().removePacketListener(this);
}
- public void sendInventoryPacket(Player player) {
- ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
- PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS);
-
- // we are sending our own inventory
- inventoryPacket.getIntegers().write(0, PLAYER_INVENTORY);
-
- ItemStack[] playerCrafting = new ItemStack[CRAFTING_SIZE];
- Arrays.fill(playerCrafting, new ItemStack(Material.AIR));
- ItemStack[] armorContents = player.getInventory().getArmorContents();
- ItemStack[] mainInventory = player.getInventory().getContents();
-
- // bukkit saves the armor in reversed order
- Collections.reverse(Arrays.asList(armorContents));
-
- // same main inventory. The hotbar is at the beginning but it should be at the end of the array
- ItemStack[] hotbar = Arrays.copyOfRange(mainInventory, 0, HOTBAR_SIZE);
- ItemStack[] storedInventory = Arrays.copyOfRange(mainInventory, HOTBAR_SIZE, mainInventory.length);
-
- // concat all parts of the inventory together
- int inventorySize = CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE + HOTBAR_SIZE;
- if (offHandSupported) {
- inventorySize++;
- }
-
- ItemStack[] completeInventory = new ItemStack[inventorySize];
-
- System.arraycopy(playerCrafting, 0, completeInventory, 0, CRAFTING_SIZE);
- System.arraycopy(armorContents, 0, completeInventory, CRAFTING_SIZE, ARMOR_SIZE);
-
- // storedInventory and hotbar
- System.arraycopy(storedInventory, 0, completeInventory, CRAFTING_SIZE + ARMOR_SIZE, MAIN_SIZE);
- System.arraycopy(hotbar, 0, completeInventory, CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE, HOTBAR_SIZE);
-
- if (offHandSupported) {
- completeInventory[OFF_HAND_POSITION] = player.getInventory().getItemInOffHand();
- }
-
- inventoryPacket.getItemArrayModifier().write(0, completeInventory);
- try {
- protocolManager.sendServerPacket(player, inventoryPacket, false);
- } catch (InvocationTargetException invocationExc) {
- plugin.getLogger().log(Level.WARNING, "Error during inventory recovery", invocationExc);
- }
- }
-
public void sendBlankInventoryPacket(Player player) {
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS);
diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java
new file mode 100644
index 00000000..ae373bb0
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java
@@ -0,0 +1,120 @@
+package fr.xephi.authme.listener.protocollib;
+
+import ch.jalu.injector.annotations.NoFieldScan;
+import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.cache.auth.PlayerCache;
+import fr.xephi.authme.initialization.SettingsDependent;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.RestrictionSettings;
+import fr.xephi.authme.util.BukkitService;
+import org.bukkit.entity.Player;
+
+import javax.inject.Inject;
+
+@NoFieldScan
+public class ProtocolLibService implements SettingsDependent {
+
+ /* Packet Adapters */
+ private InventoryPacketAdapter inventoryPacketAdapter;
+ private TabCompletePacketAdapter tabCompletePacketAdapter;
+
+ /* Settings */
+ private boolean protectInvBeforeLogin;
+ private boolean denyTabCompleteBeforeLogin;
+
+ /* Service */
+ private boolean isEnabled;
+ private AuthMe plugin;
+ private BukkitService bukkitService;
+ private PlayerCache playerCache;
+
+ @Inject
+ ProtocolLibService(AuthMe plugin, Settings settings, BukkitService bukkitService, PlayerCache playerCache) {
+ this.plugin = plugin;
+ this.bukkitService = bukkitService;
+ this.playerCache = playerCache;
+ reload(settings);
+ }
+
+ /**
+ * Set up the ProtocolLib packet adapters.
+ */
+ public void setup() {
+ // Check if ProtocolLib is enabled on the server.
+ if (!plugin.getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
+ if (protectInvBeforeLogin) {
+ ConsoleLogger.warning("WARNING! The protectInventory feature requires ProtocolLib! Disabling it...");
+ }
+
+ if (denyTabCompleteBeforeLogin) {
+ ConsoleLogger.warning("WARNING! The denyTabComplete feature requires ProtocolLib! Disabling it...");
+ }
+
+ this.isEnabled = false;
+ return;
+ }
+
+ // Set up packet adapters
+ if (protectInvBeforeLogin && inventoryPacketAdapter == null) {
+ inventoryPacketAdapter = new InventoryPacketAdapter(plugin);
+ inventoryPacketAdapter.register();
+ } else if (inventoryPacketAdapter != null) {
+ inventoryPacketAdapter.unregister();
+ inventoryPacketAdapter = null;
+ }
+ if (denyTabCompleteBeforeLogin && tabCompletePacketAdapter == null) {
+ tabCompletePacketAdapter = new TabCompletePacketAdapter(plugin);
+ tabCompletePacketAdapter.register();
+ } else if (tabCompletePacketAdapter != null) {
+ tabCompletePacketAdapter.unregister();
+ tabCompletePacketAdapter = null;
+ }
+
+ this.isEnabled = true;
+ }
+
+ public void disable() {
+ isEnabled = false;
+
+ if (inventoryPacketAdapter != null) {
+ inventoryPacketAdapter.unregister();
+ inventoryPacketAdapter = null;
+ }
+ if (tabCompletePacketAdapter != null) {
+ tabCompletePacketAdapter.unregister();
+ tabCompletePacketAdapter = null;
+ }
+ }
+
+ /**
+ * Send a packet to the player to give them a blank inventory.
+ *
+ * @param player The player to send the packet to.
+ */
+ public void sendBlankInventoryPacket(Player player) {
+ if (isEnabled && inventoryPacketAdapter != null) {
+ inventoryPacketAdapter.sendBlankInventoryPacket(player);
+ }
+ }
+
+ @Override
+ public void reload(Settings settings) {
+ boolean oldProtectInventory = this.protectInvBeforeLogin;
+
+ this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN);
+ this.denyTabCompleteBeforeLogin = settings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
+
+ //it was true and will be deactivated now, so we need to restore the inventory for every player
+ if (oldProtectInventory && !protectInvBeforeLogin) {
+ inventoryPacketAdapter.unregister();
+ for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
+ if (!playerCache.isAuthenticated(onlinePlayer.getName())) {
+ onlinePlayer.updateInventory();
+ }
+ }
+ }
+ setup();
+ }
+
+}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/TabCompletePacketAdapter.java
similarity index 81%
rename from src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
rename to src/main/java/fr/xephi/authme/listener/protocollib/TabCompletePacketAdapter.java
index ae6c47bc..35058731 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
+++ b/src/main/java/fr/xephi/authme/listener/protocollib/TabCompletePacketAdapter.java
@@ -1,4 +1,4 @@
-package fr.xephi.authme.listener;
+package fr.xephi.authme.listener.protocollib;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
@@ -6,17 +6,13 @@ import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.FieldAccessException;
-
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache;
-import javax.inject.Inject;
+class TabCompletePacketAdapter extends PacketAdapter {
-public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
-
- @Inject
- public AuthMeTabCompletePacketAdapter(AuthMe plugin) {
+ public TabCompletePacketAdapter(AuthMe plugin) {
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
}
@@ -28,7 +24,7 @@ public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
event.setCancelled(true);
}
} catch (FieldAccessException e) {
- ConsoleLogger.showError("Couldn't access field.");
+ ConsoleLogger.warning("Couldn't access field.");
}
}
}
diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
index 58b64d6b..6088a5bc 100644
--- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
+++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
@@ -3,47 +3,74 @@ package fr.xephi.authme.mail;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
+import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.StringUtils;
import org.apache.commons.mail.EmailConstants;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
-import org.bukkit.Bukkit;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.imageio.ImageIO;
+import javax.inject.Inject;
import javax.mail.Session;
import java.io.File;
import java.io.IOException;
import java.security.Security;
import java.util.Properties;
+import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
+import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
+
/**
* @author Xephi59
*/
public class SendMailSSL {
- private final AuthMe plugin;
- private final NewSetting settings;
+ @Inject
+ private AuthMe plugin;
+ @Inject
+ private Settings settings;
+ @Inject
+ private BukkitService bukkitService;
- public SendMailSSL(AuthMe plugin, NewSetting settings) {
- this.plugin = plugin;
- this.settings = settings;
+ SendMailSSL() {
}
- public void main(final PlayerAuth auth, final String newPass) {
- final String mailText = replaceMailTags(settings.getEmailMessage(), plugin, auth, newPass);
- Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
+ /**
+ * Returns whether all necessary settings are set for sending mails.
+ *
+ * @return true if the necessary email settings are set, false otherwise
+ */
+ public boolean hasAllInformation() {
+ return !settings.getProperty(MAIL_ACCOUNT).isEmpty()
+ && !settings.getProperty(MAIL_PASSWORD).isEmpty();
+ }
+
+ /**
+ * Sends an email to the user with his new password.
+ *
+ * @param auth the player auth of the player
+ * @param newPass the new password
+ */
+ public void sendPasswordMail(final PlayerAuth auth, final String newPass) {
+ if (!hasAllInformation()) {
+ ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
+ return;
+ }
+
+ final String mailText = replaceMailTags(settings.getEmailMessage(), auth, newPass);
+ bukkitService.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
HtmlEmail email;
try {
- email = initializeMail(auth, settings);
+ email = initializeMail(auth.getEmail());
} catch (EmailException e) {
ConsoleLogger.logException("Failed to create email with the given settings:", e);
return;
@@ -54,7 +81,7 @@ public class SendMailSSL {
File file = null;
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
try {
- file = generateImage(auth, plugin, newPass);
+ file = generateImage(auth.getNickname(), plugin, newPass);
content = embedImageIntoEmailContent(file, email, content);
} catch (IOException | EmailException e) {
ConsoleLogger.logException(
@@ -67,13 +94,12 @@ public class SendMailSSL {
file.delete();
}
}
-
});
}
- private static File generateImage(PlayerAuth auth, AuthMe plugin, String newPass) throws IOException {
+ private static File generateImage(String name, AuthMe plugin, String newPass) throws IOException {
ImageGenerator gen = new ImageGenerator(newPass);
- File file = new File(plugin.getDataFolder(), auth.getNickname() + "_new_pass.jpg");
+ File file = new File(plugin.getDataFolder(), name + "_new_pass.jpg");
ImageIO.write(gen.generateImage(), "jpg", file);
return file;
}
@@ -85,8 +111,7 @@ public class SendMailSSL {
return content.replace("", "
");
}
- private static HtmlEmail initializeMail(PlayerAuth auth, NewSetting settings)
- throws EmailException {
+ private HtmlEmail initializeMail(String emailAddress) throws EmailException {
String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT);
String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
? senderMail
@@ -98,12 +123,12 @@ public class SendMailSSL {
email.setCharset(EmailConstants.UTF_8);
email.setSmtpPort(port);
email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST));
- email.addTo(auth.getEmail());
+ email.addTo(emailAddress);
email.setFrom(senderMail, senderName);
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
email.setAuthentication(senderMail, mailPassword);
- setPropertiesForPort(email, port, settings);
+ setPropertiesForPort(email, port);
return email;
}
@@ -124,15 +149,14 @@ public class SendMailSSL {
}
}
- private static String replaceMailTags(String mailText, AuthMe plugin, PlayerAuth auth, String newPass) {
+ private String replaceMailTags(String mailText, PlayerAuth auth, String newPass) {
return mailText
.replace("", auth.getNickname())
.replace("", plugin.getServer().getServerName())
.replace("", newPass);
}
- private static void setPropertiesForPort(HtmlEmail email, int port, NewSetting settings)
- throws EmailException {
+ private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException {
switch (port) {
case 587:
String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN);
diff --git a/src/main/java/fr/xephi/authme/output/Log4JFilter.java b/src/main/java/fr/xephi/authme/output/Log4JFilter.java
index 8bc52452..90b9f0fb 100644
--- a/src/main/java/fr/xephi/authme/output/Log4JFilter.java
+++ b/src/main/java/fr/xephi/authme/output/Log4JFilter.java
@@ -2,9 +2,9 @@ package fr.xephi.authme.output;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.message.Message;
/**
@@ -12,7 +12,8 @@ import org.apache.logging.log4j.message.Message;
*
* @author Xephi59
*/
-public class Log4JFilter implements Filter {
+@SuppressWarnings("serial")
+public class Log4JFilter extends AbstractFilter {
/**
* Constructor.
@@ -50,42 +51,30 @@ public class Log4JFilter implements Filter {
}
@Override
- public Result filter(LogEvent record) {
- if (record == null) {
- return Result.NEUTRAL;
+ public Result filter(LogEvent event) {
+ Message candidate = null;
+ if(event != null) {
+ candidate = event.getMessage();
}
- return validateMessage(record.getMessage());
+ return validateMessage(candidate);
}
@Override
- public Result filter(Logger arg0, Level arg1, Marker arg2, String message, Object... arg4) {
- if (message == null) {
- return Result.NEUTRAL;
+ public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
+ return validateMessage(msg);
+ }
+
+ @Override
+ public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {
+ return validateMessage(msg);
+ }
+
+ @Override
+ public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
+ String candidate = null;
+ if(msg != null) {
+ candidate = msg.toString();
}
- return validateMessage(message);
+ return validateMessage(candidate);
}
-
- @Override
- public Result filter(Logger arg0, Level arg1, Marker arg2, Object message, Throwable arg4) {
- if (message == null) {
- return Result.NEUTRAL;
- }
- return validateMessage(message.toString());
- }
-
- @Override
- public Result filter(Logger arg0, Level arg1, Marker arg2, Message message, Throwable arg4) {
- return validateMessage(message);
- }
-
- @Override
- public Result getOnMatch() {
- return Result.NEUTRAL;
- }
-
- @Override
- public Result getOnMismatch() {
- return Result.NEUTRAL;
- }
-
}
diff --git a/src/main/java/fr/xephi/authme/output/LogLevel.java b/src/main/java/fr/xephi/authme/output/LogLevel.java
new file mode 100644
index 00000000..f958e6d4
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/output/LogLevel.java
@@ -0,0 +1,38 @@
+package fr.xephi.authme.output;
+
+/**
+ * Log level.
+ */
+public enum LogLevel {
+
+ /** Info: general messages. */
+ INFO(3),
+
+ /** Fine: more detailed messages that may still be interesting to plugin users. */
+ FINE(2),
+
+ /** Debug: very detailed messages for debugging. */
+ DEBUG(1);
+
+ private int value;
+
+ /**
+ * Constructor.
+ *
+ * @param value the log level; the higher the number the more "important" the level.
+ * A log level enables its number and all above.
+ */
+ LogLevel(int value) {
+ this.value = value;
+ }
+
+ /**
+ * Return whether the current log level includes the given log level.
+ *
+ * @param level the level to process
+ * @return true if the level is enabled, false otherwise
+ */
+ public boolean includes(LogLevel level) {
+ return value <= level.value;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/output/MessageKey.java b/src/main/java/fr/xephi/authme/output/MessageKey.java
index 670366f5..c445b9a2 100644
--- a/src/main/java/fr/xephi/authme/output/MessageKey.java
+++ b/src/main/java/fr/xephi/authme/output/MessageKey.java
@@ -143,7 +143,11 @@ public enum MessageKey {
ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"),
- ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count");
+ ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"),
+
+ KICK_FOR_ADMIN_REGISTER("kicked_admin_registered"),
+
+ INCOMPLETE_EMAIL_SETTINGS("incomplete_email_settings");
private String key;
private String[] tags;
diff --git a/src/main/java/fr/xephi/authme/output/Messages.java b/src/main/java/fr/xephi/authme/output/Messages.java
index 61bf3d7d..5c076f1a 100644
--- a/src/main/java/fr/xephi/authme/output/Messages.java
+++ b/src/main/java/fr/xephi/authme/output/Messages.java
@@ -2,13 +2,13 @@ package fr.xephi.authme.output;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.SettingsDependent;
-import fr.xephi.authme.settings.NewSetting;
-import fr.xephi.authme.util.StringUtils;
+import fr.xephi.authme.settings.Settings;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
+import javax.inject.Inject;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -18,6 +18,9 @@ import java.io.InputStreamReader;
*/
public class Messages implements SettingsDependent {
+ // Custom Authme tag replaced to new line
+ private static final String NEWLINE_TAG = "%nl%";
+
private FileConfiguration configuration;
private String fileName;
private final String defaultFile;
@@ -26,12 +29,12 @@ public class Messages implements SettingsDependent {
/**
* Constructor.
*
- * @param messageFile The messages file to use
- * @param defaultFile The file with messages to use as default if missing
+ * @param settings The settings
*/
- public Messages(File messageFile, String defaultFile) {
- initializeFile(messageFile);
- this.defaultFile = defaultFile;
+ @Inject
+ Messages(Settings settings) {
+ reload(settings);
+ this.defaultFile = settings.getDefaultMessagesFile();
}
/**
@@ -70,18 +73,12 @@ public class Messages implements SettingsDependent {
* @return The message split by new lines
*/
public String[] retrieve(MessageKey key) {
- final String code = key.getKey();
- String message = configuration.getString(code);
-
- if (message == null) {
- ConsoleLogger.showError("Error getting message with key '" + code + "'. "
- + "Please verify your config file at '" + fileName + "'");
- return formatMessage(getDefault(code));
- }
- if(message.isEmpty()) {
+ String message = retrieveMessage(key);
+ if (message.isEmpty()) {
+ // Return empty array instead of array with 1 empty string as entry
return new String[0];
}
- return formatMessage(message);
+ return message.split("\n");
}
/**
@@ -90,8 +87,16 @@ public class Messages implements SettingsDependent {
* @param key The message key to retrieve
* @return The message from the file
*/
- public String retrieveSingle(MessageKey key) {
- return StringUtils.join("\n", retrieve(key));
+ private String retrieveMessage(MessageKey key) {
+ final String code = key.getKey();
+ String message = configuration.getString(code);
+
+ if (message == null) {
+ ConsoleLogger.warning("Error getting message with key '" + code + "'. "
+ + "Please verify your config file at '" + fileName + "'");
+ return formatMessage(getDefault(code));
+ }
+ return formatMessage(message);
}
/**
@@ -104,24 +109,21 @@ public class Messages implements SettingsDependent {
* @return The message from the file with replacements
*/
public String retrieveSingle(MessageKey key, String... replacements) {
- String message = retrieveSingle(key);
+ String message = retrieveMessage(key);
String[] tags = key.getTags();
if (replacements.length == tags.length) {
for (int i = 0; i < tags.length; ++i) {
message = message.replace(tags[i], replacements[i]);
}
} else {
- ConsoleLogger.showError("Invalid number of replacements for message key '" + key + "'");
+ ConsoleLogger.warning("Invalid number of replacements for message key '" + key + "'");
}
return message;
}
@Override
- public void loadSettings(NewSetting settings) {
- initializeFile(settings.getMessagesFile());
- }
-
- private void initializeFile(File messageFile) {
+ public void reload(Settings settings) {
+ File messageFile = settings.getMessagesFile();
this.configuration = YamlConfiguration.loadConfiguration(messageFile);
this.fileName = messageFile.getName();
}
@@ -143,12 +145,9 @@ public class Messages implements SettingsDependent {
return "Error retrieving message '" + code + "'";
}
- private static String[] formatMessage(String message) {
- String[] lines = message.split("&n");
- for (int i = 0; i < lines.length; ++i) {
- lines[i] = ChatColor.translateAlternateColorCodes('&', lines[i]);
- }
- return lines;
+ private static String formatMessage(String message) {
+ return ChatColor.translateAlternateColorCodes('&', message)
+ .replace(NEWLINE_TAG, "\n");
}
}
diff --git a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java
index c7557fc2..7d2136f0 100644
--- a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java
@@ -2,10 +2,12 @@ package fr.xephi.authme.permission;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.limbo.LimboCache;
-import fr.xephi.authme.cache.limbo.LimboPlayer;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.cache.limbo.PlayerData;
+import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
+import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -14,17 +16,21 @@ import java.util.Arrays;
/**
* Changes the permission group according to the auth status of the player and the configuration.
*/
-public class AuthGroupHandler {
+public class AuthGroupHandler implements Reloadable {
@Inject
private PermissionsManager permissionsManager;
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private LimboCache limboCache;
+ private String unloggedInGroup;
+ private String unregisteredGroup;
+ private String registeredGroup;
+
AuthGroupHandler() { }
/**
@@ -44,41 +50,74 @@ public class AuthGroupHandler {
// Make sure group support is available
if (!permissionsManager.hasGroupSupport()) {
- ConsoleLogger.showError("The current permissions system doesn't have group support, unable to set group!");
+ ConsoleLogger.warning("The current permissions system doesn't have group support, unable to set group!");
return false;
}
switch (group) {
case UNREGISTERED:
// Remove the other group type groups, set the current group
- permissionsManager.removeGroups(player, Arrays.asList(Settings.getRegisteredGroup, Settings.getUnloggedinGroup));
- return permissionsManager.addGroup(player, Settings.unRegisteredGroup);
+ permissionsManager.removeGroups(player, Arrays.asList(registeredGroup, unloggedInGroup));
+ return permissionsManager.addGroup(player, unregisteredGroup);
case REGISTERED:
// Remove the other group type groups, set the current group
- permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getUnloggedinGroup));
- return permissionsManager.addGroup(player, Settings.getRegisteredGroup);
+ permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, unloggedInGroup));
+ return permissionsManager.addGroup(player, registeredGroup);
case NOT_LOGGED_IN:
// Remove the other group type groups, set the current group
- permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup));
- return permissionsManager.addGroup(player, Settings.getUnloggedinGroup);
+ permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup));
+ return permissionsManager.addGroup(player, unloggedInGroup);
case LOGGED_IN:
- // Get the limbo player data
- LimboPlayer limbo = limboCache.getLimboPlayer(player.getName().toLowerCase());
- if (limbo == null)
+ // Get the player data
+ PlayerData data = limboCache.getPlayerData(player.getName().toLowerCase());
+ if (data == null) {
return false;
+ }
// Get the players group
- String realGroup = limbo.getGroup();
+ String realGroup = data.getGroup();
// Remove the other group types groups, set the real group
- permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup, Settings.getUnloggedinGroup));
+ permissionsManager.removeGroups(player,
+ Arrays.asList(unregisteredGroup, registeredGroup, unloggedInGroup)
+ );
return permissionsManager.addGroup(player, realGroup);
default:
return false;
}
}
+ /**
+ * TODO: This method requires better explanation.
+ *
+ * Set the normal group of a player.
+ *
+ * @param player The player.
+ * @param group The normal group.
+ *
+ * @return True on success, false on failure.
+ */
+ public boolean addNormal(Player player, String group) {
+ // Check whether the permissions check is enabled
+ if (!settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
+ return false;
+ }
+
+ // Remove old groups
+ permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup, unloggedInGroup));
+
+ // Add the normal group, return the result
+ return permissionsManager.addGroup(player, group);
+ }
+
+ @Override
+ public void reload() {
+ unloggedInGroup = settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP);
+ unregisteredGroup = settings.getProperty(HooksSettings.UNREGISTERED_GROUP);
+ registeredGroup = settings.getProperty(HooksSettings.REGISTERED_GROUP);
+ }
+
}
diff --git a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java
index 3acbfa8c..96e979a6 100644
--- a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java
+++ b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java
@@ -1,6 +1,6 @@
package fr.xephi.authme.permission;
-import org.bukkit.command.CommandSender;
+import org.bukkit.permissions.ServerOperator;
/**
* The default permission to fall back to if there is no support for permission nodes.
@@ -10,7 +10,7 @@ public enum DefaultPermission {
/** No one has permission. */
NOT_ALLOWED("No permission") {
@Override
- public boolean evaluate(CommandSender sender) {
+ public boolean evaluate(ServerOperator sender) {
return false;
}
},
@@ -18,15 +18,15 @@ public enum DefaultPermission {
/** Only players with OP status have permission. */
OP_ONLY("OP's only") {
@Override
- public boolean evaluate(CommandSender sender) {
- return sender.isOp();
+ public boolean evaluate(ServerOperator sender) {
+ return sender != null && sender.isOp();
}
},
/** Everyone is granted permission. */
ALLOWED("Everyone allowed") {
@Override
- public boolean evaluate(CommandSender sender) {
+ public boolean evaluate(ServerOperator sender) {
return true;
}
};
@@ -48,7 +48,7 @@ public enum DefaultPermission {
* @param sender the sender to process
* @return true if the sender has permission, false otherwise
*/
- public abstract boolean evaluate(CommandSender sender);
+ public abstract boolean evaluate(ServerOperator sender);
/**
* Return the textual representation.
diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
index e0065fa4..52ec20db 100644
--- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
+++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
@@ -1,25 +1,23 @@
package fr.xephi.authme.permission;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.permission.handlers.BPermissionsHandler;
import fr.xephi.authme.permission.handlers.GroupManagerHandler;
import fr.xephi.authme.permission.handlers.PermissionHandler;
+import fr.xephi.authme.permission.handlers.PermissionHandlerException;
import fr.xephi.authme.permission.handlers.PermissionsBukkitHandler;
import fr.xephi.authme.permission.handlers.PermissionsExHandler;
import fr.xephi.authme.permission.handlers.VaultHandler;
import fr.xephi.authme.permission.handlers.ZPermissionsHandler;
import fr.xephi.authme.util.StringUtils;
-import net.milkbowl.vault.permission.Permission;
import org.anjocaido.groupmanager.GroupManager;
-import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
-import org.bukkit.plugin.RegisteredServiceProvider;
-import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
-import ru.tehkode.permissions.bukkit.PermissionsEx;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
@@ -38,7 +36,7 @@ import java.util.List;
* @author Tim Visée, http://timvisee.com
* @version 0.3
*/
-public class PermissionsManager {
+public class PermissionsManager implements Reloadable {
private final Server server;
private final PluginManager pluginManager;
@@ -74,90 +72,17 @@ public class PermissionsManager {
* Setup and hook into the permissions systems.
*/
@PostConstruct
- public void setup() {
- // Force-unhook from current hooked permissions systems
- unhook();
-
+ private void setup() {
// Loop through all the available permissions system types
for (PermissionsSystemType type : PermissionsSystemType.values()) {
- // Try to find and hook the current plugin if available, print an error if failed
try {
- // Try to find the plugin for the current permissions system
- Plugin plugin = pluginManager.getPlugin(type.getPluginName());
-
- // Make sure a plugin with this name was found
- if (plugin == null)
- continue;
-
- // Make sure the plugin is enabled before hooking
- if (!plugin.isEnabled()) {
- ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!");
- continue;
+ PermissionHandler handler = getPermissionHandler(type);
+ if (handler != null) {
+ // Show a success message and return
+ this.handler = handler;
+ ConsoleLogger.info("Hooked into " + type.getName() + "!");
+ return;
}
-
- // Use the proper method to hook this plugin
- switch (type) {
- case PERMISSIONS_EX:
- // Get the permissions manager for PermissionsEx and make sure it isn't null
- if (PermissionsEx.getPermissionManager() == null) {
- ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
- continue;
- }
-
- handler = new PermissionsExHandler(PermissionsEx.getPermissionManager());
- break;
-
- case ESSENTIALS_GROUP_MANAGER:
- // Set the plugin instance
- handler = new GroupManagerHandler((GroupManager) plugin);
- break;
-
- case Z_PERMISSIONS:
- // Set the zPermissions service and make sure it's valid
- ZPermissionsService zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class);
- if (zPermissionsService == null) {
- ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
- continue;
- }
-
- handler = new ZPermissionsHandler(zPermissionsService);
- break;
-
- case VAULT:
- // Get the permissions provider service
- RegisteredServiceProvider permissionProvider = this.server.getServicesManager().getRegistration(Permission.class);
- if (permissionProvider == null) {
- ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
- continue;
- }
-
- // Get the Vault provider and make sure it's valid
- Permission vaultPerms = permissionProvider.getProvider();
- if (vaultPerms == null) {
- ConsoleLogger.info("Not using " + type.getName() + " because it's disabled!");
- continue;
- }
-
- handler = new VaultHandler(vaultPerms);
- break;
-
- case B_PERMISSIONS:
- handler = new BPermissionsHandler();
- break;
-
- case PERMISSIONS_BUKKIT:
- handler = new PermissionsBukkitHandler();
- break;
-
- default:
- }
-
- // Show a success message
- ConsoleLogger.info("Hooked into " + type.getName() + "!");
-
- // Return the used permissions system type
- return;
-
} catch (Exception ex) {
// An error occurred, show a warning message
ConsoleLogger.logException("Error while hooking into " + type.getName(), ex);
@@ -168,10 +93,42 @@ public class PermissionsManager {
ConsoleLogger.info("No supported permissions system found! Permissions are disabled!");
}
+ private PermissionHandler getPermissionHandler(PermissionsSystemType type) throws PermissionHandlerException {
+ // Try to find the plugin for the current permissions system
+ Plugin plugin = pluginManager.getPlugin(type.getPluginName());
+
+ if (plugin == null) {
+ return null;
+ }
+
+ // Make sure the plugin is enabled before hooking
+ if (!plugin.isEnabled()) {
+ ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!");
+ return null;
+ }
+
+ switch (type) {
+ case PERMISSIONS_EX:
+ return new PermissionsExHandler();
+ case ESSENTIALS_GROUP_MANAGER:
+ return new GroupManagerHandler((GroupManager) plugin);
+ case Z_PERMISSIONS:
+ return new ZPermissionsHandler();
+ case VAULT:
+ return new VaultHandler(server);
+ case B_PERMISSIONS:
+ return new BPermissionsHandler();
+ case PERMISSIONS_BUKKIT:
+ return new PermissionsBukkitHandler();
+ default:
+ throw new IllegalStateException("Unhandled permission type '" + type + "'");
+ }
+ }
+
/**
* Break the hook with all permission systems.
*/
- public void unhook() {
+ private void unhook() {
// Reset the current used permissions system
this.handler = null;
@@ -182,11 +139,12 @@ public class PermissionsManager {
/**
* Reload the permissions manager, and re-hook all permission plugins.
*/
+ @Override
public void reload() {
// Unhook all permission plugins
unhook();
- // Set up the permissions manager again, return the result
+ // Set up the permissions manager again
setup();
}
@@ -216,6 +174,15 @@ public class PermissionsManager {
}
}
+ /**
+ * Return the permissions system that is hooked into.
+ *
+ * @return The permissions system, or null.
+ */
+ public PermissionsSystemType getPermissionSystem() {
+ return isEnabled() ? handler.getPermissionSystem() : null;
+ }
+
/**
* Check if the command sender has permission for the given permissions node. If no permissions system is used or
* if the sender is not a player (e.g. console user), the player has to be OP in order to have the permission.
@@ -240,6 +207,39 @@ public class PermissionsManager {
return handler.hasPermission(player, permissionNode);
}
+ /**
+ * Check if a player has permission for the given permission node. This is for offline player checks. If no permissions
+ * system is used, then the player will not have permission.
+ *
+ * @param player The offline player
+ * @param permissionNode The permission node to verify
+ *
+ * @return true if the player has permission, false otherwise
+ */
+ public boolean hasPermissionOffline(OfflinePlayer player, PermissionNode permissionNode) {
+ // Check if the permission node is null
+ if (permissionNode == null) {
+ return true;
+ }
+
+ if (!isEnabled()) {
+ return permissionNode.getDefaultPermission().evaluate(player);
+ }
+
+ return handler.hasPermissionOffline(player.getName(), permissionNode);
+ }
+
+ public boolean hasPermissionOffline(String name, PermissionNode permissionNode) {
+ if (permissionNode == null) {
+ return true;
+ }
+ if (!isEnabled()) {
+ return permissionNode.getDefaultPermission().evaluate(null);
+ }
+
+ return handler.hasPermissionOffline(name, permissionNode);
+ }
+
/**
* Check whether the current permissions system has group support.
* If no permissions system is hooked, false will be returned.
diff --git a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
index fd023935..d733814e 100644
--- a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
+++ b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
@@ -24,7 +24,12 @@ public enum PlayerStatePermission implements PermissionNode {
/**
* Permission to be able to register multiple accounts.
*/
- ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY);
+ ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY),
+
+ /**
+ * Permission to bypass the purging process
+ */
+ BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED);
/**
* The permission node.
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java
index 45592323..c448d7b7 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java
@@ -27,6 +27,11 @@ public class BPermissionsHandler implements PermissionHandler {
return ApiLayer.hasPermission(player.getWorld().getName(), CalculableType.USER, player.getName(), node.getNode());
}
+ @Override
+ public boolean hasPermissionOffline(String name, PermissionNode node) {
+ return ApiLayer.hasPermission(null, CalculableType.USER, name, node.getNode());
+ }
+
@Override
public boolean isInGroup(Player player, String group) {
return ApiLayer.hasGroup(player.getWorld().getName(), CalculableType.USER, player.getName(), group);
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java
index fe0b0236..18d813e8 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java
@@ -35,6 +35,17 @@ public class GroupManagerHandler implements PermissionHandler {
return handler != null && handler.has(player, node.getNode());
}
+ @Override
+ public boolean hasPermissionOffline(String name, PermissionNode node) {
+ final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissionsByPlayerName(name);
+ if(handler == null) {
+ return false;
+ }
+
+ List perms = handler.getAllPlayersPermissions(name);
+ return perms.contains(node.getNode());
+ }
+
@Override
public boolean isInGroup(Player player, String group) {
final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissions(player);
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java
index 5d467cea..bf294c52 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java
@@ -38,6 +38,17 @@ public interface PermissionHandler {
*/
boolean hasPermission(Player player, PermissionNode node);
+ /**
+ * Check if a player has permission by their name.
+ * Used to check an offline player's permission.
+ *
+ * @param name The player's name.
+ * @param node The permission node.
+ *
+ * @return True if the player has permission.
+ */
+ boolean hasPermissionOffline(String name, PermissionNode node);
+
/**
* Check whether the player is in the specified group.
*
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java
new file mode 100644
index 00000000..3037c4dd
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java
@@ -0,0 +1,12 @@
+package fr.xephi.authme.permission.handlers;
+
+/**
+ * Exception during the instantiation of a {@link PermissionHandler}.
+ */
+@SuppressWarnings("serial")
+public class PermissionHandlerException extends Exception {
+
+ public PermissionHandlerException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java
index fb1edcae..22edea69 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java
@@ -25,6 +25,11 @@ public class PermissionsBukkitHandler implements PermissionHandler {
return player.hasPermission(node.getNode());
}
+ @Override
+ public boolean hasPermissionOffline(String name, PermissionNode node) {
+ return false;
+ }
+
@Override
public boolean isInGroup(Player player, String group) {
List groupNames = getGroups(player);
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java
index b49e4b37..7b1096f9 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java
@@ -1,6 +1,5 @@
package fr.xephi.authme.permission.handlers;
-import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsSystemType;
import org.bukkit.entity.Player;
@@ -15,14 +14,16 @@ public class PermissionsExHandler implements PermissionHandler {
private PermissionManager permissionManager;
- public PermissionsExHandler(PermissionManager permissionManager) {
- this.permissionManager = permissionManager;
+ public PermissionsExHandler() throws PermissionHandlerException {
+ permissionManager = PermissionsEx.getPermissionManager();
+ if (permissionManager == null) {
+ throw new PermissionHandlerException("Could not get manager of PermissionsEx");
+ }
}
@Override
public boolean addToGroup(Player player, String group) {
if (!PermissionsEx.getPermissionManager().getGroupNames().contains(group)) {
- ConsoleLogger.showError("The plugin tried to set " + player + "'s group to '" + group + "', but it doesn't exist!");
return false;
}
@@ -42,6 +43,12 @@ public class PermissionsExHandler implements PermissionHandler {
return user.has(node.getNode());
}
+ @Override
+ public boolean hasPermissionOffline(String name, PermissionNode node) {
+ PermissionUser user = permissionManager.getUser(name);
+ return user.has(node.getNode());
+ }
+
@Override
public boolean isInGroup(Player player, String group) {
PermissionUser user = permissionManager.getUser(player);
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java
index 7b99b5ed..f8e322d6 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java
@@ -3,7 +3,9 @@ package fr.xephi.authme.permission.handlers;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsSystemType;
import net.milkbowl.vault.permission.Permission;
+import org.bukkit.Server;
import org.bukkit.entity.Player;
+import org.bukkit.plugin.RegisteredServiceProvider;
import java.util.Arrays;
import java.util.List;
@@ -12,8 +14,24 @@ public class VaultHandler implements PermissionHandler {
private Permission vaultProvider;
- public VaultHandler(Permission vaultProvider) {
- this.vaultProvider = vaultProvider;
+ public VaultHandler(Server server) throws PermissionHandlerException {
+ this.vaultProvider = getVaultPermission(server);
+ }
+
+ private static Permission getVaultPermission(Server server) throws PermissionHandlerException {
+ // Get the permissions provider service
+ RegisteredServiceProvider permissionProvider = server
+ .getServicesManager().getRegistration(Permission.class);
+ if (permissionProvider == null) {
+ throw new PermissionHandlerException("Could not load permissions provider service");
+ }
+
+ // Get the Vault provider and make sure it's valid
+ Permission vaultPerms = permissionProvider.getProvider();
+ if (vaultPerms == null) {
+ throw new PermissionHandlerException("Could not load Vault permissions provider");
+ }
+ return vaultPerms;
}
@Override
@@ -31,6 +49,11 @@ public class VaultHandler implements PermissionHandler {
return vaultProvider.has(player, node.getNode());
}
+ @Override
+ public boolean hasPermissionOffline(String name, PermissionNode node) {
+ return vaultProvider.has("", name, node.getNode());
+ }
+
@Override
public boolean isInGroup(Player player, String group) {
return vaultProvider.playerInGroup(player, group);
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java
index fb2490f7..b4f3198f 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java
@@ -14,7 +14,12 @@ public class ZPermissionsHandler implements PermissionHandler {
private ZPermissionsService zPermissionsService;
- public ZPermissionsHandler(ZPermissionsService zPermissionsService) {
+ public ZPermissionsHandler() throws PermissionHandlerException {
+ // Set the zPermissions service and make sure it's valid
+ ZPermissionsService zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class);
+ if (zPermissionsService == null) {
+ throw new PermissionHandlerException("Failed to get the ZPermissions service!");
+ }
this.zPermissionsService = zPermissionsService;
}
@@ -37,6 +42,15 @@ public class ZPermissionsHandler implements PermissionHandler {
return node.getDefaultPermission().evaluate(player);
}
+ @Override
+ public boolean hasPermissionOffline(String name, PermissionNode node) {
+ Map perms = zPermissionsService.getPlayerPermissions(null, null, name);
+ if (perms.containsKey(node.getNode()))
+ return perms.get(node.getNode());
+ else
+ return false;
+ }
+
@Override
public boolean isInGroup(Player player, String group) {
return getGroups(player).contains(group);
diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java
index 5e72fad7..63d96b97 100644
--- a/src/main/java/fr/xephi/authme/process/Management.java
+++ b/src/main/java/fr/xephi/authme/process/Management.java
@@ -10,6 +10,7 @@ import fr.xephi.authme.process.quit.AsynchronousQuit;
import fr.xephi.authme.process.register.AsyncRegister;
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
import fr.xephi.authme.util.BukkitService;
+import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -70,11 +71,20 @@ public class Management {
});
}
- public void performUnregister(final Player player, final String password, final boolean isForce) {
+ public void performUnregister(final Player player, final String password) {
runTask(new Runnable() {
@Override
public void run() {
- asynchronousUnregister.unregister(player, password, isForce);
+ asynchronousUnregister.unregister(player, password);
+ }
+ });
+ }
+
+ public void performUnregisterByAdmin(final CommandSender initiator, final String name, final Player player) {
+ runTask(new Runnable() {
+ @Override
+ public void run() {
+ asynchronousUnregister.adminUnregister(initiator, name, player);
}
});
}
@@ -88,11 +98,11 @@ public class Management {
});
}
- public void performQuit(final Player player, final boolean isKick) {
+ public void performQuit(final Player player) {
runTask(new Runnable() {
@Override
public void run() {
- asynchronousQuit.processQuit(player, isKick);
+ asynchronousQuit.processQuit(player);
}
});
}
diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java
index fd2e5657..db5b4211 100644
--- a/src/main/java/fr/xephi/authme/process/ProcessService.java
+++ b/src/main/java/fr/xephi/authme/process/ProcessService.java
@@ -6,7 +6,7 @@ import fr.xephi.authme.permission.AuthGroupHandler;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
@@ -20,7 +20,7 @@ import javax.inject.Inject;
public class ProcessService {
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private Messages messages;
@@ -50,7 +50,7 @@ public class ProcessService {
*
* @return settings manager
*/
- public NewSetting getSettings() {
+ public Settings getSettings() {
return settings;
}
diff --git a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java b/src/main/java/fr/xephi/authme/process/SyncProcessManager.java
index 221e1e8c..894c3a48 100644
--- a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java
+++ b/src/main/java/fr/xephi/authme/process/SyncProcessManager.java
@@ -71,11 +71,11 @@ public class SyncProcessManager {
});
}
- public void processSyncPlayerQuit(final Player player, final boolean isOp, final boolean needToChange) {
+ public void processSyncPlayerQuit(final Player player) {
runTask(new Runnable() {
@Override
public void run() {
- processSyncronousPlayerQuit.processSyncQuit(player, isOp, needToChange);
+ processSyncronousPlayerQuit.processSyncQuit(player);
}
});
}
diff --git a/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java b/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java
index 4389ac35..992a5617 100644
--- a/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java
+++ b/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java
@@ -1,8 +1,5 @@
package fr.xephi.authme.process.changepassword;
-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.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
@@ -12,8 +9,7 @@ import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
-import fr.xephi.authme.settings.properties.HooksSettings;
-import fr.xephi.authme.util.BukkitService;
+import fr.xephi.authme.service.BungeeService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -21,7 +17,7 @@ import javax.inject.Inject;
public class AsyncChangePassword implements AsynchronousProcess {
@Inject
- private AuthMe plugin;
+ private BungeeService bungeeService;
@Inject
private DataSource dataSource;
@@ -35,9 +31,6 @@ public class AsyncChangePassword implements AsynchronousProcess {
@Inject
private PlayerCache playerCache;
- @Inject
- private BukkitService bukkitService;
-
AsyncChangePassword() { }
@@ -56,21 +49,9 @@ public class AsyncChangePassword implements AsynchronousProcess {
playerCache.updatePlayer(auth);
processService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(player.getName() + " changed his password");
- if (processService.getProperty(HooksSettings.BUNGEECORD)) {
- final String hash = hashedPassword.getHash();
- final String salt = hashedPassword.getSalt();
- bukkitService.scheduleSyncDelayedTask(new Runnable() {
- @Override
- public void run() {
- ByteArrayDataOutput out = ByteStreams.newDataOutput();
- out.writeUTF("Forward");
- out.writeUTF("ALL");
- out.writeUTF("AuthMe");
- out.writeUTF("changepassword;" + name + ";" + hash + ";" + salt);
- player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
- }
- });
- }
+
+ // Send a Bungee message for the password change
+ bungeeService.sendPasswordChanged(player, hashedPassword);
} else {
processService.send(player, MessageKey.WRONG_PASSWORD);
}
diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
index d7aa3127..d61d39c2 100644
--- a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
+++ b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
@@ -47,7 +47,7 @@ public class AsyncAddEmail implements AsynchronousProcess {
playerCache.updatePlayer(auth);
service.send(player, MessageKey.EMAIL_ADDED_SUCCESS);
} else {
- ConsoleLogger.showError("Could not save email for player '" + player + "'");
+ ConsoleLogger.warning("Could not save email for player '" + player + "'");
service.send(player, MessageKey.ERROR);
}
}
diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
index cf1741c1..d9be3617 100644
--- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
+++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
@@ -2,6 +2,7 @@ package fr.xephi.authme.process.join;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.cache.SessionManager;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache;
@@ -13,14 +14,13 @@ import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.settings.properties.SecuritySettings;
-import fr.xephi.authme.task.LimboPlayerTaskManager;
+import fr.xephi.authme.task.PlayerDataTaskManager;
import fr.xephi.authme.util.BukkitService;
-import fr.xephi.authme.util.TeleportationService;
import fr.xephi.authme.util.Utils;
import org.apache.commons.lang.reflect.MethodUtils;
import org.bukkit.GameMode;
@@ -34,7 +34,9 @@ import javax.inject.Inject;
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
-
+/**
+ * Asynchronous process for when a player joins.
+ */
public class AsynchronousJoin implements AsynchronousProcess {
private static final boolean DISABLE_COLLISIONS = MethodUtils
@@ -56,18 +58,22 @@ public class AsynchronousJoin implements AsynchronousProcess {
private LimboCache limboCache;
@Inject
- private PluginHooks pluginHooks;
+ private SessionManager sessionManager;
@Inject
- private TeleportationService teleportationService;
+ private PluginHooks pluginHooks;
@Inject
private BukkitService bukkitService;
@Inject
- private LimboPlayerTaskManager limboPlayerTaskManager;
+ private PlayerDataTaskManager playerDataTaskManager;
- AsynchronousJoin() { }
+ @Inject
+ private AsynchronousLogin asynchronousLogin;
+
+ AsynchronousJoin() {
+ }
public void processJoin(final Player player) {
@@ -114,44 +120,45 @@ public class AsynchronousJoin implements AsynchronousProcess {
return;
}
+
final boolean isAuthAvailable = database.isAuthAvailable(name);
if (isAuthAvailable) {
+ limboCache.addPlayerData(player);
service.setGroup(player, AuthGroupType.NOT_LOGGED_IN);
- teleportationService.teleportOnJoin(player);
- limboCache.updateLimboPlayer(player);
// Protect inventory
- if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.inventoryProtector != null) {
+ if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
ProtectInventoryEvent ev = new ProtectInventoryEvent(player);
bukkitService.callEvent(ev);
if (ev.isCancelled()) {
- plugin.inventoryProtector.sendInventoryPacket(player);
- if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + "...");
- }
+ player.updateInventory();
+ ConsoleLogger.fine("ProtectInventoryEvent has been cancelled for " + player.getName() + "...");
}
}
// Session logic
- if (service.getProperty(PluginSettings.SESSIONS_ENABLED) && (playerCache.isAuthenticated(name) || database.isLogged(name))) {
- if (plugin.sessions.containsKey(name)) {
- plugin.sessions.get(name).cancel();
- plugin.sessions.remove(name);
- }
+ if (sessionManager.hasSession(name) || database.isLogged(name)) {
PlayerAuth auth = database.getAuth(name);
database.setUnlogged(name);
playerCache.removePlayer(name);
if (auth != null && auth.getIp().equals(ip)) {
service.send(player, MessageKey.SESSION_RECONNECTION);
- plugin.getManagement().performLogin(player, "dontneed", true);
+ bukkitService.runTaskAsynchronously(new Runnable() {
+ @Override
+ public void run() {
+ asynchronousLogin.login(player, "dontneed", true);
+ }
+ });
return;
} else if (service.getProperty(PluginSettings.SESSIONS_EXPIRE_ON_IP_CHANGE)) {
service.send(player, MessageKey.SESSION_EXPIRED);
}
}
} else {
- // Not Registered
+ // Not Registered. Delete old data, load default one.
+ limboCache.deletePlayerData(player);
+ limboCache.addPlayerData(player);
// Groups logic
service.setGroup(player, AuthGroupType.UNREGISTERED);
@@ -160,13 +167,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
if (!service.getProperty(RegistrationSettings.FORCE)) {
return;
}
-
- teleportationService.teleportOnJoin(player);
- }
- // The user is not logged in
-
- if (!limboCache.hasLimboPlayer(name)) {
- limboCache.addLimboPlayer(player);
}
final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
@@ -194,8 +194,8 @@ public class AsynchronousJoin implements AsynchronousProcess {
});
// Timeout and message task
- limboPlayerTaskManager.registerTimeoutTask(player);
- limboPlayerTaskManager.registerMessageTask(name, isAuthAvailable);
+ playerDataTaskManager.registerTimeoutTask(player);
+ playerDataTaskManager.registerMessageTask(name, isAuthAvailable);
}
private boolean isPlayerUnrestricted(String name) {
@@ -205,11 +205,12 @@ public class AsynchronousJoin implements AsynchronousProcess {
/**
* Returns whether the name is restricted based on the restriction settings.
*
- * @param name The name to check
- * @param ip The IP address of the player
+ * @param name The name to check
+ * @param ip The IP address of the player
* @param domain The hostname of the IP address
+ *
* @return True if the name is restricted (IP/domain is not allowed for the given name),
- * false if the restrictions are met or if the name has no restrictions to it
+ * false if the restrictions are met or if the name has no restrictions to it
*/
private boolean isNameRestricted(String name, String ip, String domain) {
if (!service.getProperty(RestrictionSettings.ENABLE_RESTRICTED_USERS)) {
@@ -236,7 +237,8 @@ public class AsynchronousJoin implements AsynchronousProcess {
* settings and permissions). If this is the case, the player is kicked.
*
* @param player the player to verify
- * @param ip the ip address of the player
+ * @param ip the ip address of the player
+ *
* @return true if the verification is OK (no infraction), false if player has been kicked
*/
private boolean validatePlayerCountForIp(final Player player, String ip) {
diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
index 18e7e8e4..cb4df02c 100644
--- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
+++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
@@ -6,7 +6,7 @@ import fr.xephi.authme.cache.TempbanManager;
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.cache.limbo.PlayerData;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent;
import fr.xephi.authme.output.MessageKey;
@@ -18,16 +18,14 @@ import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity;
-import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.EmailSettings;
+import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.settings.properties.SecuritySettings;
-import fr.xephi.authme.task.LimboPlayerTaskManager;
+import fr.xephi.authme.task.PlayerDataTaskManager;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
-import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
@@ -70,24 +68,10 @@ public class AsynchronousLogin implements AsynchronousProcess {
private TempbanManager tempbanManager;
@Inject
- private LimboPlayerTaskManager limboPlayerTaskManager;
+ private PlayerDataTaskManager playerDataTaskManager;
AsynchronousLogin() { }
-
- /**
- * Queries the {@link fr.xephi.authme.cache.CaptchaManager} to
- * see if a captcha needs to be entered in order to log in.
- *
- * @param player The player to check
- * @return True if a captcha needs to be entered
- */
- private boolean needsCaptcha(Player player) {
- final String playerName = player.getName();
-
- return captchaManager.isCaptchaRequired(playerName);
- }
-
/**
* Checks the precondition for authentication (like user known) and returns
* the playerAuth-State
@@ -106,11 +90,12 @@ public class AsynchronousLogin implements AsynchronousProcess {
service.send(player, MessageKey.USER_NOT_REGISTERED);
// TODO ljacqu 20160612: Why is the message task being canceled and added again here?
- limboPlayerTaskManager.registerMessageTask(name, false);
+ playerDataTaskManager.registerMessageTask(name, false);
return null;
}
- if (!service.getProperty(DatabaseSettings.MYSQL_COL_GROUP).isEmpty() && pAuth.getGroupId() == Settings.getNonActivatedGroup) {
+ if (!service.getProperty(DatabaseSettings.MYSQL_COL_GROUP).isEmpty()
+ && pAuth.getGroupId() == service.getProperty(HooksSettings.NON_ACTIVATED_USERS_GROUP)) {
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
return null;
}
@@ -126,7 +111,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
}
AuthMeAsyncPreLoginEvent event = new AuthMeAsyncPreLoginEvent(player);
- Bukkit.getServer().getPluginManager().callEvent(event);
+ bukkitService.callEvent(event);
if (!event.canLogin()) {
return null;
}
@@ -142,7 +127,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
final String name = player.getName().toLowerCase();
// If Captcha is required send a message to the player and deny to login
- if (needsCaptcha(player)) {
+ if (captchaManager.isCaptchaRequired(name)) {
service.send(player, MessageKey.USAGE_CAPTCHA, captchaManager.getCaptchaCodeOrGenerateNew(name));
return;
}
@@ -154,11 +139,6 @@ public class AsynchronousLogin implements AsynchronousProcess {
captchaManager.increaseCount(name);
tempbanManager.increaseCount(ip);
- if ("127.0.0.1".equals(pAuth.getIp()) && !pAuth.getIp().equals(ip)) {
- pAuth.setIp(ip);
- database.updateIp(pAuth.getNickname(), ip);
- }
-
String email = pAuth.getEmail();
boolean passwordVerified = forceLogin || passwordSecurity.comparePassword(
password, pAuth.getPassword(), player.getName());
@@ -185,9 +165,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
service.send(player, MessageKey.ADD_EMAIL_MESSAGE);
}
- if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info(player.getName() + " logged in!");
- }
+ ConsoleLogger.fine(player.getName() + " logged in!");
// makes player isLoggedin via API
playerCache.addPlayer(auth);
@@ -197,20 +175,13 @@ public class AsynchronousLogin implements AsynchronousProcess {
// task, we schedule it in the end
// so that we can be sure, and have not to care if it might be
// processed in other order.
- LimboPlayer limboPlayer = limboCache.getLimboPlayer(name);
- if (limboPlayer != null) {
- if (limboPlayer.getTimeoutTask() != null) {
- limboPlayer.getTimeoutTask().cancel();
- }
- if (limboPlayer.getMessageTask() != null) {
- limboPlayer.getMessageTask().cancel();
- }
+ PlayerData playerData = limboCache.getPlayerData(name);
+ if (playerData != null) {
+ playerData.clearTasks();
}
syncProcessManager.processSyncPlayerLogin(player);
} else if (player.isOnline()) {
- if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info(player.getName() + " used the wrong password");
- }
+ ConsoleLogger.fine(player.getName() + " used the wrong password");
if (service.getProperty(RestrictionSettings.KICK_ON_WRONG_PASSWORD)) {
bukkitService.scheduleSyncDelayedTask(new Runnable() {
@Override
@@ -224,12 +195,12 @@ public class AsynchronousLogin implements AsynchronousProcess {
service.send(player, MessageKey.WRONG_PASSWORD);
// If the authentication fails check if Captcha is required and send a message to the player
- if (needsCaptcha(player)) {
+ if (captchaManager.isCaptchaRequired(name)) {
service.send(player, MessageKey.USAGE_CAPTCHA, captchaManager.getCaptchaCodeOrGenerateNew(name));
}
}
} else {
- ConsoleLogger.showError("Player " + name + " wasn't online during login process, aborted... ");
+ ConsoleLogger.warning("Player " + name + " wasn't online during login process, aborted... ");
}
}
@@ -255,10 +226,8 @@ public class AsynchronousLogin implements AsynchronousProcess {
String message = ChatColor.GRAY + StringUtils.join(ChatColor.GRAY + ", ", formattedNames) + ".";
- if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info("The user " + player.getName() + " has " + auths.size() + " accounts:");
- ConsoleLogger.info(message);
- }
+ ConsoleLogger.fine("The user " + player.getName() + " has " + auths.size() + " accounts:");
+ ConsoleLogger.fine(message);
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
if (onlinePlayer.getName().equalsIgnoreCase(player.getName())
diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java
index 28304e00..ebbcbc99 100644
--- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java
+++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java
@@ -1,21 +1,17 @@
package fr.xephi.authme.process.login;
-import com.google.common.io.ByteArrayDataOutput;
-import com.google.common.io.ByteStreams;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.limbo.LimboCache;
-import fr.xephi.authme.cache.limbo.LimboPlayer;
+import fr.xephi.authme.cache.limbo.PlayerData;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.LoginEvent;
import fr.xephi.authme.events.RestoreInventoryEvent;
-import fr.xephi.authme.listener.AuthMePlayerListener;
-import fr.xephi.authme.permission.AuthGroupType;
+import fr.xephi.authme.listener.PlayerListener;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SynchronousProcess;
-import fr.xephi.authme.settings.properties.HooksSettings;
+import fr.xephi.authme.service.BungeeService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
-import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.TeleportationService;
import org.apache.commons.lang.reflect.MethodUtils;
@@ -38,15 +34,15 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
@Inject
private AuthMe plugin;
+ @Inject
+ private BungeeService bungeeService;
+
@Inject
private ProcessService service;
@Inject
private LimboCache limboCache;
- @Inject
- private DataSource dataSource;
-
@Inject
private BukkitService bukkitService;
@@ -56,22 +52,17 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
@Inject
private TeleportationService teleportationService;
- ProcessSyncPlayerLogin() { }
+ @Inject
+ private DataSource dataSource;
-
- private void restoreSpeedEffects(Player player) {
- if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
- && service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
- player.setWalkSpeed(0.2F);
- player.setFlySpeed(0.1F);
- }
+ ProcessSyncPlayerLogin() {
}
private void restoreInventory(Player player) {
RestoreInventoryEvent event = new RestoreInventoryEvent(player);
pluginManager.callEvent(event);
- if (!event.isCancelled() && plugin.inventoryProtector != null) {
- plugin.inventoryProtector.sendInventoryPacket(player);
+ if (!event.isCancelled()) {
+ player.updateInventory();
}
}
@@ -87,35 +78,29 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
public void processPlayerLogin(Player player) {
final String name = player.getName().toLowerCase();
+
+ final PlayerData limbo = limboCache.getPlayerData(name);
// Limbo contains the State of the Player before /login
- final LimboPlayer limbo = limboCache.getLimboPlayer(name);
- final PlayerAuth auth = dataSource.getAuth(name);
-
if (limbo != null) {
- // Restore Op state and Permission Group
- restoreOpState(player, limbo);
- service.setGroup(player, AuthGroupType.LOGGED_IN);
-
- teleportationService.teleportOnLogin(player, auth, limbo);
-
- if (RESTORE_COLLISIONS && !service.getProperty(KEEP_COLLISIONS_DISABLED)) {
- player.setCollidable(true);
- }
-
- if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
- restoreInventory(player);
- }
-
- if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) {
- plugin.tablistHider.sendTablist(player);
- }
-
- // Clean up no longer used temporary data
- limboCache.deleteLimboPlayer(name);
+ limboCache.restoreData(player);
+ limboCache.deletePlayerData(player);
+ // do we really need to use location from database for now?
+ // because LimboCache#restoreData teleport player to last location.
}
+ if (RESTORE_COLLISIONS && !service.getProperty(KEEP_COLLISIONS_DISABLED)) {
+ player.setCollidable(true);
+ }
+
+ if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
+ restoreInventory(player);
+ }
+
+ final PlayerAuth auth = dataSource.getAuth(name);
+ teleportationService.teleportOnLogin(player, auth, limbo);
+
// We can now display the join message (if delayed)
- String jm = AuthMePlayerListener.joinMessage.get(name);
+ String jm = PlayerListener.joinMessage.get(name);
if (jm != null) {
if (!jm.isEmpty()) {
for (Player p : bukkitService.getOnlinePlayers()) {
@@ -124,10 +109,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
}
}
}
- AuthMePlayerListener.joinMessage.remove(name);
+ PlayerListener.joinMessage.remove(name);
}
- restoreSpeedEffects(player);
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
player.removePotionEffect(PotionEffectType.BLINDNESS);
}
@@ -135,9 +119,8 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
// The Login event now fires (as intended) after everything is processed
bukkitService.callEvent(new LoginEvent(player));
player.saveData();
- if (service.getProperty(HooksSettings.BUNGEECORD)) {
- sendBungeeMessage(player);
- }
+ bungeeService.sendBungeeMessage(player, "login");
+
// Login is done, display welcome message
if (service.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
if (service.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
@@ -154,29 +137,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
// Login is now finished; we can force all commands
forceCommands(player);
- sendTo(player);
+ // Send Bungee stuff. The service will check if it is enabled or not.
+ bungeeService.connectPlayer(player);
}
-
- private void restoreOpState(Player player, LimboPlayer limboPlayer) {
- player.setOp(limboPlayer.isOperator());
- }
-
- private void sendTo(Player player) {
- if (!service.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) {
- ByteArrayDataOutput out = ByteStreams.newDataOutput();
- out.writeUTF("Connect");
- out.writeUTF(service.getProperty(HooksSettings.BUNGEECORD_SERVER));
- player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
- }
- }
-
- private void sendBungeeMessage(Player player) {
- ByteArrayDataOutput out = ByteStreams.newDataOutput();
- out.writeUTF("Forward");
- out.writeUTF("ALL");
- out.writeUTF("AuthMe");
- out.writeUTF("login;" + player.getName());
- player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
- }
-
}
diff --git a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java
index fc81017d..34a5b493 100644
--- a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java
+++ b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java
@@ -5,12 +5,10 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
-import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SyncProcessManager;
-import fr.xephi.authme.util.BukkitService;
-import fr.xephi.authme.util.Utils;
+import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -32,10 +30,8 @@ public class AsynchronousLogout implements AsynchronousProcess {
@Inject
private SyncProcessManager syncProcessManager;
- @Inject
- private BukkitService bukkitService;
-
- AsynchronousLogout() { }
+ AsynchronousLogout() {
+ }
public void logout(final Player player) {
final String name = player.getName().toLowerCase();
@@ -43,27 +39,17 @@ public class AsynchronousLogout implements AsynchronousProcess {
service.send(player, MessageKey.NOT_LOGGED_IN);
return;
}
+
PlayerAuth auth = playerCache.getAuth(name);
database.updateSession(auth);
- auth.setQuitLocX(player.getLocation().getX());
- auth.setQuitLocY(player.getLocation().getY());
- auth.setQuitLocZ(player.getLocation().getZ());
- auth.setWorld(player.getWorld().getName());
- database.updateQuitLoc(auth);
+ if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) {
+ auth.setQuitLocation(player.getLocation());
+ database.updateQuitLoc(auth);
+ }
+ limboCache.addPlayerData(player);
playerCache.removePlayer(name);
database.setUnlogged(name);
- bukkitService.scheduleSyncDelayedTask(new Runnable() {
- @Override
- public void run() {
- Utils.teleportToSpawn(player);
- }
- });
- if (limboCache.hasLimboPlayer(name)) {
- limboCache.deleteLimboPlayer(name);
- }
- limboCache.addLimboPlayer(player);
- service.setGroup(player, AuthGroupType.NOT_LOGGED_IN);
syncProcessManager.processSyncPlayerLogout(player);
}
}
diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java
index c70f4cd0..bfff2e3a 100644
--- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java
+++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java
@@ -1,18 +1,19 @@
package fr.xephi.authme.process.logout;
-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.cache.SessionManager;
import fr.xephi.authme.events.LogoutEvent;
+import fr.xephi.authme.listener.protocollib.ProtocolLibService;
import fr.xephi.authme.output.MessageKey;
+import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SynchronousProcess;
-import fr.xephi.authme.settings.properties.HooksSettings;
+import fr.xephi.authme.service.BungeeService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.task.LimboPlayerTaskManager;
+import fr.xephi.authme.task.PlayerDataTaskManager;
import fr.xephi.authme.util.BukkitService;
+import fr.xephi.authme.util.TeleportationService;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -25,7 +26,7 @@ import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
@Inject
- private AuthMe plugin;
+ private BungeeService bungeeService;
@Inject
private ProcessService service;
@@ -34,56 +35,63 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
private BukkitService bukkitService;
@Inject
- private LimboPlayerTaskManager limboPlayerTaskManager;
+ private ProtocolLibService protocolLibService;
- ProcessSynchronousPlayerLogout() { }
+ @Inject
+ private PlayerDataTaskManager playerDataTaskManager;
+ @Inject
+ private SessionManager sessionManager;
- private void sendBungeeMessage(Player player) {
- ByteArrayDataOutput out = ByteStreams.newDataOutput();
- out.writeUTF("Forward");
- out.writeUTF("ALL");
- out.writeUTF("AuthMe");
- out.writeUTF("logout;" + player.getName());
- player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
- }
+ @Inject
+ private TeleportationService teleportationService;
- private void restoreSpeedEffect(Player player) {
- if (service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
- player.setWalkSpeed(0.0F);
- player.setFlySpeed(0.0F);
- }
+ ProcessSynchronousPlayerLogout() {
}
public void processSyncLogout(Player player) {
final String name = player.getName().toLowerCase();
- if (plugin.sessions.containsKey(name)) {
- plugin.sessions.get(name).cancel();
- plugin.sessions.remove(name);
- }
+
+ sessionManager.removeSession(name);
if (service.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) {
- plugin.inventoryProtector.sendBlankInventoryPacket(player);
+ protocolLibService.sendBlankInventoryPacket(player);
}
- limboPlayerTaskManager.registerTimeoutTask(player);
- limboPlayerTaskManager.registerMessageTask(name, true);
+ playerDataTaskManager.registerTimeoutTask(player);
+ playerDataTaskManager.registerMessageTask(name, true);
+
+ applyLogoutEffect(player);
- if (player.isInsideVehicle() && player.getVehicle() != null) {
- player.getVehicle().eject();
- }
- final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
- if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
- player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
- }
- player.setOp(false);
- restoreSpeedEffect(player);
// Player is now logout... Time to fire event !
bukkitService.callEvent(new LogoutEvent(player));
- if (service.getProperty(HooksSettings.BUNGEECORD)) {
- sendBungeeMessage(player);
- }
+ // Send Bungee stuff. The service will check if it is enabled or not.
+ bungeeService.sendBungeeMessage(player, "logout");
+
service.send(player, MessageKey.LOGOUT_SUCCESS);
ConsoleLogger.info(player.getName() + " logged out");
}
+ private void applyLogoutEffect(Player player) {
+ // dismount player
+ player.leaveVehicle();
+ teleportationService.teleportOnJoin(player);
+
+ // Apply Blindness effect
+ final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
+ if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
+ player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
+ }
+
+ // Set player's data to unauthenticated
+ service.setGroup(player, AuthGroupType.NOT_LOGGED_IN);
+ player.setOp(false);
+ player.setAllowFlight(false);
+ // Remove speed
+ if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
+ && service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
+ player.setFlySpeed(0.0f);
+ player.setWalkSpeed(0.0f);
+ }
+ }
+
}
diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
index d31f305c..cc7eb60f 100644
--- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
+++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
@@ -1,27 +1,23 @@
package fr.xephi.authme.process.quit;
import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.cache.SessionManager;
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.CacheDataSource;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SyncProcessManager;
-import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
+import fr.xephi.authme.util.ValidationService;
import org.bukkit.Location;
import org.bukkit.entity.Player;
-import org.bukkit.scheduler.BukkitTask;
import javax.inject.Inject;
-import static fr.xephi.authme.util.BukkitService.TICKS_PER_MINUTE;
-
public class AsynchronousQuit implements AsynchronousProcess {
@Inject
@@ -36,31 +32,38 @@ public class AsynchronousQuit implements AsynchronousProcess {
@Inject
private PlayerCache playerCache;
- @Inject
- private LimboCache limboCache;
-
@Inject
private SyncProcessManager syncProcessManager;
- AsynchronousQuit() { }
+ @Inject
+ private SessionManager sessionManager;
+
+ @Inject
+ private SpawnLoader spawnLoader;
+
+ @Inject
+ private ValidationService validationService;
+
+ AsynchronousQuit() {
+ }
- public void processQuit(Player player, boolean isKick) {
- if (player == null || Utils.isUnrestricted(player)) {
+ public void processQuit(Player player) {
+ if (player == null || validationService.isUnrestricted(player.getName())) {
return;
}
final String name = player.getName().toLowerCase();
- String ip = Utils.getPlayerIp(player);
-
if (playerCache.isAuthenticated(name)) {
if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) {
- Location loc = player.getLocation();
+ Location loc = spawnLoader.getPlayerLocationOrSpawn(player);
PlayerAuth auth = PlayerAuth.builder()
.name(name).location(loc)
.realName(player.getName()).build();
database.updateQuitLoc(auth);
}
+
+ final String ip = Utils.getPlayerIp(player);
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(player.getName())
@@ -68,45 +71,18 @@ public class AsynchronousQuit implements AsynchronousProcess {
.lastLogin(System.currentTimeMillis())
.build();
database.updateSession(auth);
+
+ sessionManager.addSession(name);
}
- boolean needToChange = false;
- boolean isOp = false;
+ //always unauthenticate the player - use session only for auto logins on the same ip
+ playerCache.removePlayer(name);
- LimboPlayer limbo = limboCache.getLimboPlayer(name);
- if (limbo != null) {
- if (!StringUtils.isEmpty(limbo.getGroup())) {
- Utils.addNormal(player, limbo.getGroup());
- }
- needToChange = true;
- isOp = limbo.isOperator();
- limboCache.deleteLimboPlayer(name);
- }
- if (Settings.isSessionsEnabled && !isKick) {
- if (Settings.getSessionTimeout != 0) {
- if (plugin.isEnabled()) {
- BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() {
-
- @Override
- public void run() {
- postLogout(name);
- }
-
- }, Settings.getSessionTimeout * TICKS_PER_MINUTE);
-
- plugin.sessions.put(name, task);
- } else {
- //plugin is disabled; we cannot schedule more tasks so run it directly here
- postLogout(name);
- }
- }
- } else {
- playerCache.removePlayer(name);
- database.setUnlogged(name);
- }
+ //always update the database when the player quit the game
+ database.setUnlogged(name);
if (plugin.isEnabled()) {
- syncProcessManager.processSyncPlayerQuit(player, isOp, needToChange);
+ syncProcessManager.processSyncPlayerQuit(player);
}
// remove player from cache
if (database instanceof CacheDataSource) {
@@ -114,9 +90,4 @@ public class AsynchronousQuit implements AsynchronousProcess {
}
}
- private void postLogout(String name) {
- PlayerCache.getInstance().removePlayer(name);
- database.setUnlogged(name);
- plugin.sessions.remove(name);
- }
}
diff --git a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java
index c1382c2c..27f46071 100644
--- a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java
+++ b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java
@@ -1,15 +1,32 @@
package fr.xephi.authme.process.quit;
+import fr.xephi.authme.cache.backup.PlayerDataStorage;
+import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.process.SynchronousProcess;
import org.bukkit.entity.Player;
+import javax.inject.Inject;
+
public class ProcessSyncronousPlayerQuit implements SynchronousProcess {
- public void processSyncQuit(Player player, boolean isOp, boolean needToChange) {
- if (needToChange) {
- player.setOp(isOp);
+ @Inject
+ private PlayerDataStorage playerDataStorage;
+
+ @Inject
+ private LimboCache limboCache;
+
+ public void processSyncQuit(Player player) {
+ if (limboCache.hasPlayerData(player.getName())) { // it mean player is not authenticated
+ limboCache.restoreData(player);
+ limboCache.removeFromCache(player);
+ } else {
+ // Save player's data, so we could retrieve it later on player next join
+ if (!playerDataStorage.hasData(player)) {
+ playerDataStorage.saveData(player);
+ }
}
+
player.leaveVehicle();
}
}
diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
index 44f0fd0b..57390a54 100644
--- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
@@ -1,23 +1,24 @@
package fr.xephi.authme.process.register;
-import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SyncProcessManager;
+import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.TwoFactor;
-import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
+import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.ValidationService;
@@ -30,11 +31,11 @@ import java.util.List;
import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS;
+/**
+ * Asynchronous processing of a request for registration.
+ */
public class AsyncRegister implements AsynchronousProcess {
- @Inject
- private AuthMe plugin;
-
@Inject
private DataSource database;
@@ -56,6 +57,16 @@ public class AsyncRegister implements AsynchronousProcess {
@Inject
private ValidationService validationService;
+ @Inject
+ private SendMailSSL sendMailSsl;
+
+ @Inject
+ private AsynchronousLogin asynchronousLogin;
+
+ @Inject
+ private BukkitService bukkitService;
+
+
AsyncRegister() { }
private boolean preRegisterCheck(Player player, String password) {
@@ -138,11 +149,11 @@ public class AsyncRegister implements AsynchronousProcess {
}
database.updateEmail(auth);
database.updateSession(auth);
- plugin.mail.main(auth, password);
+ sendMailSsl.sendPasswordMail(auth, password);
syncProcessManager.processSyncEmailRegister(player);
}
- private void passwordRegister(Player player, String password, boolean autoLogin) {
+ private void passwordRegister(final Player player, String password, boolean autoLogin) {
final String name = player.getName().toLowerCase();
final String ip = Utils.getPlayerIp(player);
final HashedPassword hashedPassword = passwordSecurity.computeHash(password, name);
@@ -159,11 +170,13 @@ public class AsyncRegister implements AsynchronousProcess {
return;
}
- if (!Settings.forceRegLogin && autoLogin) {
- //PlayerCache.getInstance().addPlayer(auth);
- //database.setLogged(name);
- // TODO: check this...
- plugin.getManagement().performLogin(player, "dontneed", true);
+ if (!service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER) && autoLogin) {
+ bukkitService.runTaskAsynchronously(new Runnable(){
+ @Override
+ public void run() {
+ asynchronousLogin.login(player, "dontneed", true);
+ }
+ });
}
syncProcessManager.processSyncPasswordRegister(player);
diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
index 41d8fe97..cd10a69b 100644
--- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
@@ -5,9 +5,8 @@ import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SynchronousProcess;
-import fr.xephi.authme.settings.Settings;
-import fr.xephi.authme.settings.properties.SecuritySettings;
-import fr.xephi.authme.task.LimboPlayerTaskManager;
+import fr.xephi.authme.settings.properties.HooksSettings;
+import fr.xephi.authme.task.PlayerDataTaskManager;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
@@ -20,25 +19,23 @@ public class ProcessSyncEmailRegister implements SynchronousProcess {
private ProcessService service;
@Inject
- private LimboPlayerTaskManager limboPlayerTaskManager;
+ private PlayerDataTaskManager playerDataTaskManager;
ProcessSyncEmailRegister() { }
public void processEmailRegister(Player player) {
final String name = player.getName().toLowerCase();
- if (!Settings.getRegisteredGroup.isEmpty()) {
+ if (!service.getProperty(HooksSettings.REGISTERED_GROUP).isEmpty()) {
service.setGroup(player, AuthGroupType.REGISTERED);
}
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
- limboPlayerTaskManager.registerTimeoutTask(player);
- limboPlayerTaskManager.registerMessageTask(name, true);
+ playerDataTaskManager.registerTimeoutTask(player);
+ playerDataTaskManager.registerMessageTask(name, true);
player.saveData();
- if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info(player.getName() + " registered " + Utils.getPlayerIp(player));
- }
+ ConsoleLogger.fine(player.getName() + " registered " + Utils.getPlayerIp(player));
}
}
diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
index 16f1ad36..a7ea4aeb 100644
--- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
@@ -1,63 +1,39 @@
package fr.xephi.authme.process.register;
-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.cache.limbo.LimboCache;
-import fr.xephi.authme.cache.limbo.LimboPlayer;
-import fr.xephi.authme.events.LoginEvent;
-import fr.xephi.authme.events.RestoreInventoryEvent;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SynchronousProcess;
-import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.service.BungeeService;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
-import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.settings.properties.SecuritySettings;
-import fr.xephi.authme.task.LimboPlayerTaskManager;
-import fr.xephi.authme.util.BukkitService;
+import fr.xephi.authme.task.PlayerDataTaskManager;
import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
-import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
-import static fr.xephi.authme.settings.properties.RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN;
-
/**
*/
public class ProcessSyncPasswordRegister implements SynchronousProcess {
@Inject
- private AuthMe plugin;
+ private BungeeService bungeeService;
@Inject
private ProcessService service;
- @Inject
- private BukkitService bukkitService;
-
@Inject
private LimboCache limboCache;
@Inject
- private LimboPlayerTaskManager limboPlayerTaskManager;
+ private PlayerDataTaskManager playerDataTaskManager;
- ProcessSyncPasswordRegister() { }
-
-
- private void sendBungeeMessage(Player player) {
- ByteArrayDataOutput out = ByteStreams.newDataOutput();
- out.writeUTF("Forward");
- out.writeUTF("ALL");
- out.writeUTF("AuthMe");
- out.writeUTF("register;" + player.getName());
- player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
+ ProcessSyncPasswordRegister() {
}
private void forceCommands(Player player) {
@@ -66,7 +42,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
}
for (String command : service.getProperty(RegistrationSettings.FORCE_REGISTER_COMMANDS_AS_CONSOLE)) {
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(),
- command.replace("%p", player.getName()));
+ command.replace("%p", player.getName()));
}
}
@@ -77,11 +53,9 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
*/
private void requestLogin(Player player) {
final String name = player.getName().toLowerCase();
- Utils.teleportToSpawn(player);
-
- limboCache.updateLimboPlayer(player);
- limboPlayerTaskManager.registerTimeoutTask(player);
- limboPlayerTaskManager.registerMessageTask(name, true);
+ limboCache.updatePlayerData(player);
+ playerDataTaskManager.registerTimeoutTask(player);
+ playerDataTaskManager.registerMessageTask(name, true);
if (player.isInsideVehicle() && player.getVehicle() != null) {
player.getVehicle().eject();
@@ -89,27 +63,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
}
public void processPasswordRegister(Player player) {
- final String name = player.getName().toLowerCase();
- LimboPlayer limbo = limboCache.getLimboPlayer(name);
- if (limbo != null) {
- if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) {
- plugin.tablistHider.sendTablist(player);
- }
-
- Utils.teleportToSpawn(player);
-
- if (service.getProperty(HIDE_TABLIST_BEFORE_LOGIN) && plugin.inventoryProtector != null) {
- RestoreInventoryEvent event = new RestoreInventoryEvent(player);
- bukkitService.callEvent(event);
- if (!event.isCancelled()) {
- plugin.inventoryProtector.sendInventoryPacket(player);
- }
- }
-
- limboCache.deleteLimboPlayer(name);
- }
-
- if (!Settings.getRegisteredGroup.isEmpty()) {
+ if (!service.getProperty(HooksSettings.REGISTERED_GROUP).isEmpty()) {
service.setGroup(player, AuthGroupType.REGISTERED);
}
@@ -119,17 +73,8 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
service.send(player, MessageKey.ADD_EMAIL_MESSAGE);
}
- if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
- player.removePotionEffect(PotionEffectType.BLINDNESS);
- }
-
- // The LoginEvent now fires (as intended) after everything is processed
- bukkitService.callEvent(new LoginEvent(player));
player.saveData();
-
- if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
- ConsoleLogger.info(player.getName() + " registered " + Utils.getPlayerIp(player));
- }
+ ConsoleLogger.fine(player.getName() + " registered " + Utils.getPlayerIp(player));
// Kick Player after Registration is enabled, kick the player
if (service.getProperty(RegistrationSettings.FORCE_KICK_AFTER_REGISTER)) {
@@ -146,19 +91,8 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
return;
}
- if (service.getProperty(HooksSettings.BUNGEECORD)) {
- sendBungeeMessage(player);
- }
-
- sendTo(player);
- }
-
- private void sendTo(Player player) {
- if (!service.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) {
- ByteArrayDataOutput out = ByteStreams.newDataOutput();
- out.writeUTF("Connect");
- out.writeUTF(service.getProperty(HooksSettings.BUNGEECORD_SERVER));
- player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
- }
+ // Send Bungee stuff. The service will check if it is enabled or not.
+ bungeeService.sendBungeeMessage(player, "register");
+ bungeeService.connectPlayer(player);
}
}
diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
index b9b87252..82fea4db 100644
--- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
+++ b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
@@ -6,15 +6,17 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
+import fr.xephi.authme.permission.AuthGroupHandler;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.security.PasswordSecurity;
-import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.task.LimboPlayerTaskManager;
-import fr.xephi.authme.util.Utils;
+import fr.xephi.authme.task.PlayerDataTaskManager;
+import fr.xephi.authme.util.BukkitService;
+import fr.xephi.authme.util.TeleportationService;
+import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -37,53 +39,96 @@ public class AsynchronousUnregister implements AsynchronousProcess {
@Inject
private PlayerCache playerCache;
+ @Inject
+ private BukkitService bukkitService;
+
@Inject
private LimboCache limboCache;
@Inject
- private LimboPlayerTaskManager limboPlayerTaskManager;
+ private PlayerDataTaskManager playerDataTaskManager;
+
+ @Inject
+ private TeleportationService teleportationService;
+
+ @Inject
+ private AuthGroupHandler authGroupHandler;
AsynchronousUnregister() { }
-
- public void unregister(Player player, String password, boolean force) {
- final String name = player.getName().toLowerCase();
- PlayerAuth cachedAuth = playerCache.getAuth(name);
- if (force || passwordSecurity.comparePassword(password, cachedAuth.getPassword(), player.getName())) {
- if (!dataSource.removeAuth(name)) {
+ /**
+ * Processes a player's request to unregister himself. Unregisters the player after
+ * successful password check.
+ *
+ * @param player the player
+ * @param password the input password to check before unregister
+ */
+ public void unregister(Player player, String password) {
+ final String name = player.getName();
+ final PlayerAuth cachedAuth = playerCache.getAuth(name);
+ if (passwordSecurity.comparePassword(password, cachedAuth.getPassword(), name)) {
+ if (dataSource.removeAuth(name)) {
+ performUnregister(name, player);
+ ConsoleLogger.info(name + " unregistered himself");
+ } else {
service.send(player, MessageKey.ERROR);
- return;
}
-
- if (service.getProperty(RegistrationSettings.FORCE)) {
- Utils.teleportToSpawn(player);
- player.saveData();
- playerCache.removePlayer(player.getName().toLowerCase());
- if (!Settings.getRegisteredGroup.isEmpty()) {
- service.setGroup(player, AuthGroupType.UNREGISTERED);
- }
- limboCache.addLimboPlayer(player);
- limboPlayerTaskManager.registerTimeoutTask(player);
- limboPlayerTaskManager.registerMessageTask(name, false);
-
- service.send(player, MessageKey.UNREGISTERED_SUCCESS);
- ConsoleLogger.info(player.getDisplayName() + " unregistered himself");
- return; // TODO ljacqu 20160612: Why return here? No blind effect? Player not removed from PlayerCache?
- }
- if (!Settings.unRegisteredGroup.isEmpty()) {
- service.setGroup(player, AuthGroupType.UNREGISTERED);
- }
- playerCache.removePlayer(name);
-
- // Apply blind effect
- int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
- if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
- player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
- }
- service.send(player, MessageKey.UNREGISTERED_SUCCESS);
- ConsoleLogger.info(player.getDisplayName() + " unregistered himself");
} else {
service.send(player, MessageKey.WRONG_PASSWORD);
}
}
+
+ /**
+ * Unregisters a player.
+ *
+ * @param initiator the initiator of this process (nullable)
+ * @param name the name of the player
+ * @param player the according Player object (nullable)
+ */
+ // We need to have the name and the player separate because Player might be null in this case:
+ // we might have some player in the database that has never been online on the server
+ public void adminUnregister(CommandSender initiator, String name, Player player) {
+ if (dataSource.removeAuth(name)) {
+ performUnregister(name, player);
+ if (initiator == null) {
+ ConsoleLogger.info(name + " was unregistered");
+ } else {
+ ConsoleLogger.info(name + " was unregistered by " + initiator.getName());
+ service.send(initiator, MessageKey.UNREGISTERED_SUCCESS);
+ }
+ }
+ }
+
+ private void performUnregister(String name, Player player) {
+ playerCache.removePlayer(name);
+ if (player == null || !player.isOnline()) {
+ return;
+ }
+
+ if (service.getProperty(RegistrationSettings.FORCE)) {
+ teleportationService.teleportOnJoin(player);
+ player.saveData();
+
+ limboCache.deletePlayerData(player);
+ limboCache.addPlayerData(player);
+
+ playerDataTaskManager.registerTimeoutTask(player);
+ playerDataTaskManager.registerMessageTask(name, false);
+ applyBlindEffect(player);
+ }
+ authGroupHandler.setGroup(player, AuthGroupType.UNREGISTERED);
+ service.send(player, MessageKey.UNREGISTERED_SUCCESS);
+ }
+
+ private void applyBlindEffect(final Player player) {
+ if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
+ final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
+ bukkitService.runTask(new Runnable() {
+ @Override
+ public void run() {
+ player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
+ }
+ });
+ }
+ }
}
diff --git a/src/main/java/fr/xephi/authme/security/HashUtils.java b/src/main/java/fr/xephi/authme/security/HashUtils.java
index c4fb4edf..946af52b 100644
--- a/src/main/java/fr/xephi/authme/security/HashUtils.java
+++ b/src/main/java/fr/xephi/authme/security/HashUtils.java
@@ -67,6 +67,17 @@ public final class HashUtils {
}
}
+ /**
+ * Return whether the given hash starts like a BCrypt hash. Checking with this method
+ * beforehand prevents the BcryptService from throwing certain exceptions.
+ *
+ * @param hash The salt to verify
+ * @return True if the salt is valid, false otherwise
+ */
+ public static boolean isValidBcryptHash(String hash) {
+ return hash.length() > 3 && hash.substring(0, 2).equals("$2");
+ }
+
/**
* Hash the message with the given algorithm and return the hash in its hexadecimal notation.
*
diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
index 6e6eac83..521decfa 100644
--- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
+++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
@@ -1,12 +1,12 @@
package fr.xephi.authme.security;
+import ch.jalu.injector.Injector;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.PasswordEncryptionEvent;
-import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HashedPassword;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.plugin.PluginManager;
@@ -19,7 +19,7 @@ import javax.inject.Inject;
public class PasswordSecurity implements Reloadable {
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private DataSource dataSource;
@@ -28,7 +28,7 @@ public class PasswordSecurity implements Reloadable {
private PluginManager pluginManager;
@Inject
- private AuthMeServiceInitializer initializer;
+ private Injector injector;
private HashAlgorithm algorithm;
private boolean supportOldAlgorithm;
@@ -155,7 +155,7 @@ public class PasswordSecurity implements Reloadable {
if (HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)) {
return null;
}
- return initializer.newInstance(algorithm.getClazz());
+ return injector.newInstance(algorithm.getClazz());
}
private void hashPasswordForNewAlgorithm(String password, String playerName) {
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 cda26091..aae6b910 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java
@@ -1,11 +1,12 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.security.HashUtils;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.Usage;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.util.StringUtils;
@@ -18,7 +19,7 @@ public class BCRYPT implements EncryptionMethod {
private final int bCryptLog2Rounds;
@Inject
- public BCRYPT(NewSetting settings) {
+ public BCRYPT(Settings settings) {
bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND);
}
@@ -36,9 +37,9 @@ public class BCRYPT implements EncryptionMethod {
@Override
public boolean comparePassword(String password, HashedPassword hash, String name) {
try {
- return hash.getHash().length() > 3 && BCryptService.checkpw(password, hash.getHash());
+ return HashUtils.isValidBcryptHash(hash.getHash()) && BCryptService.checkpw(password, hash.getHash());
} catch (IllegalArgumentException e) {
- ConsoleLogger.showError("Bcrypt checkpw() returned " + StringUtils.formatException(e));
+ ConsoleLogger.warning("Bcrypt checkpw() returned " + StringUtils.formatException(e));
}
return false;
}
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 27ca14f8..79d06e0a 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java
@@ -32,7 +32,7 @@ public class CryptPBKDF2Django extends HexSaltedMethod {
try {
iterations = Integer.parseInt(line[1]);
} catch (NumberFormatException e) {
- ConsoleLogger.showError("Could not read number of rounds for CryptPBKDF2Django:"
+ ConsoleLogger.warning("Could not read number of rounds for CryptPBKDF2Django:"
+ StringUtils.formatException(e));
return false;
}
diff --git a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java b/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java
index b1c0b003..83cc6c8c 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java
@@ -3,9 +3,7 @@ package fr.xephi.authme.security.crypts;
/**
* Public interface for custom password encryption methods.
*
- * Note that {@link fr.xephi.authme.security.PasswordSecurity} requires classes implementing this interface
- * to either have the default constructor or an accessible constructor with one parameter of type
- * {@link fr.xephi.authme.settings.NewSetting}.
+ * Instantiation of these methods is done via automatic dependency injection.
*/
public interface EncryptionMethod {
diff --git a/src/main/java/fr/xephi/authme/security/crypts/IPB4.java b/src/main/java/fr/xephi/authme/security/crypts/IPB4.java
index e54bcd03..0eede2a2 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/IPB4.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/IPB4.java
@@ -1,6 +1,7 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.security.HashUtils;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
@@ -34,9 +35,9 @@ public class IPB4 implements EncryptionMethod {
@Override
public boolean comparePassword(String password, HashedPassword hash, String name) {
try {
- return hash.getHash().length() > 3 && BCryptService.checkpw(password, hash.getHash());
+ return HashUtils.isValidBcryptHash(hash.getHash()) && BCryptService.checkpw(password, hash.getHash());
} catch (IllegalArgumentException e) {
- ConsoleLogger.showError("Bcrypt checkpw() returned " + StringUtils.formatException(e));
+ ConsoleLogger.warning("Bcrypt checkpw() returned " + StringUtils.formatException(e));
}
return false;
}
diff --git a/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java b/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java
index a96cc0d5..2b683bb2 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java
@@ -5,7 +5,7 @@ import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.Usage;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import javax.inject.Inject;
@@ -19,7 +19,7 @@ public class SALTED2MD5 extends SeparateSaltMethod {
private final int saltLength;
@Inject
- public SALTED2MD5(NewSetting settings) {
+ public SALTED2MD5(Settings settings) {
saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH);
}
diff --git a/src/main/java/fr/xephi/authme/security/crypts/TwoFactor.java b/src/main/java/fr/xephi/authme/security/crypts/TwoFactor.java
index 21a5f2fc..e9a48845 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/TwoFactor.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/TwoFactor.java
@@ -4,12 +4,14 @@ import com.google.common.escape.Escaper;
import com.google.common.io.BaseEncoding;
import com.google.common.net.UrlEscapers;
import com.google.common.primitives.Ints;
-
+import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.Usage;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@@ -17,9 +19,6 @@ import java.util.Arrays;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
@Recommendation(Usage.DOES_NOT_WORK)
@HasSalt(SaltType.NONE)
public class TwoFactor extends UnsaltedMethod {
@@ -58,12 +57,13 @@ public class TwoFactor extends UnsaltedMethod {
public boolean comparePassword(String password, HashedPassword hashedPassword, String name) {
try {
return checkPassword(hashedPassword.getHash(), password);
- } catch (NoSuchAlgorithmException | InvalidKeyException encryptionException) {
- throw new UnsupportedOperationException("Failed to compare passwords", encryptionException);
+ } catch (Exception e) {
+ ConsoleLogger.logException("Failed to verify two auth code:", e);
+ return false;
}
}
- public boolean checkPassword(String secretKey, String userInput)
+ private boolean checkPassword(String secretKey, String userInput)
throws NoSuchAlgorithmException, InvalidKeyException {
Integer code = Ints.tryParse(userInput);
if (code == null) {
diff --git a/src/main/java/fr/xephi/authme/security/crypts/XFBCRYPT.java b/src/main/java/fr/xephi/authme/security/crypts/XFBCRYPT.java
index 4f7ed04c..a20ee65a 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/XFBCRYPT.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/XFBCRYPT.java
@@ -1,6 +1,7 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.security.HashUtils;
import fr.xephi.authme.util.StringUtils;
import java.util.regex.Matcher;
@@ -29,9 +30,9 @@ public class XFBCRYPT implements EncryptionMethod {
@Override
public boolean comparePassword(String password, HashedPassword hash, String salt) {
try {
- return hash.getHash().length() > 3 && BCryptService.checkpw(password, hash.getHash());
+ return HashUtils.isValidBcryptHash(hash.getHash()) && BCryptService.checkpw(password, hash.getHash());
} catch (IllegalArgumentException e) {
- ConsoleLogger.showError("XfBCrypt checkpw() returned " + StringUtils.formatException(e));
+ ConsoleLogger.warning("XfBCrypt checkpw() returned " + StringUtils.formatException(e));
}
return false;
}
diff --git a/src/main/java/fr/xephi/authme/service/BungeeService.java b/src/main/java/fr/xephi/authme/service/BungeeService.java
new file mode 100644
index 00000000..3a881d8d
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/service/BungeeService.java
@@ -0,0 +1,119 @@
+package fr.xephi.authme.service;
+
+import com.google.common.io.ByteArrayDataOutput;
+import com.google.common.io.ByteStreams;
+import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.hooks.BungeeCordMessage;
+import fr.xephi.authme.initialization.SettingsDependent;
+import fr.xephi.authme.security.crypts.HashedPassword;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.HooksSettings;
+import fr.xephi.authme.util.BukkitService;
+
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.messaging.Messenger;
+
+import javax.inject.Inject;
+
+/**
+ * Class to manage all BungeeCord related processes.
+ */
+public class BungeeService implements SettingsDependent {
+
+ private AuthMe plugin;
+ private BukkitService bukkitService;
+ private BungeeCordMessage bungeeCordMessage;
+
+ private boolean isEnabled;
+ private String bungeeServer;
+
+ /*
+ * Constructor.
+ */
+ @Inject
+ BungeeService(AuthMe plugin, BukkitService bukkitService, Settings settings, BungeeCordMessage bungeeCordMessage) {
+ this.plugin = plugin;
+ this.bukkitService = bukkitService;
+ this.bungeeCordMessage = bungeeCordMessage;
+ reload(settings);
+ }
+
+ /**
+ * Sends a Bungee message to a player, e.g. login.
+ *
+ * @param player The player to send the message to.
+ * @param action The action to send, e.g. login.
+ */
+ public void sendBungeeMessage(Player player, String action) {
+ if (!isEnabled) {
+ return;
+ }
+
+ ByteArrayDataOutput out = ByteStreams.newDataOutput();
+ out.writeUTF("Forward");
+ out.writeUTF("ALL");
+ out.writeUTF("AuthMe");
+ out.writeUTF(action + ";" + player.getName());
+ player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
+ }
+
+ /**
+ * Send a Bungee message for a password change.
+ *
+ * @param player The player who's password is changed.
+ * @param password The new password.
+ */
+ public void sendPasswordChanged(final Player player, HashedPassword password) {
+ if (!isEnabled) {
+ return;
+ }
+
+ final String hash = password.getHash();
+ final String salt = password.getSalt();
+
+ bukkitService.scheduleSyncDelayedTask(new Runnable() {
+ @Override
+ public void run() {
+ ByteArrayDataOutput out = ByteStreams.newDataOutput();
+ out.writeUTF("Forward");
+ out.writeUTF("ALL");
+ out.writeUTF("AuthMe");
+ out.writeUTF("changepassword;" + player.getName() + ";" + hash + ";" + salt);
+ player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
+ }
+ });
+ }
+
+ /**
+ * Send a player to a specified server. If no server is configured, this will
+ * do nothing.
+ *
+ * @param player The player to send.
+ */
+ public void connectPlayer(Player player) {
+ if (!isEnabled || bungeeServer.isEmpty()) {
+ return;
+ }
+
+ ByteArrayDataOutput out = ByteStreams.newDataOutput();
+ out.writeUTF("Connect");
+ out.writeUTF(bungeeServer);
+ player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
+ }
+
+ @Override
+ public void reload(Settings settings) {
+ this.isEnabled = settings.getProperty(HooksSettings.BUNGEECORD);
+ this.bungeeServer = settings.getProperty(HooksSettings.BUNGEECORD_SERVER);
+ Messenger messenger = plugin.getServer().getMessenger();
+ if (!this.isEnabled) {
+ return;
+ }
+ if (!messenger.isIncomingChannelRegistered(plugin, "BungeeCord")) {
+ messenger.registerIncomingPluginChannel(plugin, "BungeeCord", bungeeCordMessage);
+ }
+ if (!messenger.isOutgoingChannelRegistered(plugin, "BungeeCord")) {
+ messenger.registerOutgoingPluginChannel(plugin, "BungeeCord");
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java
deleted file mode 100644
index 90719daa..00000000
--- a/src/main/java/fr/xephi/authme/settings/NewSetting.java
+++ /dev/null
@@ -1,289 +0,0 @@
-package fr.xephi.authme.settings;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
-import com.google.common.io.Files;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.settings.domain.Property;
-import fr.xephi.authme.settings.properties.PluginSettings;
-import fr.xephi.authme.settings.properties.RegistrationSettings;
-import fr.xephi.authme.settings.propertymap.PropertyMap;
-import fr.xephi.authme.util.CollectionUtils;
-import fr.xephi.authme.util.StringUtils;
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
-
-/**
- * The new settings manager.
- */
-public class NewSetting {
-
- private final File pluginFolder;
- private final File configFile;
- private final PropertyMap propertyMap;
- private final SettingsMigrationService migrationService;
- private FileConfiguration configuration;
- /** The file with the localized messages based on {@link PluginSettings#MESSAGES_LANGUAGE}. */
- private File messagesFile;
- private List welcomeMessage;
- private String emailMessage;
-
- /**
- * Constructor. Checks the given {@link FileConfiguration} object for completeness.
- *
- * @param configFile The configuration file
- * @param pluginFolder The AuthMe plugin folder
- * @param propertyMap Collection of all available settings
- * @param migrationService Migration service to check the settings file with
- */
- public NewSetting(File configFile, File pluginFolder, PropertyMap propertyMap,
- SettingsMigrationService migrationService) {
- this.configuration = YamlConfiguration.loadConfiguration(configFile);
- this.configFile = configFile;
- this.pluginFolder = pluginFolder;
- this.propertyMap = propertyMap;
- this.migrationService = migrationService;
- validateAndLoadOptions();
- }
-
- /**
- * Constructor for testing purposes, allowing more options.
- *
- * @param configuration The FileConfiguration object to use
- * @param configFile The file to write to
- * @param pluginFolder The plugin folder
- * @param propertyMap The property map whose properties should be verified for presence, or null to skip this
- * @param migrationService Migration service, or null to skip migration checks
- */
- @VisibleForTesting
- NewSetting(FileConfiguration configuration, File configFile, File pluginFolder, PropertyMap propertyMap,
- SettingsMigrationService migrationService) {
- this.configuration = configuration;
- this.configFile = configFile;
- this.pluginFolder = pluginFolder;
- this.propertyMap = propertyMap;
- this.migrationService = migrationService;
-
- if (propertyMap != null && migrationService != null) {
- validateAndLoadOptions();
- }
- }
-
- /**
- * Get the given property from the configuration.
- *
- * @param property The property to retrieve
- * @param The property's type
- * @return The property's value
- */
- public T getProperty(Property property) {
- return property.getFromFile(configuration);
- }
-
- /**
- * Set a new value for the given property.
- *
- * @param property The property to modify
- * @param value The new value to assign to the property
- * @param The property's type
- */
- public void setProperty(Property property, T value) {
- configuration.set(property.getPath(), value);
- }
-
- /**
- * Return the messages file based on the messages language config.
- *
- * @return The messages file to read messages from
- */
- public File getMessagesFile() {
- return messagesFile;
- }
-
- /**
- * Return the path to the default messages file within the JAR.
- *
- * @return The default messages file path
- */
- public String getDefaultMessagesFile() {
- return "/messages/messages_en.yml";
- }
-
- /**
- * Return the text to use in email registrations.
- *
- * @return The email message
- */
- public String getEmailMessage() {
- return emailMessage;
- }
-
- /**
- * Return the lines to output after an in-game registration.
- *
- * @return The welcome message
- */
- public List getWelcomeMessage() {
- return welcomeMessage;
- }
-
- /**
- * Reload the configuration.
- */
- public void reload() {
- configuration = YamlConfiguration.loadConfiguration(configFile);
- validateAndLoadOptions();
- }
-
- /**
- * Save the config file. Use after migrating one or more settings.
- */
- public void save() {
- try (FileWriter writer = new FileWriter(configFile)) {
- Yaml simpleYaml = newYaml(false);
- Yaml singleQuoteYaml = newYaml(true);
-
- writer.write("");
- // Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username"
- List currentPath = new ArrayList<>();
- for (Map.Entry, String[]> entry : propertyMap.entrySet()) {
- Property> property = entry.getKey();
-
- // Handle properties
- List propertyPath = Arrays.asList(property.getPath().split("\\."));
- List commonPathParts = CollectionUtils.filterCommonStart(
- currentPath, propertyPath.subList(0, propertyPath.size() - 1));
- List newPathParts = CollectionUtils.getRange(propertyPath, commonPathParts.size());
-
- if (commonPathParts.isEmpty()) {
- writer.append("\n");
- }
-
- int indentationLevel = commonPathParts.size();
- if (newPathParts.size() > 1) {
- for (String path : newPathParts.subList(0, newPathParts.size() - 1)) {
- writer.append("\n")
- .append(indent(indentationLevel))
- .append(path)
- .append(": ");
- ++indentationLevel;
- }
- }
- for (String comment : entry.getValue()) {
- writer.append("\n")
- .append(indent(indentationLevel))
- .append("# ")
- .append(comment);
- }
- writer.append("\n")
- .append(indent(indentationLevel))
- .append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0))
- .append(": ")
- .append(toYaml(property, indentationLevel, simpleYaml, singleQuoteYaml));
-
- currentPath = propertyPath.subList(0, propertyPath.size() - 1);
- }
- writer.flush();
- writer.close();
- } catch (IOException e) {
- ConsoleLogger.logException("Could not save config file:", e);
- }
- }
-
- private void validateAndLoadOptions() {
- if (migrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) {
- ConsoleLogger.info("Merged new config options");
- ConsoleLogger.info("Please check your config.yml file for new settings!");
- save();
- }
-
- messagesFile = buildMessagesFile();
- welcomeMessage = readWelcomeMessage();
- emailMessage = readEmailMessage();
- }
-
- private String toYaml(Property property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) {
- String representation = property.toYaml(configuration, simpleYaml, singleQuoteYaml);
- return Joiner.on("\n" + indent(indent)).join(representation.split("\\n"));
- }
-
- private File buildMessagesFile() {
- String languageCode = getProperty(PluginSettings.MESSAGES_LANGUAGE);
-
- String filePath = buildMessagesFilePathFromCode(languageCode);
- File messagesFile = new File(pluginFolder, filePath);
- if (copyFileFromResource(messagesFile, filePath)) {
- return messagesFile;
- }
-
- // File doesn't exist or couldn't be copied - try again with default, "en"
- String defaultFilePath = buildMessagesFilePathFromCode("en");
- File defaultFile = new File(pluginFolder, defaultFilePath);
- copyFileFromResource(defaultFile, defaultFilePath);
-
- // No matter the result, need to return a file
- return defaultFile;
- }
-
- private static String buildMessagesFilePathFromCode(String language) {
- return StringUtils.makePath("messages", "messages_" + language + ".yml");
- }
-
- private List readWelcomeMessage() {
- if (getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
- final File welcomeFile = new File(pluginFolder, "welcome.txt");
- final Charset charset = Charset.forName("UTF-8");
- if (copyFileFromResource(welcomeFile, "welcome.txt")) {
- try {
- return Files.readLines(welcomeFile, charset);
- } catch (IOException e) {
- ConsoleLogger.logException("Failed to read file '" + welcomeFile.getPath() + "':", e);
- }
- }
- }
- return new ArrayList<>(0);
- }
-
- private String readEmailMessage() {
- final File emailFile = new File(pluginFolder, "email.html");
- final Charset charset = Charset.forName("UTF-8");
- if (copyFileFromResource(emailFile, "email.html")) {
- try {
- return Files.toString(emailFile, charset);
- } catch (IOException e) {
- ConsoleLogger.logException("Failed to read file '" + emailFile.getPath() + "':", e);
- }
- }
- return "";
- }
-
- private static Yaml newYaml(boolean useSingleQuotes) {
- DumperOptions options = new DumperOptions();
- options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
- options.setAllowUnicode(true);
- if (useSingleQuotes) {
- options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
- }
- return new Yaml(options);
- }
-
- private static String indent(int level) {
- // We use an indentation of 4 spaces
- return Strings.repeat(" ", level * 4);
- }
-
-}
diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java
index 23580155..35b320d0 100644
--- a/src/main/java/fr/xephi/authme/settings/Settings.java
+++ b/src/main/java/fr/xephi/authme/settings/Settings.java
@@ -1,82 +1,289 @@
package fr.xephi.authme.settings;
-import fr.xephi.authme.AuthMe;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.io.Files;
+import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
-import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.settings.properties.SecuritySettings;
+import fr.xephi.authme.settings.propertymap.PropertyMap;
+import fr.xephi.authme.util.CollectionUtils;
+import fr.xephi.authme.util.StringUtils;
import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+
+import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
/**
- * Old settings manager. See {@link NewSetting} for the new manager.
+ * The AuthMe settings manager.
*/
-@Deprecated
-public final class Settings {
+public class Settings {
- public static List getUnrestrictedName;
- public static boolean isPermissionCheckEnabled;
- public static boolean isTeleportToSpawnEnabled;
- public static boolean isSessionsEnabled;
- public static boolean isAllowRestrictedIp;
- public static boolean isSaveQuitLocationEnabled;
- public static boolean protectInventoryBeforeLogInEnabled;
- public static boolean isStopEnabled;
- public static boolean reloadSupport;
- public static boolean forceRegLogin;
- public static boolean noTeleport;
- public static boolean isRemoveSpeedEnabled;
- public static String getUnloggedinGroup;
- public static String unRegisteredGroup;
- public static String getRegisteredGroup;
- public static String defaultWorld;
- public static String crazyloginFileName;
- public static int getSessionTimeout;
- public static int getNonActivatedGroup;
- private static FileConfiguration configFile;
+ private final File pluginFolder;
+ private final File configFile;
+ private final PropertyMap propertyMap;
+ private final SettingsMigrationService migrationService;
+ private FileConfiguration configuration;
+ /** The file with the localized messages based on {@link PluginSettings#MESSAGES_LANGUAGE}. */
+ private File messagesFile;
+ private List welcomeMessage;
+ private String emailMessage;
/**
- * Constructor for Settings.
+ * Constructor. Checks the given {@link FileConfiguration} object for completeness.
*
- * @param pl AuthMe
+ * @param configFile The configuration file
+ * @param pluginFolder The AuthMe plugin folder
+ * @param propertyMap Collection of all available settings
+ * @param migrationService Migration service to check the settings file with
*/
- public Settings(AuthMe pl) {
- configFile = pl.getConfig();
- loadVariables();
- }
-
- private static void loadVariables() {
- isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK);
- isTeleportToSpawnEnabled = load(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN);
- isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED);
- getSessionTimeout = configFile.getInt("settings.sessions.timeout", 10);
- isAllowRestrictedIp = load(RestrictionSettings.ENABLE_RESTRICTED_USERS);
- isRemoveSpeedEnabled = load(RestrictionSettings.REMOVE_SPEED);
- isSaveQuitLocationEnabled = load(RestrictionSettings.SAVE_QUIT_LOCATION);
- getUnloggedinGroup = load(SecuritySettings.UNLOGGEDIN_GROUP);
- getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1);
- unRegisteredGroup = configFile.getString("GroupOptions.UnregisteredPlayerGroup", "");
- getUnrestrictedName = load(RestrictionSettings.UNRESTRICTED_NAMES);
- getRegisteredGroup = configFile.getString("GroupOptions.RegisteredPlayerGroup", "");
- protectInventoryBeforeLogInEnabled = load(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN);
- isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true);
- reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true);
- defaultWorld = configFile.getString("Purge.defaultWorld", "world");
- forceRegLogin = load(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER);
- noTeleport = load(RestrictionSettings.NO_TELEPORT);
- crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db");
+ public Settings(File configFile, File pluginFolder, PropertyMap propertyMap,
+ SettingsMigrationService migrationService) {
+ this.configuration = YamlConfiguration.loadConfiguration(configFile);
+ this.configFile = configFile;
+ this.pluginFolder = pluginFolder;
+ this.propertyMap = propertyMap;
+ this.migrationService = migrationService;
+ validateAndLoadOptions();
}
/**
- * Load the value via the new Property setup for temporary support within this old settings manager.
+ * Constructor for testing purposes, allowing more options.
*
- * @param property The property to load
- * @param The property type
- * @return The config value of the property
+ * @param configuration The FileConfiguration object to use
+ * @param configFile The file to write to
+ * @param pluginFolder The plugin folder
+ * @param propertyMap The property map whose properties should be verified for presence, or null to skip this
+ * @param migrationService Migration service, or null to skip migration checks
*/
- private static T load(Property property) {
- return property.getFromFile(configFile);
+ @VisibleForTesting
+ Settings(FileConfiguration configuration, File configFile, File pluginFolder, PropertyMap propertyMap,
+ SettingsMigrationService migrationService) {
+ this.configuration = configuration;
+ this.configFile = configFile;
+ this.pluginFolder = pluginFolder;
+ this.propertyMap = propertyMap;
+ this.migrationService = migrationService;
+
+ if (propertyMap != null && migrationService != null) {
+ validateAndLoadOptions();
+ }
}
+
+ /**
+ * Get the given property from the configuration.
+ *
+ * @param property The property to retrieve
+ * @param The property's type
+ * @return The property's value
+ */
+ public T getProperty(Property property) {
+ return property.getFromFile(configuration);
+ }
+
+ /**
+ * Set a new value for the given property.
+ *
+ * @param property The property to modify
+ * @param value The new value to assign to the property
+ * @param The property's type
+ */
+ public void setProperty(Property property, T value) {
+ configuration.set(property.getPath(), value);
+ }
+
+ /**
+ * Return the messages file based on the messages language config.
+ *
+ * @return The messages file to read messages from
+ */
+ public File getMessagesFile() {
+ return messagesFile;
+ }
+
+ /**
+ * Return the path to the default messages file within the JAR.
+ *
+ * @return The default messages file path
+ */
+ public String getDefaultMessagesFile() {
+ return "/messages/messages_en.yml";
+ }
+
+ /**
+ * Return the text to use in email registrations.
+ *
+ * @return The email message
+ */
+ public String getEmailMessage() {
+ return emailMessage;
+ }
+
+ /**
+ * Return the lines to output after an in-game registration.
+ *
+ * @return The welcome message
+ */
+ public List getWelcomeMessage() {
+ return welcomeMessage;
+ }
+
+ /**
+ * Reload the configuration.
+ */
+ public void reload() {
+ configuration = YamlConfiguration.loadConfiguration(configFile);
+ validateAndLoadOptions();
+ }
+
+ /**
+ * Save the config file. Use after migrating one or more settings.
+ */
+ public void save() {
+ try (FileWriter writer = new FileWriter(configFile)) {
+ Yaml simpleYaml = newYaml(false);
+ Yaml singleQuoteYaml = newYaml(true);
+
+ writer.write("");
+ // Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username"
+ List currentPath = new ArrayList<>();
+ for (Map.Entry, String[]> entry : propertyMap.entrySet()) {
+ Property> property = entry.getKey();
+
+ // Handle properties
+ List propertyPath = Arrays.asList(property.getPath().split("\\."));
+ List commonPathParts = CollectionUtils.filterCommonStart(
+ currentPath, propertyPath.subList(0, propertyPath.size() - 1));
+ List newPathParts = CollectionUtils.getRange(propertyPath, commonPathParts.size());
+
+ if (commonPathParts.isEmpty()) {
+ writer.append("\n");
+ }
+
+ int indentationLevel = commonPathParts.size();
+ if (newPathParts.size() > 1) {
+ for (String path : newPathParts.subList(0, newPathParts.size() - 1)) {
+ writer.append("\n")
+ .append(indent(indentationLevel))
+ .append(path)
+ .append(": ");
+ ++indentationLevel;
+ }
+ }
+ for (String comment : entry.getValue()) {
+ writer.append("\n")
+ .append(indent(indentationLevel))
+ .append("# ")
+ .append(comment);
+ }
+ writer.append("\n")
+ .append(indent(indentationLevel))
+ .append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0))
+ .append(": ")
+ .append(toYaml(property, indentationLevel, simpleYaml, singleQuoteYaml));
+
+ currentPath = propertyPath.subList(0, propertyPath.size() - 1);
+ }
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ ConsoleLogger.logException("Could not save config file:", e);
+ }
+ }
+
+ private void validateAndLoadOptions() {
+ if (migrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) {
+ ConsoleLogger.info("Merged new config options");
+ ConsoleLogger.info("Please check your config.yml file for new settings!");
+ save();
+ }
+
+ messagesFile = buildMessagesFile();
+ welcomeMessage = readWelcomeMessage();
+ emailMessage = readEmailMessage();
+ }
+
+ private String toYaml(Property property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) {
+ String representation = property.toYaml(configuration, simpleYaml, singleQuoteYaml);
+ return Joiner.on("\n" + indent(indent)).join(representation.split("\\n"));
+ }
+
+ private File buildMessagesFile() {
+ String languageCode = getProperty(PluginSettings.MESSAGES_LANGUAGE);
+
+ String filePath = buildMessagesFilePathFromCode(languageCode);
+ File messagesFile = new File(pluginFolder, filePath);
+ if (copyFileFromResource(messagesFile, filePath)) {
+ return messagesFile;
+ }
+
+ // File doesn't exist or couldn't be copied - try again with default, "en"
+ String defaultFilePath = buildMessagesFilePathFromCode("en");
+ File defaultFile = new File(pluginFolder, defaultFilePath);
+ copyFileFromResource(defaultFile, defaultFilePath);
+
+ // No matter the result, need to return a file
+ return defaultFile;
+ }
+
+ private static String buildMessagesFilePathFromCode(String language) {
+ return StringUtils.makePath("messages", "messages_" + language + ".yml");
+ }
+
+ private List readWelcomeMessage() {
+ if (getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
+ final File welcomeFile = new File(pluginFolder, "welcome.txt");
+ final Charset charset = Charset.forName("UTF-8");
+ if (copyFileFromResource(welcomeFile, "welcome.txt")) {
+ try {
+ return Files.readLines(welcomeFile, charset);
+ } catch (IOException e) {
+ ConsoleLogger.logException("Failed to read file '" + welcomeFile.getPath() + "':", e);
+ }
+ }
+ }
+ return new ArrayList<>(0);
+ }
+
+ private String readEmailMessage() {
+ final File emailFile = new File(pluginFolder, "email.html");
+ final Charset charset = Charset.forName("UTF-8");
+ if (copyFileFromResource(emailFile, "email.html")) {
+ try {
+ return Files.toString(emailFile, charset);
+ } catch (IOException e) {
+ ConsoleLogger.logException("Failed to read file '" + emailFile.getPath() + "':", e);
+ }
+ }
+ return "";
+ }
+
+ private static Yaml newYaml(boolean useSingleQuotes) {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ options.setAllowUnicode(true);
+ if (useSingleQuotes) {
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
+ }
+ return new Yaml(options);
+ }
+
+ private static String indent(int level) {
+ // We use an indentation of 4 spaces
+ return Strings.repeat(" ", level * 4);
+ }
+
}
diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
index fdafea6f..1fc80ce6 100644
--- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
+++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
@@ -1,7 +1,9 @@
package fr.xephi.authme.settings;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.domain.Property;
+import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.FileConfiguration;
@@ -48,7 +50,8 @@ public class SettingsMigrationService {
return changes
| performMailTextToFileMigration(configuration, pluginFolder)
| migrateJoinLeaveMessages(configuration)
- | migrateForceSpawnSettings(configuration);
+ | migrateForceSpawnSettings(configuration)
+ | changeBooleanSettingToLogLevelProperty(configuration);
}
public boolean containsAllSettings(FileConfiguration configuration, PropertyMap propertyMap) {
@@ -64,7 +67,8 @@ public class SettingsMigrationService {
String[] deprecatedProperties = {
"Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications",
"Passpartu", "Performances", "settings.restrictions.enablePasswordVerifier", "Xenoforo.predefinedSalt",
- "VeryGames", "settings.restrictions.allowAllCommandsIfRegistrationIsOptional"};
+ "VeryGames", "settings.restrictions.allowAllCommandsIfRegistrationIsOptional", "DataSource.mySQLWebsite",
+ "Hooks.customAttributes", "Security.stop.kickPlayersBeforeStopping"};
for (String deprecatedPath : deprecatedProperties) {
if (configuration.contains(deprecatedPath)) {
return true;
@@ -92,10 +96,10 @@ public class SettingsMigrationService {
final File emailFile = new File(pluginFolder, "email.html");
final String mailText = configuration.getString(oldSettingPath)
- .replace("", "")
- .replace("", "")
- .replace("", "")
- .replace("", "");
+ .replace("", "").replace("%playername%", "")
+ .replace("", "").replace("%servername%", "")
+ .replace("", "").replace("%generatedpass%", "")
+ .replace("", "").replace("%image%", "");
if (!emailFile.exists()) {
try (FileWriter fw = new FileWriter(emailFile)) {
fw.write(mailText);
@@ -141,6 +145,25 @@ public class SettingsMigrationService {
| moveProperty(oldForceWorlds, FORCE_SPAWN_ON_WORLDS, configuration);
}
+ /**
+ * Changes the old boolean property "hide spam from console" to the new property specifying
+ * the log level.
+ *
+ * @param configuration The file configuration
+ * @return True if the configuration has changed, false otherwise
+ */
+ private static boolean changeBooleanSettingToLogLevelProperty(FileConfiguration configuration) {
+ final String oldPath = "Security.console.noConsoleSpam";
+ final Property newProperty = PluginSettings.LOG_LEVEL;
+ if (!newProperty.isPresent(configuration) && configuration.contains(oldPath)) {
+ ConsoleLogger.info("Moving '" + oldPath + "' to '" + newProperty.getPath() + "'");
+ LogLevel level = configuration.getBoolean(oldPath) ? LogLevel.INFO : LogLevel.FINE;
+ configuration.set(newProperty.getPath(), level.name());
+ return true;
+ }
+ return false;
+ }
+
/**
* Checks for an old property path and moves it to a new path if present.
*
diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
index ecb1d379..3345ef8d 100644
--- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
+++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
@@ -1,8 +1,6 @@
package fr.xephi.authme.settings;
-import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.initialization.DataFolder;
@@ -33,9 +31,8 @@ import java.io.IOException;
public class SpawnLoader implements Reloadable {
private final File authMeConfigurationFile;
- private final NewSetting settings;
+ private final Settings settings;
private final PluginHooks pluginHooks;
- private final DataSource dataSource;
private FileConfiguration authMeConfiguration;
private String[] spawnPriority;
private Location essentialsSpawn;
@@ -44,20 +41,19 @@ public class SpawnLoader implements Reloadable {
* Constructor.
*
* @param pluginFolder The AuthMe data folder
- * @param settings The setting instance
- * @param pluginHooks The plugin hooks instance
- * @param dataSource The plugin auth database instance
+ * @param settings The setting instance
+ * @param pluginHooks The plugin hooks instance
+ * @param dataSource The plugin auth database instance
*/
@Inject
- public SpawnLoader(@DataFolder File pluginFolder, NewSetting settings, PluginHooks pluginHooks,
- DataSource dataSource) {
+ SpawnLoader(@DataFolder File pluginFolder, Settings settings, PluginHooks pluginHooks,
+ DataSource dataSource) {
File spawnFile = new File(pluginFolder, "spawn.yml");
// TODO ljacqu 20160312: Check if resource could be copied and handle the case if not
FileUtils.copyFileFromResource(spawnFile, "spawn.yml");
this.authMeConfigurationFile = new File(pluginFolder, "spawn.yml");
this.settings = settings;
this.pluginHooks = pluginHooks;
- this.dataSource = dataSource;
reload();
}
@@ -84,6 +80,7 @@ public class SpawnLoader implements Reloadable {
* Set the AuthMe spawn point.
*
* @param location The location to use
+ *
* @return True upon success, false otherwise
*/
public boolean setSpawn(Location location) {
@@ -103,6 +100,7 @@ public class SpawnLoader implements Reloadable {
* Set the AuthMe first spawn location.
*
* @param location The location to use
+ *
* @return True upon success, false otherwise
*/
public boolean setFirstSpawn(Location location) {
@@ -141,12 +139,13 @@ public class SpawnLoader implements Reloadable {
* depending on the spawn priority setting.
*
* @param player The player to retrieve the spawn point for
+ *
* @return The spawn location, or the default spawn location upon failure
+ *
* @see RestrictionSettings#SPAWN_PRIORITY
*/
public Location getSpawnLocation(Player player) {
- AuthMe plugin = AuthMe.getInstance();
- if (plugin == null || player == null || player.getWorld() == null) {
+ if (player == null || player.getWorld() == null) {
return null;
}
@@ -168,15 +167,7 @@ public class SpawnLoader implements Reloadable {
spawnLoc = essentialsSpawn;
break;
case "authme":
- String playerNameLower = player.getName().toLowerCase();
- if (PlayerCache.getInstance().isAuthenticated(playerNameLower)) {
- spawnLoc = getSpawn();
- } else if (getFirstSpawn() != null && (!player.hasPlayedBefore() ||
- !dataSource.isAuthAvailable(playerNameLower))) {
- spawnLoc = getFirstSpawn();
- } else {
- spawnLoc = getSpawn();
- }
+ spawnLoc = getSpawn();
break;
}
if (spawnLoc != null) {
@@ -189,8 +180,9 @@ public class SpawnLoader implements Reloadable {
/**
* Save the location under the given prefix.
*
- * @param prefix The prefix to save the spawn under
+ * @param prefix The prefix to save the spawn under
* @param location The location to persist
+ *
* @return True upon success, false otherwise
*/
private boolean setLocation(String prefix, Location location) {
@@ -216,11 +208,26 @@ public class SpawnLoader implements Reloadable {
return false;
}
+ /**
+ * Return player's location if player is alive, or player's spawn location if dead.
+ *
+ * @param player player to retrieve
+ *
+ * @return location of the given player if alive, spawn location if dead.
+ */
+ public Location getPlayerLocationOrSpawn(Player player) {
+ if (player.isOnline() && player.isDead()) {
+ return getSpawnLocation(player);
+ }
+ return player.getLocation();
+ }
+
/**
* Build a {@link Location} object from the given path in the file configuration.
*
* @param configuration The file configuration to read from
- * @param pathPrefix The path to get the spawn point from
+ * @param pathPrefix The path to get the spawn point from
+ *
* @return Location corresponding to the values in the path
*/
private static Location getLocationFromConfiguration(FileConfiguration configuration, String pathPrefix) {
@@ -242,7 +249,8 @@ public class SpawnLoader implements Reloadable {
* under the given path.
*
* @param configuration The file configuration to use
- * @param pathPrefix The path to verify
+ * @param pathPrefix The path to verify
+ *
* @return True if all spawn fields are present, false otherwise
*/
private static boolean containsAllSpawnFields(FileConfiguration configuration, String pathPrefix) {
@@ -259,7 +267,8 @@ public class SpawnLoader implements Reloadable {
* Retrieve a property as a float from the given file configuration.
*
* @param configuration The file configuration to use
- * @param path The path of the property to retrieve
+ * @param path The path of the property to retrieve
+ *
* @return The float
*/
private static float getFloat(FileConfiguration configuration, String path) {
diff --git a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java
index eedce464..f9e59c93 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java
@@ -50,7 +50,7 @@ public class DatabaseSettings implements SettingsClass {
public static final Property MYSQL_COL_NAME =
newProperty("DataSource.mySQLColumnName", "username");
- @Comment("Column for storing or checking players RealName ")
+ @Comment("Column for storing or checking players RealName")
public static final Property MYSQL_COL_REALNAME =
newProperty("DataSource.mySQLRealName", "realname");
@@ -98,10 +98,6 @@ public class DatabaseSettings implements SettingsClass {
public static final Property MYSQL_COL_GROUP =
newProperty("ExternalBoardOptions.mySQLColumnGroup", "");
- @Comment("Enable this when you allow registration through a website")
- public static final Property MYSQL_WEBSITE =
- newProperty("DataSource.mySQLWebsite", false);
-
private DatabaseSettings() {
}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java
index 01e11a9c..6bab2e81 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java
@@ -31,10 +31,6 @@ public class HooksSettings implements SettingsClass {
public static final Property USE_ESSENTIALS_MOTD =
newProperty("Hooks.useEssentialsMotd", false);
- @Comment("Do we need to cache custom Attributes?")
- public static final Property CACHE_CUSTOM_ATTRIBUTES =
- newProperty("Hooks.customAttributes", false);
-
@Comment({
"-1 means disabled. If you want that only activated players",
"can log into your server, you can set here the group number",
@@ -62,6 +58,14 @@ public class HooksSettings implements SettingsClass {
public static final Property WORDPRESS_TABLE_PREFIX =
newProperty("ExternalBoardOptions.wordpressTablePrefix", "wp_");
+ @Comment("Unregistered permission group")
+ public static final Property UNREGISTERED_GROUP =
+ newProperty("GroupOptions.UnregisteredPlayerGroup", "");
+
+ @Comment("Registered permission group")
+ public static final Property REGISTERED_GROUP =
+ newProperty("GroupOptions.RegisteredPlayerGroup", "");
+
private HooksSettings() {
}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
index cf0f7932..1a58e0ed 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
@@ -1,5 +1,6 @@
package fr.xephi.authme.settings.properties;
+import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
@@ -25,7 +26,6 @@ public class PluginSettings implements SettingsClass {
@Comment({
"After how many minutes should a session expire?",
- "0 for unlimited time (Very dangerous, use it at your own risk!)",
"Remember that sessions will end only after the timeout, and",
"if the player's IP has changed but the timeout hasn't expired,",
"the player will be kicked from the server due to invalid session"
@@ -45,8 +45,8 @@ public class PluginSettings implements SettingsClass {
newProperty("settings.messagesLanguage", "en");
@Comment({
- "Take care with this option; if you don't want",
- "to use Vault and group switching of AuthMe",
+ "Take care with this option; if you want",
+ "to use group switching of AuthMe",
"for unloggedIn players, set this setting to true.",
"Default is false."
})
@@ -60,6 +60,14 @@ public class PluginSettings implements SettingsClass {
public static final Property KEEP_COLLISIONS_DISABLED =
newProperty("settings.restrictions.keepCollisionsDisabled", false);
+ @Comment({
+ "Log level: INFO, FINE, DEBUG. Use INFO for general messages,",
+ "FINE for some additional detailed ones (like password failed),",
+ "and DEBUG for debugging"
+ })
+ public static final Property LOG_LEVEL =
+ newProperty(LogLevel.class, "settings.logLevel", LogLevel.FINE);
+
private PluginSettings() {
}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
index 312f3f51..49bad830 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
@@ -16,6 +16,10 @@ public class ProtectionSettings implements SettingsClass {
public static final Property ENABLE_PROTECTION =
newProperty("Protection.enableProtection", false);
+ @Comment("Apply the protection also to registered usernames")
+ public static final Property ENABLE_PROTECTION_REGISTERED =
+ newProperty("Protection.enableProtectionRegistered", true);
+
@Comment({"Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes",
"PLEASE USE QUOTES!"})
public static final Property> COUNTRIES_WHITELIST =
diff --git a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
index db1cb1ee..1d79b082 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
@@ -84,11 +84,15 @@ public class RegistrationSettings implements SettingsClass {
public static final Property DELAY_JOIN_MESSAGE =
newProperty("settings.delayJoinMessage", false);
+ @Comment("Should we remove the leave messages of unlogged users?")
+ public static final Property REMOVE_UNLOGGED_LEAVE_MESSAGE =
+ newProperty("settings.removeUnloggedLeaveMessage", false);
+
@Comment("Should we remove join messages altogether?")
public static final Property REMOVE_JOIN_MESSAGE =
newProperty("settings.removeJoinMessage", false);
- @Comment("Should we remove leave messages?")
+ @Comment("Should we remove leave messages altogether?")
public static final Property REMOVE_LEAVE_MESSAGE =
newProperty("settings.removeLeaveMessage", false);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
index 3fd7b40b..169d2fab 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
@@ -50,11 +50,11 @@ public class RestrictionSettings implements SettingsClass {
newProperty("settings.restrictions.ForceSingleSession", true);
@Comment({
- "If enabled, every player will be teleported to the world spawnpoint",
- "after successful authentication.",
+ "If enabled, every player that spawn in one of the world listed in \"ForceSpawnLocOnJoin.worlds\"",
+ "will be teleported to the 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."})
+ "to the spawnpoint on join."})
public static final Property FORCE_SPAWN_LOCATION_AFTER_LOGIN =
newProperty("settings.restrictions.ForceSpawnLocOnJoin.enabled", false);
@@ -141,10 +141,6 @@ public class RestrictionSettings implements SettingsClass {
public static final Property DENY_TABCOMPLETE_BEFORE_LOGIN =
newProperty("settings.restrictions.DenyTabCompleteBeforeLogin", true);
- @Comment("Should we hide the tablist before logging in? Requires ProtocolLib.")
- public static final Property HIDE_TABLIST_BEFORE_LOGIN =
- newProperty("settings.restrictions.HideTablistBeforeLogin", true);
-
@Comment({
"Should we display all other accounts from a player when he joins?",
"permission: /authme.admin.accounts"})
diff --git a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
index ddc98dbd..d9806086 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
@@ -22,10 +22,6 @@ public class SecuritySettings implements SettingsClass {
public static final Property USE_RELOAD_COMMAND_SUPPORT =
newProperty("Security.ReloadCommand.useReloadCommandSupport", true);
- @Comment("Remove spam from console?")
- public static final Property REMOVE_SPAM_FROM_CONSOLE =
- newProperty("Security.console.noConsoleSpam", false);
-
@Comment("Remove passwords from console?")
public static final Property REMOVE_PASSWORD_FROM_CONSOLE =
newProperty("Security.console.removePassword", true);
@@ -46,11 +42,6 @@ public class SecuritySettings implements SettingsClass {
public static final Property CAPTCHA_LENGTH =
newProperty("Security.captcha.captchaLength", 5);
- @Comment({"Kick players before stopping the server, that allow us to save position of players",
- "and all needed information correctly without any corruption."})
- public static final Property KICK_PLAYERS_BEFORE_STOPPING =
- newProperty("Security.stop.kickPlayersBeforeStopping", true);
-
@Comment("Minimum length of password")
public static final Property MIN_PASSWORD_LENGTH =
newProperty("settings.security.minPasswordLength", 5);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java b/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java
index ac8d65d9..a04deada 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java
@@ -4,7 +4,6 @@ import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import fr.xephi.authme.settings.propertymap.PropertyMap;
-import fr.xephi.authme.util.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -67,7 +66,7 @@ public final class SettingsFieldRetriever {
return (Property>) field.get(null);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not fetch field '" + field.getName() + "' from class '"
- + field.getDeclaringClass().getSimpleName() + "': " + StringUtils.formatException(e));
+ + field.getDeclaringClass().getSimpleName() + "'", e);
}
}
return null;
diff --git a/src/main/java/fr/xephi/authme/settings/propertymap/Node.java b/src/main/java/fr/xephi/authme/settings/propertymap/Node.java
index 5586a578..7d281989 100644
--- a/src/main/java/fr/xephi/authme/settings/propertymap/Node.java
+++ b/src/main/java/fr/xephi/authme/settings/propertymap/Node.java
@@ -77,7 +77,7 @@ final class Node {
}
if (commonNode == null) {
- ConsoleLogger.showError("Could not find common node for '" + fullPath1 + "' at index " + commonCount);
+ ConsoleLogger.warning("Could not find common node for '" + fullPath1 + "' at index " + commonCount);
return fullPath1.compareTo(fullPath2); // fallback
} else if (commonCount >= path1.length || commonCount >= path2.length) {
return Integer.compare(path1.length, path2.length);
diff --git a/src/main/java/fr/xephi/authme/task/CleanupTask.java b/src/main/java/fr/xephi/authme/task/CleanupTask.java
new file mode 100644
index 00000000..1a5bbdd6
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/task/CleanupTask.java
@@ -0,0 +1,26 @@
+package fr.xephi.authme.task;
+
+import ch.jalu.injector.Injector;
+import fr.xephi.authme.initialization.HasCleanup;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import javax.inject.Inject;
+
+/**
+ * Task run periodically to invoke the cleanup task on services.
+ */
+public class CleanupTask extends BukkitRunnable {
+
+ @Inject
+ private Injector injector;
+
+ CleanupTask() {
+ }
+
+ @Override
+ public void run() {
+ for (HasCleanup service : injector.retrieveAllOfType(HasCleanup.class)) {
+ service.performCleanup();
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/task/MessageTask.java b/src/main/java/fr/xephi/authme/task/MessageTask.java
index 590913db..7282bc65 100644
--- a/src/main/java/fr/xephi/authme/task/MessageTask.java
+++ b/src/main/java/fr/xephi/authme/task/MessageTask.java
@@ -45,8 +45,8 @@ public class MessageTask implements Runnable {
player.sendMessage(ms);
}
BukkitTask nextTask = bukkitService.runTaskLater(this, interval * TICKS_PER_SECOND);
- if (limboCache.hasLimboPlayer(name)) {
- limboCache.getLimboPlayer(name).setMessageTask(nextTask);
+ if (limboCache.hasPlayerData(name)) {
+ limboCache.getPlayerData(name).setMessageTask(nextTask);
}
return;
}
diff --git a/src/main/java/fr/xephi/authme/task/LimboPlayerTaskManager.java b/src/main/java/fr/xephi/authme/task/PlayerDataTaskManager.java
similarity index 77%
rename from src/main/java/fr/xephi/authme/task/LimboPlayerTaskManager.java
rename to src/main/java/fr/xephi/authme/task/PlayerDataTaskManager.java
index 36530c99..b4e1846d 100644
--- a/src/main/java/fr/xephi/authme/task/LimboPlayerTaskManager.java
+++ b/src/main/java/fr/xephi/authme/task/PlayerDataTaskManager.java
@@ -3,10 +3,10 @@ package fr.xephi.authme.task;
import fr.xephi.authme.ConsoleLogger;
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.cache.limbo.PlayerData;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
-import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.BukkitService;
@@ -18,15 +18,15 @@ import javax.inject.Inject;
import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
/**
- * Registers tasks associated with a LimboPlayer.
+ * Registers tasks associated with a PlayerData.
*/
-public class LimboPlayerTaskManager {
+public class PlayerDataTaskManager {
@Inject
private Messages messages;
@Inject
- private NewSetting settings;
+ private Settings settings;
@Inject
private BukkitService bukkitService;
@@ -37,7 +37,8 @@ public class LimboPlayerTaskManager {
@Inject
private PlayerCache playerCache;
- LimboPlayerTaskManager() { }
+ PlayerDataTaskManager() {
+ }
/**
@@ -51,14 +52,14 @@ public class LimboPlayerTaskManager {
final int interval = settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL);
final MessageKey key = getMessageKey(isRegistered);
if (interval > 0) {
- final LimboPlayer limboPlayer = limboCache.getLimboPlayer(name);
- if (limboPlayer == null) {
- ConsoleLogger.info("LimboPlayer for '" + name + "' is not available");
+ final PlayerData playerData = limboCache.getPlayerData(name);
+ if (playerData == null) {
+ ConsoleLogger.info("PlayerData for '" + name + "' is not available");
} else {
- cancelTask(limboPlayer.getMessageTask());
+ cancelTask(playerData.getMessageTask());
BukkitTask messageTask = bukkitService.runTask(new MessageTask(name, messages.retrieve(key),
interval, bukkitService, limboCache, playerCache));
- limboPlayer.setMessageTask(messageTask);
+ playerData.setMessageTask(messageTask);
}
}
}
@@ -71,14 +72,14 @@ public class LimboPlayerTaskManager {
public void registerTimeoutTask(Player player) {
final int timeout = settings.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
if (timeout > 0) {
- final LimboPlayer limboPlayer = limboCache.getLimboPlayer(player.getName());
- if (limboPlayer == null) {
- ConsoleLogger.info("LimboPlayer for '" + player.getName() + "' is not available");
+ final PlayerData playerData = limboCache.getPlayerData(player.getName());
+ if (playerData == null) {
+ ConsoleLogger.info("PlayerData for '" + player.getName() + "' is not available");
} else {
- cancelTask(limboPlayer.getTimeoutTask());
+ cancelTask(playerData.getTimeoutTask());
String message = messages.retrieveSingle(MessageKey.LOGIN_TIMEOUT_ERROR);
BukkitTask task = bukkitService.runTaskLater(new TimeoutTask(player, message, playerCache), timeout);
- limboPlayer.setTimeoutTask(task);
+ playerData.setTimeoutTask(task);
}
}
}
diff --git a/src/main/java/fr/xephi/authme/task/PurgeTask.java b/src/main/java/fr/xephi/authme/task/PurgeTask.java
deleted file mode 100644
index 97ffcc88..00000000
--- a/src/main/java/fr/xephi/authme/task/PurgeTask.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package fr.xephi.authme.task;
-
-import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.settings.NewSetting;
-import fr.xephi.authme.settings.properties.PurgeSettings;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.bukkit.scheduler.BukkitRunnable;
-
-public class PurgeTask extends BukkitRunnable {
-
- //how many players we should check for each tick
- private static final int INTERVALL_CHECK = 5;
-
- private final AuthMe plugin;
- private final NewSetting newSetting;
-
- private final UUID sender;
- private final Set toPurge;
-
- private final OfflinePlayer[] offlinePlayers;
-
- private final boolean autoPurging;
- private final int totalPurgeCount;
-
- private int currentPage = 0;
-
- public PurgeTask(AuthMe plugin, CommandSender sender, Set