diff --git a/pom.xml b/pom.xml index 5b130946..094b2e19 100644 --- a/pom.xml +++ b/pom.xml @@ -405,6 +405,13 @@ true + + + javax.inject + javax.inject + 1 + + com.maxmind.geoip diff --git a/src/main/java/fr/xephi/authme/AntiBot.java b/src/main/java/fr/xephi/authme/AntiBot.java index 75a2a3b5..fcdb2206 100644 --- a/src/main/java/fr/xephi/authme/AntiBot.java +++ b/src/main/java/fr/xephi/authme/AntiBot.java @@ -9,6 +9,7 @@ import fr.xephi.authme.settings.properties.ProtectionSettings; import fr.xephi.authme.util.BukkitService; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @@ -27,6 +28,7 @@ public class AntiBot { private final List antibotPlayers = new ArrayList<>(); private AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED; + @Inject public AntiBot(NewSetting settings, Messages messages, PermissionsManager permissionsManager, BukkitService bukkitService) { this.settings = settings; diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 66a49dbd..647484cd 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -1,32 +1,5 @@ package fr.xephi.authme; -import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT; -import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD; -import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS; -import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; - -import java.io.File; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; - -import org.apache.logging.log4j.LogManager; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitTask; - import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.cache.auth.PlayerAuth; @@ -34,12 +7,8 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; -import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandHandler; import fr.xephi.authme.command.CommandInitializer; -import fr.xephi.authme.command.CommandMapper; -import fr.xephi.authme.command.CommandService; -import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.datasource.CacheDataSource; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSourceType; @@ -48,8 +17,11 @@ import fr.xephi.authme.datasource.MySQL; import fr.xephi.authme.datasource.SQLite; import fr.xephi.authme.hooks.BungeeCordMessage; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; +import fr.xephi.authme.initialization.BaseCommands; +import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.initialization.MetricsStarter; import fr.xephi.authme.listener.AuthMeBlockListener; -import fr.xephi.authme.listener.AuthMeEntityListener; import fr.xephi.authme.listener.AuthMeInventoryPacketAdapter; import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.listener.AuthMePlayerListener16; @@ -66,7 +38,6 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.Management; -import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.settings.NewSetting; @@ -89,7 +60,31 @@ import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.MigrationService; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; -import fr.xephi.authme.util.ValidationService; +import org.apache.logging.log4j.LogManager; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; + +import java.io.File; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT; +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD; +import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS; /** * The AuthMe main class. @@ -105,7 +100,6 @@ public class AuthMe extends JavaPlugin { // Private Instances private static AuthMe plugin; - private static Server server; /* * Maps and stuff */ @@ -140,7 +134,6 @@ public class AuthMe extends JavaPlugin { private DataSource database; private PluginHooks pluginHooks; private SpawnLoader spawnLoader; - private AntiBot antiBot; private boolean autoPurging; private BukkitService bukkitService; @@ -217,17 +210,15 @@ public class AuthMe extends JavaPlugin { @Override public void onEnable() { // Set various instances - server = getServer(); plugin = this; ConsoleLogger.setLogger(getLogger()); - setPluginInfos(); // Load settings and custom configurations, if it fails, stop the server due to security reasons. newSettings = createNewSetting(); if (newSettings == null) { ConsoleLogger.showError("Could not load configuration. Aborting."); - server.shutdown(); + getServer().shutdown(); return; } ConsoleLogger.setLoggingOptions(newSettings.getProperty(SecuritySettings.USE_LOGGING), @@ -235,7 +226,7 @@ public class AuthMe extends JavaPlugin { // Old settings manager if (!loadSettings()) { - server.shutdown(); + getServer().shutdown(); setEnabled(false); return; } @@ -251,23 +242,40 @@ public class AuthMe extends JavaPlugin { stopOrUnload(); return; } - - bukkitService = new BukkitService(this); - pluginHooks = new PluginHooks(server.getPluginManager()); - MigrationService.changePlainTextToSha256(newSettings, database, new SHA256()); - passwordSecurity = new PasswordSecurity(getDataSource(), newSettings, Bukkit.getPluginManager()); - // Initialize spawn loader - spawnLoader = new SpawnLoader(getDataFolder(), newSettings, pluginHooks); - permsMan = initializePermissionsManager(); - antiBot = new AntiBot(newSettings, messages, permsMan, bukkitService); - ValidationService validationService = new ValidationService(newSettings, database, permsMan); - commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, - pluginHooks, spawnLoader, antiBot, validationService, bukkitService); + + AuthMeServiceInitializer initializer = new AuthMeServiceInitializer("fr.xephi.authme"); + // Register elements of the Bukkit / JavaPlugin environment + initializer.register(AuthMe.class, this); + initializer.register(Server.class, getServer()); + initializer.register(PluginManager.class, getServer().getPluginManager()); + initializer.register(BukkitScheduler.class, getServer().getScheduler()); + initializer.provide(DataFolder.class, getDataFolder()); + + // Register elements we instantiate manually + initializer.register(NewSetting.class, newSettings); + initializer.register(Messages.class, messages); + initializer.register(DataSource.class, database); + + // Some statically injected things + initializer.register(PlayerCache.class, PlayerCache.getInstance()); + initializer.register(LimboCache.class, LimboCache.getInstance()); + initializer.provide(BaseCommands.class, CommandInitializer.buildCommands(initializer)); + + permsMan = initializer.get(PermissionsManager.class); + bukkitService = initializer.get(BukkitService.class); + pluginHooks = initializer.get(PluginHooks.class); + passwordSecurity = initializer.get(PasswordSecurity.class); + spawnLoader = initializer.get(SpawnLoader.class); + commandHandler = initializer.get(CommandHandler.class); + api = initializer.get(NewAPI.class); + management = initializer.get(Management.class); + dataManager = initializer.get(DataManager.class); + initializer.get(API.class); // Set up Metrics - MetricsStarter.setupMetrics(plugin, newSettings); + MetricsStarter.setupMetrics(this, newSettings); // Set console filter setupConsoleFilter(); @@ -284,22 +292,12 @@ public class AuthMe extends JavaPlugin { // End of Hooks // Do a backup on start - new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.START); + new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.START); // Setup the inventory backup playerBackup = new JsonCache(); - // Set the DataManager - dataManager = new DataManager(this, pluginHooks, bukkitService); - - // Set up the new API - setupApi(); - - // Set up the management - ProcessService processService = new ProcessService(newSettings, messages, this, database, - passwordSecurity, pluginHooks, spawnLoader, validationService, bukkitService); - management = new Management(this, processService, database, PlayerCache.getInstance()); // Set up the BungeeCord hook setupBungeeCordHook(newSettings); @@ -308,8 +306,7 @@ public class AuthMe extends JavaPlugin { reloadSupportHook(); // Register event listeners - registerEventListeners( - messages, database, management, pluginHooks, spawnLoader, antiBot, bukkitService, validationService); + registerEventListeners(initializer); // Start Email recall task if needed scheduleRecallEmailTask(); @@ -373,38 +370,34 @@ public class AuthMe extends JavaPlugin { /** * Register all event listeners. */ - private void registerEventListeners(Messages messages, DataSource dataSource, Management management, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, - BukkitService bukkitService, ValidationService validationService) { + private void registerEventListeners(AuthMeServiceInitializer initializer) { // Get the plugin manager instance - PluginManager pluginManager = server.getPluginManager(); + PluginManager pluginManager = getServer().getPluginManager(); // Register event listeners - pluginManager.registerEvents(new AuthMePlayerListener( - this, newSettings, messages, dataSource, antiBot, management, bukkitService, validationService), this); - pluginManager.registerEvents(new AuthMeBlockListener(), this); - pluginManager.registerEvents(new AuthMeEntityListener(), this); - pluginManager.registerEvents(new AuthMeServerListener( - this, messages, newSettings, pluginHooks, spawnLoader, validationService), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this); + pluginManager.registerEvents(initializer.get(AuthMeBlockListener.class), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this); + pluginManager.registerEvents(initializer.get(AuthMeServerListener.class), this); // Try to register 1.6 player listeners try { Class.forName("org.bukkit.event.player.PlayerEditBookEvent"); - pluginManager.registerEvents(new AuthMePlayerListener16(), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener16.class), this); } catch (ClassNotFoundException ignore) { } // Try to register 1.8 player listeners try { Class.forName("org.bukkit.event.player.PlayerInteractAtEntityEvent"); - pluginManager.registerEvents(new AuthMePlayerListener18(), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener18.class), this); } catch (ClassNotFoundException ignore) { } - + // Try to register 1.9 player listeners try { Class.forName("org.spigotmc.event.player.PlayerSpawnLocationEvent"); - pluginManager.registerEvents(new AuthMePlayerListener19(this), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener19.class), this); } catch (ClassNotFoundException ignore) { } } @@ -438,30 +431,6 @@ public class AuthMe extends JavaPlugin { } } - private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages, - PasswordSecurity passwordSecurity, NewSetting settings, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, - ValidationService validationService, BukkitService bukkitService) { - HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER)); - Set baseCommands = CommandInitializer.buildCommands(); - CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager); - CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService); - return new CommandHandler(commandService); - } - - /** - * Set up the API. This sets up the new and the old API. - */ - @SuppressWarnings("deprecation") - private void setupApi() { - // Set up the API - api = new NewAPI(this); - - // Set up the deprecated API - new API(this); - } - /** * Load the plugin's settings. * @@ -474,7 +443,7 @@ public class AuthMe extends JavaPlugin { } catch (Exception e) { ConsoleLogger.logException("Can't load the configuration file... Something went wrong. " + "To avoid security issues the server will shut down!", e); - server.shutdown(); + getServer().shutdown(); } return false; } @@ -519,14 +488,15 @@ public class AuthMe extends JavaPlugin { // Do backup on stop if enabled if (newSettings != null) { - new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP); + new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.STOP); } + final AuthMe pluginInstance = this; new Thread(new Runnable() { @Override public void run() { List pendingTasks = new ArrayList<>(); for (BukkitTask pendingTask : getServer().getScheduler().getPendingTasks()) { - if (pendingTask.getOwner().equals(plugin) && !pendingTask.isSync()) { + if (pendingTask.getOwner().equals(pluginInstance) && !pendingTask.isSync()) { pendingTasks.add(pendingTask.getTaskId()); } } @@ -565,9 +535,9 @@ public class AuthMe extends JavaPlugin { public void stopOrUnload() { if (Settings.isStopEnabled) { ConsoleLogger.showError("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!"); - server.shutdown(); + getServer().shutdown(); } else { - server.getPluginManager().disablePlugin(AuthMe.getInstance()); + getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); } } @@ -610,7 +580,7 @@ public class AuthMe extends JavaPlugin { database = dataSource; if (DataSourceType.SQLITE == dataSourceType) { - server.getScheduler().runTaskAsynchronously(this, new Runnable() { + getServer().getScheduler().runTaskAsynchronously(this, new Runnable() { @Override public void run() { int accounts = database.getAccountsRegistered(); @@ -623,15 +593,6 @@ public class AuthMe extends JavaPlugin { } } - /** - * Set up the permissions manager. - */ - private PermissionsManager initializePermissionsManager() { - PermissionsManager manager = new PermissionsManager(Bukkit.getServer(), getLogger()); - manager.setup(); - return manager; - } - // Set the console filter to remove the passwords private void setLog4JFilter() { Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { @@ -648,7 +609,7 @@ public class AuthMe extends JavaPlugin { // Check the presence of the ProtocolLib plugin public void checkProtocolLib() { - if (!server.getPluginManager().isPluginEnabled("ProtocolLib")) { + if (!getServer().getPluginManager().isPluginEnabled("ProtocolLib")) { if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it..."); Settings.protectInventoryBeforeLogInEnabled = false; @@ -683,7 +644,7 @@ public class AuthMe extends JavaPlugin { // Save Player Data private void savePlayer(Player player) { - if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { + if (safeIsNpc(player) || Utils.isUnrestricted(player)) { return; } String name = player.getName().toLowerCase(); @@ -711,6 +672,10 @@ public class AuthMe extends JavaPlugin { PlayerCache.getInstance().removePlayer(name); } + private boolean safeIsNpc(Player player) { + return pluginHooks != null && pluginHooks.isNpc(player) || player.hasMetadata("NPC"); + } + // Select the player to kick when a vip player joins the server when full public Player generateKickPlayer(Collection collection) { for (Player player : collection) { @@ -727,7 +692,7 @@ public class AuthMe extends JavaPlugin { return; } autoPurging = true; - server.getScheduler().runTaskAsynchronously(this, new Runnable() { + getServer().getScheduler().runTaskAsynchronously(this, new Runnable() { @Override public void run() { ConsoleLogger.info("AutoPurging the Database..."); @@ -784,6 +749,7 @@ public class AuthMe extends JavaPlugin { public String replaceAllInfo(String message, Player player) { String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size()); String ipAddress = Utils.getPlayerIp(player); + Server server = getServer(); return message .replace("&", "\u00a7") .replace("{PLAYER}", player.getName()) diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 061683fa..f5751d42 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -2,32 +2,37 @@ package fr.xephi.authme; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import javax.inject.Inject; import java.io.File; import java.util.ArrayList; import java.util.List; +import static fr.xephi.authme.util.StringUtils.makePath; + /** */ public class DataManager { - private final AuthMe plugin; - private final PluginHooks pluginHooks; - private final BukkitService bukkitService; + @Inject + private Server server; + @Inject + private PluginHooks pluginHooks; + @Inject + private BukkitService bukkitService; + @Inject + private NewSetting settings; + @Inject + private PermissionsManager permissionsManager; - /* - * Constructor. - */ - public DataManager(AuthMe plugin, PluginHooks pluginHooks, BukkitService bukkitService) { - this.plugin = plugin; - this.pluginHooks = pluginHooks; - this.bukkitService = bukkitService; - } + DataManager() { } private List getOfflinePlayers(List names) { List result = new ArrayList<>(); @@ -98,9 +103,8 @@ public class DataManager { public synchronized void purgeDat(List cleared) { int i = 0; - File dataFolder = new File(plugin.getServer().getWorldContainer() - + File.separator + plugin.getSettings().getProperty(PurgeSettings.DEFAULT_WORLD) - + File.separator + "players"); + File dataFolder = new File(server.getWorldContainer(), + makePath(settings.getProperty(PurgeSettings.DEFAULT_WORLD), "players")); List offlinePlayers = getOfflinePlayers(cleared); for (OfflinePlayer player : offlinePlayers) { File playerFile = new File(dataFolder, Utils.getUUIDorName(player) + ".dat"); @@ -142,14 +146,8 @@ public class DataManager { // TODO: What is this method for? Is it correct? // TODO: Make it work with OfflinePlayers group data. public synchronized void purgePermissions(List cleared) { - // Get the permissions manager, and make sure it's valid - PermissionsManager permsMan = plugin.getPermissionsManager(); - if (permsMan == null) { - ConsoleLogger.showError("Unable to access permissions manager instance!"); - return; - } for (String name : cleared) { - permsMan.removeAllGroups(bukkitService.getPlayerExact(name)); + permissionsManager.removeAllGroups(bukkitService.getPlayerExact(name)); } ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); } diff --git a/src/main/java/fr/xephi/authme/api/API.java b/src/main/java/fr/xephi/authme/api/API.java index 58960f9d..26f5ea8f 100644 --- a/src/main/java/fr/xephi/authme/api/API.java +++ b/src/main/java/fr/xephi/authme/api/API.java @@ -3,6 +3,8 @@ 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.process.Management; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.util.Utils; @@ -12,6 +14,8 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; +import javax.inject.Inject; + /** * Deprecated API of AuthMe. Please use {@link NewAPI} instead. */ @@ -20,7 +24,9 @@ public class API { public static final String newline = System.getProperty("line.separator"); public static AuthMe instance; + private static DataSource dataSource; private static PasswordSecurity passwordSecurity; + private static Management management; /** * Constructor for the deprecated API. @@ -28,9 +34,12 @@ public class API { * @param instance AuthMe */ @Deprecated - public API(AuthMe instance) { + @Inject + API(AuthMe instance, DataSource dataSource, PasswordSecurity passwordSecurity, Management management) { API.instance = instance; - passwordSecurity = instance.getPasswordSecurity(); + API.dataSource = dataSource; + API.passwordSecurity = passwordSecurity; + API.management = management; } /** @@ -109,7 +118,7 @@ public class API { @Deprecated public static boolean isRegistered(String playerName) { String player = playerName.toLowerCase(); - return instance.getDataSource().isAuthAvailable(player); + return dataSource.isAuthAvailable(player); } /** @@ -144,7 +153,7 @@ public class API { .lastLogin(0) .realName(playerName) .build(); - return instance.getDataSource().saveAuth(auth); + return dataSource.saveAuth(auth); } /** @@ -154,7 +163,7 @@ public class API { */ @Deprecated public static void forceLogin(Player player) { - instance.getManagement().performLogin(player, "dontneed", true); + management.performLogin(player, "dontneed", true); } @Deprecated diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index 0f543762..d3a0b7d8 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -12,6 +12,8 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.util.Utils; +import javax.inject.Inject; + /** * The current API of AuthMe. Recommended method of retrieving the API object: * @@ -28,6 +30,7 @@ public class NewAPI { * * @param plugin The AuthMe plugin instance */ + @Inject public NewAPI(AuthMe plugin) { this.plugin = plugin; } diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java index 37c1a2a1..5f7b32af 100644 --- a/src/main/java/fr/xephi/authme/command/CommandHandler.java +++ b/src/main/java/fr/xephi/authme/command/CommandHandler.java @@ -1,14 +1,14 @@ package fr.xephi.authme.command; -import java.util.ArrayList; -import java.util.List; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.help.HelpProvider; +import fr.xephi.authme.util.StringUtils; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; -import fr.xephi.authme.util.StringUtils; +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; /** * The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription} @@ -29,6 +29,7 @@ public class CommandHandler { * * @param commandService The CommandService instance */ + @Inject public CommandHandler(CommandService commandService) { this.commandService = commandService; } diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index 6635545f..14d72f4a 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -33,6 +33,7 @@ import fr.xephi.authme.command.executable.login.LoginCommand; import fr.xephi.authme.command.executable.logout.LogoutCommand; import fr.xephi.authme.command.executable.register.RegisterCommand; import fr.xephi.authme.command.executable.unregister.UnregisterCommand; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; import fr.xephi.authme.permission.AdminPermission; import fr.xephi.authme.permission.PlayerPermission; @@ -53,13 +54,13 @@ public final class CommandInitializer { // Helper class } - public static Set buildCommands() { + public static Set buildCommands(AuthMeServiceInitializer initializer) { // Register the base AuthMe Reloaded command final CommandDescription AUTHME_BASE = CommandDescription.builder() .labels("authme") .description("Main command") .detailedDescription("The main AuthMeReloaded command. The root for all admin commands.") - .executableCommand(new AuthMeCommand()) + .executableCommand(initializer.newInstance(AuthMeCommand.class)) .build(); // Register the register command @@ -71,7 +72,7 @@ public final class CommandInitializer { .withArgument("player", "Player name", false) .withArgument("password", "Password", false) .permissions(OP_ONLY, AdminPermission.REGISTER) - .executableCommand(new RegisterAdminCommand()) + .executableCommand(initializer.newInstance(RegisterAdminCommand.class)) .build(); // Register the unregister command @@ -82,7 +83,7 @@ public final class CommandInitializer { .detailedDescription("Unregister the specified player.") .withArgument("player", "Player name", false) .permissions(OP_ONLY, AdminPermission.UNREGISTER) - .executableCommand(new UnregisterAdminCommand()) + .executableCommand(initializer.newInstance(UnregisterAdminCommand.class)) .build(); // Register the forcelogin command @@ -93,7 +94,7 @@ public final class CommandInitializer { .detailedDescription("Enforce the specified player to login.") .withArgument("player", "Online player name", true) .permissions(OP_ONLY, AdminPermission.FORCE_LOGIN) - .executableCommand(new ForceLoginCommand()) + .executableCommand(initializer.newInstance(ForceLoginCommand.class)) .build(); // Register the changepassword command @@ -105,7 +106,7 @@ public final class CommandInitializer { .withArgument("player", "Player name", false) .withArgument("pwd", "New password", false) .permissions(OP_ONLY, AdminPermission.CHANGE_PASSWORD) - .executableCommand(new ChangePasswordAdminCommand()) + .executableCommand(initializer.newInstance(ChangePasswordAdminCommand.class)) .build(); // Register the last login command @@ -116,7 +117,7 @@ public final class CommandInitializer { .detailedDescription("View the date of the specified players last login.") .withArgument("player", "Player name", true) .permissions(OP_ONLY, AdminPermission.LAST_LOGIN) - .executableCommand(new LastLoginCommand()) + .executableCommand(initializer.newInstance(LastLoginCommand.class)) .build(); // Register the accounts command @@ -127,7 +128,7 @@ public final class CommandInitializer { .detailedDescription("Display all accounts of a player by his player name or IP.") .withArgument("player", "Player name or IP", true) .permissions(OP_ONLY, AdminPermission.ACCOUNTS) - .executableCommand(new AccountsCommand()) + .executableCommand(initializer.newInstance(AccountsCommand.class)) .build(); // Register the getemail command @@ -138,7 +139,7 @@ public final class CommandInitializer { .detailedDescription("Display the email address of the specified player if set.") .withArgument("player", "Player name", true) .permissions(OP_ONLY, AdminPermission.GET_EMAIL) - .executableCommand(new GetEmailCommand()) + .executableCommand(initializer.newInstance(GetEmailCommand.class)) .build(); // Register the setemail command @@ -150,7 +151,7 @@ public final class CommandInitializer { .withArgument("player", "Player name", false) .withArgument("email", "Player email", false) .permissions(OP_ONLY, AdminPermission.CHANGE_EMAIL) - .executableCommand(new SetEmailCommand()) + .executableCommand(initializer.newInstance(SetEmailCommand.class)) .build(); // Register the getip command @@ -161,7 +162,7 @@ public final class CommandInitializer { .detailedDescription("Get the IP address of the specified online player.") .withArgument("player", "Player name", false) .permissions(OP_ONLY, AdminPermission.GET_IP) - .executableCommand(new GetIpCommand()) + .executableCommand(initializer.newInstance(GetIpCommand.class)) .build(); // Register the spawn command @@ -171,7 +172,7 @@ public final class CommandInitializer { .description("Teleport to spawn") .detailedDescription("Teleport to the spawn.") .permissions(OP_ONLY, AdminPermission.SPAWN) - .executableCommand(new SpawnCommand()) + .executableCommand(initializer.newInstance(SpawnCommand.class)) .build(); // Register the setspawn command @@ -181,7 +182,7 @@ public final class CommandInitializer { .description("Change the spawn") .detailedDescription("Change the player's spawn to your current position.") .permissions(OP_ONLY, AdminPermission.SET_SPAWN) - .executableCommand(new SetSpawnCommand()) + .executableCommand(initializer.newInstance(SetSpawnCommand.class)) .build(); // Register the firstspawn command @@ -191,7 +192,7 @@ public final class CommandInitializer { .description("Teleport to first spawn") .detailedDescription("Teleport to the first spawn.") .permissions(OP_ONLY, AdminPermission.FIRST_SPAWN) - .executableCommand(new FirstSpawnCommand()) + .executableCommand(initializer.newInstance(FirstSpawnCommand.class)) .build(); // Register the setfirstspawn command @@ -201,7 +202,7 @@ public final class CommandInitializer { .description("Change the first spawn") .detailedDescription("Change the first player's spawn to your current position.") .permissions(OP_ONLY, AdminPermission.SET_FIRST_SPAWN) - .executableCommand(new SetFirstSpawnCommand()) + .executableCommand(initializer.newInstance(SetFirstSpawnCommand.class)) .build(); // Register the purge command @@ -212,7 +213,7 @@ public final class CommandInitializer { .detailedDescription("Purge old AuthMeReloaded data longer than the specified amount of days ago.") .withArgument("days", "Number of days", false) .permissions(OP_ONLY, AdminPermission.PURGE) - .executableCommand(new PurgeCommand()) + .executableCommand(initializer.newInstance(PurgeCommand.class)) .build(); // Register the purgelastposition command @@ -224,7 +225,7 @@ public final class CommandInitializer { .detailedDescription("Purge the last know position of the specified player or all of them.") .withArgument("player/*", "Player name or * for all players", false) .permissions(OP_ONLY, AdminPermission.PURGE_LAST_POSITION) - .executableCommand(new PurgeLastPositionCommand()) + .executableCommand(initializer.newInstance(PurgeLastPositionCommand.class)) .build(); // Register the purgebannedplayers command @@ -234,7 +235,7 @@ public final class CommandInitializer { .description("Purge banned players data") .detailedDescription("Purge all AuthMeReloaded data for banned players.") .permissions(OP_ONLY, AdminPermission.PURGE_BANNED_PLAYERS) - .executableCommand(new PurgeBannedPlayersCommand()) + .executableCommand(initializer.newInstance(PurgeBannedPlayersCommand.class)) .build(); // Register the switchantibot command @@ -245,7 +246,7 @@ public final class CommandInitializer { .detailedDescription("Switch or toggle the AntiBot mode to the specified state.") .withArgument("mode", "ON / OFF", true) .permissions(OP_ONLY, AdminPermission.SWITCH_ANTIBOT) - .executableCommand(new SwitchAntiBotCommand()) + .executableCommand(initializer.newInstance(SwitchAntiBotCommand.class)) .build(); // Register the reload command @@ -255,7 +256,7 @@ public final class CommandInitializer { .description("Reload plugin") .detailedDescription("Reload the AuthMeReloaded plugin.") .permissions(OP_ONLY, AdminPermission.RELOAD) - .executableCommand(new ReloadCommand()) + .executableCommand(initializer.newInstance(ReloadCommand.class)) .build(); // Register the version command @@ -265,7 +266,7 @@ public final class CommandInitializer { .description("Version info") .detailedDescription("Show detailed information about the installed AuthMeReloaded version, the " + "developers, contributors, and license.") - .executableCommand(new VersionCommand()) + .executableCommand(initializer.newInstance(VersionCommand.class)) .build(); CommandDescription.builder() @@ -276,7 +277,7 @@ public final class CommandInitializer { .withArgument("job", "Conversion job: xauth / crazylogin / rakamak / " + "royalauth / vauth / sqlitetosql", false) .permissions(OP_ONLY, AdminPermission.CONVERTER) - .executableCommand(new ConverterCommand()) + .executableCommand(initializer.newInstance(ConverterCommand.class)) .build(); // Register the base login command @@ -287,7 +288,7 @@ public final class CommandInitializer { .detailedDescription("Command to log in using AuthMeReloaded.") .withArgument("password", "Login password", false) .permissions(ALLOWED, PlayerPermission.LOGIN) - .executableCommand(new LoginCommand()) + .executableCommand(initializer.newInstance(LoginCommand.class)) .build(); // Register the base logout command @@ -297,7 +298,7 @@ public final class CommandInitializer { .description("Logout command") .detailedDescription("Command to logout using AuthMeReloaded.") .permissions(ALLOWED, PlayerPermission.LOGOUT) - .executableCommand(new LogoutCommand()) + .executableCommand(initializer.newInstance(LogoutCommand.class)) .build(); // Register the base register command @@ -309,7 +310,7 @@ public final class CommandInitializer { .withArgument("password", "Password", true) .withArgument("verifyPassword", "Verify password", true) .permissions(ALLOWED, PlayerPermission.REGISTER) - .executableCommand(new RegisterCommand()) + .executableCommand(initializer.newInstance(RegisterCommand.class)) .build(); // Register the base unregister command @@ -320,7 +321,7 @@ public final class CommandInitializer { .detailedDescription("Command to unregister using AuthMeReloaded.") .withArgument("password", "Password", false) .permissions(ALLOWED, PlayerPermission.UNREGISTER) - .executableCommand(new UnregisterCommand()) + .executableCommand(initializer.newInstance(UnregisterCommand.class)) .build(); // Register the base changepassword command @@ -332,7 +333,7 @@ public final class CommandInitializer { .withArgument("oldPassword", "Old Password", false) .withArgument("newPassword", "New Password.", false) .permissions(ALLOWED, PlayerPermission.CHANGE_PASSWORD) - .executableCommand(new ChangePasswordCommand()) + .executableCommand(initializer.newInstance(ChangePasswordCommand.class)) .build(); // Register the base Email command @@ -341,7 +342,7 @@ public final class CommandInitializer { .labels("email", "mail") .description("Email command") .detailedDescription("The AuthMeReloaded Email command base.") - .executableCommand(new EmailBaseCommand()) + .executableCommand(initializer.newInstance(EmailBaseCommand.class)) .build(); // Register the add command @@ -353,7 +354,7 @@ public final class CommandInitializer { .withArgument("email", "Email address", false) .withArgument("verifyEmail", "Email address verification", false) .permissions(ALLOWED, PlayerPermission.ADD_EMAIL) - .executableCommand(new AddEmailCommand()) + .executableCommand(initializer.newInstance(AddEmailCommand.class)) .build(); // Register the change command @@ -365,7 +366,7 @@ public final class CommandInitializer { .withArgument("oldEmail", "Old email address", false) .withArgument("newEmail", "New email address", false) .permissions(ALLOWED, PlayerPermission.CHANGE_EMAIL) - .executableCommand(new ChangeEmailCommand()) + .executableCommand(initializer.newInstance(ChangeEmailCommand.class)) .build(); // Register the recover command @@ -377,7 +378,7 @@ public final class CommandInitializer { "a new password.") .withArgument("email", "Email address", false) .permissions(ALLOWED, PlayerPermission.RECOVER_EMAIL) - .executableCommand(new RecoverEmailCommand()) + .executableCommand(initializer.newInstance(RecoverEmailCommand.class)) .build(); // Register the base captcha command @@ -388,7 +389,7 @@ public final class CommandInitializer { .detailedDescription("Captcha command for AuthMeReloaded.") .withArgument("captcha", "The Captcha", false) .permissions(ALLOWED, PlayerPermission.CAPTCHA) - .executableCommand(new CaptchaCommand()) + .executableCommand(initializer.newInstance(CaptchaCommand.class)) .build(); Set baseCommands = ImmutableSet.of( @@ -401,7 +402,7 @@ public final class CommandInitializer { EMAIL_BASE, CAPTCHA_BASE); - setHelpOnAllBases(baseCommands); + setHelpOnAllBases(baseCommands, initializer); return baseCommands; } @@ -409,9 +410,11 @@ public final class CommandInitializer { * Set the help command on all base commands, e.g. to register /authme help or /register help. * * @param commands The list of base commands to register a help child command on + * @param initializer The service initializer */ - private static void setHelpOnAllBases(Collection commands) { - final HelpCommand helpCommandExecutable = new HelpCommand(); + private static void setHelpOnAllBases(Collection commands, + AuthMeServiceInitializer initializer) { + final HelpCommand helpCommandExecutable = initializer.newInstance(HelpCommand.class); final List helpCommandLabels = Arrays.asList("help", "hlp", "h", "sos", "?"); for (CommandDescription base : commands) { diff --git a/src/main/java/fr/xephi/authme/command/CommandMapper.java b/src/main/java/fr/xephi/authme/command/CommandMapper.java index e43ee4bb..18473b28 100644 --- a/src/main/java/fr/xephi/authme/command/CommandMapper.java +++ b/src/main/java/fr/xephi/authme/command/CommandMapper.java @@ -1,11 +1,13 @@ package fr.xephi.authme.command; import fr.xephi.authme.command.executable.HelpCommand; +import fr.xephi.authme.initialization.BaseCommands; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.StringUtils; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -28,7 +30,8 @@ public class CommandMapper { private final Set baseCommands; private final PermissionsManager permissionsManager; - public CommandMapper(Set baseCommands, PermissionsManager permissionsManager) { + @Inject + public CommandMapper(@BaseCommands Set baseCommands, PermissionsManager permissionsManager) { this.baseCommands = baseCommands; this.permissionsManager = permissionsManager; } diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 5c5abfcc..95ddb563 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -1,10 +1,7 @@ package fr.xephi.authme.command; -import fr.xephi.authme.AntiBot; import fr.xephi.authme.AuthMe; -import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.help.HelpProvider; -import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; @@ -19,6 +16,7 @@ import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.util.Collection; import java.util.List; @@ -28,39 +26,28 @@ import java.util.List; */ public class CommandService { - private final AuthMe authMe; - private final Messages messages; - private final HelpProvider helpProvider; - private final CommandMapper commandMapper; - private final PasswordSecurity passwordSecurity; - private final PermissionsManager permissionsManager; - private final NewSetting settings; - private final PluginHooks pluginHooks; - private final SpawnLoader spawnLoader; - private final AntiBot antiBot; - private final ValidationService validationService; - private final BukkitService bukkitService; - - /* - * Constructor. - */ - public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages, - PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, - ValidationService validationService, BukkitService bukkitService) { - this.authMe = authMe; - this.messages = messages; - this.helpProvider = helpProvider; - this.commandMapper = commandMapper; - this.passwordSecurity = passwordSecurity; - this.permissionsManager = permissionsManager; - this.settings = settings; - this.pluginHooks = pluginHooks; - this.spawnLoader = spawnLoader; - this.antiBot = antiBot; - this.validationService = validationService; - this.bukkitService = bukkitService; - } + @Inject + private AuthMe authMe; + @Inject + private Messages messages; + @Inject + private HelpProvider helpProvider; + @Inject + private CommandMapper commandMapper; + @Inject + private PasswordSecurity passwordSecurity; + @Inject + private PermissionsManager permissionsManager; + @Inject + private NewSetting settings; + @Inject + private PluginHooks pluginHooks; + @Inject + private SpawnLoader spawnLoader; + @Inject + private ValidationService validationService; + @Inject + private BukkitService bukkitService; /** * Send a message to a player. @@ -103,15 +90,6 @@ public class CommandService { authMe.getServer().getScheduler().runTaskAsynchronously(authMe, task); } - /** - * Return the AuthMe data source. - * - * @return The used data source - */ - public DataSource getDataSource() { - return authMe.getDataSource(); - } - /** * Return the AuthMe instance for further manipulation. Use only if other methods from * the command service cannot be used. @@ -122,15 +100,6 @@ public class CommandService { return authMe; } - /** - * Return the PasswordSecurity instance. - * - * @return The password security instance - */ - public PasswordSecurity getPasswordSecurity() { - return passwordSecurity; - } - /** * Output the help for a given command. * @@ -193,10 +162,6 @@ public class CommandService { return settings; } - public PlayerCache getPlayerCache() { - return PlayerCache.getInstance(); - } - public PluginHooks getPluginHooks() { return pluginHooks; } @@ -205,10 +170,6 @@ public class CommandService { return spawnLoader; } - public AntiBot getAntiBot() { - return antiBot; - } - /** * Verifies whether a password is valid according to the plugin settings. * diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java index d3698cfd..ad5bf9b2 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java @@ -3,10 +3,13 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.cache.auth.PlayerAuth; 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.output.Messages; import fr.xephi.authme.util.StringUtils; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.List; /** @@ -14,6 +17,11 @@ import java.util.List; */ public class AccountsCommand implements ExecutableCommand { + @Inject + private DataSource dataSource; + @Inject + private Messages messages; + @Override public void executeCommand(final CommandSender sender, List arguments, final CommandService commandService) { @@ -24,15 +32,15 @@ public class AccountsCommand implements ExecutableCommand { commandService.runTaskAsynchronously(new Runnable() { @Override public void run() { - PlayerAuth auth = commandService.getDataSource().getAuth(playerName.toLowerCase()); + PlayerAuth auth = dataSource.getAuth(playerName.toLowerCase()); if (auth == null) { - commandService.send(sender, MessageKey.UNKNOWN_USER); + messages.send(sender, MessageKey.UNKNOWN_USER); return; } - List accountList = commandService.getDataSource().getAllAuthsByIp(auth.getIp()); + List accountList = dataSource.getAllAuthsByIp(auth.getIp()); if (accountList.isEmpty()) { - commandService.send(sender, MessageKey.USER_NOT_REGISTERED); + messages.send(sender, MessageKey.USER_NOT_REGISTERED); } else if (accountList.size() == 1) { sender.sendMessage("[AuthMe] " + playerName + " is a single account player"); } else { @@ -44,7 +52,7 @@ public class AccountsCommand implements ExecutableCommand { commandService.runTaskAsynchronously(new Runnable() { @Override public void run() { - List accountList = commandService.getDataSource().getAllAuthsByIp(playerName); + List accountList = dataSource.getAllAuthsByIp(playerName); if (accountList.isEmpty()) { sender.sendMessage("[AuthMe] This IP does not exist in the database."); } else if (accountList.size() == 1) { 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 867443ed..f81ac07f 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 @@ -2,13 +2,16 @@ package fr.xephi.authme.command.executable.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.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.List; /** @@ -16,6 +19,15 @@ import java.util.List; */ public class ChangePasswordAdminCommand implements ExecutableCommand { + @Inject + private PasswordSecurity passwordSecurity; + + @Inject + private PlayerCache playerCache; + + @Inject + private DataSource dataSource; + @Override public void executeCommand(final CommandSender sender, List arguments, final CommandService commandService) { @@ -36,10 +48,9 @@ public class ChangePasswordAdminCommand implements ExecutableCommand { @Override public void run() { - DataSource dataSource = commandService.getDataSource(); PlayerAuth auth = null; - if (commandService.getPlayerCache().isAuthenticated(playerNameLowerCase)) { - auth = commandService.getPlayerCache().getAuth(playerNameLowerCase); + if (playerCache.isAuthenticated(playerNameLowerCase)) { + auth = playerCache.getAuth(playerNameLowerCase); } else if (dataSource.isAuthAvailable(playerNameLowerCase)) { auth = dataSource.getAuth(playerNameLowerCase); } @@ -48,8 +59,7 @@ public class ChangePasswordAdminCommand implements ExecutableCommand { return; } - HashedPassword hashedPassword = commandService.getPasswordSecurity() - .computeHash(playerPass, playerNameLowerCase); + HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase); auth.setPassword(hashedPassword); if (!dataSource.updatePassword(auth)) { diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java index 53a3051c..ede9a424 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java @@ -3,9 +3,11 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.cache.auth.PlayerAuth; 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 org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.List; /** @@ -13,11 +15,14 @@ import java.util.List; */ public class GetEmailCommand implements ExecutableCommand { + @Inject + private DataSource dataSource; + @Override public void executeCommand(CommandSender sender, List arguments, CommandService commandService) { String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - PlayerAuth auth = commandService.getDataSource().getAuth(playerName); + PlayerAuth auth = dataSource.getAuth(playerName); if (auth == null) { commandService.send(sender, MessageKey.UNKNOWN_USER); } else { diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java index 05fdab2b..4f0135a2 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java @@ -3,9 +3,11 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.cache.auth.PlayerAuth; 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 org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.Date; import java.util.List; @@ -14,12 +16,15 @@ import java.util.List; */ public class LastLoginCommand implements ExecutableCommand { + @Inject + private DataSource dataSource; + @Override public void executeCommand(CommandSender sender, List arguments, CommandService commandService) { // Get the player String playerName = (arguments.size() >= 1) ? arguments.get(0) : sender.getName(); - PlayerAuth auth = commandService.getDataSource().getAuth(playerName); + PlayerAuth auth = dataSource.getAuth(playerName); if (auth == null) { commandService.send(sender, MessageKey.USER_NOT_REGISTERED); return; 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 0ace9424..99535027 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 @@ -3,10 +3,12 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.settings.properties.PurgeSettings; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @@ -16,6 +18,9 @@ import java.util.List; */ public class PurgeBannedPlayersCommand implements ExecutableCommand { + @Inject + private DataSource dataSource; + @Override public void executeCommand(CommandSender sender, List arguments, CommandService commandService) { // AuthMe plugin instance @@ -23,12 +28,12 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand { // Get the list of banned players List bannedPlayers = new ArrayList<>(); - for (OfflinePlayer offlinePlayer : plugin.getServer().getBannedPlayers()) { + for (OfflinePlayer offlinePlayer : commandService.getBukkitService().getBannedPlayers()) { bannedPlayers.add(offlinePlayer.getName().toLowerCase()); } // Purge the banned players - commandService.getDataSource().purgeBanned(bannedPlayers); + dataSource.purgeBanned(bannedPlayers); if (commandService.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES) && commandService.getPluginHooks().isEssentialsAvailable()) plugin.dataManager.purgeEssentials(bannedPlayers); 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 43e1daa5..51ca6df1 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 @@ -3,10 +3,12 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.settings.properties.PurgeSettings; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.Calendar; import java.util.List; @@ -18,6 +20,9 @@ public class PurgeCommand implements ExecutableCommand { private static final int MINIMUM_LAST_SEEN_DAYS = 30; + @Inject + private DataSource dataSource; + @Override public void executeCommand(CommandSender sender, List arguments, CommandService commandService) { // Get the days parameter @@ -45,7 +50,7 @@ public class PurgeCommand implements ExecutableCommand { long until = calendar.getTimeInMillis(); // Purge the data, get the purged values - List purged = commandService.getDataSource().autoPurgeDatabase(until); + List purged = dataSource.autoPurgeDatabase(until); // Show a status message sender.sendMessage(ChatColor.GOLD + "Deleted " + purged.size() + " user accounts"); diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java index 118f8460..7c88df86 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java @@ -3,9 +3,11 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.cache.auth.PlayerAuth; 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 org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.List; /** @@ -13,26 +15,29 @@ import java.util.List; */ public class PurgeLastPositionCommand implements ExecutableCommand { + @Inject + private DataSource dataSource; + @Override public void executeCommand(final CommandSender sender, List arguments, CommandService commandService) { String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); if ("*".equals(playerName)) { - for (PlayerAuth auth : commandService.getDataSource().getAllAuths()) { + for (PlayerAuth auth : dataSource.getAllAuths()) { resetLastPosition(auth); - commandService.getDataSource().updateQuitLoc(auth); + dataSource.updateQuitLoc(auth); } sender.sendMessage("All players last position locations are now reset"); } else { // Get the user auth and make sure the user exists - PlayerAuth auth = commandService.getDataSource().getAuth(playerName); + PlayerAuth auth = dataSource.getAuth(playerName); if (auth == null) { commandService.send(sender, MessageKey.UNKNOWN_USER); return; } resetLastPosition(auth); - commandService.getDataSource().updateQuitLoc(auth); + dataSource.updateQuitLoc(auth); sender.sendMessage(playerName + "'s last position location is now reset"); } } 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 2c842aee..5ddd0b95 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 @@ -1,22 +1,30 @@ package fr.xephi.authme.command.executable.authme; -import java.util.List; - -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; 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.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import javax.inject.Inject; +import java.util.List; /** * Admin command to register a user. */ public class RegisterAdminCommand implements ExecutableCommand { + @Inject + private PasswordSecurity passwordSecurity; + + @Inject + private DataSource dataSource; + @Override public void executeCommand(final CommandSender sender, List arguments, final CommandService commandService) { @@ -36,33 +44,31 @@ public class RegisterAdminCommand implements ExecutableCommand { @Override public void run() { - if (commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) { + if (dataSource.isAuthAvailable(playerNameLowerCase)) { commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED); return; } - HashedPassword hashedPassword = commandService.getPasswordSecurity() - .computeHash(playerPass, playerNameLowerCase); + HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase); PlayerAuth auth = PlayerAuth.builder() .name(playerNameLowerCase) .realName(playerName) .password(hashedPassword) .build(); - if (!commandService.getDataSource().saveAuth(auth)) { + if (!dataSource.saveAuth(auth)) { commandService.send(sender, MessageKey.ERROR); return; } - commandService.getDataSource().setUnlogged(playerNameLowerCase); + dataSource.setUnlogged(playerNameLowerCase); commandService.send(sender, MessageKey.REGISTER_SUCCESS); ConsoleLogger.info(sender.getName() + " registered " + playerName); - Player player = commandService.getPlayer(playerName); + final Player player = commandService.getPlayer(playerName); if (player != null) { - final Player p = player; - p.getServer().getScheduler().scheduleSyncDelayedTask(commandService.getAuthMe(), new Runnable() { + commandService.getBukkitService().scheduleSyncDelayedTask(new Runnable() { @Override public void run() { - p.kickPlayer("An admin just registered you, please log in again"); + player.kickPlayer("An admin just registered you, please log in again"); } }); } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java index 0e7bcf35..989c7210 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java @@ -8,6 +8,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.List; /** @@ -15,6 +16,12 @@ import java.util.List; */ public class SetEmailCommand implements ExecutableCommand { + @Inject + private DataSource dataSource; + + @Inject + private PlayerCache playerCache; + @Override public void executeCommand(final CommandSender sender, List arguments, final CommandService commandService) { @@ -32,7 +39,6 @@ public class SetEmailCommand implements ExecutableCommand { @Override public void run() { // Validate the user - DataSource dataSource = commandService.getDataSource(); PlayerAuth auth = dataSource.getAuth(playerName); if (auth == null) { commandService.send(sender, MessageKey.UNKNOWN_USER); @@ -50,8 +56,8 @@ public class SetEmailCommand implements ExecutableCommand { } // Update the player cache - if (PlayerCache.getInstance().getAuth(playerName) != null) { - PlayerCache.getInstance().updatePlayer(auth); + if (playerCache.getAuth(playerName) != null) { + playerCache.updatePlayer(auth); } // Show a status message diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommand.java index 3c36c169..e996e6f0 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommand.java @@ -8,6 +8,7 @@ import fr.xephi.authme.command.help.HelpProvider; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.Arrays; import java.util.List; @@ -16,9 +17,11 @@ import java.util.List; */ public class SwitchAntiBotCommand implements ExecutableCommand { + @Inject + private AntiBot antiBot; + @Override public void executeCommand(final CommandSender sender, List arguments, CommandService commandService) { - AntiBot antiBot = commandService.getAntiBot(); if (arguments.isEmpty()) { sender.sendMessage("[AuthMe] AntiBot status: " + antiBot.getAntiBotStatus().name()); return; 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 5c8196dd..c69f9aff 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 @@ -6,6 +6,7 @@ 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.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; @@ -19,6 +20,7 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitTask; +import javax.inject.Inject; import java.util.List; import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND; @@ -28,6 +30,12 @@ import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND; */ public class UnregisterAdminCommand implements ExecutableCommand { + @Inject + private DataSource dataSource; + + @Inject + private PlayerCache playerCache; + @Override public void executeCommand(final CommandSender sender, List arguments, CommandService commandService) { // Get the player name @@ -35,20 +43,20 @@ public class UnregisterAdminCommand implements ExecutableCommand { String playerNameLowerCase = playerName.toLowerCase(); // Make sure the user is valid - if (!commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) { + if (!dataSource.isAuthAvailable(playerNameLowerCase)) { commandService.send(sender, MessageKey.UNKNOWN_USER); return; } // Remove the player - if (!commandService.getDataSource().removeAuth(playerNameLowerCase)) { + if (!dataSource.removeAuth(playerNameLowerCase)) { commandService.send(sender, MessageKey.ERROR); return; } // Unregister the player Player target = commandService.getPlayer(playerNameLowerCase); - PlayerCache.getInstance().removePlayer(playerNameLowerCase); + playerCache.removePlayer(playerNameLowerCase); Utils.setGroup(target, Utils.GroupType.UNREGISTERED); if (target != null && target.isOnline()) { if (commandService.getProperty(RegistrationSettings.FORCE)) { 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 7d378ca8..67df2d86 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 @@ -8,6 +8,7 @@ import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.task.ChangePasswordTask; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.util.List; /** @@ -15,13 +16,15 @@ import java.util.List; */ public class ChangePasswordCommand extends PlayerCommand { + @Inject + private PlayerCache playerCache; + @Override public void runCommand(Player player, List arguments, CommandService commandService) { String oldPassword = arguments.get(0); String newPassword = arguments.get(1); String name = player.getName().toLowerCase(); - final PlayerCache playerCache = commandService.getPlayerCache(); if (!playerCache.isAuthenticated(name)) { commandService.send(player, MessageKey.NOT_LOGGED_IN); return; 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 f4a319a5..56fb5e5c 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 @@ -8,16 +8,27 @@ import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.datasource.DataSource; 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; import java.util.List; public class RecoverEmailCommand extends PlayerCommand { + @Inject + private PasswordSecurity passwordSecurity; + + @Inject + private DataSource dataSource; + + @Inject + private PlayerCache playerCache; + @Override public void runCommand(Player player, List arguments, CommandService commandService) { final String playerMail = arguments.get(0); @@ -29,7 +40,6 @@ public class RecoverEmailCommand extends PlayerCommand { commandService.send(player, MessageKey.ERROR); return; } - DataSource dataSource = commandService.getDataSource(); if (dataSource.isAuthAvailable(playerName)) { if (PlayerCache.getInstance().isAuthenticated(playerName)) { commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); @@ -37,10 +47,10 @@ public class RecoverEmailCommand extends PlayerCommand { } String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH)); - HashedPassword hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName); + HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName); PlayerAuth auth; - if (PlayerCache.getInstance().isAuthenticated(playerName)) { - auth = PlayerCache.getInstance().getAuth(playerName); + if (playerCache.isAuthenticated(playerName)) { + auth = playerCache.getAuth(playerName); } else if (dataSource.isAuthAvailable(playerName)) { auth = dataSource.getAuth(playerName); } else { 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 7bc06f03..c5a3ec5f 100644 --- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java +++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java @@ -10,10 +10,13 @@ import fr.xephi.authme.command.FoundCommandResult; 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.properties.PluginSettings; import fr.xephi.authme.util.CollectionUtils; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @@ -45,9 +48,10 @@ public class HelpProvider { private final PermissionsManager permissionsManager; private final String helpHeader; - public HelpProvider(PermissionsManager permissionsManager, String helpHeader) { + @Inject + public HelpProvider(PermissionsManager permissionsManager, NewSetting settings) { this.permissionsManager = permissionsManager; - this.helpHeader = helpHeader; + this.helpHeader = settings.getProperty(PluginSettings.HELP_HEADER); } public List printHelp(CommandSender sender, FoundCommandResult result, int options) { diff --git a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java index fd455bb1..76f8e034 100644 --- a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java +++ b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java @@ -1,19 +1,18 @@ package fr.xephi.authme.hooks; -import java.io.File; - +import com.earth2me.essentials.Essentials; +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorldManager; +import fr.xephi.authme.ConsoleLogger; +import net.minelink.ctplus.CombatTagPlus; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; -import com.earth2me.essentials.Essentials; -import com.onarandombox.MultiverseCore.MultiverseCore; -import com.onarandombox.MultiverseCore.api.MVWorldManager; - -import fr.xephi.authme.ConsoleLogger; -import net.minelink.ctplus.CombatTagPlus; +import javax.inject.Inject; +import java.io.File; /** * Hooks into third-party plugins and allows to perform actions on them. @@ -30,6 +29,7 @@ public class PluginHooks { * * @param pluginManager The server's plugin manager */ + @Inject public PluginHooks(PluginManager pluginManager) { this.pluginManager = pluginManager; tryHookToCombatPlus(); @@ -77,13 +77,23 @@ public class PluginHooks { return null; } + /** + * Checks whether the player is an NPC. + * + * @param player The player to process + * @return True if player is NPC, false otherwise + */ + public boolean isNpc(Player player) { + return player.hasMetadata("NPC") || isNpcInCombatTagPlus(player); + } + /** * Query the CombatTagPlus plugin whether the given player is an NPC. * * @param player The player to verify * @return True if the player is an NPC according to CombatTagPlus, false if not or if the plugin is unavailable */ - public boolean isNpcInCombatTagPlus(Player player) { + private boolean isNpcInCombatTagPlus(Player player) { return combatTagPlus != null && combatTagPlus.getNpcPlayerHelper().isNpc(player); } diff --git a/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java new file mode 100644 index 00000000..c2241c11 --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java @@ -0,0 +1,263 @@ +package fr.xephi.authme.initialization; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; + +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 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 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 or the value associated with an annotation, + * 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; + } + + /** + * Instantiates the given class by locating an @Inject constructor and retrieving + * or instantiating its parameters. + * + * @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)); + 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); + executePostConstructMethods(object); + return object; + } + + /** + * Resolves the dependencies for the given constructor, i.e. returns a collection that satisfy + * the constructor's parameter types 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) { + 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; + } else { + values[i] = get(dependencies[i], traversedClasses); + } + } + 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."); + } + + private static void executePostConstructMethods(Object object) { + for (Method method : object.getClass().getDeclaredMethods()) { + if (method.isAnnotationPresent(PostConstruct.class)) { + if (method.getParameterTypes().length == 0 && !Modifier.isStatic(method.getModifiers())) { + try { + method.setAccessible(true); + method.invoke(object); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new UnsupportedOperationException(e); + } + } else { + throw new IllegalStateException(String.format("@PostConstruct methods may not be static or have " + + " any parameters. Method '%s' of class '%s' is either static or has parameters", + method.getName(), object.getClass().getSimpleName())); + } + } + } + } + + private static void validateInstantiable(Class clazz) { + if (clazz.isEnum() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { + throw new IllegalStateException("Class " + clazz.getSimpleName() + " cannot be instantiated"); + } + } + + @SafeVarargs + private static Injection firstNotNull(Provider>... providers) { + for (Provider> provider : providers) { + Injection object = provider.get(); + if (object != null) { + return object; + } + } + return null; + } +} diff --git a/src/main/java/fr/xephi/authme/initialization/BaseCommands.java b/src/main/java/fr/xephi/authme/initialization/BaseCommands.java new file mode 100644 index 00000000..8ff263ab --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/BaseCommands.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to denote the collection of AuthMe commands. + */ +@Target({ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface BaseCommands { +} diff --git a/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java new file mode 100644 index 00000000..e80ea128 --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java @@ -0,0 +1,86 @@ +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. + */ +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/DataFolder.java b/src/main/java/fr/xephi/authme/initialization/DataFolder.java new file mode 100644 index 00000000..0288f45a --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/DataFolder.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for specifying the plugin's data folder. + */ +@Target({ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface DataFolder { +} diff --git a/src/main/java/fr/xephi/authme/initialization/FieldInjection.java b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java new file mode 100644 index 00000000..1e7973e2 --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java @@ -0,0 +1,127 @@ +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. + */ +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 + */ + 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 == null ? 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; + } + + 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/Injection.java b/src/main/java/fr/xephi/authme/initialization/Injection.java new file mode 100644 index 00000000..6e85b4ce --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/Injection.java @@ -0,0 +1,36 @@ +package fr.xephi.authme.initialization; + +/** + * Common interface for all injection methods. + * + * @param the type of the concerned object + */ +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/MetricsStarter.java b/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java similarity index 93% rename from src/main/java/fr/xephi/authme/MetricsStarter.java rename to src/main/java/fr/xephi/authme/initialization/MetricsStarter.java index eac9ebaf..4a163f98 100644 --- a/src/main/java/fr/xephi/authme/MetricsStarter.java +++ b/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java @@ -1,5 +1,7 @@ -package fr.xephi.authme; +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.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.PluginSettings; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index e3753793..a0fa4011 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -18,6 +18,7 @@ import fr.xephi.authme.permission.PlayerStatePermission; 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.ProtectionSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; @@ -54,6 +55,7 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerShearEntityEvent; +import javax.inject.Inject; import java.util.concurrent.ConcurrentHashMap; import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent; @@ -68,27 +70,24 @@ public class AuthMePlayerListener implements Listener { public static final ConcurrentHashMap joinMessage = new ConcurrentHashMap<>(); public static final ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap<>(); - private final AuthMe plugin; - private final NewSetting settings; - private final Messages m; - private final DataSource dataSource; - private final AntiBot antiBot; - private final Management management; - private final BukkitService bukkitService; - private final ValidationService validationService; - - public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource, - AntiBot antiBot, Management management, BukkitService bukkitService, - ValidationService validationService) { - this.plugin = plugin; - this.settings = settings; - this.m = messages; - this.dataSource = dataSource; - this.antiBot = antiBot; - this.management = management; - this.bukkitService = bukkitService; - this.validationService = validationService; - } + @Inject + private AuthMe plugin; + @Inject + private NewSetting settings; + @Inject + private Messages m; + @Inject + private DataSource dataSource; + @Inject + private AntiBot antiBot; + @Inject + private Management management; + @Inject + private BukkitService bukkitService; + @Inject + private SpawnLoader spawnLoader; + @Inject + private ValidationService validationService; private void handleChat(AsyncPlayerChatEvent event) { if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) { @@ -205,7 +204,7 @@ public class AuthMePlayerListener implements Listener { return; } - Location spawn = plugin.getSpawnLocation(player); + Location spawn = spawnLoader.getSpawnLocation(player); if (spawn != null && spawn.getWorld() != null) { if (!player.getWorld().equals(spawn.getWorld())) { player.teleport(spawn); @@ -513,7 +512,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - Location spawn = plugin.getSpawnLocation(player); + Location spawn = spawnLoader.getSpawnLocation(player); if (Settings.isSaveQuitLocationEnabled && dataSource.isAuthAvailable(name)) { PlayerAuth auth = PlayerAuth.builder() .name(name) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java index 5e6525bb..8be48ba2 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java @@ -7,16 +7,17 @@ import org.spigotmc.event.player.PlayerSpawnLocationEvent; import fr.xephi.authme.AuthMe; +import javax.inject.Inject; + /** * Listener of player events for events introduced in Minecraft 1.9. */ public class AuthMePlayerListener19 implements Listener { - private final AuthMe plugin; + @Inject + private AuthMe plugin; - public AuthMePlayerListener19(AuthMe plugin) { - this.plugin = plugin; - } + public AuthMePlayerListener19() { } @EventHandler(priority = EventPriority.LOWEST) public void onPlayerSpawn(PlayerSpawnLocationEvent event) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index 96f5320a..bb85374d 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -16,26 +16,24 @@ 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 { - private final AuthMe plugin; - private final Messages messages; - private final NewSetting settings; - private final PluginHooks pluginHooks; - private final SpawnLoader spawnLoader; - private final ValidationService validationService; - - public AuthMeServerListener(AuthMe plugin, Messages messages, NewSetting settings, PluginHooks pluginHooks, - SpawnLoader spawnLoader, ValidationService validationService) { - this.plugin = plugin; - this.messages = messages; - this.settings = settings; - this.pluginHooks = pluginHooks; - this.spawnLoader = spawnLoader; - this.validationService = validationService; - } + @Inject + private AuthMe plugin; + @Inject + private Messages messages; + @Inject + private NewSetting settings; + @Inject + private PluginHooks pluginHooks; + @Inject + private SpawnLoader spawnLoader; + @Inject + private ValidationService validationService; @EventHandler(priority = EventPriority.HIGHEST) public void onServerPing(ServerListPingEvent event) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java index d8266985..ae6c47bc 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java @@ -11,8 +11,11 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; +import javax.inject.Inject; + public class AuthMeTabCompletePacketAdapter extends PacketAdapter { + @Inject public AuthMeTabCompletePacketAdapter(AuthMe plugin) { super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index 6d4ea8ba..17b4a60a 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -14,14 +14,13 @@ 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; @@ -30,6 +29,7 @@ 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; diff --git a/src/main/java/fr/xephi/authme/ImageGenerator.java b/src/main/java/fr/xephi/authme/mail/ImageGenerator.java similarity index 88% rename from src/main/java/fr/xephi/authme/ImageGenerator.java rename to src/main/java/fr/xephi/authme/mail/ImageGenerator.java index e529efab..77d98901 100644 --- a/src/main/java/fr/xephi/authme/ImageGenerator.java +++ b/src/main/java/fr/xephi/authme/mail/ImageGenerator.java @@ -1,6 +1,9 @@ -package fr.xephi.authme; +package fr.xephi.authme.mail; -import java.awt.*; +import java.awt.Color; +import java.awt.Font; +import java.awt.GradientPaint; +import java.awt.Graphics2D; import java.awt.image.BufferedImage; /** diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java index c80001c3..d8332602 100644 --- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java +++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java @@ -2,7 +2,6 @@ package fr.xephi.authme.mail; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.ImageGenerator; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.EmailSettings; diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index ee27f82c..7dfcd40c 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -2,6 +2,7 @@ package fr.xephi.authme.permission; import de.bananaco.bpermissions.api.ApiLayer; import de.bananaco.bpermissions.api.CalculableType; +import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.util.CollectionUtils; import net.milkbowl.vault.permission.Permission; @@ -20,11 +21,12 @@ import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; import ru.tehkode.permissions.PermissionUser; import ru.tehkode.permissions.bukkit.PermissionsEx; +import javax.annotation.PostConstruct; +import javax.inject.Inject; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.logging.Logger; /** *

@@ -48,10 +50,7 @@ public class PermissionsManager implements PermissionsService { * Server instance. */ private final Server server; - /** - * Logger instance. - */ - private Logger log; + private final PluginManager pluginManager; /** * Type of permissions system that is currently used. * Null if no permissions system is hooked and/or used. @@ -70,11 +69,11 @@ public class PermissionsManager implements PermissionsService { * Constructor. * * @param server Server instance - * @param log Logger */ - public PermissionsManager(Server server, Logger log) { + @Inject + public PermissionsManager(Server server, PluginManager pluginManager) { this.server = server; - this.log = log; + this.pluginManager = pluginManager; } /** @@ -100,39 +99,37 @@ public class PermissionsManager implements PermissionsService { * * @return The detected permissions system. */ + @PostConstruct public PermissionsSystemType setup() { // Force-unhook from current hooked permissions systems unhook(); - // Define the plugin manager - final PluginManager pluginManager = this.server.getPluginManager(); - // Reset used permissions system type flag permsType = null; // Loop through all the available permissions system types - for(PermissionsSystemType type : PermissionsSystemType.values()) { + 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) + if (plugin == null) continue; // Make sure the plugin is enabled before hooking - if(!plugin.isEnabled()) { - this.log.info("Not hooking into " + type.getName() + " because it's disabled!"); + if (!plugin.isEnabled()) { + ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!"); continue; } // Use the proper method to hook this plugin - switch(type) { + switch (type) { case PERMISSIONS_EX: // Get the permissions manager for PermissionsEx and make sure it isn't null - if(PermissionsEx.getPermissionManager() == null) { - this.log.info("Failed to hook into " + type.getName() + "!"); + if (PermissionsEx.getPermissionManager() == null) { + ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); continue; } @@ -146,8 +143,8 @@ public class PermissionsManager implements PermissionsService { case Z_PERMISSIONS: // Set the zPermissions service and make sure it's valid zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class); - if(zPermissionsService == null) { - this.log.info("Failed to hook into " + type.getName() + "!"); + if (zPermissionsService == null) { + ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); continue; } @@ -157,14 +154,14 @@ public class PermissionsManager implements PermissionsService { // Get the permissions provider service RegisteredServiceProvider permissionProvider = this.server.getServicesManager().getRegistration(Permission.class); if (permissionProvider == null) { - this.log.info("Failed to hook into " + type.getName() + "!"); + ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); continue; } // Get the Vault provider and make sure it's valid vaultPerms = permissionProvider.getProvider(); - if(vaultPerms == null) { - this.log.info("Not using " + type.getName() + " because it's disabled!"); + if (vaultPerms == null) { + ConsoleLogger.info("Not using " + type.getName() + " because it's disabled!"); continue; } @@ -177,19 +174,19 @@ public class PermissionsManager implements PermissionsService { this.permsType = type; // Show a success message - this.log.info("Hooked into " + type.getName() + "!"); + ConsoleLogger.info("Hooked into " + type.getName() + "!"); // Return the used permissions system type return type; } catch (Exception ex) { // An error occurred, show a warning message - this.log.info("Error while hooking into " + type.getName() + "!"); + ConsoleLogger.logException("Error while hooking into " + type.getName(), ex); } } // No recognized permissions system found, show a message and return - this.log.info("No supported permissions system found! Permissions are disabled!"); + ConsoleLogger.info("No supported permissions system found! Permissions are disabled!"); return null; } @@ -201,7 +198,7 @@ public class PermissionsManager implements PermissionsService { this.permsType = null; // Print a status message to the console - this.log.info("Unhooked from Permissions!"); + ConsoleLogger.info("Unhooked from Permissions!"); } /** @@ -232,7 +229,7 @@ public class PermissionsManager implements PermissionsService { if (pluginName.equals("PermissionsEx") || pluginName.equals("PermissionsBukkit") || pluginName.equals("bPermissions") || pluginName.equals("GroupManager") || pluginName.equals("zPermissions") || pluginName.equals("Vault")) { - this.log.info(pluginName + " plugin enabled, dynamically updating permissions hooks!"); + ConsoleLogger.info(pluginName + " plugin enabled, dynamically updating permissions hooks!"); setup(); } } @@ -251,7 +248,7 @@ public class PermissionsManager implements PermissionsService { if (pluginName.equals("PermissionsEx") || pluginName.equals("PermissionsBukkit") || pluginName.equals("bPermissions") || pluginName.equals("GroupManager") || pluginName.equals("zPermissions") || pluginName.equals("Vault")) { - this.log.info(pluginName + " plugin disabled, updating hooks!"); + ConsoleLogger.info(pluginName + " plugin disabled, updating hooks!"); setup(); } } diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java index 4b279c9a..04a0f414 100644 --- a/src/main/java/fr/xephi/authme/process/Management.java +++ b/src/main/java/fr/xephi/authme/process/Management.java @@ -3,6 +3,7 @@ package fr.xephi.authme.process; import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.process.email.AsyncAddEmail; import fr.xephi.authme.process.email.AsyncChangeEmail; import fr.xephi.authme.process.join.AsynchronousJoin; @@ -14,23 +15,26 @@ import fr.xephi.authme.process.unregister.AsynchronousUnregister; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitScheduler; +import javax.inject.Inject; + /** */ public class Management { - private final AuthMe plugin; - private final BukkitScheduler sched; - private final ProcessService processService; - private final DataSource dataSource; - private final PlayerCache playerCache; + @Inject + private AuthMe plugin; + @Inject + private BukkitScheduler sched; + @Inject + private ProcessService processService; + @Inject + private DataSource dataSource; + @Inject + private PlayerCache playerCache; + @Inject + private PluginHooks pluginHooks; - public Management(AuthMe plugin, ProcessService processService, DataSource dataSource, PlayerCache playerCache) { - this.plugin = plugin; - this.sched = this.plugin.getServer().getScheduler(); - this.processService = processService; - this.dataSource = dataSource; - this.playerCache = playerCache; - } + Management() { } public void performLogin(final Player player, final String password, final boolean forceLogin) { runTask(new AsynchronousLogin(player, password, forceLogin, plugin, dataSource, processService)); @@ -49,7 +53,7 @@ public class Management { } public void performJoin(final Player player) { - runTask(new AsynchronousJoin(player, plugin, dataSource, playerCache, processService)); + runTask(new AsynchronousJoin(player, plugin, dataSource, playerCache, pluginHooks, processService)); } public void performQuit(final Player player, final boolean isKick) { diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java index 653be156..a338cad4 100644 --- a/src/main/java/fr/xephi/authme/process/ProcessService.java +++ b/src/main/java/fr/xephi/authme/process/ProcessService.java @@ -17,6 +17,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.scheduler.BukkitTask; +import javax.inject.Inject; import java.util.Collection; /** @@ -24,29 +25,24 @@ import java.util.Collection; */ public class ProcessService { - private final NewSetting settings; - private final Messages messages; - private final AuthMe authMe; - private final DataSource dataSource; - private final PasswordSecurity passwordSecurity; - private final PluginHooks pluginHooks; - private final SpawnLoader spawnLoader; - private final ValidationService validationService; - private final BukkitService bukkitService; - - public ProcessService(NewSetting settings, Messages messages, AuthMe authMe, DataSource dataSource, - PasswordSecurity passwordSecurity, PluginHooks pluginHooks, SpawnLoader spawnLoader, - ValidationService validationService, BukkitService bukkitService) { - this.settings = settings; - this.messages = messages; - this.authMe = authMe; - this.dataSource = dataSource; - this.passwordSecurity = passwordSecurity; - this.pluginHooks = pluginHooks; - this.spawnLoader = spawnLoader; - this.validationService = validationService; - this.bukkitService = bukkitService; - } + @Inject + private NewSetting settings; + @Inject + private Messages messages; + @Inject + private AuthMe authMe; + @Inject + private DataSource dataSource; + @Inject + private PasswordSecurity passwordSecurity; + @Inject + private PluginHooks pluginHooks; + @Inject + private SpawnLoader spawnLoader; + @Inject + private ValidationService validationService; + @Inject + private BukkitService bukkitService; /** * Retrieve a property's value. 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 37b0dfbd..c9ab7159 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -9,6 +9,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.FirstSpawnTeleportEvent; import fr.xephi.authme.events.ProtectInventoryEvent; import fr.xephi.authme.events.SpawnTeleportEvent; +import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.PlayerStatePermission; @@ -45,18 +46,20 @@ public class AsynchronousJoin implements Process { private final String name; private final ProcessService service; private final PlayerCache playerCache; + private final PluginHooks pluginHooks; private final boolean disableCollisions = MethodUtils .getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null; public AsynchronousJoin(Player player, AuthMe plugin, DataSource database, PlayerCache playerCache, - ProcessService service) { + PluginHooks pluginHooks, ProcessService service) { this.player = player; this.plugin = plugin; this.database = database; this.name = player.getName().toLowerCase(); this.service = service; this.playerCache = playerCache; + this.pluginHooks = pluginHooks; } @Override @@ -190,7 +193,7 @@ public class AsynchronousJoin implements Process { player.setWalkSpeed(0.0f); } player.setNoDamageTicks(registrationTimeout); - if (plugin.getPluginHooks().isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) { + if (pluginHooks.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) { player.performCommand("motd"); } if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index 94a8abeb..4a525531 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -2,32 +2,43 @@ package fr.xephi.authme.security; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.PasswordEncryptionEvent; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; 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.properties.SecuritySettings; import org.bukkit.plugin.PluginManager; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import javax.annotation.PostConstruct; +import javax.inject.Inject; /** * Manager class for password-related operations. */ public class PasswordSecurity { - private final NewSetting settings; + @Inject + private NewSetting settings; + + @Inject + private DataSource dataSource; + + @Inject + private PluginManager pluginManager; + + @Inject + private AuthMeServiceInitializer initializer; + private HashAlgorithm algorithm; private boolean supportOldAlgorithm; - private final DataSource dataSource; - private final PluginManager pluginManager; - public PasswordSecurity(DataSource dataSource, NewSetting settings, PluginManager pluginManager) { - this.settings = settings; + /** + * Load or reload the configuration. + */ + @PostConstruct + public void reload() { this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); this.supportOldAlgorithm = settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH); - this.dataSource = dataSource; - this.pluginManager = pluginManager; } /** @@ -73,14 +84,6 @@ public class PasswordSecurity { || supportOldAlgorithm && compareWithAllEncryptionMethods(password, hashedPassword, playerLowerCase); } - /** - * Reload the configuration. - */ - public void reload() { - this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); - this.supportOldAlgorithm = settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH); - } - /** * Compare the given hash with all available encryption methods to support * the migration to a new encryption method. Upon a successful match, the password @@ -95,7 +98,7 @@ public class PasswordSecurity { private boolean compareWithAllEncryptionMethods(String password, HashedPassword hashedPassword, String playerName) { for (HashAlgorithm algorithm : HashAlgorithm.values()) { if (!HashAlgorithm.CUSTOM.equals(algorithm)) { - EncryptionMethod method = initializeEncryptionMethod(algorithm, settings); + EncryptionMethod method = initializeEncryptionMethod(algorithm); if (methodMatches(method, password, hashedPassword, playerName)) { hashPasswordForNewAlgorithm(password, playerName); return true; @@ -133,7 +136,7 @@ public class PasswordSecurity { * @return The encryption method */ private EncryptionMethod initializeEncryptionMethodWithEvent(HashAlgorithm algorithm, String playerName) { - EncryptionMethod method = initializeEncryptionMethod(algorithm, settings); + EncryptionMethod method = initializeEncryptionMethod(algorithm); PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName); pluginManager.callEvent(event); return event.getMethod(); @@ -143,30 +146,14 @@ public class PasswordSecurity { * Initialize the encryption method associated with the given hash algorithm. * * @param algorithm The algorithm to retrieve the encryption method for - * @param settings The settings instance to pass to the constructor if required * * @return The associated encryption method, or null if CUSTOM / deprecated */ - public static EncryptionMethod initializeEncryptionMethod(HashAlgorithm algorithm, - NewSetting settings) { - try { - if (HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)) { - return null; - } - Constructor constructor = algorithm.getClazz().getConstructors()[0]; - Class[] parameters = constructor.getParameterTypes(); - if (parameters.length == 0) { - return (EncryptionMethod) constructor.newInstance(); - } else if (parameters.length == 1 && parameters[0] == NewSetting.class) { - return (EncryptionMethod) constructor.newInstance(settings); - } else { - throw new UnsupportedOperationException("Did not find default constructor or constructor with settings " - + "parameter in class " + algorithm.getClazz().getSimpleName()); - } - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new UnsupportedOperationException("Constructor for '" + algorithm.getClazz().getSimpleName() - + "' could not be invoked. (Is there no default constructor?)", e); + public EncryptionMethod initializeEncryptionMethod(HashAlgorithm algorithm) { + if (HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)) { + return null; } + return initializer.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 a114adc0..67d8c794 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java +++ b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java @@ -9,13 +9,15 @@ import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.util.StringUtils; +import javax.inject.Inject; @Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8 -@HasSalt(value = SaltType.TEXT) // length depends on Settings.bCryptLog2Rounds +@HasSalt(value = SaltType.TEXT) // length depends on the bcryptLog2Rounds setting public class BCRYPT implements EncryptionMethod { private final int bCryptLog2Rounds; + @Inject public BCRYPT(NewSetting settings) { this.bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND); } 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 27066f7a..bf67432b 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java +++ b/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java @@ -8,14 +8,17 @@ import fr.xephi.authme.security.crypts.description.Usage; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.SecuritySettings; +import javax.inject.Inject; + import static fr.xephi.authme.security.HashUtils.md5; @Recommendation(Usage.ACCEPTABLE) // presuming that length is something sensible (>= 8) -@HasSalt(value = SaltType.TEXT) // length defined by Settings.saltLength +@HasSalt(value = SaltType.TEXT) // length defined by the doubleMd5SaltLength setting public class SALTED2MD5 extends SeparateSaltMethod { private final int saltLength; + @Inject public SALTED2MD5(NewSetting settings) { saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH); } diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java index 59693a98..a046d813 100644 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java @@ -4,6 +4,7 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.initialization.DataFolder; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.FileUtils; import fr.xephi.authme.util.StringUtils; @@ -14,6 +15,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.io.File; import java.io.IOException; @@ -40,7 +42,8 @@ public class SpawnLoader { * @param settings The setting instance * @param pluginHooks The plugin hooks instance */ - public SpawnLoader(File pluginFolder, NewSetting settings, PluginHooks pluginHooks) { + @Inject + public SpawnLoader(@DataFolder File pluginFolder, NewSetting settings, PluginHooks pluginHooks) { 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"); diff --git a/src/main/java/fr/xephi/authme/util/BukkitService.java b/src/main/java/fr/xephi/authme/util/BukkitService.java index ea405d80..592caa22 100644 --- a/src/main/java/fr/xephi/authme/util/BukkitService.java +++ b/src/main/java/fr/xephi/authme/util/BukkitService.java @@ -7,6 +7,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; +import javax.inject.Inject; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; @@ -28,6 +29,7 @@ public class BukkitService { private final boolean getOnlinePlayersIsCollection; private Method getOnlinePlayers; + @Inject public BukkitService(AuthMe authMe) { this.authMe = authMe; getOnlinePlayersIsCollection = initializeOnlinePlayersIsCollectionField(); diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index 5850645b..5d8c08ee 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -165,8 +165,9 @@ public final class Utils { }); } + @Deprecated public static boolean isNPC(Player player) { - return player.hasMetadata("NPC") || plugin.getPluginHooks().isNpcInCombatTagPlus(player); + return plugin.getPluginHooks().isNpc(player); } public static void teleportToSpawn(Player player) { diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java index 95dff810..999e2d1c 100644 --- a/src/main/java/fr/xephi/authme/util/ValidationService.java +++ b/src/main/java/fr/xephi/authme/util/ValidationService.java @@ -12,6 +12,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.Collection; import java.util.List; @@ -24,6 +25,7 @@ public class ValidationService { private final DataSource dataSource; private final PermissionsManager permissionsManager; + @Inject public ValidationService(NewSetting settings, DataSource dataSource, PermissionsManager permissionsManager) { this.settings = settings; this.dataSource = dataSource; diff --git a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java index 6e5418d5..7c62377f 100644 --- a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java @@ -1,10 +1,13 @@ package fr.xephi.authme.command; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; import fr.xephi.authme.permission.AdminPermission; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.util.StringUtils; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Collection; @@ -21,6 +24,9 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * Test for {@link CommandInitializer} to guarantee the integrity of the defined commands. @@ -37,7 +43,16 @@ public class CommandInitializerTest { @BeforeClass public static void initializeCommandManager() { - commands = CommandInitializer.buildCommands(); + AuthMeServiceInitializer initializer = mock(AuthMeServiceInitializer.class); + when(initializer.newInstance(any(Class.class))).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + Class clazz = (Class) invocation.getArguments()[0]; + return mock(clazz); + } + }); + + commands = CommandInitializer.buildCommands(initializer); } @Test diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index 89a35571..76685fce 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -1,9 +1,7 @@ package fr.xephi.authme.command; -import fr.xephi.authme.AntiBot; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.help.HelpProvider; -import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; @@ -18,10 +16,10 @@ import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -41,6 +39,7 @@ import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class CommandServiceTest { + @InjectMocks private CommandService commandService; @Mock private AuthMe authMe; @@ -61,18 +60,10 @@ public class CommandServiceTest { @Mock private SpawnLoader spawnLoader; @Mock - private AntiBot antiBot; - @Mock private ValidationService validationService; @Mock private BukkitService bukkitService; - @Before - public void setUpService() { - commandService = new CommandService(authMe, commandMapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService); - } - @Test public void shouldSendMessage() { // given @@ -113,28 +104,6 @@ public class CommandServiceTest { verify(commandMapper).mapPartsToCommand(sender, commandParts); } - @Test - public void shouldGetDataSource() { - // given - DataSource dataSource = mock(DataSource.class); - given(authMe.getDataSource()).willReturn(dataSource); - - // when - DataSource result = commandService.getDataSource(); - - // then - assertThat(result, equalTo(dataSource)); - } - - @Test - public void shouldGetPasswordSecurity() { - // given/when - PasswordSecurity passwordSecurity = commandService.getPasswordSecurity(); - - // then - assertThat(passwordSecurity, equalTo(this.passwordSecurity)); - } - @Test public void shouldOutputHelp() { // given diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java index 5a837280..95124658 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java @@ -4,10 +4,14 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.output.Messages; import org.bukkit.command.CommandSender; -import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.Arrays; import java.util.Collections; @@ -22,26 +26,23 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; /** * Test for {@link AccountsCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class AccountsCommandTest { + @InjectMocks private AccountsCommand command; + @Mock private CommandSender sender; + @Mock private CommandService service; + @Mock private DataSource dataSource; - - @Before - public void setUpMocks() { - command = new AccountsCommand(); - sender = mock(CommandSender.class); - dataSource = mock(DataSource.class); - service = mock(CommandService.class); - when(service.getDataSource()).thenReturn(dataSource); - } + @Mock + private Messages messages; @Test public void shouldGetAccountsOfCurrentUser() { @@ -72,7 +73,7 @@ public class AccountsCommandTest { runInnerRunnable(service); // then - verify(service).send(sender, MessageKey.UNKNOWN_USER); + verify(messages).send(sender, MessageKey.UNKNOWN_USER); verify(sender, never()).sendMessage(anyString()); } @@ -88,7 +89,7 @@ public class AccountsCommandTest { runInnerRunnable(service); // then - verify(service).send(sender, MessageKey.USER_NOT_REGISTERED); + verify(messages).send(sender, MessageKey.USER_NOT_REGISTERED); verify(sender, never()).sendMessage(anyString()); } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java index b4f42886..163bee15 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java @@ -4,7 +4,6 @@ import fr.xephi.authme.TestHelper; 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.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.PasswordSecurity; @@ -13,6 +12,7 @@ import org.bukkit.command.CommandSender; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -24,6 +24,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link ChangePasswordAdminCommand}. @@ -31,9 +32,21 @@ import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class ChangePasswordAdminCommandTest { + @InjectMocks + private ChangePasswordAdminCommand command; + @Mock private CommandService service; + @Mock + private PasswordSecurity passwordSecurity; + + @Mock + private DataSource dataSource; + + @Mock + private PlayerCache playerCache; + @BeforeClass public static void setUpLogger() { TestHelper.setupLogger(); @@ -42,7 +55,6 @@ public class ChangePasswordAdminCommandTest { @Test public void shouldRejectInvalidPassword() { // given - ExecutableCommand command = new ChangePasswordAdminCommand(); CommandSender sender = mock(CommandSender.class); given(service.validatePassword("Bobby", "bobby")).willReturn(MessageKey.PASSWORD_IS_USERNAME_ERROR); @@ -52,23 +64,16 @@ public class ChangePasswordAdminCommandTest { // then verify(service).validatePassword("Bobby", "bobby"); verify(service).send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); - verify(service, never()).getDataSource(); + verifyZeroInteractions(dataSource); } @Test public void shouldRejectCommandForUnknownUser() { // given - ExecutableCommand command = new ChangePasswordAdminCommand(); CommandSender sender = mock(CommandSender.class); String player = "player"; - - PlayerCache playerCache = mock(PlayerCache.class); given(playerCache.isAuthenticated(player)).willReturn(false); - given(service.getPlayerCache()).willReturn(playerCache); - - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(player)).willReturn(null); - given(service.getDataSource()).willReturn(dataSource); // when command.executeCommand(sender, Arrays.asList(player, "password"), service); @@ -82,26 +87,17 @@ public class ChangePasswordAdminCommandTest { @Test public void shouldUpdatePasswordOfLoggedInUser() { // given - ExecutableCommand command = new ChangePasswordAdminCommand(); CommandSender sender = mock(CommandSender.class); - String player = "my_user12"; String password = "passPass"; PlayerAuth auth = mock(PlayerAuth.class); - PlayerCache playerCache = mock(PlayerCache.class); given(playerCache.isAuthenticated(player)).willReturn(true); given(playerCache.getAuth(player)).willReturn(auth); - given(service.getPlayerCache()).willReturn(playerCache); - PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); HashedPassword hashedPassword = mock(HashedPassword.class); given(passwordSecurity.computeHash(password, player)).willReturn(hashedPassword); - given(service.getPasswordSecurity()).willReturn(passwordSecurity); - - DataSource dataSource = mock(DataSource.class); given(dataSource.updatePassword(auth)).willReturn(true); - given(service.getDataSource()).willReturn(dataSource); // when command.executeCommand(sender, Arrays.asList(player, password), service); @@ -118,27 +114,17 @@ public class ChangePasswordAdminCommandTest { @Test public void shouldUpdatePasswordOfOfflineUser() { // given - ExecutableCommand command = new ChangePasswordAdminCommand(); CommandSender sender = mock(CommandSender.class); - String player = "my_user12"; String password = "passPass"; PlayerAuth auth = mock(PlayerAuth.class); - - PlayerCache playerCache = mock(PlayerCache.class); given(playerCache.isAuthenticated(player)).willReturn(false); - given(service.getPlayerCache()).willReturn(playerCache); - - DataSource dataSource = mock(DataSource.class); given(dataSource.isAuthAvailable(player)).willReturn(true); given(dataSource.getAuth(player)).willReturn(auth); given(dataSource.updatePassword(auth)).willReturn(true); - given(service.getDataSource()).willReturn(dataSource); - PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); HashedPassword hashedPassword = mock(HashedPassword.class); given(passwordSecurity.computeHash(password, player)).willReturn(hashedPassword); - given(service.getPasswordSecurity()).willReturn(passwordSecurity); // when command.executeCommand(sender, Arrays.asList(player, password), service); @@ -155,26 +141,16 @@ public class ChangePasswordAdminCommandTest { @Test public void shouldReportWhenSaveFailed() { // given - ExecutableCommand command = new ChangePasswordAdminCommand(); CommandSender sender = mock(CommandSender.class); - String player = "my_user12"; String password = "passPass"; PlayerAuth auth = mock(PlayerAuth.class); - - PlayerCache playerCache = mock(PlayerCache.class); given(playerCache.isAuthenticated(player)).willReturn(true); given(playerCache.getAuth(player)).willReturn(auth); - given(service.getPlayerCache()).willReturn(playerCache); - PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); HashedPassword hashedPassword = mock(HashedPassword.class); given(passwordSecurity.computeHash(password, player)).willReturn(hashedPassword); - given(service.getPasswordSecurity()).willReturn(passwordSecurity); - - DataSource dataSource = mock(DataSource.class); given(dataSource.updatePassword(auth)).willReturn(false); - given(service.getDataSource()).willReturn(dataSource); // when command.executeCommand(sender, Arrays.asList(player, password), service); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java index 6d232037..f03ff426 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java @@ -2,11 +2,14 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.cache.auth.PlayerAuth; 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 org.bukkit.command.CommandSender; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.Collections; @@ -19,19 +22,26 @@ import static org.mockito.Mockito.verify; /** * Test for {@link GetEmailCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class GetEmailCommandTest { + @InjectMocks + private GetEmailCommand command; + + @Mock + private DataSource dataSource; + + @Mock + private CommandSender sender; + + @Mock + private CommandService service; + @Test public void shouldReportUnknownUser() { // given String user = "myTestUser"; - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(user)).willReturn(null); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new GetEmailCommand(); // when command.executeCommand(sender, Collections.singletonList(user), service); @@ -47,14 +57,7 @@ public class GetEmailCommandTest { String email = "user.email@example.org"; PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(email); - - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(user)).willReturn(auth); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new GetEmailCommand(); // when command.executeCommand(sender, Collections.singletonList(user), service); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java index d1e58e92..04ffabef 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java @@ -2,12 +2,15 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.cache.auth.PlayerAuth; 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 org.bukkit.command.CommandSender; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.Collections; import java.util.Date; @@ -23,8 +26,21 @@ import static org.mockito.Mockito.verify; /** * Test for {@link LastLoginCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class LastLoginCommandTest { + @InjectMocks + private LastLoginCommand command; + + @Mock + private DataSource dataSource; + + @Mock + private CommandService service; + + @Mock + private CommandSender sender; + private static final long HOUR_IN_MSEC = 3600 * 1000; private static final long DAY_IN_MSEC = 24 * HOUR_IN_MSEC; @@ -32,15 +48,8 @@ public class LastLoginCommandTest { public void shouldRejectNonExistentUser() { // given String player = "tester"; - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(player)).willReturn(null); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new LastLoginCommand(); - // when command.executeCommand(sender, Collections.singletonList(player), service); @@ -58,14 +67,7 @@ public class LastLoginCommandTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getLastLogin()).willReturn(lastLogin); given(auth.getIp()).willReturn("123.45.66.77"); - - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(player)).willReturn(auth); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new LastLoginCommand(); // when command.executeCommand(sender, Collections.singletonList(player), service); @@ -85,7 +87,6 @@ public class LastLoginCommandTest { public void shouldDisplayLastLoginOfCommandSender() { // given String name = "CommandSender"; - CommandSender sender = mock(CommandSender.class); given(sender.getName()).willReturn(name); long lastLogin = System.currentTimeMillis() - @@ -93,14 +94,7 @@ public class LastLoginCommandTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getLastLogin()).willReturn(lastLogin); given(auth.getIp()).willReturn("123.45.66.77"); - - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(name)).willReturn(auth); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - - ExecutableCommand command = new LastLoginCommand(); // when command.executeCommand(sender, Collections.emptyList(), service); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java index bcce0342..2c80a19d 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java @@ -2,11 +2,14 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.cache.auth.PlayerAuth; 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 org.bukkit.command.CommandSender; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.Arrays; import java.util.Collections; @@ -20,21 +23,27 @@ import static org.mockito.Mockito.verify; /** * Test for {@link PurgeLastPositionCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class PurgeLastPositionCommandTest { + @InjectMocks + private PurgeLastPositionCommand command; + + @Mock + private DataSource dataSource; + + @Mock + private CommandService service; + + @Mock + private CommandSender sender; + @Test public void shouldPurgeLastPosOfUser() { // given String player = "_Bobby"; PlayerAuth auth = mock(PlayerAuth.class); - - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(player)).willReturn(auth); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new PurgeLastPositionCommand(); // when command.executeCommand(sender, Collections.singletonList(player), service); @@ -51,14 +60,8 @@ public class PurgeLastPositionCommandTest { String player = "_Bobby"; CommandSender sender = mock(CommandSender.class); given(sender.getName()).willReturn(player); - PlayerAuth auth = mock(PlayerAuth.class); - DataSource dataSource = mock(DataSource.class); given(dataSource.getAuth(player)).willReturn(auth); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - ExecutableCommand command = new PurgeLastPositionCommand(); // when command.executeCommand(sender, Collections.emptyList(), service); @@ -72,12 +75,6 @@ public class PurgeLastPositionCommandTest { @Test public void shouldHandleNonExistentUser() { // given - DataSource dataSource = mock(DataSource.class); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - ExecutableCommand command = new PurgeLastPositionCommand(); - CommandSender sender = mock(CommandSender.class); String name = "invalidPlayer"; // when @@ -94,14 +91,7 @@ public class PurgeLastPositionCommandTest { PlayerAuth auth1 = mock(PlayerAuth.class); PlayerAuth auth2 = mock(PlayerAuth.class); PlayerAuth auth3 = mock(PlayerAuth.class); - - DataSource dataSource = mock(DataSource.class); given(dataSource.getAllAuths()).willReturn(Arrays.asList(auth1, auth2, auth3)); - CommandService service = mock(CommandService.class); - given(service.getDataSource()).willReturn(dataSource); - - ExecutableCommand command = new PurgeLastPositionCommand(); - CommandSender sender = mock(CommandSender.class); // when command.executeCommand(sender, Collections.singletonList("*"), service); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java index d2c7fd1e..47f4de1b 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java @@ -1,32 +1,34 @@ package fr.xephi.authme.command.executable.authme; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import java.util.Arrays; - +import fr.xephi.authme.TestHelper; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.security.PasswordSecurity; +import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.util.BukkitService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import fr.xephi.authme.TestHelper; -import fr.xephi.authme.cache.auth.PlayerAuth; -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.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; +import java.util.Arrays; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; /** * Test for {@link RegisterAdminCommand}. @@ -34,11 +36,21 @@ import fr.xephi.authme.security.crypts.HashedPassword; @RunWith(MockitoJUnitRunner.class) public class RegisterAdminCommandTest { + @InjectMocks + private RegisterAdminCommand command; + + @Mock + private PasswordSecurity passwordSecurity; + @Mock private CommandSender sender; + @Mock private CommandService commandService; + @Mock + private DataSource dataSource; + @BeforeClass public static void setUpLogger() { TestHelper.setupLogger(); @@ -50,7 +62,6 @@ public class RegisterAdminCommandTest { String user = "tester"; String password = "myPassword"; given(commandService.validatePassword(password, user)).willReturn(MessageKey.INVALID_PASSWORD_LENGTH); - ExecutableCommand command = new RegisterAdminCommand(); // when command.executeCommand(sender, Arrays.asList(user, password), commandService); @@ -67,10 +78,7 @@ public class RegisterAdminCommandTest { String user = "my_name55"; String password = "@some-pass@"; given(commandService.validatePassword(password, user)).willReturn(null); - DataSource dataSource = mock(DataSource.class); given(dataSource.isAuthAvailable(user)).willReturn(true); - given(commandService.getDataSource()).willReturn(dataSource); - ExecutableCommand command = new RegisterAdminCommand(); // when command.executeCommand(sender, Arrays.asList(user, password), commandService); @@ -88,15 +96,10 @@ public class RegisterAdminCommandTest { String user = "test-test"; String password = "afdjhfkt"; given(commandService.validatePassword(password, user)).willReturn(null); - DataSource dataSource = mock(DataSource.class); given(dataSource.isAuthAvailable(user)).willReturn(false); given(dataSource.saveAuth(any(PlayerAuth.class))).willReturn(false); - given(commandService.getDataSource()).willReturn(dataSource); - PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); HashedPassword hashedPassword = new HashedPassword("235sdf4w5udsgf"); given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); - given(commandService.getPasswordSecurity()).willReturn(passwordSecurity); - ExecutableCommand command = new RegisterAdminCommand(); // when command.executeCommand(sender, Arrays.asList(user, password), commandService); @@ -116,16 +119,11 @@ public class RegisterAdminCommandTest { String user = "someone"; String password = "Al1O3P49S5%"; given(commandService.validatePassword(password, user)).willReturn(null); - DataSource dataSource = mock(DataSource.class); given(dataSource.isAuthAvailable(user)).willReturn(false); given(dataSource.saveAuth(any(PlayerAuth.class))).willReturn(true); - given(commandService.getDataSource()).willReturn(dataSource); - PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); HashedPassword hashedPassword = new HashedPassword("$aea2345EW235dfsa@#R%987048"); given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); - given(commandService.getPasswordSecurity()).willReturn(passwordSecurity); given(commandService.getPlayer(user)).willReturn(null); - ExecutableCommand command = new RegisterAdminCommand(); // when command.executeCommand(sender, Arrays.asList(user, password), commandService); @@ -146,19 +144,19 @@ public class RegisterAdminCommandTest { String user = "someone"; String password = "Al1O3P49S5%"; given(commandService.validatePassword(password, user)).willReturn(null); - DataSource dataSource = mock(DataSource.class); given(dataSource.isAuthAvailable(user)).willReturn(false); given(dataSource.saveAuth(any(PlayerAuth.class))).willReturn(true); - given(commandService.getDataSource()).willReturn(dataSource); - PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); HashedPassword hashedPassword = new HashedPassword("$aea2345EW235dfsa@#R%987048"); given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); - given(commandService.getPasswordSecurity()).willReturn(passwordSecurity); - ExecutableCommand command = new RegisterAdminCommand(); + Player player = mock(Player.class); + given(commandService.getPlayer(user)).willReturn(player); + BukkitService bukkitService = mock(BukkitService.class); + given(commandService.getBukkitService()).willReturn(bukkitService); // when command.executeCommand(sender, Arrays.asList(user, password), commandService); TestHelper.runInnerRunnable(commandService); + runSyncDelayedTask(bukkitService); // then verify(commandService).validatePassword(password, user); @@ -167,6 +165,7 @@ public class RegisterAdminCommandTest { verify(dataSource).saveAuth(captor.capture()); assertAuthHasInfo(captor.getValue(), user, hashedPassword); verify(dataSource).setUnlogged(user); + verify(player).kickPlayer(argThat(containsString("please log in again"))); } private void assertAuthHasInfo(PlayerAuth auth, String name, HashedPassword hashedPassword) { @@ -174,4 +173,11 @@ public class RegisterAdminCommandTest { assertThat(auth.getNickname(), equalTo(name.toLowerCase())); assertThat(auth.getPassword(), equalTo(hashedPassword)); } + + private static void runSyncDelayedTask(BukkitService bukkitService) { + ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(bukkitService).scheduleSyncDelayedTask(captor.capture()); + Runnable runnable = captor.getValue(); + runnable.run(); + } } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommandTest.java index 3f9767f9..f8945a1c 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommandTest.java @@ -2,11 +2,14 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AntiBot; import fr.xephi.authme.command.CommandService; -import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.command.help.HelpProvider; import org.bukkit.command.CommandSender; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.Collections; @@ -22,17 +25,23 @@ import static org.mockito.Mockito.verify; /** * Test for {@link SwitchAntiBotCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class SwitchAntiBotCommandTest { + @InjectMocks + private SwitchAntiBotCommand command; + + @Mock + private AntiBot antiBot; + + @Mock + private CommandService service; + @Test public void shouldReturnAntiBotState() { // given - AntiBot antiBot = mock(AntiBot.class); given(antiBot.getAntiBotStatus()).willReturn(AntiBot.AntiBotStatus.ACTIVE); - CommandService service = mock(CommandService.class); - given(service.getAntiBot()).willReturn(antiBot); CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new SwitchAntiBotCommand(); // when command.executeCommand(sender, Collections.emptyList(), service); @@ -44,11 +53,7 @@ public class SwitchAntiBotCommandTest { @Test public void shouldActivateAntiBot() { // given - AntiBot antiBot = mock(AntiBot.class); - CommandService service = mock(CommandService.class); - given(service.getAntiBot()).willReturn(antiBot); CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new SwitchAntiBotCommand(); // when command.executeCommand(sender, Collections.singletonList("on"), service); @@ -61,11 +66,7 @@ public class SwitchAntiBotCommandTest { @Test public void shouldDeactivateAntiBot() { // given - AntiBot antiBot = mock(AntiBot.class); - CommandService service = mock(CommandService.class); - given(service.getAntiBot()).willReturn(antiBot); CommandSender sender = mock(CommandSender.class); - ExecutableCommand command = new SwitchAntiBotCommand(); // when command.executeCommand(sender, Collections.singletonList("Off"), service); @@ -79,15 +80,9 @@ public class SwitchAntiBotCommandTest { public void shouldShowHelpForUnknownState() { // given CommandSender sender = mock(CommandSender.class); - - AntiBot antiBot = mock(AntiBot.class); FoundCommandResult foundCommandResult = mock(FoundCommandResult.class); - CommandService service = mock(CommandService.class); - given(service.getAntiBot()).willReturn(antiBot); given(service.mapPartsToCommand(sender, asList("authme", "antibot"))).willReturn(foundCommandResult); - ExecutableCommand command = new SwitchAntiBotCommand(); - // when command.executeCommand(sender, Collections.singletonList("wrong"), service); diff --git a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java index bc8e0876..1dc4dbb1 100644 --- a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java @@ -12,7 +12,11 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.ArrayList; import java.util.Arrays; @@ -33,26 +37,31 @@ import static org.mockito.Mockito.when; /** * Test for {@link ChangePasswordCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class ChangePasswordCommandTest { + @InjectMocks + private ChangePasswordCommand command; + + @Mock + private PlayerCache playerCache; + + @Mock private CommandService commandService; @Before - public void setUpMocks() { - commandService = mock(CommandService.class); - + public void setSettings() { when(commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)).thenReturn(2); when(commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)).thenReturn(50); // Only allow passwords with alphanumerical characters for the test when(commandService.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)).thenReturn("[a-zA-Z0-9]+"); - when(commandService.getProperty(SecuritySettings.UNSAFE_PASSWORDS)).thenReturn(Collections. emptyList()); + when(commandService.getProperty(SecuritySettings.UNSAFE_PASSWORDS)).thenReturn(Collections.emptyList()); } @Test public void shouldRejectNonPlayerSender() { // given CommandSender sender = mock(BlockCommandSender.class); - ChangePasswordCommand command = new ChangePasswordCommand(); // when command.executeCommand(sender, new ArrayList(), commandService); @@ -65,7 +74,6 @@ public class ChangePasswordCommandTest { public void shouldRejectNotLoggedInPlayer() { // given CommandSender sender = initPlayerWithName("name", false); - ChangePasswordCommand command = new ChangePasswordCommand(); // when command.executeCommand(sender, Arrays.asList("pass", "pass"), commandService); @@ -78,7 +86,6 @@ public class ChangePasswordCommandTest { public void shouldRejectInvalidPassword() { // given CommandSender sender = initPlayerWithName("abc12", true); - ChangePasswordCommand command = new ChangePasswordCommand(); String password = "newPW"; given(commandService.validatePassword(password, "abc12")).willReturn(MessageKey.INVALID_PASSWORD_LENGTH); @@ -94,7 +101,6 @@ public class ChangePasswordCommandTest { public void shouldForwardTheDataForValidPassword() { // given CommandSender sender = initPlayerWithName("parker", true); - ChangePasswordCommand command = new ChangePasswordCommand(); // when command.executeCommand(sender, Arrays.asList("abc123", "abc123"), commandService); @@ -112,9 +118,7 @@ public class ChangePasswordCommandTest { private Player initPlayerWithName(String name, boolean loggedIn) { Player player = mock(Player.class); when(player.getName()).thenReturn(name); - PlayerCache playerCache = mock(PlayerCache.class); when(playerCache.isAuthenticated(name)).thenReturn(loggedIn); - when(commandService.getPlayerCache()).thenReturn(playerCache); return player; } diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java index 3ec47a4f..e7d85f14 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java @@ -6,6 +6,8 @@ import fr.xephi.authme.command.FoundResultStatus; import fr.xephi.authme.command.TestCommandsUtil; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerPermission; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.PluginSettings; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.junit.Before; @@ -52,7 +54,9 @@ public class HelpProviderTest { @Before public void setUpHelpProvider() { permissionsManager = mock(PermissionsManager.class); - helpProvider = new HelpProvider(permissionsManager, HELP_HEADER); + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(PluginSettings.HELP_HEADER)).willReturn(HELP_HEADER); + helpProvider = new HelpProvider(permissionsManager, settings); sender = mock(CommandSender.class); } diff --git a/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java b/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java new file mode 100644 index 00000000..0541c704 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java @@ -0,0 +1,234 @@ +package fr.xephi.authme.initialization; + +import fr.xephi.authme.initialization.samples.AlphaService; +import fr.xephi.authme.initialization.samples.BadFieldInjection; +import fr.xephi.authme.initialization.samples.BetaManager; +import fr.xephi.authme.initialization.samples.CircularClasses; +import fr.xephi.authme.initialization.samples.ClassWithAbstractDependency; +import fr.xephi.authme.initialization.samples.ClassWithAnnotations; +import fr.xephi.authme.initialization.samples.Duration; +import fr.xephi.authme.initialization.samples.FieldInjectionWithAnnotations; +import fr.xephi.authme.initialization.samples.InvalidClass; +import fr.xephi.authme.initialization.samples.InvalidPostConstruct; +import fr.xephi.authme.initialization.samples.InvalidStaticFieldInjection; +import fr.xephi.authme.initialization.samples.PostConstructTestClass; +import fr.xephi.authme.initialization.samples.ProvidedClass; +import fr.xephi.authme.initialization.samples.Size; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.sameInstance; +import static org.junit.Assert.assertThat; + +/** + * Test for {@link AuthMeServiceInitializer}. + */ +public class AuthMeServiceInitializerTest { + + private static final String ALLOWED_PACKAGE = "fr.xephi.authme.initialization"; + + private AuthMeServiceInitializer initializer; + + @Before + public void setInitializer() { + initializer = new AuthMeServiceInitializer(ALLOWED_PACKAGE); + initializer.register(ProvidedClass.class, new ProvidedClass("")); + } + + @Test + public void shouldInitializeElements() { + // given / when + BetaManager betaManager = initializer.get(BetaManager.class); + + // then + assertThat(betaManager, not(nullValue())); + for (Object o : betaManager.getDependencies()) { + assertThat(o, not(nullValue())); + } + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForInvalidPackage() { + // given / when / then + initializer.get(InvalidClass.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForUnregisteredPrimitiveType() { + // given / when / then + initializer.get(int.class); + } + + @Test + public void shouldPassValueByAnnotation() { + // given + int size = 12; + long duration = -15482L; + initializer.provide(Size.class, size); + initializer.provide(Duration.class, duration); + + // when + ClassWithAnnotations object = initializer.get(ClassWithAnnotations.class); + + // then + assertThat(object, not(nullValue())); + assertThat(object.getSize(), equalTo(size)); + assertThat(object.getDuration(), equalTo(duration)); + // some sample check to make sure we only have one instance of GammaService + assertThat(object.getGammaService(), equalTo(initializer.get(BetaManager.class).getDependencies()[1])); + } + + @Test(expected = RuntimeException.class) + public void shouldRecognizeCircularReferences() { + // given / when / then + initializer.get(CircularClasses.Circular3.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForUnregisteredAnnotation() { + // given + initializer.provide(Size.class, 4523); + + // when / then + initializer.get(ClassWithAnnotations.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForFieldInjectionWithNoDefaultConstructor() { + // given / when / then + initializer.get(BadFieldInjection.class); + } + + @Test + public void shouldInjectFieldsWithAnnotationsProperly() { + // given + initializer.provide(Size.class, 2809375); + initializer.provide(Duration.class, 13095L); + + // when + FieldInjectionWithAnnotations result = initializer.get(FieldInjectionWithAnnotations.class); + + // then + assertThat(result.getSize(), equalTo(2809375)); + assertThat(result.getDuration(), equalTo(13095L)); + assertThat(result.getBetaManager(), not(nullValue())); + assertThat(result.getClassWithAnnotations(), not(nullValue())); + assertThat(result.getClassWithAnnotations().getGammaService(), + equalTo(result.getBetaManager().getDependencies()[1])); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForAnnotationAsKey() { + // given / when / then + initializer.get(Size.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForSecondRegistration() { + // given / when / then + initializer.register(ProvidedClass.class, new ProvidedClass("")); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForSecondAnnotationRegistration() { + // given + initializer.provide(Size.class, 12); + + // when / then + initializer.provide(Size.class, -8); + } + + @Test(expected = NullPointerException.class) + public void shouldThrowForNullValueAssociatedToAnnotation() { + // given / when / then + initializer.provide(Duration.class, null); + } + + @Test(expected = NullPointerException.class) + public void shouldThrowForRegisterWithNull() { + // given / when / then + initializer.register(String.class, null); + } + + @Test + public void shouldExecutePostConstructMethod() { + // given + initializer.provide(Size.class, 15123); + + // when + PostConstructTestClass testClass = initializer.get(PostConstructTestClass.class); + + // then + assertThat(testClass.werePostConstructsCalled(), equalTo(true)); + assertThat(testClass.getBetaManager(), not(nullValue())); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForInvalidPostConstructMethod() { + // given / when / then + initializer.get(InvalidPostConstruct.WithParams.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForStaticPostConstructMethod() { + // given / when / then + initializer.get(InvalidPostConstruct.Static.class); + } + + @Test(expected = RuntimeException.class) + public void shouldForwardExceptionFromPostConstruct() { + // given / when / then + initializer.get(InvalidPostConstruct.ThrowsException.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForAbstractNonRegisteredDependency() { + // given / when / then + initializer.get(ClassWithAbstractDependency.class); + } + + @Test + public void shouldInstantiateWithImplementationOfAbstractDependency() { + // given + ClassWithAbstractDependency.ConcreteDependency concrete = new ClassWithAbstractDependency.ConcreteDependency(); + initializer.register(ClassWithAbstractDependency.AbstractDependency.class, concrete); + + // when + ClassWithAbstractDependency cwad = initializer.get(ClassWithAbstractDependency.class); + + // then + assertThat(cwad.getAbstractDependency() == concrete, equalTo(true)); + assertThat(cwad.getAlphaService(), not(nullValue())); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForAlreadyRegisteredClass() { + // given + initializer.register(BetaManager.class, new BetaManager()); + + // when / then + initializer.register(BetaManager.class, new BetaManager()); + } + + @Test + public void shouldCreateNewUntrackedInstance() { + // given / when + AlphaService singletonScoped = initializer.get(AlphaService.class); + AlphaService requestScoped = initializer.newInstance(AlphaService.class); + + // then + assertThat(singletonScoped.getProvidedClass(), not(nullValue())); + assertThat(singletonScoped.getProvidedClass(), equalTo(requestScoped.getProvidedClass())); + assertThat(singletonScoped, not(sameInstance(requestScoped))); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForStaticFieldInjection() { + // given / when / then + initializer.newInstance(InvalidStaticFieldInjection.class); + } + +} diff --git a/src/test/java/fr/xephi/authme/initialization/ConstructorInjectionTest.java b/src/test/java/fr/xephi/authme/initialization/ConstructorInjectionTest.java new file mode 100644 index 00000000..dd21a590 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/ConstructorInjectionTest.java @@ -0,0 +1,81 @@ +package fr.xephi.authme.initialization; + +import fr.xephi.authme.initialization.samples.AlphaService; +import fr.xephi.authme.initialization.samples.ClassWithAnnotations; +import fr.xephi.authme.initialization.samples.Duration; +import fr.xephi.authme.initialization.samples.GammaService; +import fr.xephi.authme.initialization.samples.InvalidClass; +import fr.xephi.authme.initialization.samples.ProvidedClass; +import fr.xephi.authme.initialization.samples.Size; +import org.junit.Test; + +import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +/** + * Test for {@link ConstructorInjection}. + */ +public class ConstructorInjectionTest { + + @Test + public void shouldReturnDependencies() { + // given + Injection injection = ConstructorInjection.provide(ClassWithAnnotations.class).get(); + + // when + Class[] dependencies = injection.getDependencies(); + Class[] annotations = injection.getDependencyAnnotations(); + + // then + assertThat(dependencies, arrayContaining(int.class, GammaService.class, long.class)); + assertThat(annotations, arrayContaining((Class) Size.class, null, Duration.class)); + } + + @Test + public void shouldInstantiate() { + // given + GammaService gammaService = new GammaService( + AlphaService.newInstance(new ProvidedClass(""))); + Injection injection = ConstructorInjection.provide(ClassWithAnnotations.class).get(); + + // when + ClassWithAnnotations instance = injection.instantiateWith(-112, gammaService, 19L); + + // then + assertThat(instance, not(nullValue())); + assertThat(instance.getSize(), equalTo(-112)); + assertThat(instance.getGammaService(), equalTo(gammaService)); + assertThat(instance.getDuration(), equalTo(19L)); + } + + @Test(expected = NullPointerException.class) + public void shouldThrowForNullValue() { + // given + Injection injection = ConstructorInjection.provide(ClassWithAnnotations.class).get(); + + // when / then + injection.instantiateWith(-112, null, 12L); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowUponInstantiationError() { + // given + AlphaService alphaService = AlphaService.newInstance(new ProvidedClass("")); + Injection injection = ConstructorInjection.provide(InvalidClass.class).get(); + + // when + injection.instantiateWith(alphaService, 5); + } + + @Test + public void shouldReturnNullForNoConstructorInjection() { + // given / when + Injection injection = ConstructorInjection.provide(FieldInjection.class).get(); + + // then + assertThat(injection, nullValue()); + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/FieldInjectionTest.java b/src/test/java/fr/xephi/authme/initialization/FieldInjectionTest.java new file mode 100644 index 00000000..9d2294ae --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/FieldInjectionTest.java @@ -0,0 +1,115 @@ +package fr.xephi.authme.initialization; + +import fr.xephi.authme.initialization.samples.AlphaService; +import fr.xephi.authme.initialization.samples.BadFieldInjection; +import fr.xephi.authme.initialization.samples.BetaManager; +import fr.xephi.authme.initialization.samples.ClassWithAnnotations; +import fr.xephi.authme.initialization.samples.Duration; +import fr.xephi.authme.initialization.samples.FieldInjectionWithAnnotations; +import fr.xephi.authme.initialization.samples.GammaService; +import fr.xephi.authme.initialization.samples.InvalidStaticFieldInjection; +import fr.xephi.authme.initialization.samples.ProvidedClass; +import fr.xephi.authme.initialization.samples.Size; +import org.junit.Test; + +import javax.inject.Inject; + +import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +/** + * Test for {@link FieldInjection}. + */ +public class FieldInjectionTest { + + @Test + public void shouldReturnDependencies() { + // given + FieldInjection injection = + FieldInjection.provide(FieldInjectionWithAnnotations.class).get(); + + // when + Class[] dependencies = injection.getDependencies(); + Class[] annotations = injection.getDependencyAnnotations(); + + // then + assertThat(dependencies, arrayContaining(BetaManager.class, int.class, long.class, ClassWithAnnotations.class)); + assertThat(annotations, arrayContaining((Class) null, Size.class, Duration.class, null)); + } + + @Test + public void shouldInstantiateClass() { + // given + FieldInjection injection = FieldInjection.provide(BetaManager.class).get(); + ProvidedClass providedClass = new ProvidedClass(""); + AlphaService alphaService = AlphaService.newInstance(providedClass); + GammaService gammaService = new GammaService(alphaService); + + // when + BetaManager betaManager = injection.instantiateWith(providedClass, gammaService, alphaService); + + // then + assertThat(betaManager, not(nullValue())); + assertThat(betaManager.getDependencies(), arrayContaining(providedClass, gammaService, alphaService)); + } + + @Test + public void shouldProvideNullForImpossibleFieldInjection() { + // given / when + FieldInjection injection = FieldInjection.provide(BadFieldInjection.class).get(); + + // then + assertThat(injection, nullValue()); + } + + @Test(expected = RuntimeException.class) + public void shouldForwardExceptionDuringInstantiation() { + // given + FieldInjection injection = FieldInjection.provide(ThrowingConstructor.class).get(); + + // when / when + injection.instantiateWith(new ProvidedClass("")); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForInvalidFieldValue() { + // given + ProvidedClass providedClass = new ProvidedClass(""); + AlphaService alphaService = AlphaService.newInstance(providedClass); + GammaService gammaService = new GammaService(alphaService); + FieldInjection injection = FieldInjection.provide(BetaManager.class).get(); + + // when / then + // Correct order is provided, gamma, alpha + injection.instantiateWith(providedClass, alphaService, gammaService); + } + + @Test(expected = NullPointerException.class) + public void shouldThrowForNullValue() { + // given + ProvidedClass providedClass = new ProvidedClass(""); + AlphaService alphaService = AlphaService.newInstance(providedClass); + FieldInjection injection = FieldInjection.provide(BetaManager.class).get(); + + // when / then + // Correct order is provided, gamma, alpha + injection.instantiateWith(providedClass, null, alphaService); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForStaticFieldInjection() { + // given / when / then + FieldInjection.provide(InvalidStaticFieldInjection.class).get(); + } + + private static class ThrowingConstructor { + @Inject + private ProvidedClass providedClass; + + public ThrowingConstructor() { + throw new UnsupportedOperationException("Exception in constructor"); + } + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java b/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java new file mode 100644 index 00000000..21dd3b32 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java @@ -0,0 +1,30 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - class with dependency to ProvidedClass. + */ +public class AlphaService { + + private ProvidedClass providedClass; + + @Inject + AlphaService(ProvidedClass providedClass) { + this.providedClass = providedClass; + } + + public ProvidedClass getProvidedClass() { + return providedClass; + } + + /** + * Creates a new instance (for instantiations in tests). + * + * @param providedClass . + * @return created instance + */ + public static AlphaService newInstance(ProvidedClass providedClass) { + return new AlphaService(providedClass); + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java b/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java new file mode 100644 index 00000000..9dc41548 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java @@ -0,0 +1,16 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample class with invalid field injection (requires default constructor). + */ +public class BadFieldInjection { + + @Inject + private AlphaService alphaService; + + public BadFieldInjection(BetaManager betaManager) { + throw new IllegalStateException("Should never be called"); + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java b/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java new file mode 100644 index 00000000..8c2fe923 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java @@ -0,0 +1,20 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - depends on Provided, alpha and gamma. + */ +public class BetaManager { + + @Inject + private ProvidedClass providedClass; + @Inject + private GammaService gammaService; + @Inject + private AlphaService alphaService; + + public Object[] getDependencies() { + return new Object[]{providedClass, gammaService, alphaService}; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java b/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java new file mode 100644 index 00000000..dc2313e3 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java @@ -0,0 +1,30 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Classes with circular dependencies. + */ +public abstract class CircularClasses { + + public static final class Circular1 { + @Inject + public Circular1(AlphaService alphaService, Circular3 circular3) { + // -- + } + } + + public static final class Circular2 { + @Inject + public Circular2(Circular1 circular1) { + // -- + } + } + + public static final class Circular3 { + @Inject + public Circular3(Circular2 circular2, BetaManager betaManager) { + // -- + } + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java new file mode 100644 index 00000000..25b651b3 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java @@ -0,0 +1,32 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Test with an abstract class declared as dependency. + */ +public class ClassWithAbstractDependency { + + private final AlphaService alphaService; + private final AbstractDependency abstractDependency; + + @Inject + public ClassWithAbstractDependency(AlphaService as, AbstractDependency ad) { + this.alphaService = as; + this.abstractDependency = ad; + } + + public AlphaService getAlphaService() { + return alphaService; + } + + public AbstractDependency getAbstractDependency() { + return abstractDependency; + } + + public static abstract class AbstractDependency { + } + + public static final class ConcreteDependency extends AbstractDependency { + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java new file mode 100644 index 00000000..61dca71b --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java @@ -0,0 +1,29 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +public class ClassWithAnnotations { + + private int size; + private GammaService gammaService; + private long duration; + + @Inject + ClassWithAnnotations(@Size int size, GammaService gammaService, @Duration long duration) { + this.size = size; + this.gammaService = gammaService; + this.duration = duration; + } + + public int getSize() { + return size; + } + + public GammaService getGammaService() { + return gammaService; + } + + public long getDuration() { + return duration; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/Duration.java b/src/test/java/fr/xephi/authme/initialization/samples/Duration.java new file mode 100644 index 00000000..e61c6d28 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/Duration.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization.samples; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Sample annotation. + */ +@Target({ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Duration { +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java b/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java new file mode 100644 index 00000000..65bdf537 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java @@ -0,0 +1,40 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - field injection, including custom annotations. + */ +public class FieldInjectionWithAnnotations { + + @Inject + private BetaManager betaManager; + @Inject + @Size + private int size; + @Duration + @Inject + private long duration; + @Inject + protected ClassWithAnnotations classWithAnnotations; + + FieldInjectionWithAnnotations() { + } + + public BetaManager getBetaManager() { + return betaManager; + } + + public int getSize() { + return size; + } + + public long getDuration() { + return duration; + } + + public ClassWithAnnotations getClassWithAnnotations() { + return classWithAnnotations; + } + +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java b/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java new file mode 100644 index 00000000..9d6f9bfa --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java @@ -0,0 +1,20 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - class dependent on alpha service. + */ +public class GammaService { + + private AlphaService alphaService; + + @Inject + public GammaService(AlphaService alphaService) { + this.alphaService = alphaService; + } + + public AlphaService getAlphaService() { + return alphaService; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java b/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java new file mode 100644 index 00000000..b896af9d --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - invalid class, since Integer parameter type is outside of the allowed package and not annotated. + */ +public class InvalidClass { + + @Inject + public InvalidClass(AlphaService alphaService, Integer i) { + throw new IllegalStateException("Should never be called"); + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java b/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java new file mode 100644 index 00000000..e97c4f98 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java @@ -0,0 +1,42 @@ +package fr.xephi.authme.initialization.samples; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +/** + * Class with invalid @PostConstruct method. + */ +public abstract class InvalidPostConstruct { + + public static final class WithParams { + @Inject + private AlphaService alphaService; + @Inject + private ProvidedClass providedClass; + + WithParams() { } + + @PostConstruct + public void invalidPostConstr(BetaManager betaManager) { + } + } + + public static final class Static { + @Inject + Static(BetaManager betaManager) { + // -- + } + + @PostConstruct + public static void invalidMethod() { + // -- + } + } + + public static final class ThrowsException { + @PostConstruct + public void throwingPostConstruct() { + throw new IllegalStateException("Exception in post construct"); + } + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/InvalidStaticFieldInjection.java b/src/test/java/fr/xephi/authme/initialization/samples/InvalidStaticFieldInjection.java new file mode 100644 index 00000000..199b2f4a --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/InvalidStaticFieldInjection.java @@ -0,0 +1,17 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample class - attempted field injection on a static member. + */ +public class InvalidStaticFieldInjection { + + @Inject + private ProvidedClass providedClass; + @Inject + protected static AlphaService alphaService; + + InvalidStaticFieldInjection() { } + +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java b/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java new file mode 100644 index 00000000..0bec84ee --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java @@ -0,0 +1,37 @@ +package fr.xephi.authme.initialization.samples; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +/** + * Sample class for testing the execution of @PostConstruct methods. + */ +public class PostConstructTestClass { + + @Inject + @Size + private int size; + @Inject + private BetaManager betaManager; + private boolean wasPostConstructCalled = false; + private boolean wasSecondPostConstructCalled = false; + + @PostConstruct + protected void setFieldToTrue() { + wasPostConstructCalled = true; + } + + @PostConstruct + public int otherPostConstructMethod() { + wasSecondPostConstructCalled = true; + return 42; + } + + public boolean werePostConstructsCalled() { + return wasPostConstructCalled && wasSecondPostConstructCalled; + } + + public BetaManager getBetaManager() { + return betaManager; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java b/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java new file mode 100644 index 00000000..7ce81bd3 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java @@ -0,0 +1,18 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - class that is always provided to the initializer beforehand. + */ +public class ProvidedClass { + + @Inject + public ProvidedClass() { + throw new IllegalStateException("Should never be called (tests always provide this class)"); + } + + public ProvidedClass(String manualConstructor) { + } + +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/Size.java b/src/test/java/fr/xephi/authme/initialization/samples/Size.java new file mode 100644 index 00000000..320a7b7c --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/Size.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization.samples; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Sample annotation. + */ +@Target({ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Size { +} diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java index ab935d02..f641b1f0 100644 --- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java +++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java @@ -13,9 +13,9 @@ import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class ProcessServiceTest { + @InjectMocks private ProcessService processService; @Mock private ValidationService validationService; @@ -51,12 +52,6 @@ public class ProcessServiceTest { @Mock private BukkitService bukkitService; - @Before - public void setUpService() { - processService = new ProcessService(settings, messages, authMe, dataSource, passwordSecurity, - pluginHooks, spawnLoader, validationService, bukkitService); - } - @Test public void shouldGetProperty() { // given diff --git a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java index 976a7a44..30940c34 100644 --- a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java @@ -1,5 +1,6 @@ package fr.xephi.authme.security; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.NewSetting; @@ -13,8 +14,6 @@ import java.util.HashSet; import java.util.Set; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.BDDMockito.given; @@ -25,13 +24,15 @@ import static org.mockito.Mockito.mock; */ public class HashAlgorithmIntegrationTest { - private static NewSetting settings; + private static AuthMeServiceInitializer initializer; @BeforeClass public static void setUpWrapper() { - settings = mock(NewSetting.class); + NewSetting settings = mock(NewSetting.class); given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8); given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(16); + initializer = new AuthMeServiceInitializer(); + initializer.register(NewSetting.class, settings); } @Test @@ -55,9 +56,7 @@ public class HashAlgorithmIntegrationTest { // given / when / then for (HashAlgorithm algorithm : HashAlgorithm.values()) { if (!HashAlgorithm.CUSTOM.equals(algorithm) && !HashAlgorithm.PLAINTEXT.equals(algorithm)) { - EncryptionMethod method = PasswordSecurity.initializeEncryptionMethod(algorithm, settings); - assertThat("Encryption method for algorithm '" + algorithm + "' is not null", - method, not(nullValue())); + EncryptionMethod method = initializer.newInstance(algorithm.getClazz()); HashedPassword hashedPassword = method.computeHash("pwd", "name"); assertThat("Salt should not be null if method.hasSeparateSalt(), and vice versa. Method: '" + method + "'", StringUtils.isEmpty(hashedPassword.getSalt()), equalTo(!method.hasSeparateSalt())); diff --git a/src/test/java/fr/xephi/authme/security/HashUtilsTest.java b/src/test/java/fr/xephi/authme/security/HashUtilsTest.java index e515fdbb..c7ef1ccd 100644 --- a/src/test/java/fr/xephi/authme/security/HashUtilsTest.java +++ b/src/test/java/fr/xephi/authme/security/HashUtilsTest.java @@ -18,7 +18,7 @@ public class HashUtilsTest { /** * List of passwords whose hash is provided to the class to test against. */ - public static final String[] GIVEN_PASSWORDS = {"", "password", "PassWord1", "&^%te$t?Pw@_"}; + private static final String[] GIVEN_PASSWORDS = {"", "password", "PassWord1", "&^%te$t?Pw@_"}; @Test public void shouldHashMd5() { diff --git a/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java b/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java index 470b8a2d..f3d577dc 100644 --- a/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java +++ b/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java @@ -4,6 +4,7 @@ import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.PasswordEncryptionEvent; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.JOOMLA; @@ -30,7 +31,6 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -41,12 +41,20 @@ import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class PasswordSecurityTest { + private AuthMeServiceInitializer initializer; + + @Mock + private NewSetting settings; + @Mock private PluginManager pluginManager; + @Mock private DataSource dataSource; + @Mock private EncryptionMethod method; + private Class caughtClassInEvent; @BeforeClass @@ -71,6 +79,10 @@ public class PasswordSecurityTest { return null; } }).when(pluginManager).callEvent(any(Event.class)); + initializer = new AuthMeServiceInitializer(new String[]{}); + initializer.register(NewSetting.class, settings); + initializer.register(DataSource.class, dataSource); + initializer.register(PluginManager.class, pluginManager); } @Test @@ -84,8 +96,8 @@ public class PasswordSecurityTest { given(dataSource.getPassword(playerName)).willReturn(password); given(method.comparePassword(clearTextPass, password, playerLowerCase)).willReturn(true); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.BCRYPT, false), pluginManager); + initSettings(HashAlgorithm.BCRYPT, false); + PasswordSecurity security = initializer.newInstance(PasswordSecurity.class); // when boolean result = security.comparePassword(clearTextPass, playerName); @@ -107,8 +119,8 @@ public class PasswordSecurityTest { given(dataSource.getPassword(playerName)).willReturn(password); given(method.comparePassword(clearTextPass, password, playerLowerCase)).willReturn(false); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.CUSTOM, false), pluginManager); + initSettings(HashAlgorithm.CUSTOM, false); + PasswordSecurity security = initializer.newInstance(PasswordSecurity.class); // when boolean result = security.comparePassword(clearTextPass, playerName); @@ -127,8 +139,8 @@ public class PasswordSecurityTest { String clearTextPass = "tables"; given(dataSource.getPassword(playerName)).willReturn(null); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.MD5, false), pluginManager); + initSettings(HashAlgorithm.MD5, false); + PasswordSecurity security = initializer.newInstance(PasswordSecurity.class); // when boolean result = security.comparePassword(clearTextPass, playerName); @@ -155,8 +167,8 @@ public class PasswordSecurityTest { given(dataSource.getPassword(argThat(equalToIgnoringCase(playerName)))).willReturn(password); given(method.comparePassword(clearTextPass, password, playerLowerCase)).willReturn(false); given(method.computeHash(clearTextPass, playerLowerCase)).willReturn(newPassword); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.MD5, true), pluginManager); + initSettings(HashAlgorithm.MD5, true); + PasswordSecurity security = initializer.newInstance(PasswordSecurity.class); // when boolean result = security.comparePassword(clearTextPass, playerName); @@ -180,8 +192,8 @@ public class PasswordSecurityTest { String clearTextPass = "someInvalidPassword"; given(dataSource.getPassword(playerName)).willReturn(password); given(method.comparePassword(clearTextPass, password, playerName)).willReturn(false); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.MD5, true), pluginManager); + initSettings(HashAlgorithm.MD5, true); + PasswordSecurity security = initializer.newInstance(PasswordSecurity.class); // when boolean result = security.comparePassword(clearTextPass, playerName); @@ -199,8 +211,8 @@ public class PasswordSecurityTest { String usernameLowerCase = username.toLowerCase(); HashedPassword hashedPassword = new HashedPassword("$T$est#Hash", "__someSalt__"); given(method.computeHash(password, usernameLowerCase)).willReturn(hashedPassword); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.JOOMLA, true), pluginManager); + initSettings(HashAlgorithm.JOOMLA, true); + PasswordSecurity security = initializer.newInstance(PasswordSecurity.class); // when HashedPassword result = security.computeHash(password, username); @@ -222,8 +234,8 @@ public class PasswordSecurityTest { HashedPassword hashedPassword = new HashedPassword("~T!est#Hash"); given(method.computeHash(password, username)).willReturn(hashedPassword); given(method.hasSeparateSalt()).willReturn(true); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.XAUTH, false), pluginManager); + initSettings(HashAlgorithm.XAUTH, false); + PasswordSecurity security = initializer.newInstance(PasswordSecurity.class); // when boolean result = security.comparePassword(password, hashedPassword, username); @@ -238,8 +250,8 @@ public class PasswordSecurityTest { @Test public void shouldReloadSettings() { // given - NewSetting settings = mockSettings(HashAlgorithm.BCRYPT, false); - PasswordSecurity passwordSecurity = new PasswordSecurity(dataSource, settings, pluginManager); + initSettings(HashAlgorithm.BCRYPT, false); + PasswordSecurity passwordSecurity = initializer.newInstance(PasswordSecurity.class); given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.MD5); given(settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH)).willReturn(true); @@ -253,13 +265,11 @@ public class PasswordSecurityTest { equalTo((Object) Boolean.TRUE)); } - private static NewSetting mockSettings(HashAlgorithm algorithm, boolean supportOldPassword) { - NewSetting settings = mock(NewSetting.class); + private void initSettings(HashAlgorithm algorithm, boolean supportOldPassword) { given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(algorithm); given(settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH)).willReturn(supportOldPassword); given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8); given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(16); - return settings; } } diff --git a/src/tools/commands/CommandPageCreater.java b/src/tools/commands/CommandPageCreater.java index 8d92dbfb..3369b906 100644 --- a/src/tools/commands/CommandPageCreater.java +++ b/src/tools/commands/CommandPageCreater.java @@ -2,7 +2,6 @@ package commands; import fr.xephi.authme.command.CommandArgumentDescription; import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.command.CommandInitializer; import fr.xephi.authme.command.CommandPermissions; import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.permission.PermissionNode; @@ -13,6 +12,7 @@ import utils.ToolTask; import utils.ToolsConstants; import java.util.Collection; +import java.util.HashSet; import java.util.Scanner; import java.util.Set; @@ -27,7 +27,8 @@ public class CommandPageCreater implements ToolTask { @Override public void execute(Scanner scanner) { - final Set baseCommands = CommandInitializer.buildCommands(); + // TODO ljacqu 20160427: Fix initialization of commands + final Set baseCommands = new HashSet<>();//CommandInitializer.buildCommands(); NestedTagValue commandTags = new NestedTagValue(); addCommandsInfo(commandTags, baseCommands); diff --git a/src/tools/hashmethods/EncryptionMethodInfoGatherer.java b/src/tools/hashmethods/EncryptionMethodInfoGatherer.java index 4ade88ce..d56e370d 100644 --- a/src/tools/hashmethods/EncryptionMethodInfoGatherer.java +++ b/src/tools/hashmethods/EncryptionMethodInfoGatherer.java @@ -1,7 +1,6 @@ package hashmethods; import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.HexSaltedMethod; import fr.xephi.authme.security.crypts.description.AsciiRestricted; @@ -55,7 +54,7 @@ public class EncryptionMethodInfoGatherer { private static MethodDescription createDescription(HashAlgorithm algorithm) { Class clazz = algorithm.getClazz(); - EncryptionMethod method = PasswordSecurity.initializeEncryptionMethod(algorithm, settings); + EncryptionMethod method = null; // TODO ljacqu PasswordSecurity.initializeEncryptionMethod(algorithm, settings); if (method == null) { throw new NullPointerException("Method for '" + algorithm + "' is null"); }