From 5870a4a4338f2822de8f6de6980d67984c04239b Mon Sep 17 00:00:00 2001 From: EbonJaguar Date: Tue, 14 Jun 2016 22:47:35 -0400 Subject: [PATCH 001/217] Add ability to check permissions by player name --- src/main/java/fr/xephi/authme/AuthMe.java | 7 +++++ .../authme/permission/PermissionsManager.java | 31 +++++++++++++++++++ .../authme/permission/PlayerPermission.java | 7 ++++- .../handlers/BPermissionsHandler.java | 5 +++ .../handlers/GroupManagerHandler.java | 8 +++++ .../handlers/PermissionHandler.java | 11 +++++++ .../handlers/PermissionsBukkitHandler.java | 5 +++ .../handlers/PermissionsExHandler.java | 6 ++++ .../permission/handlers/VaultHandler.java | 5 +++ .../handlers/ZPermissionsHandler.java | 10 ++++++ .../java/fr/xephi/authme/task/PurgeTask.java | 5 +++ 11 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 058c21bd..b9a2c867 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -34,6 +34,7 @@ import fr.xephi.authme.output.Log4JFilter; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.permission.PermissionsSystemType; import fr.xephi.authme.process.Management; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.SHA256; @@ -302,6 +303,12 @@ public class AuthMe extends JavaPlugin { // Successful message ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!"); + // If server is using PermissionsBukkit, print a warning that some features may not be supported + if (permsMan.isEnabled() && + permsMan.getHandler().getPermissionSystem() == PermissionsSystemType.PERMISSIONS_BUKKIT) { + ConsoleLogger.info("Warning! This server uses PermissionsBukkit for permissions! Some permissions features may not be supported!"); + } + // Purge on start if enabled runAutoPurge(); } diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index e0065fa4..2e5437a5 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -216,6 +216,15 @@ public class PermissionsManager { } } + /** + * Get the current permissions system handler. + * + * @return The permissions system handler. + */ + public PermissionHandler getHandler() { + return handler; + } + /** * Check if the command sender has permission for the given permissions node. If no permissions system is used or * if the sender is not a player (e.g. console user), the player has to be OP in order to have the permission. @@ -240,6 +249,28 @@ public class PermissionsManager { return handler.hasPermission(player, permissionNode); } + /** + * Check if a player has permission for the given permission node. This is for offline player checks. If no permissions + * system is used, then the player will not have permission. + * + * @param name The name of the player. + * @param permissionNode The permission node to verify. + * + * @return + */ + public boolean hasPermission(String name, PermissionNode permissionNode) { + // Check if the permission node is null + if (permissionNode == null) { + return true; + } + + if (!isEnabled()) { + return false; + } + + return handler.hasPermission(name, permissionNode); + } + /** * Check whether the current permissions system has group support. * If no permissions system is hooked, false will be returned. diff --git a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java index e2932e93..1e765000 100644 --- a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java +++ b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java @@ -58,7 +58,12 @@ public enum PlayerPermission implements PermissionNode { /** * Permission to use to see own other accounts. */ - SEE_OWN_ACCOUNTS("authme.player.seeownaccounts", DefaultPermission.ALLOWED); + SEE_OWN_ACCOUNTS("authme.player.seeownaccounts", DefaultPermission.ALLOWED), + + /** + * Permission to bypass the purging process + */ + BYPASS_PURGE("authme.player.bypasspurge", DefaultPermission.NOT_ALLOWED); /** * The permission node. diff --git a/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java index 45592323..71a6772b 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java @@ -27,6 +27,11 @@ public class BPermissionsHandler implements PermissionHandler { return ApiLayer.hasPermission(player.getWorld().getName(), CalculableType.USER, player.getName(), node.getNode()); } + @Override + public boolean hasPermission(String name, PermissionNode node) { + return ApiLayer.hasPermission(null, CalculableType.USER, name, node.getNode()); + } + @Override public boolean isInGroup(Player player, String group) { return ApiLayer.hasGroup(player.getWorld().getName(), CalculableType.USER, player.getName(), group); diff --git a/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java index fe0b0236..475fafee 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java @@ -3,6 +3,7 @@ package fr.xephi.authme.permission.handlers; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsSystemType; import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.User; import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -35,6 +36,13 @@ public class GroupManagerHandler implements PermissionHandler { return handler != null && handler.has(player, node.getNode()); } + @Override + public boolean hasPermission(String name, PermissionNode node) { + final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissionsByPlayerName(name); + List perms = handler.getAllPlayersPermissions(name); + return perms.contains(node.getNode()); + } + @Override public boolean isInGroup(Player player, String group) { final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissions(player); diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java index 5d467cea..b47261bb 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java @@ -38,6 +38,17 @@ public interface PermissionHandler { */ boolean hasPermission(Player player, PermissionNode node); + /** + * Check if a player has permission by their name. + * Used to check an offline player's permission. + * + * @param name The player's name. + * @param node The permission node. + * + * @return True if the player has permission. + */ + boolean hasPermission(String name, PermissionNode node); + /** * Check whether the player is in the specified group. * diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java index fb1edcae..bb351c80 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java @@ -25,6 +25,11 @@ public class PermissionsBukkitHandler implements PermissionHandler { return player.hasPermission(node.getNode()); } + @Override + public boolean hasPermission(String name, PermissionNode node) { + return false; + } + @Override public boolean isInGroup(Player player, String group) { List groupNames = getGroups(player); diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java index b49e4b37..4c6035b1 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java @@ -42,6 +42,12 @@ public class PermissionsExHandler implements PermissionHandler { return user.has(node.getNode()); } + @Override + public boolean hasPermission(String name, PermissionNode node) { + PermissionUser user = permissionManager.getUser(name); + return user.has(node.getNode()); + } + @Override public boolean isInGroup(Player player, String group) { PermissionUser user = permissionManager.getUser(player); diff --git a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java index 7b99b5ed..3a40f974 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java @@ -31,6 +31,11 @@ public class VaultHandler implements PermissionHandler { return vaultProvider.has(player, node.getNode()); } + @Override + public boolean hasPermission(String name, PermissionNode node) { + return vaultProvider.has("", name, node.getNode()); + } + @Override public boolean isInGroup(Player player, String group) { return vaultProvider.playerInGroup(player, group); diff --git a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java index fb2490f7..a47461c6 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java @@ -4,6 +4,7 @@ import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsSystemType; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.inventory.meta.BookMeta; import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; import java.util.ArrayList; @@ -37,6 +38,15 @@ public class ZPermissionsHandler implements PermissionHandler { return node.getDefaultPermission().evaluate(player); } + @Override + public boolean hasPermission(String name, PermissionNode node) { + Map perms = zPermissionsService.getPlayerPermissions(null, null, name); + if (perms.containsKey(node.getNode())) + return perms.get(node.getNode()); + else + return false; + } + @Override public boolean isInGroup(Player player, String group) { return getGroups(player).contains(group); diff --git a/src/main/java/fr/xephi/authme/task/PurgeTask.java b/src/main/java/fr/xephi/authme/task/PurgeTask.java index 97ffcc88..8849c766 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeTask.java +++ b/src/main/java/fr/xephi/authme/task/PurgeTask.java @@ -2,6 +2,9 @@ package fr.xephi.authme.task; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.permission.PermissionNode; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.PurgeSettings; @@ -16,6 +19,8 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import javax.inject.Inject; + public class PurgeTask extends BukkitRunnable { //how many players we should check for each tick From 3a102c324e14afb4e3c50cdf8fef196ab90278fd Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Wed, 15 Jun 2016 15:15:39 -0400 Subject: [PATCH 002/217] move bypass permission location --- .../java/fr/xephi/authme/permission/PlayerPermission.java | 7 +------ .../fr/xephi/authme/permission/PlayerStatePermission.java | 7 ++++++- .../authme/permission/handlers/ZPermissionsHandler.java | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java index 1e765000..e2932e93 100644 --- a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java +++ b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java @@ -58,12 +58,7 @@ public enum PlayerPermission implements PermissionNode { /** * Permission to use to see own other accounts. */ - SEE_OWN_ACCOUNTS("authme.player.seeownaccounts", DefaultPermission.ALLOWED), - - /** - * Permission to bypass the purging process - */ - BYPASS_PURGE("authme.player.bypasspurge", DefaultPermission.NOT_ALLOWED); + SEE_OWN_ACCOUNTS("authme.player.seeownaccounts", DefaultPermission.ALLOWED); /** * The permission node. diff --git a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java index fd023935..d733814e 100644 --- a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java +++ b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java @@ -24,7 +24,12 @@ public enum PlayerStatePermission implements PermissionNode { /** * Permission to be able to register multiple accounts. */ - ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY); + ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY), + + /** + * Permission to bypass the purging process + */ + BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED); /** * The permission node. diff --git a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java index a47461c6..49322109 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java @@ -4,7 +4,6 @@ import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsSystemType; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.inventory.meta.BookMeta; import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; import java.util.ArrayList; From df17821e8581b98ed6cc58d704ed9422d64056ef Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 16 Jun 2016 04:26:30 +0200 Subject: [PATCH 003/217] Let's switch again to SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 33181e69..ec21ff63 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ fr.xephi authme - 5.2-BETA3 + 5.2-SNAPSHOT jar AuthMeReloaded From 2c4d1b54cf13934d55bf4a6228c352ed755a69c1 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 16 Jun 2016 08:03:48 +0200 Subject: [PATCH 004/217] Remove solved todo message --- .../command/executable/changepassword/ChangePasswordCommand.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java index 68377390..0fdbf607 100644 --- a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java @@ -47,7 +47,6 @@ public class ChangePasswordCommand extends PlayerCommand { return; } - // TODO ljacqu 20160117: Call async task via Management management.performPasswordChange(player, oldPassword, newPassword); } } From a298773cd339ca1d99f68a0ba83b9e8b45bc8868 Mon Sep 17 00:00:00 2001 From: Maxetto Date: Thu, 16 Jun 2016 15:52:17 +0200 Subject: [PATCH 005/217] Periodic Italian Update Still keeping it updated :wink: --- src/main/resources/messages/messages_it.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml index e4b9b7ae..7a5f6b2f 100644 --- a/src/main/resources/messages/messages_it.yml +++ b/src/main/resources/messages/messages_it.yml @@ -1,4 +1,7 @@ # Lingua Italiana creata da Maxetto e sgdc3. +denied_command: '&cPer poter usare questo comando devi essere autenticato!' +same_ip_online: 'Un giocatore con il tuo stesso IP è già connesso sul server!' +denied_chat: '&cPer poter scrivere messaggi in chat devi essere autenticato!' kick_antibot: 'Il servizio di AntiBot è attualmente attivo! Devi aspettare qualche minuto prima di poter entrare nel server.' unknown_user: '&cL''utente non è presente nel database.' unsafe_spawn: '&cIl tuo punto di disconnessione risulta ostruito o insicuro, sei stato teletrasportato al punto di rigenerazione!' @@ -30,7 +33,7 @@ invalid_session: '&cIl tuo indirizzo IP è cambiato e la tua sessione è stata t reg_only: '&4Puoi giocare in questo server solo dopo aver effettuato la registrazione attraverso il sito web! Per favore, vai su http://esempio.it per procedere!' logged_in: '&cHai già eseguito l''autenticazione, non è necessario eseguirla nuovamente!' logout: '&2Disconnessione avvenuta correttamente!' -same_nick: '&4Questo stesso nome utente è già online sul server!' +same_nick: '&4Un giocatore con il tuo stesso nome utente è già connesso sul server!' registered: '&2Registrato correttamente!' pass_len: '&cLa password che hai inserito è troppo corta o troppo lunga, per favore scegline un''altra...' reload: '&2La configurazione e il database sono stati ricaricati correttamente!' @@ -63,6 +66,6 @@ email_already_used: '&4L''indirizzo email inserito è già in uso' two_factor_create: '&2Il tuo codice segreto è: &f%code&n&2Puoi anche scannerizzare il codice QR da qui: &f%url' not_owner_error: 'Non sei il proprietario di questo account. Per favore scegli un altro nome!' invalid_name_case: 'Dovresti entrare con questo nome utente: "%valid", al posto di: "%invalid".' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' \ No newline at end of file +tempban_max_logins: '&cSei stato temporaneamente bandito per aver fallito l''autenticazione troppe volte.' +accounts_owned_self: 'Possiedi %count account:' +accounts_owned_other: 'Il giocatore %name possiede %count account:' From af1520802d19007762beca3d44bf9bf1bc4929e1 Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Thu, 16 Jun 2016 12:28:42 -0400 Subject: [PATCH 006/217] major refactor of the purging process --- src/main/java/fr/xephi/authme/AuthMe.java | 28 +- .../authme/PurgeBannedPlayersCommand.java | 14 +- .../executable/authme/PurgeCommand.java | 13 +- .../authme/datasource/CacheDataSource.java | 12 + .../xephi/authme/datasource/DataSource.java | 17 +- .../fr/xephi/authme/datasource/FlatFile.java | 60 ++++ .../fr/xephi/authme/datasource/MySQL.java | 33 ++ .../fr/xephi/authme/datasource/SQLite.java | 32 ++ .../authme/process/purge/PurgeService.java | 310 ++++++++++++++++++ .../java/fr/xephi/authme/task/PurgeTask.java | 69 ++-- 10 files changed, 499 insertions(+), 89 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/process/purge/PurgeService.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index b9a2c867..1748d82d 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -36,6 +36,7 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsSystemType; import fr.xephi.authme.process.Management; +import fr.xephi.authme.process.purge.PurgeService; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.settings.NewSetting; @@ -133,6 +134,7 @@ public class AuthMe extends JavaPlugin { private boolean autoPurging; private BukkitService bukkitService; private AuthMeServiceInitializer initializer; + private PurgeService purgeService; /** * Get the plugin's instance. @@ -255,6 +257,7 @@ public class AuthMe extends JavaPlugin { api = initializer.get(NewAPI.class); management = initializer.get(Management.class); dataManager = initializer.get(DataManager.class); + purgeService = initializer.get(PurgeService.class); initializer.get(API.class); // Set up Metrics @@ -310,7 +313,7 @@ public class AuthMe extends JavaPlugin { } // Purge on start if enabled - runAutoPurge(); + purgeService.runAutoPurge(); } /** @@ -643,29 +646,6 @@ public class AuthMe extends JavaPlugin { return pluginHooks != null && pluginHooks.isNpc(player) || player.hasMetadata("NPC"); } - // Purge inactive players from the database, as defined in the configuration - private void runAutoPurge() { - if (!newSettings.getProperty(PurgeSettings.USE_AUTO_PURGE) || autoPurging) { - return; - } - - autoPurging = true; - - ConsoleLogger.info("AutoPurging the Database..."); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.DATE, -newSettings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)); - long until = calendar.getTimeInMillis(); - Set cleared = database.autoPurgeDatabase(until); - if (CollectionUtils.isEmpty(cleared)) { - return; - } - - ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!"); - ConsoleLogger.info("Purging user accounts..."); - new PurgeTask(plugin, Bukkit.getConsoleSender(), cleared, true, Bukkit.getOfflinePlayers()) - .runTaskTimer(plugin, 0, 1); - } - // Return the spawn location of a player @Deprecated public Location getSpawnLocation(Player player) { diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java index c80a790d..28c5e5ff 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,6 +3,7 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.process.purge.PurgeService; import fr.xephi.authme.task.PurgeTask; import fr.xephi.authme.util.BukkitService; import org.bukkit.ChatColor; @@ -21,10 +22,7 @@ import java.util.Set; public class PurgeBannedPlayersCommand implements ExecutableCommand { @Inject - private DataSource dataSource; - - @Inject - private AuthMe plugin; + private PurgeService purgeService; @Inject private BukkitService bukkitService; @@ -38,12 +36,6 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand { namedBanned.add(offlinePlayer.getName().toLowerCase()); } - //todo: note this should may run async because it may executes a SQL-Query - // Purge the banned players - dataSource.purgeBanned(namedBanned); - - // Show a status message - sender.sendMessage(ChatColor.GOLD + "Purging user accounts..."); - new PurgeTask(plugin, sender, namedBanned, bannedPlayers).runTaskTimer(plugin, 0, 1); + purgeService.purgeBanned(sender, namedBanned, 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 73e8e7c0..99814566 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,6 +3,7 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.process.purge.PurgeService; import fr.xephi.authme.task.PurgeTask; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -21,7 +22,7 @@ public class PurgeCommand implements ExecutableCommand { private static final int MINIMUM_LAST_SEEN_DAYS = 30; @Inject - private DataSource dataSource; + private PurgeService purgeService; @Inject private AuthMe plugin; @@ -52,13 +53,7 @@ public class PurgeCommand implements ExecutableCommand { calendar.add(Calendar.DATE, -days); long until = calendar.getTimeInMillis(); - //todo: note this should may run async because it may executes a SQL-Query - // Purge the data, get the purged values - Set purged = dataSource.autoPurgeDatabase(until); - - // Show a status message - sender.sendMessage(ChatColor.GOLD + "Deleted " + purged.size() + " user accounts"); - sender.sendMessage(ChatColor.GOLD + "Purging user accounts..."); - new PurgeTask(plugin, sender, purged).runTaskTimer(plugin, 0, 1); + // Run the purge + purgeService.runPurge(sender, until); } } diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 12d45d20..141b4fc0 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -148,6 +148,18 @@ public class CacheDataSource implements DataSource { return cleared; } + @Override + public Set getRecordsToPurge(long until) { + return source.getRecordsToPurge(until); + } + + @Override + public void purgeRecords(Set toPurge) { + for (String name : toPurge) { + cachedAuths.invalidate(name); + } + } + @Override public boolean removeAuth(String name) { name = name.toLowerCase(); diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index dd80bc76..c0415858 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -71,13 +71,28 @@ public interface DataSource extends Reloadable { /** * Purge all records in the database whose last login was longer ago than - * the given time. + * the given time if they do not have the bypass permission. * * @param until The minimum last login * @return The account names that have been removed */ Set autoPurgeDatabase(long until); + /** + * Get all records in the database whose last login was before the given time. + * + * @param until The minimum last login + * @return The account names selected to purge + */ + Set getRecordsToPurge(long until); + + /** + * Purge the given players from the database. + * + * @param toPurge The players to purge + */ + void purgeRecords(Set toPurge); + /** * Remove a user record from the database. * diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index fa9d291e..1c4e8fba 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -8,6 +8,7 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; +import javax.swing.*; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Closeable; @@ -262,6 +263,65 @@ public class FlatFile implements DataSource { return cleared; } + @Override + public Set getRecordsToPurge(long until) { + BufferedReader br = null; + Set list = new HashSet<>(); + + try { + br = new BufferedReader(new FileReader(source)); + String line; + while ((line = br.readLine()) != null) { + String[] args = line.split(":"); + if (args.length >= 4) { + if (Long.parseLong(args[3]) >= until) { + list.add(args[0]); + continue; + } + } + } + } catch (IOException ex) { + ConsoleLogger.showError(ex.getMessage()); + return list; + } finally { + silentClose(br); + } + + return list; + } + + @Override + public void purgeRecords(Set toPurge) { + BufferedReader br = null; + BufferedWriter bw = null; + ArrayList lines = new ArrayList<>(); + + try { + br = new BufferedReader(new FileReader(source)); + bw = new BufferedWriter(new FileWriter(source)); + String line; + while ((line = br.readLine()) != null) { + String[] args = line.split(":"); + if (args.length >= 4) { + if (toPurge.contains(args[0])) { + lines.add(line); + continue; + } + } + } + + for (String l : lines) { + bw.write(l + "\n"); + } + } catch (IOException ex) { + ConsoleLogger.showError(ex.getMessage()); + return; + } finally { + silentClose(br); + silentClose(bw); + } + } + @Override public synchronized boolean removeAuth(String user) { if (!isAuthAvailable(user)) { diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 94e43e00..ac96714d 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -635,6 +635,39 @@ public class MySQL implements DataSource { return list; } + @Override + public Set getRecordsToPurge(long until) { + Set list = new HashSet<>(); + + String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + " toPurge) { + String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; + try (Connection con = getConnection(); PreparedStatement deletePst = con.prepareStatement(delete)) { + for (String name : toPurge) { + deletePst.setString(1, name); + deletePst.executeUpdate(); + } + } catch (SQLException ex) { + logSqlException(ex); + } + } + @Override public boolean removeAuth(String user) { user = user.toLowerCase(); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index 8072d58f..f5cac059 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -314,6 +314,38 @@ public class SQLite implements DataSource { return list; } + @Override + public Set getRecordsToPurge(long until) { + Set list = new HashSet<>(); + + String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + " toPurge) { + String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; + for (String name : toPurge) { + try (PreparedStatement deletePst = con.prepareStatement(delete)) { + deletePst.setString(1, name); + deletePst.executeUpdate(); + } catch (SQLException ex) { + logSqlException(ex); + } + } + } + @Override public boolean removeAuth(String user) { PreparedStatement pst = null; diff --git a/src/main/java/fr/xephi/authme/process/purge/PurgeService.java b/src/main/java/fr/xephi/authme/process/purge/PurgeService.java new file mode 100644 index 00000000..6970a5ba --- /dev/null +++ b/src/main/java/fr/xephi/authme/process/purge/PurgeService.java @@ -0,0 +1,310 @@ +package fr.xephi.authme.process.purge; + +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.initialization.Reloadable; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.permission.PlayerStatePermission; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.PurgeSettings; +import fr.xephi.authme.task.PurgeTask; +import fr.xephi.authme.util.BukkitService; +import fr.xephi.authme.util.CollectionUtils; +import fr.xephi.authme.util.Utils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import java.io.File; +import java.util.Calendar; +import java.util.HashSet; +import java.util.Set; + +import static fr.xephi.authme.util.StringUtils.makePath; + +public class PurgeService implements Reloadable { + + @Inject + private BukkitService bukkitService; + + @Inject + private DataSource dataSource; + + @Inject + private NewSetting settings; + + @Inject + private PermissionsManager permissionsManager; + + @Inject + private PluginHooks pluginHooks; + + @Inject + private Server server; + + private boolean autoPurging = false; + + // Settings + private boolean useAutoPurge; + private boolean removeEssentialsFiles; + private boolean removePlayerDat; + private boolean removeLimitedCreativeInventories; + private boolean removeAntiXrayFiles; + private boolean removePermissions; + private int daysBeforePurge; + + /** + * Return whether an automatic purge is in progress. + * + * @return True if purging. + */ + public boolean isAutoPurging() { + return this.autoPurging; + } + + /** + * Set if an automatic purge is currently in progress. + * + * @param autoPurging True if automatically purging. + */ + public void setAutoPurging(boolean autoPurging) { + this.autoPurging = autoPurging; + } + + /** + * Purges players from the database. Ran on startup. + */ + public void runAutoPurge() { + if (!useAutoPurge || autoPurging) { + return; + } + + this.autoPurging = true; + + // Get the initial list of players to purge + ConsoleLogger.info("Automatically purging the database..."); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DATE, daysBeforePurge); + long until = calendar.getTimeInMillis(); + Set initialPurge = dataSource.getRecordsToPurge(until); + + if (CollectionUtils.isEmpty(initialPurge)) { + return; + } + + // Remove players from the purge list if they have bypass permission + Set toPurge = getFinalPurgeList(initialPurge); + + // Purge players from the database + dataSource.purgeRecords(toPurge); + ConsoleLogger.info("Purged the database: " + toPurge.size() + " accounts removed!"); + ConsoleLogger.info("Purging user accounts..."); + + // Schedule a PurgeTask + PurgeTask purgeTask = new PurgeTask(this, Bukkit.getConsoleSender(), toPurge, Bukkit.getOfflinePlayers(), true); + bukkitService.runTaskAsynchronously(purgeTask); + } + + /** + * Run a purge with a specified time. + * + * @param sender Sender running the command. + * @param until The minimum last login. + */ + public void runPurge(CommandSender sender, long until) { + //todo: note this should may run async because it may executes a SQL-Query + Set initialPurge = dataSource.getRecordsToPurge(until); + if (CollectionUtils.isEmpty(initialPurge)) { + return; + } + + Set toPurge = getFinalPurgeList(initialPurge); + + // Purge records from the database + dataSource.purgeRecords(toPurge); + sender.sendMessage(ChatColor.GOLD + "Deleted " + toPurge.size() + " user accounts"); + sender.sendMessage(ChatColor.GOLD + "Purging user accounts..."); + + // Schedule a PurgeTask + PurgeTask purgeTask = new PurgeTask(this, sender, toPurge, Bukkit.getOfflinePlayers(), false); + bukkitService.runTaskAsynchronously(purgeTask); + } + + public void purgeBanned(CommandSender sender, Set bannedNames, Set bannedPlayers) { + //todo: note this should may run async because it may executes a SQL-Query + dataSource.purgeBanned(bannedNames); + + OfflinePlayer[] bannedPlayersArray = new OfflinePlayer[bannedPlayers.size()]; + bannedPlayers.toArray(bannedPlayersArray); + PurgeTask purgeTask = new PurgeTask(this, sender, bannedNames, bannedPlayersArray, false); + bukkitService.runTaskAsynchronously(purgeTask); + } + + /** + * Check each name in the initial purge findings to remove any player from the purge list + * that has the bypass permission. + * + * @param initial The initial list of players to purge. + * + * @return The list of players to purge after permission check. + */ + private Set getFinalPurgeList(Set initial) { + Set toPurge = new HashSet<>(); + + for (String name : initial) { + if (!permissionsManager.hasPermission(name, PlayerStatePermission.BYPASS_PURGE)) { + toPurge.add(name); + } + } + + return toPurge; + } + + public synchronized void purgeAntiXray(Set cleared) { + if (!removeAntiXrayFiles) { + return; + } + + int i = 0; + File dataFolder = new File("." + File.separator + "plugins" + File.separator + "AntiXRayData" + + File.separator + "PlayerData"); + if (!dataFolder.exists() || !dataFolder.isDirectory()) { + return; + } + + for (String file : dataFolder.list()) { + if (cleared.contains(file.toLowerCase())) { + File playerFile = new File(dataFolder, file); + if (playerFile.exists() && playerFile.delete()) { + i++; + } + } + } + + ConsoleLogger.info("AutoPurge: Removed " + i + " AntiXRayData Files"); + } + + public synchronized void purgeLimitedCreative(Set cleared) { + if (!removeLimitedCreativeInventories) { + return; + } + + int i = 0; + File dataFolder = new File("." + File.separator + "plugins" + File.separator + "LimitedCreative" + + File.separator + "inventories"); + if (!dataFolder.exists() || !dataFolder.isDirectory()) { + return; + } + for (String file : dataFolder.list()) { + String name = file; + int idx; + idx = file.lastIndexOf("_creative.yml"); + if (idx != -1) { + name = name.substring(0, idx); + } else { + idx = file.lastIndexOf("_adventure.yml"); + if (idx != -1) { + name = name.substring(0, idx); + } else { + idx = file.lastIndexOf(".yml"); + if (idx != -1) { + name = name.substring(0, idx); + } + } + } + if (name.equals(file)) { + continue; + } + if (cleared.contains(name.toLowerCase())) { + File dataFile = new File(dataFolder, file); + if (dataFile.exists() && dataFile.delete()) { + i++; + } + } + } + ConsoleLogger.info("AutoPurge: Removed " + i + " LimitedCreative Survival, Creative and Adventure files"); + } + + public synchronized void purgeDat(Set cleared) { + if (!removePlayerDat) { + return; + } + + int i = 0; + File dataFolder = new File(server.getWorldContainer() + , makePath(settings.getProperty(PurgeSettings.DEFAULT_WORLD), "players")); + + for (OfflinePlayer offlinePlayer : cleared) { + File playerFile = new File(dataFolder, Utils.getUUIDorName(offlinePlayer) + ".dat"); + if (playerFile.delete()) { + i++; + } + } + + ConsoleLogger.info("AutoPurge: Removed " + i + " .dat Files"); + } + + /** + * Method purgeEssentials. + * + * @param cleared List of String + */ + public synchronized void purgeEssentials(Set cleared) { + if (!removeEssentialsFiles && !pluginHooks.isEssentialsAvailable()) { + return; + } + + int i = 0; + File essentialsDataFolder = pluginHooks.getEssentialsDataFolder(); + if (essentialsDataFolder == null) { + ConsoleLogger.info("Cannot purge Essentials: plugin is not loaded"); + return; + } + + final File userDataFolder = new File(essentialsDataFolder, "userdata"); + if (!userDataFolder.exists() || !userDataFolder.isDirectory()) { + return; + } + + for (OfflinePlayer offlinePlayer : cleared) { + File playerFile = new File(userDataFolder, Utils.getUUIDorName(offlinePlayer) + ".yml"); + if (playerFile.exists() && playerFile.delete()) { + i++; + } + } + + ConsoleLogger.info("AutoPurge: Removed " + i + " EssentialsFiles"); + } + + // TODO: What is this method for? Is it correct? + // TODO: Make it work with OfflinePlayers group data. + public synchronized void purgePermissions(Set cleared) { + if (!removePermissions) { + return; + } + + for (OfflinePlayer offlinePlayer : cleared) { + String name = offlinePlayer.getName(); + permissionsManager.removeAllGroups(bukkitService.getPlayerExact(name)); + } + + ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); + } + + @PostConstruct + @Override + public void reload() { + this.useAutoPurge = settings.getProperty(PurgeSettings.USE_AUTO_PURGE); + this.removeEssentialsFiles = settings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES); + this.removePlayerDat = settings.getProperty(PurgeSettings.REMOVE_PLAYER_DAT); + this.removeAntiXrayFiles = settings.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE); + this.removeLimitedCreativeInventories = settings.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES); + this.removePermissions = settings.getProperty(PurgeSettings.REMOVE_PERMISSIONS); + this.daysBeforePurge = settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER); + } +} diff --git a/src/main/java/fr/xephi/authme/task/PurgeTask.java b/src/main/java/fr/xephi/authme/task/PurgeTask.java index 8849c766..cd1dadaf 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeTask.java +++ b/src/main/java/fr/xephi/authme/task/PurgeTask.java @@ -1,12 +1,7 @@ package fr.xephi.authme.task; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.properties.PurgeSettings; +import fr.xephi.authme.process.purge.PurgeService; import java.util.HashSet; import java.util.Set; @@ -19,16 +14,13 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import javax.inject.Inject; - public class PurgeTask extends BukkitRunnable { + private PurgeService purgeService; + //how many players we should check for each tick private static final int INTERVALL_CHECK = 5; - private final AuthMe plugin; - private final NewSetting newSetting; - private final UUID sender; private final Set toPurge; @@ -39,19 +31,8 @@ public class PurgeTask extends BukkitRunnable { private int currentPage = 0; - public PurgeTask(AuthMe plugin, CommandSender sender, Set purged) { - this(plugin, sender, purged, false, Bukkit.getOfflinePlayers()); - } - - public PurgeTask(AuthMe plugin, CommandSender sender, Set purged, Set offlinePlayers) { - this(plugin, sender, purged, false - , offlinePlayers.toArray(new OfflinePlayer[offlinePlayers.size()])); - } - - public PurgeTask(AuthMe plugin, CommandSender sender, Set purged + public PurgeTask(CommandSender sender, Set purged , boolean autoPurge, OfflinePlayer[] offlinePlayers) { - this.plugin = plugin; - this.newSetting = plugin.getSettings(); if (sender instanceof Player) { this.sender = ((Player) sender).getUniqueId(); @@ -72,6 +53,21 @@ public class PurgeTask extends BukkitRunnable { // } } + public PurgeTask(PurgeService service, CommandSender sender, Set toPurge, OfflinePlayer[] offlinePlayers, + boolean autoPurging) { + this.purgeService = service; + if (sender instanceof Player) { + this.sender = ((Player) sender).getUniqueId(); + } else { + this.sender = null; + } + + this.toPurge = toPurge; + this.totalPurgeCount = toPurge.size(); + this.autoPurging = autoPurging; + this.offlinePlayers = offlinePlayers; + } + @Override public void run() { if (toPurge.isEmpty()) { @@ -116,26 +112,11 @@ public class PurgeTask extends BukkitRunnable { private void purgeData(Set playerPortion, Set namePortion) { // Purge other data - if (newSetting.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES) - && plugin.getPluginHooks().isEssentialsAvailable()) { - plugin.dataManager.purgeEssentials(playerPortion); - } - - if (newSetting.getProperty(PurgeSettings.REMOVE_PLAYER_DAT)) { - plugin.dataManager.purgeDat(playerPortion); - } - - if (newSetting.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES)) { - plugin.dataManager.purgeLimitedCreative(namePortion); - } - - if (newSetting.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE)) { - plugin.dataManager.purgeAntiXray(namePortion); - } - - if (newSetting.getProperty(PurgeSettings.REMOVE_PERMISSIONS)) { - plugin.dataManager.purgePermissions(playerPortion); - } + purgeService.purgeEssentials(playerPortion); + purgeService.purgeDat(playerPortion); + purgeService.purgeLimitedCreative(namePortion); + purgeService.purgeAntiXray(namePortion); + purgeService.purgePermissions(playerPortion); } private void finish() { @@ -146,7 +127,7 @@ public class PurgeTask extends BukkitRunnable { ConsoleLogger.info("AutoPurge Finished!"); if (autoPurging) { - plugin.notifyAutoPurgeEnd(); + purgeService.setAutoPurging(false); } } From 5156a24b4026e9d25eadb7471116a55507163b5f Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Thu, 16 Jun 2016 12:35:49 -0400 Subject: [PATCH 007/217] remove unused PurgeTask constructor --- .../java/fr/xephi/authme/task/PurgeTask.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/main/java/fr/xephi/authme/task/PurgeTask.java b/src/main/java/fr/xephi/authme/task/PurgeTask.java index cd1dadaf..983f48f2 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeTask.java +++ b/src/main/java/fr/xephi/authme/task/PurgeTask.java @@ -31,28 +31,6 @@ public class PurgeTask extends BukkitRunnable { private int currentPage = 0; - public PurgeTask(CommandSender sender, Set purged - , boolean autoPurge, OfflinePlayer[] offlinePlayers) { - - if (sender instanceof Player) { - this.sender = ((Player) sender).getUniqueId(); - } else { - this.sender = null; - } - - this.toPurge = purged; - this.totalPurgeCount = purged.size(); - this.autoPurging = autoPurge; - this.offlinePlayers = offlinePlayers; - - //this is commented out because I assume all players in the database already have an lowercase name -// toPurge = new HashSet<>(purged.size()); - //make a new list with lowercase names to make the username test based on a hash -// for (String username : purged) { -// toPurge.add(username.toLowerCase()); -// } - } - public PurgeTask(PurgeService service, CommandSender sender, Set toPurge, OfflinePlayer[] offlinePlayers, boolean autoPurging) { this.purgeService = service; From fb8baeafd2a7b31549f66c15211cd47e07a86ede Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Thu, 16 Jun 2016 12:52:42 -0400 Subject: [PATCH 008/217] remove database auto purge methods --- .../authme/datasource/CacheDataSource.java | 10 ------ .../xephi/authme/datasource/DataSource.java | 9 ----- .../fr/xephi/authme/datasource/FlatFile.java | 34 ------------------- .../fr/xephi/authme/datasource/MySQL.java | 23 ------------- .../fr/xephi/authme/datasource/SQLite.java | 22 ------------ 5 files changed, 98 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 141b4fc0..50c61351 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -138,16 +138,6 @@ public class CacheDataSource implements DataSource { return result; } - @Override - public Set autoPurgeDatabase(long until) { - Set cleared = source.autoPurgeDatabase(until); - for (String name : cleared) { - cachedAuths.invalidate(name); - } - - return cleared; - } - @Override public Set getRecordsToPurge(long until) { return source.getRecordsToPurge(until); diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index c0415858..67484172 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -69,15 +69,6 @@ public interface DataSource extends Reloadable { */ boolean updatePassword(String user, HashedPassword password); - /** - * Purge all records in the database whose last login was longer ago than - * the given time if they do not have the bypass permission. - * - * @param until The minimum last login - * @return The account names that have been removed - */ - Set autoPurgeDatabase(long until); - /** * Get all records in the database whose last login was before the given time. * diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index 1c4e8fba..5464e0cb 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -229,40 +229,6 @@ public class FlatFile implements DataSource { return true; } - @Override - public Set autoPurgeDatabase(long until) { - BufferedReader br = null; - BufferedWriter bw = null; - ArrayList lines = new ArrayList<>(); - Set cleared = new HashSet<>(); - try { - br = new BufferedReader(new FileReader(source)); - String line; - while ((line = br.readLine()) != null) { - String[] args = line.split(":"); - if (args.length >= 4) { - if (Long.parseLong(args[3]) >= until) { - lines.add(line); - continue; - } - } - cleared.add(args[0]); - } - bw = new BufferedWriter(new FileWriter(source)); - for (String l : lines) { - bw.write(l + "\n"); - } - } catch (IOException ex) { - ConsoleLogger.showError(ex.getMessage()); - return cleared; - } finally { - silentClose(br); - silentClose(bw); - } - - return cleared; - } - @Override public Set getRecordsToPurge(long until) { BufferedReader br = null; diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index ac96714d..02aa66e3 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -612,29 +612,6 @@ public class MySQL implements DataSource { return false; } - @Override - public Set autoPurgeDatabase(long until) { - Set list = new HashSet<>(); - String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + " getRecordsToPurge(long until) { Set list = new HashSet<>(); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index f5cac059..7a0a5c8d 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -292,28 +292,6 @@ public class SQLite implements DataSource { return false; } - @Override - public Set autoPurgeDatabase(long until) { - Set list = new HashSet<>(); - String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + " getRecordsToPurge(long until) { Set list = new HashSet<>(); From 2ac89f59381983ef4751edfb2bcd25dd0ac2701b Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 16 Jun 2016 21:04:12 +0200 Subject: [PATCH 009/217] Apply minor changes to PurgeService - Remove various imports / unused fields - Make CacheDataSource call source for purging on DB - Minor: SQLite - place creation of PreparedStatement outside of loop - Make specific purge actions called from task package-private (clearer from the outside which methods can be called from the outside) --- src/main/java/fr/xephi/authme/AuthMe.java | 15 ++--------- .../authme/PurgeBannedPlayersCommand.java | 8 ++---- .../executable/authme/PurgeCommand.java | 9 +------ .../authme/datasource/CacheDataSource.java | 1 + .../fr/xephi/authme/datasource/FlatFile.java | 1 - .../fr/xephi/authme/datasource/SQLite.java | 27 +++++++++---------- .../handlers/GroupManagerHandler.java | 1 - .../{process/purge => task}/PurgeService.java | 15 +++++------ .../java/fr/xephi/authme/task/PurgeTask.java | 10 +++---- 9 files changed, 30 insertions(+), 57 deletions(-) rename src/main/java/fr/xephi/authme/{process/purge => task}/PurgeService.java (95%) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 486c474e..d9f9bd87 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -36,7 +36,7 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsSystemType; import fr.xephi.authme.process.Management; -import fr.xephi.authme.process.purge.PurgeService; +import fr.xephi.authme.task.PurgeService; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.settings.NewSetting; @@ -47,14 +47,11 @@ import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.propertymap.PropertyMap; -import fr.xephi.authme.task.PurgeTask; import fr.xephi.authme.util.BukkitService; -import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.FileUtils; import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.MigrationService; @@ -75,11 +72,9 @@ 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.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; @@ -131,10 +126,8 @@ public class AuthMe extends JavaPlugin { private DataSource database; private PluginHooks pluginHooks; private SpawnLoader spawnLoader; - private boolean autoPurging; private BukkitService bukkitService; private AuthMeServiceInitializer initializer; - private PurgeService purgeService; /** * Get the plugin's instance. @@ -257,7 +250,6 @@ public class AuthMe extends JavaPlugin { api = initializer.get(NewAPI.class); management = initializer.get(Management.class); dataManager = initializer.get(DataManager.class); - purgeService = initializer.get(PurgeService.class); initializer.get(API.class); // Set up Metrics @@ -313,6 +305,7 @@ public class AuthMe extends JavaPlugin { } // Purge on start if enabled + PurgeService purgeService = initializer.get(PurgeService.class); purgeService.runAutoPurge(); } @@ -714,10 +707,6 @@ public class AuthMe extends JavaPlugin { return commandHandler.processCommand(sender, commandLabel, args); } - public void notifyAutoPurgeEnd() { - this.autoPurging = false; - } - // ------------- // Service getters (deprecated) 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 28c5e5ff..b298fd17 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java @@ -1,12 +1,8 @@ package fr.xephi.authme.command.executable.authme; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.process.purge.PurgeService; -import fr.xephi.authme.task.PurgeTask; +import fr.xephi.authme.task.PurgeService; import fr.xephi.authme.util.BukkitService; -import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; @@ -30,8 +26,8 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand { @Override public void executeCommand(CommandSender sender, List arguments) { // Get the list of banned players - Set namedBanned = new HashSet<>(); Set bannedPlayers = bukkitService.getBannedPlayers(); + Set namedBanned = new HashSet<>(bannedPlayers.size()); for (OfflinePlayer offlinePlayer : bannedPlayers) { namedBanned.add(offlinePlayer.getName().toLowerCase()); } 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 99814566..1885dc76 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java @@ -1,17 +1,13 @@ package fr.xephi.authme.command.executable.authme; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.process.purge.PurgeService; -import fr.xephi.authme.task.PurgeTask; +import fr.xephi.authme.task.PurgeService; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import javax.inject.Inject; import java.util.Calendar; import java.util.List; -import java.util.Set; /** * Command for purging the data of players which have not been since for a given number @@ -24,9 +20,6 @@ public class PurgeCommand implements ExecutableCommand { @Inject private PurgeService purgeService; - @Inject - private AuthMe plugin; - @Override public void executeCommand(CommandSender sender, List arguments) { // Get the days parameter diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 50c61351..547110e4 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -145,6 +145,7 @@ public class CacheDataSource implements DataSource { @Override public void purgeRecords(Set toPurge) { + source.purgeRecords(toPurge); for (String name : toPurge) { cachedAuths.invalidate(name); } diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index 5464e0cb..dc15bcb9 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -8,7 +8,6 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; -import javax.swing.*; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Closeable; diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index 7a0a5c8d..fa8ddedd 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -1,5 +1,14 @@ package fr.xephi.authme.datasource; +import com.google.common.annotations.VisibleForTesting; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.util.StringUtils; + import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -11,16 +20,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import com.google.common.annotations.VisibleForTesting; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.util.StringUtils; - /** */ public class SQLite implements DataSource { @@ -314,13 +313,13 @@ public class SQLite implements DataSource { @Override public void purgeRecords(Set toPurge) { String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - for (String name : toPurge) { - try (PreparedStatement deletePst = con.prepareStatement(delete)) { + try (PreparedStatement deletePst = con.prepareStatement(delete)) { + for (String name : toPurge) { deletePst.setString(1, name); deletePst.executeUpdate(); - } catch (SQLException ex) { - logSqlException(ex); } + } catch (SQLException ex) { + logSqlException(ex); } } diff --git a/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java index 475fafee..383f109b 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/GroupManagerHandler.java @@ -3,7 +3,6 @@ package fr.xephi.authme.permission.handlers; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsSystemType; import org.anjocaido.groupmanager.GroupManager; -import org.anjocaido.groupmanager.data.User; import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; import org.bukkit.Bukkit; import org.bukkit.entity.Player; diff --git a/src/main/java/fr/xephi/authme/process/purge/PurgeService.java b/src/main/java/fr/xephi/authme/task/PurgeService.java similarity index 95% rename from src/main/java/fr/xephi/authme/process/purge/PurgeService.java rename to src/main/java/fr/xephi/authme/task/PurgeService.java index 6970a5ba..b577e4e5 100644 --- a/src/main/java/fr/xephi/authme/process/purge/PurgeService.java +++ b/src/main/java/fr/xephi/authme/task/PurgeService.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.process.purge; +package fr.xephi.authme.task; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.datasource.DataSource; @@ -8,7 +8,6 @@ import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.PurgeSettings; -import fr.xephi.authme.task.PurgeTask; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.Utils; @@ -72,7 +71,7 @@ public class PurgeService implements Reloadable { * * @param autoPurging True if automatically purging. */ - public void setAutoPurging(boolean autoPurging) { + void setAutoPurging(boolean autoPurging) { this.autoPurging = autoPurging; } @@ -165,7 +164,7 @@ public class PurgeService implements Reloadable { return toPurge; } - public synchronized void purgeAntiXray(Set cleared) { + synchronized void purgeAntiXray(Set cleared) { if (!removeAntiXrayFiles) { return; } @@ -189,7 +188,7 @@ public class PurgeService implements Reloadable { ConsoleLogger.info("AutoPurge: Removed " + i + " AntiXRayData Files"); } - public synchronized void purgeLimitedCreative(Set cleared) { + synchronized void purgeLimitedCreative(Set cleared) { if (!removeLimitedCreativeInventories) { return; } @@ -230,7 +229,7 @@ public class PurgeService implements Reloadable { ConsoleLogger.info("AutoPurge: Removed " + i + " LimitedCreative Survival, Creative and Adventure files"); } - public synchronized void purgeDat(Set cleared) { + synchronized void purgeDat(Set cleared) { if (!removePlayerDat) { return; } @@ -254,7 +253,7 @@ public class PurgeService implements Reloadable { * * @param cleared List of String */ - public synchronized void purgeEssentials(Set cleared) { + synchronized void purgeEssentials(Set cleared) { if (!removeEssentialsFiles && !pluginHooks.isEssentialsAvailable()) { return; } @@ -283,7 +282,7 @@ public class PurgeService implements Reloadable { // TODO: What is this method for? Is it correct? // TODO: Make it work with OfflinePlayers group data. - public synchronized void purgePermissions(Set cleared) { + synchronized void purgePermissions(Set cleared) { if (!removePermissions) { return; } diff --git a/src/main/java/fr/xephi/authme/task/PurgeTask.java b/src/main/java/fr/xephi/authme/task/PurgeTask.java index 983f48f2..edfb1b50 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeTask.java +++ b/src/main/java/fr/xephi/authme/task/PurgeTask.java @@ -1,12 +1,6 @@ package fr.xephi.authme.task; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.process.purge.PurgeService; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; @@ -14,6 +8,10 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + public class PurgeTask extends BukkitRunnable { private PurgeService purgeService; From 94451647f33c933f6826dc134c589ac10f3d11ce Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 16 Jun 2016 22:06:49 +0200 Subject: [PATCH 010/217] #674 #656 Delete DataManager - Replaced with PurgeService --- src/main/java/fr/xephi/authme/AuthMe.java | 3 - .../java/fr/xephi/authme/DataManager.java | 145 ------------------ 2 files changed, 148 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/DataManager.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index d9f9bd87..a5f329cf 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -107,8 +107,6 @@ public class AuthMe extends JavaPlugin { public NewAPI api; // TODO #655: Encapsulate mail public SendMailSSL mail; - // TODO #656: Encapsulate data manager - public DataManager dataManager; /* * Private instances */ @@ -249,7 +247,6 @@ public class AuthMe extends JavaPlugin { 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 diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java deleted file mode 100644 index feaa69d4..00000000 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ /dev/null @@ -1,145 +0,0 @@ -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.OfflinePlayer; -import org.bukkit.Server; - -import javax.inject.Inject; -import java.io.File; - -import static fr.xephi.authme.util.StringUtils.makePath; -import java.util.Set; - -/** - */ -public class DataManager { - - @Inject - private Server server; - @Inject - private PluginHooks pluginHooks; - @Inject - private BukkitService bukkitService; - @Inject - private NewSetting settings; - @Inject - private PermissionsManager permissionsManager; - - DataManager() { } - - public void purgeAntiXray(Set cleared) { - int i = 0; - File dataFolder = new File("." + File.separator + "plugins" + File.separator + "AntiXRayData" - + File.separator + "PlayerData"); - if (!dataFolder.exists() || !dataFolder.isDirectory()) { - return; - } - - for (String file : dataFolder.list()) { - if (cleared.contains(file.toLowerCase())) { - File playerFile = new File(dataFolder, file); - if (playerFile.exists() && playerFile.delete()) { - i++; - } - } - } - - ConsoleLogger.info("AutoPurge: Removed " + i + " AntiXRayData Files"); - } - - public synchronized void purgeLimitedCreative(Set cleared) { - int i = 0; - File dataFolder = new File("." + File.separator + "plugins" + File.separator + "LimitedCreative" - + File.separator + "inventories"); - if (!dataFolder.exists() || !dataFolder.isDirectory()) { - return; - } - for (String file : dataFolder.list()) { - String name = file; - int idx; - idx = file.lastIndexOf("_creative.yml"); - if (idx != -1) { - name = name.substring(0, idx); - } else { - idx = file.lastIndexOf("_adventure.yml"); - if (idx != -1) { - name = name.substring(0, idx); - } else { - idx = file.lastIndexOf(".yml"); - if (idx != -1) { - name = name.substring(0, idx); - } - } - } - if (name.equals(file)) { - continue; - } - if (cleared.contains(name.toLowerCase())) { - File dataFile = new File(dataFolder, file); - if (dataFile.exists() && dataFile.delete()) { - i++; - } - } - } - ConsoleLogger.info("AutoPurge: Removed " + i + " LimitedCreative Survival, Creative and Adventure files"); - } - - public synchronized void purgeDat(Set cleared) { - int i = 0; - File dataFolder = new File(server.getWorldContainer() - , makePath(settings.getProperty(PurgeSettings.DEFAULT_WORLD), "players")); - - for (OfflinePlayer offlinePlayer : cleared) { - File playerFile = new File(dataFolder, Utils.getUUIDorName(offlinePlayer) + ".dat"); - if (playerFile.delete()) { - i++; - } - } - - ConsoleLogger.info("AutoPurge: Removed " + i + " .dat Files"); - } - - /** - * Method purgeEssentials. - * - * @param cleared List of String - */ - public void purgeEssentials(Set cleared) { - int i = 0; - File essentialsDataFolder = pluginHooks.getEssentialsDataFolder(); - if (essentialsDataFolder == null) { - ConsoleLogger.info("Cannot purge Essentials: plugin is not loaded"); - return; - } - - final File userDataFolder = new File(essentialsDataFolder, "userdata"); - if (!userDataFolder.exists() || !userDataFolder.isDirectory()) { - return; - } - - for (OfflinePlayer offlinePlayer : cleared) { - File playerFile = new File(userDataFolder, Utils.getUUIDorName(offlinePlayer) + ".yml"); - if (playerFile.exists() && playerFile.delete()) { - i++; - } - } - - ConsoleLogger.info("AutoPurge: Removed " + i + " EssentialsFiles"); - } - - // TODO: What is this method for? Is it correct? - // TODO: Make it work with OfflinePlayers group data. - public synchronized void purgePermissions(Set cleared) { - for (OfflinePlayer offlinePlayer : cleared) { - String name = offlinePlayer.getName(); - permissionsManager.removeAllGroups(bukkitService.getPlayerExact(name)); - } - - ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); - } -} From 3629c51fc1798533a6101f296db2858de88df66e Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 16 Jun 2016 22:52:11 +0200 Subject: [PATCH 011/217] #674 PurgeService: Always register if purging, reduce code duplication - Rename autoPurging to isPurging: we should always register if a purge task is in progress (regardless if autopurge or not) and deny any new requests - Reduce the same logic being coded multiple times by calling through the methods - DataSource: remove purgeBanned in favor of purgeRecords, both do exactly the same thing --- .../authme/PurgeBannedPlayersCommand.java | 2 +- .../authme/datasource/CacheDataSource.java | 12 +-- .../xephi/authme/datasource/DataSource.java | 7 -- .../fr/xephi/authme/datasource/FlatFile.java | 31 ------- .../fr/xephi/authme/datasource/MySQL.java | 17 +--- .../fr/xephi/authme/datasource/SQLite.java | 13 --- .../fr/xephi/authme/task/PurgeService.java | 87 +++++++++---------- .../java/fr/xephi/authme/task/PurgeTask.java | 12 +-- .../fr/xephi/authme/util/BukkitService.java | 9 ++ .../AbstractDataSourceIntegrationTest.java | 6 +- 10 files changed, 61 insertions(+), 135 deletions(-) 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 b298fd17..30e3bd53 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 @@ -32,6 +32,6 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand { namedBanned.add(offlinePlayer.getName().toLowerCase()); } - purgeService.purgeBanned(sender, namedBanned, bannedPlayers); + purgeService.purgePlayers(sender, namedBanned, bannedPlayers.toArray(new OfflinePlayer[bannedPlayers.size()])); } } diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 547110e4..473633e4 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -143,14 +143,6 @@ public class CacheDataSource implements DataSource { return source.getRecordsToPurge(until); } - @Override - public void purgeRecords(Set toPurge) { - source.purgeRecords(toPurge); - for (String name : toPurge) { - cachedAuths.invalidate(name); - } - } - @Override public boolean removeAuth(String name) { name = name.toLowerCase(); @@ -193,8 +185,8 @@ public class CacheDataSource implements DataSource { } @Override - public void purgeBanned(final Set banned) { - source.purgeBanned(banned); + public void purgeRecords(final Set banned) { + source.purgeRecords(banned); cachedAuths.invalidateAll(banned); } diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index 67484172..f1bb991a 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -129,13 +129,6 @@ public interface DataSource extends Reloadable { */ void close(); - /** - * Purge all given players, i.e. delete all players whose name is in the list. - * - * @param banned the list of players to delete - */ - void purgeBanned(Set banned); - /** * Return the data source type. * diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index dc15bcb9..7ae6026e 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -441,37 +441,6 @@ public class FlatFile implements DataSource { return 0; } - @Override - public void purgeBanned(Set banned) { - BufferedReader br = null; - BufferedWriter bw = null; - ArrayList lines = new ArrayList<>(); - try { - br = new BufferedReader(new FileReader(source)); - String line; - while ((line = br.readLine()) != null) { - String[] args = line.split(":"); - try { - if (banned.contains(args[0])) { - lines.add(line); - } - } catch (NullPointerException | ArrayIndexOutOfBoundsException ignored) { - } - } - bw = new BufferedWriter(new FileWriter(source)); - for (String l : lines) { - bw.write(l + "\n"); - } - - } catch (IOException ex) { - ConsoleLogger.showError(ex.getMessage()); - - } finally { - silentClose(br); - silentClose(bw); - } - } - @Override public DataSourceType getType() { return DataSourceType.FILE; diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 02aa66e3..fbf51eb9 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -632,19 +632,6 @@ public class MySQL implements DataSource { return list; } - @Override - public void purgeRecords(Set toPurge) { - String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement deletePst = con.prepareStatement(delete)) { - for (String name : toPurge) { - deletePst.setString(1, name); - deletePst.executeUpdate(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - @Override public boolean removeAuth(String user) { user = user.toLowerCase(); @@ -752,10 +739,10 @@ public class MySQL implements DataSource { } @Override - public void purgeBanned(Set banned) { + public void purgeRecords(Set toPurge) { String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - for (String name : banned) { + for (String name : toPurge) { pst.setString(1, name); pst.executeUpdate(); } diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index fa8ddedd..d5109af2 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -452,19 +452,6 @@ public class SQLite implements DataSource { return 0; } - @Override - public void purgeBanned(Set banned) { - String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - for (String name : banned) { - pst.setString(1, name); - pst.executeUpdate(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - @Override public DataSourceType getType() { return DataSourceType.SQLITE; diff --git a/src/main/java/fr/xephi/authme/task/PurgeService.java b/src/main/java/fr/xephi/authme/task/PurgeService.java index b577e4e5..b7c680ba 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeService.java +++ b/src/main/java/fr/xephi/authme/task/PurgeService.java @@ -11,7 +11,6 @@ import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.Utils; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.Server; @@ -46,10 +45,9 @@ public class PurgeService implements Reloadable { @Inject private Server server; - private boolean autoPurging = false; + private boolean isPurging = false; // Settings - private boolean useAutoPurge; private boolean removeEssentialsFiles; private boolean removePlayerDat; private boolean removeLimitedCreativeInventories; @@ -58,55 +56,40 @@ public class PurgeService implements Reloadable { private int daysBeforePurge; /** - * Return whether an automatic purge is in progress. + * Return whether a purge is in progress. * * @return True if purging. */ - public boolean isAutoPurging() { - return this.autoPurging; + public boolean isPurging() { + return this.isPurging; } /** - * Set if an automatic purge is currently in progress. + * Set if a purge is currently in progress. * - * @param autoPurging True if automatically purging. + * @param purging True if purging. */ - void setAutoPurging(boolean autoPurging) { - this.autoPurging = autoPurging; + void setPurging(boolean purging) { + this.isPurging = purging; } /** - * Purges players from the database. Ran on startup. + * Purges players from the database. Run on startup if enabled. */ public void runAutoPurge() { - if (!useAutoPurge || autoPurging) { + if (!settings.getProperty(PurgeSettings.USE_AUTO_PURGE)) { + return; + } else if (daysBeforePurge <= 0) { + ConsoleLogger.showError("Configured days before purging must be positive"); return; } - this.autoPurging = true; - - // Get the initial list of players to purge ConsoleLogger.info("Automatically purging the database..."); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, daysBeforePurge); long until = calendar.getTimeInMillis(); - Set initialPurge = dataSource.getRecordsToPurge(until); - if (CollectionUtils.isEmpty(initialPurge)) { - return; - } - - // Remove players from the purge list if they have bypass permission - Set toPurge = getFinalPurgeList(initialPurge); - - // Purge players from the database - dataSource.purgeRecords(toPurge); - ConsoleLogger.info("Purged the database: " + toPurge.size() + " accounts removed!"); - ConsoleLogger.info("Purging user accounts..."); - - // Schedule a PurgeTask - PurgeTask purgeTask = new PurgeTask(this, Bukkit.getConsoleSender(), toPurge, Bukkit.getOfflinePlayers(), true); - bukkitService.runTaskAsynchronously(purgeTask); + runPurge(null, until); } /** @@ -119,28 +102,34 @@ public class PurgeService implements Reloadable { //todo: note this should may run async because it may executes a SQL-Query Set initialPurge = dataSource.getRecordsToPurge(until); if (CollectionUtils.isEmpty(initialPurge)) { + logAndSendMessage(sender, "No players to purge"); return; } Set toPurge = getFinalPurgeList(initialPurge); - - // Purge records from the database - dataSource.purgeRecords(toPurge); - sender.sendMessage(ChatColor.GOLD + "Deleted " + toPurge.size() + " user accounts"); - sender.sendMessage(ChatColor.GOLD + "Purging user accounts..."); - - // Schedule a PurgeTask - PurgeTask purgeTask = new PurgeTask(this, sender, toPurge, Bukkit.getOfflinePlayers(), false); - bukkitService.runTaskAsynchronously(purgeTask); + purgePlayers(sender, toPurge, bukkitService.getOfflinePlayers()); } - public void purgeBanned(CommandSender sender, Set bannedNames, Set bannedPlayers) { + /** + * Purges the given list of player names. + * + * @param sender Sender running the command. + * @param names The names to remove. + * @param players Collection of OfflinePlayers (including those with the given names). + */ + public void purgePlayers(CommandSender sender, Set names, OfflinePlayer[] players) { //todo: note this should may run async because it may executes a SQL-Query - dataSource.purgeBanned(bannedNames); + if (isPurging) { + logAndSendMessage(sender, "Purge is already in progress! Aborting purge request"); + return; + } - OfflinePlayer[] bannedPlayersArray = new OfflinePlayer[bannedPlayers.size()]; - bannedPlayers.toArray(bannedPlayersArray); - PurgeTask purgeTask = new PurgeTask(this, sender, bannedNames, bannedPlayersArray, false); + dataSource.purgeRecords(names); + logAndSendMessage(sender, ChatColor.GOLD + "Deleted " + names.size() + " user accounts"); + logAndSendMessage(sender, ChatColor.GOLD + "Purging user accounts..."); + + isPurging = true; + PurgeTask purgeTask = new PurgeTask(this, sender, names, players); bukkitService.runTaskAsynchronously(purgeTask); } @@ -295,10 +284,16 @@ public class PurgeService implements Reloadable { ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); } + private static void logAndSendMessage(CommandSender sender, String message) { + ConsoleLogger.info(message); + if (sender != null) { + sender.sendMessage(message); + } + } + @PostConstruct @Override public void reload() { - this.useAutoPurge = settings.getProperty(PurgeSettings.USE_AUTO_PURGE); this.removeEssentialsFiles = settings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES); this.removePlayerDat = settings.getProperty(PurgeSettings.REMOVE_PLAYER_DAT); this.removeAntiXrayFiles = settings.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE); diff --git a/src/main/java/fr/xephi/authme/task/PurgeTask.java b/src/main/java/fr/xephi/authme/task/PurgeTask.java index edfb1b50..e2252da8 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeTask.java +++ b/src/main/java/fr/xephi/authme/task/PurgeTask.java @@ -23,14 +23,11 @@ public class PurgeTask extends BukkitRunnable { private final Set toPurge; private final OfflinePlayer[] offlinePlayers; - - private final boolean autoPurging; private final int totalPurgeCount; private int currentPage = 0; - public PurgeTask(PurgeService service, CommandSender sender, Set toPurge, OfflinePlayer[] offlinePlayers, - boolean autoPurging) { + public PurgeTask(PurgeService service, CommandSender sender, Set toPurge, OfflinePlayer[] offlinePlayers) { this.purgeService = service; if (sender instanceof Player) { this.sender = ((Player) sender).getUniqueId(); @@ -40,7 +37,6 @@ public class PurgeTask extends BukkitRunnable { this.toPurge = toPurge; this.totalPurgeCount = toPurge.size(); - this.autoPurging = autoPurging; this.offlinePlayers = offlinePlayers; } @@ -101,10 +97,8 @@ public class PurgeTask extends BukkitRunnable { // Show a status message sendMessage(ChatColor.GREEN + "[AuthMe] Database has been purged correctly"); - ConsoleLogger.info("AutoPurge Finished!"); - if (autoPurging) { - purgeService.setAutoPurging(false); - } + ConsoleLogger.info("Purge Finished!"); + purgeService.setPurging(false); } private void sendMessage(String message) { diff --git a/src/main/java/fr/xephi/authme/util/BukkitService.java b/src/main/java/fr/xephi/authme/util/BukkitService.java index 8b94fe49..a88ebafc 100644 --- a/src/main/java/fr/xephi/authme/util/BukkitService.java +++ b/src/main/java/fr/xephi/authme/util/BukkitService.java @@ -135,6 +135,15 @@ public class BukkitService { return Bukkit.getBannedPlayers(); } + /** + * Gets every player that has ever played on this server. + * + * @return an array containing all previous players + */ + public OfflinePlayer[] getOfflinePlayers() { + return Bukkit.getOfflinePlayers(); + } + /** * Safe way to retrieve the list of online players from the server. Depending on the * implementation of the server, either an array of {@link Player} instances is being returned, diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java index bf8d54d5..e9488a40 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java @@ -5,13 +5,13 @@ import fr.xephi.authme.security.crypts.HashedPassword; import org.junit.Test; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static fr.xephi.authme.AuthMeMatchers.equalToHash; import static fr.xephi.authme.AuthMeMatchers.hasAuthBasicData; import static fr.xephi.authme.AuthMeMatchers.hasAuthLocation; -import java.util.HashSet; -import java.util.Set; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; @@ -227,7 +227,7 @@ public abstract class AbstractDataSourceIntegrationTest { assumeThat(dataSource.getAccountsRegistered(), equalTo(2)); // when - dataSource.purgeBanned(playersToDelete); + dataSource.purgeRecords(playersToDelete); // then assertThat(dataSource.getAccountsRegistered(), equalTo(1)); From ac73d43573cef98b3bea4fa13f9ab7b8ab5bbdb8 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 17 Jun 2016 02:17:02 +0200 Subject: [PATCH 012/217] Add Gnat008 to team.txt --- team.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/team.txt b/team.txt index 7a346aa1..0d0f7f9b 100644 --- a/team.txt +++ b/team.txt @@ -6,6 +6,7 @@ DNx5 - Developer ljacqu - Developer TimVisee - Developer games647 - Developer +Gnat008 - Developer Gabriele C. (sgdc3) - Project Manager, Contributor Retired staff: From c79857cc14e0630feea5d42d8a9eb0e46d8f547e Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 17 Jun 2016 02:18:12 +0200 Subject: [PATCH 013/217] Add Gnat008 as project author --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ec21ff63..a644b229 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ ${project.outputName} ${project.groupId}.${project.artifactId}.${bukkitplugin.name} - Xephi, sgdc3, DNx5, timvisee, games647, ljacqu + Xephi, sgdc3, DNx5, timvisee, games647, ljacqu, Gnat008 1.10-R0.1-SNAPSHOT From 16e999072363a48eb6f909584ae6b5867ef9a8bf Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Fri, 17 Jun 2016 20:49:03 -0400 Subject: [PATCH 014/217] implement checking permissions of an offline player --- .../authme/permission/DefaultPermission.java | 25 +++++++++++++++++++ .../authme/permission/PermissionsManager.java | 4 +-- .../fr/xephi/authme/task/PurgeService.java | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java index 3acbfa8c..31838b6a 100644 --- a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java +++ b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java @@ -1,5 +1,6 @@ package fr.xephi.authme.permission; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; /** @@ -13,6 +14,11 @@ public enum DefaultPermission { public boolean evaluate(CommandSender sender) { return false; } + + @Override + public boolean evaluateOffline(String name) { + return false; + } }, /** Only players with OP status have permission. */ @@ -21,6 +27,12 @@ public enum DefaultPermission { public boolean evaluate(CommandSender sender) { return sender.isOp(); } + + @Override + public boolean evaluateOffline(String name) { + // TODO Gnat008 20160617: Is this safe? + return Bukkit.getOfflinePlayer(name).isOp(); + } }, /** Everyone is granted permission. */ @@ -29,6 +41,11 @@ public enum DefaultPermission { public boolean evaluate(CommandSender sender) { return true; } + + @Override + public boolean evaluateOffline(String name) { + return true; + } }; /** Textual representation of the default permission. */ @@ -50,6 +67,14 @@ public enum DefaultPermission { */ public abstract boolean evaluate(CommandSender sender); + /** + * Evaluate whether permission is granted to an offline user. + * + * @param name The name to check + * @return True if the user has permission, false otherwise + */ + public abstract boolean evaluateOffline(String name); + /** * Return the textual representation. * diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index 2e5437a5..90199958 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -258,14 +258,14 @@ public class PermissionsManager { * * @return */ - public boolean hasPermission(String name, PermissionNode permissionNode) { + public boolean hasPermissionOffline(String name, PermissionNode permissionNode) { // Check if the permission node is null if (permissionNode == null) { return true; } if (!isEnabled()) { - return false; + return permissionNode.getDefaultPermission().evaluateOffline(name); } return handler.hasPermission(name, permissionNode); diff --git a/src/main/java/fr/xephi/authme/task/PurgeService.java b/src/main/java/fr/xephi/authme/task/PurgeService.java index b7c680ba..a2de2cd7 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeService.java +++ b/src/main/java/fr/xephi/authme/task/PurgeService.java @@ -145,7 +145,7 @@ public class PurgeService implements Reloadable { Set toPurge = new HashSet<>(); for (String name : initial) { - if (!permissionsManager.hasPermission(name, PlayerStatePermission.BYPASS_PURGE)) { + if (!permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_PURGE)) { toPurge.add(name); } } From 680427950f931a644edff0522f0adfedbe532f4e Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sat, 18 Jun 2016 15:41:05 +0700 Subject: [PATCH 015/217] derp --- .../authme/process/register/ProcessSyncPasswordRegister.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 16f1ad36..3076e7f1 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -27,7 +27,7 @@ import org.bukkit.potion.PotionEffectType; import javax.inject.Inject; -import static fr.xephi.authme.settings.properties.RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN; +import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; /** */ @@ -98,7 +98,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { Utils.teleportToSpawn(player); - if (service.getProperty(HIDE_TABLIST_BEFORE_LOGIN) && plugin.inventoryProtector != null) { + if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.inventoryProtector != null) { RestoreInventoryEvent event = new RestoreInventoryEvent(player); bukkitService.callEvent(event); if (!event.isCancelled()) { From cd1acfde1b0074ca0621d3635ec358921da7d8e6 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 18 Jun 2016 11:13:17 +0200 Subject: [PATCH 016/217] #674 Create tests for purge commands and purge service --- .../fr/xephi/authme/task/PurgeService.java | 22 +- .../authme/PurgeBannedPlayersCommandTest.java | 74 +++++ .../executable/authme/PurgeCommandTest.java | 89 ++++++ .../xephi/authme/task/PurgeServiceTest.java | 273 ++++++++++++++++++ 4 files changed, 442 insertions(+), 16 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommandTest.java create mode 100644 src/test/java/fr/xephi/authme/command/executable/authme/PurgeCommandTest.java create mode 100644 src/test/java/fr/xephi/authme/task/PurgeServiceTest.java diff --git a/src/main/java/fr/xephi/authme/task/PurgeService.java b/src/main/java/fr/xephi/authme/task/PurgeService.java index a2de2cd7..baa4e9eb 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeService.java +++ b/src/main/java/fr/xephi/authme/task/PurgeService.java @@ -48,11 +48,6 @@ public class PurgeService implements Reloadable { private boolean isPurging = false; // Settings - private boolean removeEssentialsFiles; - private boolean removePlayerDat; - private boolean removeLimitedCreativeInventories; - private boolean removeAntiXrayFiles; - private boolean removePermissions; private int daysBeforePurge; /** @@ -86,7 +81,7 @@ public class PurgeService implements Reloadable { ConsoleLogger.info("Automatically purging the database..."); Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.DATE, daysBeforePurge); + calendar.add(Calendar.DATE, -daysBeforePurge); long until = calendar.getTimeInMillis(); runPurge(null, until); @@ -154,7 +149,7 @@ public class PurgeService implements Reloadable { } synchronized void purgeAntiXray(Set cleared) { - if (!removeAntiXrayFiles) { + if (!settings.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE)) { return; } @@ -178,7 +173,7 @@ public class PurgeService implements Reloadable { } synchronized void purgeLimitedCreative(Set cleared) { - if (!removeLimitedCreativeInventories) { + if (!settings.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES)) { return; } @@ -219,7 +214,7 @@ public class PurgeService implements Reloadable { } synchronized void purgeDat(Set cleared) { - if (!removePlayerDat) { + if (!settings.getProperty(PurgeSettings.REMOVE_PLAYER_DAT)) { return; } @@ -243,7 +238,7 @@ public class PurgeService implements Reloadable { * @param cleared List of String */ synchronized void purgeEssentials(Set cleared) { - if (!removeEssentialsFiles && !pluginHooks.isEssentialsAvailable()) { + if (!settings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES) && !pluginHooks.isEssentialsAvailable()) { return; } @@ -272,7 +267,7 @@ public class PurgeService implements Reloadable { // TODO: What is this method for? Is it correct? // TODO: Make it work with OfflinePlayers group data. synchronized void purgePermissions(Set cleared) { - if (!removePermissions) { + if (!settings.getProperty(PurgeSettings.REMOVE_PERMISSIONS)) { return; } @@ -294,11 +289,6 @@ public class PurgeService implements Reloadable { @PostConstruct @Override public void reload() { - this.removeEssentialsFiles = settings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES); - this.removePlayerDat = settings.getProperty(PurgeSettings.REMOVE_PLAYER_DAT); - this.removeAntiXrayFiles = settings.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE); - this.removeLimitedCreativeInventories = settings.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES); - this.removePermissions = settings.getProperty(PurgeSettings.REMOVE_PERMISSIONS); this.daysBeforePurge = settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER); } } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommandTest.java new file mode 100644 index 00000000..295186cf --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommandTest.java @@ -0,0 +1,74 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.task.PurgeService; +import fr.xephi.authme.util.BukkitService; +import org.bukkit.OfflinePlayer; +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; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.collect.Sets.newHashSet; +import static org.hamcrest.Matchers.arrayContainingInAnyOrder; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * Test for {@link PurgeBannedPlayersCommand}. + */ +@RunWith(MockitoJUnitRunner.class) +public class PurgeBannedPlayersCommandTest { + + @InjectMocks + private PurgeBannedPlayersCommand command; + + @Mock + private PurgeService purgeService; + + @Mock + private BukkitService bukkitService; + + @Test + public void shouldForwardRequestToService() { + // given + String[] names = {"bannedPlayer", "other_banned", "evilplayer", "Someone"}; + OfflinePlayer[] players = offlinePlayersWithNames(names); + given(bukkitService.getBannedPlayers()).willReturn(newHashSet(players)); + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, Collections.emptyList()); + + // then + verify(bukkitService).getBannedPlayers(); + verify(purgeService).purgePlayers(eq(sender), eq(asLowerCaseSet(names)), + argThat(arrayContainingInAnyOrder(players))); + } + + private static OfflinePlayer[] offlinePlayersWithNames(String... names) { + OfflinePlayer[] players = new OfflinePlayer[names.length]; + for (int i = 0; i < names.length; ++i) { + OfflinePlayer player = mock(OfflinePlayer.class); + given(player.getName()).willReturn(names[i]); + players[i] = player; + } + return players; + } + + private static Set asLowerCaseSet(String... items) { + Set result = new HashSet<>(items.length); + for (String item : items) { + result.add(item.toLowerCase()); + } + return result; + } +} diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/PurgeCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeCommandTest.java new file mode 100644 index 00000000..05074adf --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeCommandTest.java @@ -0,0 +1,89 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.task.PurgeService; +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.Calendar; +import java.util.Collections; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +/** + * Test for {@link PurgeCommand}. + */ +@RunWith(MockitoJUnitRunner.class) +public class PurgeCommandTest { + + @InjectMocks + private PurgeCommand command; + + @Mock + private PurgeService purgeService; + + @Test + public void shouldHandleInvalidNumber() { + // given + String interval = "invalid"; + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, Collections.singletonList(interval)); + + // then + verify(sender).sendMessage(argThat(containsString("The value you've entered is invalid"))); + verifyZeroInteractions(purgeService); + } + + @Test + public void shouldRejectTooSmallInterval() { + // given + String interval = "29"; + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, Collections.singletonList(interval)); + + // then + verify(sender).sendMessage(argThat(containsString("You can only purge data older than 30 days"))); + verifyZeroInteractions(purgeService); + } + + @Test + public void shouldForwardToService() { + // given + String interval = "45"; + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, Collections.singletonList(interval)); + + // then + ArgumentCaptor captor = ArgumentCaptor.forClass(Long.class); + verify(purgeService).runPurge(eq(sender), captor.capture()); + + // Check the timestamp with a certain tolerance + int toleranceMillis = 100; + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DATE, -Integer.valueOf(interval)); + assertIsCloseTo(captor.getValue(), calendar.getTimeInMillis(), toleranceMillis); + } + + private static void assertIsCloseTo(long value1, long value2, long tolerance) { + assertThat(Math.abs(value1 - value2), not(greaterThan(tolerance))); + } + +} diff --git a/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java new file mode 100644 index 00000000..b20df325 --- /dev/null +++ b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java @@ -0,0 +1,273 @@ +package fr.xephi.authme.task; + +import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.TestHelper; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.initialization.FieldInjection; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.permission.PlayerStatePermission; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.PurgeSettings; +import fr.xephi.authme.util.BukkitService; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import static com.google.common.collect.Sets.newHashSet; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anySet; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +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 PurgeService}. + */ +@RunWith(MockitoJUnitRunner.class) +public class PurgeServiceTest { + + private PurgeService purgeService; + + @Mock + private BukkitService bukkitService; + @Mock + private DataSource dataSource; + @Mock + private NewSetting settings; + @Mock + private PermissionsManager permissionsManager; + @Mock + private PluginHooks pluginHooks; + @Mock + private Server server; + + @BeforeClass + public static void initLogger() { + TestHelper.setupLogger(); + } + + @Before + public void initSettingDefaults() { + given(settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)).willReturn(60); + } + + @Test + public void shouldNotRunAutoPurge() { + // given + given(settings.getProperty(PurgeSettings.USE_AUTO_PURGE)).willReturn(false); + + // when + initPurgeService(); + purgeService.runAutoPurge(); + + // then + verifyZeroInteractions(bukkitService, dataSource); + } + + @Test + public void shouldNotRunAutoPurgeForInvalidInterval() { + // given + given(settings.getProperty(PurgeSettings.USE_AUTO_PURGE)).willReturn(true); + given(settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)).willReturn(0); + + // when + initPurgeService(); + purgeService.runAutoPurge(); + + // then + verifyZeroInteractions(bukkitService, dataSource); + } + + @Test + public void shouldRunAutoPurge() { + // given + given(settings.getProperty(PurgeSettings.USE_AUTO_PURGE)).willReturn(true); + given(settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)).willReturn(60); + String[] playerNames = {"alpha", "bravo", "charlie", "delta"}; + given(dataSource.getRecordsToPurge(anyLong())).willReturn(newHashSet(playerNames)); + mockReturnedOfflinePlayers(); + mockHasBypassPurgePermission("bravo", "delta"); + + // when + initPurgeService(); + purgeService.runAutoPurge(); + + // then + ArgumentCaptor captor = ArgumentCaptor.forClass(Long.class); + verify(dataSource).getRecordsToPurge(captor.capture()); + assertCorrectPurgeTimestamp(captor.getValue(), 60); + verify(dataSource).purgeRecords(newHashSet("alpha", "charlie")); + assertThat(purgeService.isPurging(), equalTo(true)); + verifyScheduledPurgeTask(null, "alpha", "charlie"); + } + + @Test + public void shouldRecognizeNoPlayersToPurge() { + // given + long delay = 123012301L; + given(dataSource.getRecordsToPurge(delay)).willReturn(Collections.emptySet()); + CommandSender sender = mock(CommandSender.class); + + // when + initPurgeService(); + purgeService.runPurge(sender, delay); + + // then + verify(dataSource).getRecordsToPurge(delay); + verify(dataSource, never()).purgeRecords(anySet()); + verify(sender).sendMessage("No players to purge"); + verifyZeroInteractions(bukkitService, permissionsManager); + } + + @Test + public void shouldRunPurge() { + // given + long delay = 1809714L; + given(dataSource.getRecordsToPurge(delay)).willReturn(newHashSet("charlie", "delta", "echo", "foxtrot")); + mockReturnedOfflinePlayers(); + mockHasBypassPurgePermission("echo"); + Player sender = mock(Player.class); + UUID uuid = UUID.randomUUID(); + given(sender.getUniqueId()).willReturn(uuid); + + // when + initPurgeService(); + purgeService.runPurge(sender, delay); + + // then + verify(dataSource).getRecordsToPurge(delay); + verify(dataSource).purgeRecords(newHashSet("charlie", "delta", "foxtrot")); + verify(sender).sendMessage(argThat(containsString("Deleted 3 user accounts"))); + verifyScheduledPurgeTask(uuid, "charlie", "delta", "foxtrot"); + } + + @Test + public void shouldRunPurgeIfProcessIsAlreadyRunning() { + // given + initPurgeService(); + purgeService.setPurging(true); + CommandSender sender = mock(CommandSender.class); + OfflinePlayer[] players = mockReturnedOfflinePlayers(); + + // when + purgeService.purgePlayers(sender, newHashSet("test", "names"), players); + + // then + verify(sender).sendMessage(argThat(containsString("Purge is already in progress"))); + verifyZeroInteractions(bukkitService, dataSource, permissionsManager); + } + + /** + * Returns mock OfflinePlayer objects with names corresponding to A - G of the NATO phonetic alphabet, + * in various casing. + * + * @return list of offline players BukkitService is mocked to return + */ + private OfflinePlayer[] mockReturnedOfflinePlayers() { + String[] names = { "alfa", "Bravo", "charLIE", "delta", "ECHO", "Foxtrot", "golf" }; + OfflinePlayer[] players = new OfflinePlayer[names.length]; + for (int i = 0; i < names.length; ++i) { + OfflinePlayer player = mock(OfflinePlayer.class); + given(player.getName()).willReturn(names[i]); + players[i] = player; + } + given(bukkitService.getOfflinePlayers()).willReturn(players); + return players; + } + + /** + * Mocks the permission manager to say that the given names have the bypass purge permission. + * + * @param names the names + */ + private void mockHasBypassPurgePermission(String... names) { + for (String name : names) { + given(permissionsManager.hasPermissionOffline( + argThat(equalToIgnoringCase(name)), eq(PlayerStatePermission.BYPASS_PURGE))).willReturn(true); + } + } + + private void assertCorrectPurgeTimestamp(long timestamp, int configuredDays) { + final long toleranceMillis = 100L; + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DATE, -configuredDays); + long expectedTimestamp = cal.getTimeInMillis(); + + assertThat("Timestamp is equal to now minus " + configuredDays + " days (within tolerance)", + Math.abs(timestamp - expectedTimestamp), not(greaterThan(toleranceMillis))); + } + + @SuppressWarnings("unchecked") + private void verifyScheduledPurgeTask(UUID uuid, String... names) { + ArgumentCaptor captor = ArgumentCaptor.forClass(PurgeTask.class); + verify(bukkitService).runTaskAsynchronously(captor.capture()); + PurgeTask task = captor.getValue(); + + Object senderInTask = ReflectionTestUtils.getFieldValue(PurgeTask.class, task, "sender"); + Set namesInTask = (Set) ReflectionTestUtils.getFieldValue(PurgeTask.class, task, "toPurge"); + assertThat(senderInTask, Matchers.equalTo(uuid)); + assertThat(namesInTask, containsInAnyOrder(names)); + } + + // --------------- + // TODO ljacqu 20160618: Create a delayed injection test runner instead + private void initPurgeService() { + FieldInjection injection = FieldInjection.provide(PurgeService.class).get(); + purgeService = injection.instantiateWith(getFields(injection.getDependencies())); + purgeService.reload(); // because annotated with @PostConstruct + } + + private Object[] getFields(Class[] classes) { + Map, Object> mocksByType = orderMocksByType(); + List orderedMocks = new ArrayList<>(classes.length); + for (Class clazz : classes) { + orderedMocks.add(mocksByType.get(clazz)); + } + return orderedMocks.toArray(); + } + + private Map, Object> orderMocksByType() { + Map, Object> mocksByType = new HashMap<>(); + for (Field field : PurgeServiceTest.class.getDeclaredFields()) { + if (field.isAnnotationPresent(Mock.class)) { + try { + mocksByType.put(field.getType(), field.get(this)); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + } + return mocksByType; + } +} From a1c62e7c047cbd8d0a7651b93feef79c0c1b6f79 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 18 Jun 2016 13:19:07 +0200 Subject: [PATCH 017/217] Create delayed injection test runner - Test runner supporting new "DelayedInjection" annotation: such fields are only initialized with instantiation right before the first time they're used in tests, allowing to set up mock behavior beforehand --- .../AuthMeServiceInitializer.java | 42 +---- .../initialization/ConstructorInjection.java | 2 +- .../authme/initialization/FieldInjection.java | 2 +- .../initialization/InjectionHelper.java | 66 ++++++++ .../initialization/InstantiationFallback.java | 2 +- .../java/fr/xephi/authme/DelayedInject.java | 16 ++ .../xephi/authme/DelayedInjectionRunner.java | 154 ++++++++++++++++++ .../fr/xephi/authme/ReflectionTestUtils.java | 31 +++- .../authme/command/CommandMapperTest.java | 17 +- .../authme/listener/ListenerServiceTest.java | 23 +-- .../xephi/authme/task/PurgeServiceTest.java | 49 +----- .../tools/checktestmocks/CheckTestMocks.java | 9 +- .../tools/dependencygraph/DrawDependency.java | 9 +- 13 files changed, 296 insertions(+), 126 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/initialization/InjectionHelper.java create mode 100644 src/test/java/fr/xephi/authme/DelayedInject.java create mode 100644 src/test/java/fr/xephi/authme/DelayedInjectionRunner.java diff --git a/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java index 29e5adcf..33df29d0 100644 --- a/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java +++ b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java @@ -5,7 +5,6 @@ import com.google.common.collect.ImmutableSet; import fr.xephi.authme.settings.NewSetting; import javax.annotation.PostConstruct; -import javax.inject.Provider; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -167,8 +166,7 @@ public class AuthMeServiceInitializer { * @return the instantiated object */ private T instantiate(Class clazz, Set> traversedClasses) { - Injection injection = firstNotNull( - ConstructorInjection.provide(clazz), FieldInjection.provide(clazz), InstantiationFallback.provide(clazz)); + Injection injection = InjectionHelper.getInjection(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 " @@ -268,7 +266,7 @@ public class AuthMeServiceInitializer { * @param object the object to execute the post construct method for */ private static void executePostConstructMethod(Object object) { - Method postConstructMethod = getAndValidatePostConstructMethod(object.getClass()); + Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass()); if (postConstructMethod != null) { try { postConstructMethod.setAccessible(true); @@ -285,40 +283,4 @@ public class AuthMeServiceInitializer { } } - /** - * Validate and locate the given class' post construct method. Returns {@code null} if none present. - * - * @param clazz the class to search - * @return post construct method, or null - */ - private static Method getAndValidatePostConstructMethod(Class clazz) { - Method postConstructMethod = null; - for (Method method : clazz.getDeclaredMethods()) { - if (method.isAnnotationPresent(PostConstruct.class)) { - if (postConstructMethod != null) { - throw new IllegalStateException("Multiple methods with @PostConstruct on " + clazz); - } else if (method.getParameterTypes().length > 0 || Modifier.isStatic(method.getModifiers())) { - throw new IllegalStateException("@PostConstruct method may not be static or have any parameters. " - + "Invalid method in " + clazz); - } else if (method.getReturnType() != void.class) { - throw new IllegalStateException("@PostConstruct method must have return type void. " - + "Offending class: " + clazz); - } else { - postConstructMethod = method; - } - } - } - return postConstructMethod; - } - - @SafeVarargs - private static Injection firstNotNull(Provider>... 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/ConstructorInjection.java b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java index 74ea28b2..e80ea128 100644 --- a/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java +++ b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java @@ -11,7 +11,7 @@ import java.lang.reflect.InvocationTargetException; /** * Functionality for constructor injection. */ -public class ConstructorInjection implements Injection { +class ConstructorInjection implements Injection { private final Constructor constructor; diff --git a/src/main/java/fr/xephi/authme/initialization/FieldInjection.java b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java index c74e7c27..096c5f52 100644 --- a/src/main/java/fr/xephi/authme/initialization/FieldInjection.java +++ b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java @@ -16,7 +16,7 @@ import java.util.List; /** * Functionality for field injection. */ -public class FieldInjection implements Injection { +class FieldInjection implements Injection { private final Field[] fields; private final Constructor defaultConstructor; diff --git a/src/main/java/fr/xephi/authme/initialization/InjectionHelper.java b/src/main/java/fr/xephi/authme/initialization/InjectionHelper.java new file mode 100644 index 00000000..04e186b7 --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/InjectionHelper.java @@ -0,0 +1,66 @@ +package fr.xephi.authme.initialization; + +import javax.annotation.PostConstruct; +import javax.inject.Provider; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Helper class for functions relating to injecting. + */ +public class InjectionHelper { + + private InjectionHelper() { + } + + /** + * Returns the {@link Injection} for the given class, or null if none applicable. + * + * @param clazz the class to process + * @param the class' type + * @return injection of the class or null if none detected + */ + public static Injection getInjection(Class clazz) { + return firstNotNull( + ConstructorInjection.provide(clazz), + FieldInjection.provide(clazz), + InstantiationFallback.provide(clazz)); + } + + /** + * Validates and locates the given class' post construct method. Returns {@code null} if none present. + * + * @param clazz the class to search + * @return post construct method, or null + */ + public static Method getAndValidatePostConstructMethod(Class clazz) { + Method postConstructMethod = null; + for (Method method : clazz.getDeclaredMethods()) { + if (method.isAnnotationPresent(PostConstruct.class)) { + if (postConstructMethod != null) { + throw new IllegalStateException("Multiple methods with @PostConstruct on " + clazz); + } else if (method.getParameterTypes().length > 0 || Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("@PostConstruct method may not be static or have any parameters. " + + "Invalid method in " + clazz); + } else if (method.getReturnType() != void.class) { + throw new IllegalStateException("@PostConstruct method must have return type void. " + + "Offending class: " + clazz); + } else { + postConstructMethod = method; + } + } + } + return postConstructMethod; + } + + @SafeVarargs + private static Injection firstNotNull(Provider>... 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/InstantiationFallback.java b/src/main/java/fr/xephi/authme/initialization/InstantiationFallback.java index 7a1c0849..4861733f 100644 --- a/src/main/java/fr/xephi/authme/initialization/InstantiationFallback.java +++ b/src/main/java/fr/xephi/authme/initialization/InstantiationFallback.java @@ -11,7 +11,7 @@ import java.lang.reflect.InvocationTargetException; * Fallback instantiation method for classes with an accessible no-args constructor * and no elements whatsoever annotated with {@link Inject} or {@link PostConstruct}. */ -public class InstantiationFallback implements Injection { +class InstantiationFallback implements Injection { private final Constructor constructor; diff --git a/src/test/java/fr/xephi/authme/DelayedInject.java b/src/test/java/fr/xephi/authme/DelayedInject.java new file mode 100644 index 00000000..eccd7b7c --- /dev/null +++ b/src/test/java/fr/xephi/authme/DelayedInject.java @@ -0,0 +1,16 @@ +package fr.xephi.authme; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks fields to be instantiated right before a method is invoked on them for the first time. + * + * @see DelayedInjectionRunner + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface DelayedInject { +} diff --git a/src/test/java/fr/xephi/authme/DelayedInjectionRunner.java b/src/test/java/fr/xephi/authme/DelayedInjectionRunner.java new file mode 100644 index 00000000..8eb66b8d --- /dev/null +++ b/src/test/java/fr/xephi/authme/DelayedInjectionRunner.java @@ -0,0 +1,154 @@ +package fr.xephi.authme; + +import fr.xephi.authme.initialization.Injection; +import fr.xephi.authme.initialization.InjectionHelper; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkField; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.internal.runners.util.FrameworkUsageValidator; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Custom JUnit runner which adds support for {@link DelayedInject}, along with Mockito's + * {@link Mock}, {@link org.mockito.Spy} and {@link org.mockito.InjectMocks}. + *

+ * Unlike Mockito's @InjectMocks, fields annotated with {@link DelayedInject} will be + * instantiated only right before a method is invoked on them. This allows a developer to + * define the behavior of mocks the test class depends on. With {@link org.mockito.InjectMocks}, + * fields are instantiated even before {@link org.junit.Before} methods, making it impossible + * to define behavior before the class is instantiated. + *

+ * Note that it is required to declare all dependencies of classes annotated with + * {@link DelayedInject} as {@link Mock} fields. If a dependency is missing, an exception + * will be thrown. + *

+ * Additionally, this runner adds support for {@link javax.annotation.PostConstruct} methods, + * both for Mockito's @InjectMocks and the custom @DelayedInject. + */ +public class DelayedInjectionRunner extends BlockJUnit4ClassRunner { + + public DelayedInjectionRunner(Class clazz) throws InitializationError { + super(clazz); + } + + @Override + public Statement withBefores(FrameworkMethod method, Object target, Statement statement) { + // Initialize all mocks + MockitoAnnotations.initMocks(target); + + // Add support for @DelayedInject and @PostConstruct + runPostConstructOnInjectMocksFields(target); + initializeDelayedMocks(target); + + // Send to parent + return super.withBefores(method, target, statement); + } + + @Override + public void run(final RunNotifier notifier) { + // add listener that validates framework usage at the end of each test + notifier.addListener(new FrameworkUsageValidator(notifier)); + super.run(notifier); + } + + private void runPostConstructOnInjectMocksFields(Object target) { + List delayedFields = getTestClass().getAnnotatedFields(InjectMocks.class); + for (FrameworkField field : delayedFields) { + Object o = ReflectionTestUtils.getFieldValue(field.getField(), target); + executePostConstructMethod(o); + } + } + + private void initializeDelayedMocks(Object target) { + List delayedFields = getTestClass().getAnnotatedFields(DelayedInject.class); + for (FrameworkField field : delayedFields) { + setUpField(target, field.getField()); + } + } + + private void setUpField(Object target, Field field) { + final Injection injection = InjectionHelper.getInjection(field.getType()); + if (injection == null) { + throw new IllegalStateException("No injection method available for field '" + field.getName() + "'"); + } + final Object[] dependencies = fulfillDependencies(target, injection.getDependencies()); + + Object delayedInjectionMock = Mockito.mock(field.getType(), + new DelayedInstantiatingAnswer(injection, dependencies)); + ReflectionTestUtils.setField(field, target, delayedInjectionMock); + } + + private Object[] fulfillDependencies(Object target, Class[] dependencies) { + List availableMocks = getTestClass().getAnnotatedFields(Mock.class); + Map, Object> mocksByType = new HashMap<>(); + for (FrameworkField frameworkField : availableMocks) { + Field field = frameworkField.getField(); + Object fieldValue = ReflectionTestUtils.getFieldValue(field, target); + mocksByType.put(field.getType(), fieldValue); + } + + Object[] resolvedValues = new Object[dependencies.length]; + for (int i = 0; i < dependencies.length; ++i) { + Object o = mocksByType.get(dependencies[i]); + if (o == null) { + throw new IllegalStateException("No mock found for '" + dependencies[i] + "'. " + + "All dependencies of @DelayedInject must be provided as @Mock fields"); + } + resolvedValues[i] = o; + } + return resolvedValues; + } + + /** + * Executes the class' PostConstruct method if available. Validates that all rules for + * {@link javax.annotation.PostConstruct} are met. + * + * @param object the object whose PostConstruct method should be run, if available + * @see InjectionHelper#getAndValidatePostConstructMethod + */ + private static void executePostConstructMethod(Object object) { + Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass()); + if (postConstructMethod != null) { + ReflectionTestUtils.invokeMethod(postConstructMethod, object); + } + } + + private static final class DelayedInstantiatingAnswer implements Answer { + + private final Injection injection; + private final Object[] dependencies; + private Object realObject; + + public DelayedInstantiatingAnswer(Injection injection, Object... dependencies) { + this.injection = injection; + this.dependencies = dependencies; + } + + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + if (realObject == null) { + Object realObject = injection.instantiateWith(dependencies); + executePostConstructMethod(realObject); + this.realObject = realObject; + } + + Method method = invocation.getMethod(); + return ReflectionTestUtils.invokeMethod(method, realObject, invocation.getArguments()); + } + } + +} diff --git a/src/test/java/fr/xephi/authme/ReflectionTestUtils.java b/src/test/java/fr/xephi/authme/ReflectionTestUtils.java index 397181bb..887f443b 100644 --- a/src/test/java/fr/xephi/authme/ReflectionTestUtils.java +++ b/src/test/java/fr/xephi/authme/ReflectionTestUtils.java @@ -1,6 +1,7 @@ package fr.xephi.authme; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static java.lang.String.format; @@ -33,6 +34,15 @@ public final class ReflectionTestUtils { } } + public static void setField(Field field, Object instance, Object value) { + try { + field.setAccessible(true); + field.set(instance, value); + } catch (IllegalAccessException e) { + throw new UnsupportedOperationException(e); + } + } + private static Field getField(Class clazz, T instance, String fieldName) { try { Field field = clazz.getDeclaredField(fieldName); @@ -44,13 +54,23 @@ public final class ReflectionTestUtils { } } + public static Object getFieldValue(Field field, Object instance) { + try { + field.setAccessible(true); + return field.get(instance); + } catch (IllegalAccessException e) { + throw new UnsupportedOperationException("Cannot get value of field '" + + field + "' for '" + instance + "'", e); + } + } + public static Object getFieldValue(Class clazz, T instance, String fieldName) { Field field = getField(clazz, instance, fieldName); try { return field.get(instance); } catch (IllegalAccessException e) { - throw new UnsupportedOperationException("Could not get value of field '" + fieldName + "'"); + throw new UnsupportedOperationException("Could not get value of field '" + fieldName + "'", e); } } @@ -73,4 +93,13 @@ public final class ReflectionTestUtils { + clazz.getName() + "'"); } } + + public static Object invokeMethod(Method method, Object instance, Object... parameters) { + method.setAccessible(true); + try { + return method.invoke(instance, parameters); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new UnsupportedOperationException("Could not invoke method '" + method + "'", e); + } + } } diff --git a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java index 28ee861f..4bf022bd 100644 --- a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java @@ -1,5 +1,7 @@ package fr.xephi.authme.command; +import fr.xephi.authme.DelayedInject; +import fr.xephi.authme.DelayedInjectionRunner; import fr.xephi.authme.command.TestCommandsUtil.TestLoginCommand; import fr.xephi.authme.command.TestCommandsUtil.TestRegisterCommand; import fr.xephi.authme.command.TestCommandsUtil.TestUnregisterCommand; @@ -10,6 +12,8 @@ import org.bukkit.command.CommandSender; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; import java.util.List; import java.util.Set; @@ -32,12 +36,20 @@ import static org.mockito.Mockito.mock; /** * Test for {@link CommandMapper}. */ +@RunWith(DelayedInjectionRunner.class) public class CommandMapperTest { private static Set commands; + + @DelayedInject private CommandMapper mapper; + + @Mock private PermissionsManager permissionsManager; + @Mock + private CommandInitializer commandInitializer; + @BeforeClass public static void setUpCommandHandler() { commands = TestCommandsUtil.generateCommands(); @@ -45,10 +57,7 @@ public class CommandMapperTest { @Before public void setUpMocks() { - permissionsManager = mock(PermissionsManager.class); - CommandInitializer initializer = mock(CommandInitializer.class); - given(initializer.getCommands()).willReturn(commands); - mapper = new CommandMapper(initializer, permissionsManager); + given(commandInitializer.getCommands()).willReturn(commands); } // ----------- diff --git a/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java b/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java index 6b87ffe1..5ace33c4 100644 --- a/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java +++ b/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java @@ -1,5 +1,7 @@ package fr.xephi.authme.listener; +import fr.xephi.authme.DelayedInject; +import fr.xephi.authme.DelayedInjectionRunner; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; @@ -15,11 +17,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; -import java.lang.reflect.Method; import java.util.Arrays; import static org.hamcrest.Matchers.equalTo; @@ -32,9 +30,10 @@ import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link ListenerService}. */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(DelayedInjectionRunner.class) public class ListenerServiceTest { + @DelayedInject private ListenerService listenerService; @Mock @@ -49,25 +48,11 @@ public class ListenerServiceTest { @Mock private PlayerCache playerCache; - @SuppressWarnings("rawtypes") @Before public void initializeTestSetup() { given(settings.getProperty(RegistrationSettings.FORCE)).willReturn(true); given(settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES)).willReturn( Arrays.asList("npc1", "npc2", "npc3")); - - // Note ljacqu 20160602: We use a hacky way to avoid having to instantiate the service in each test: - // the listenerService test is initialized as a mock that will answer to any method invocation by creating an - // actual service object (with the @Mock fields) and then invoking the method on that actual service. - // As long as there is no interaction with listenerService all of the mock setups will have effect. - listenerService = mock(ListenerService.class, new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Exception { - Method method = invocation.getMethod(); - ListenerService service = new ListenerService(settings, dataSource, pluginHooks, playerCache); - return method.invoke(service, invocation.getArguments()); - } - }); } @Test diff --git a/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java index b20df325..8e87d91d 100644 --- a/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java +++ b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java @@ -1,10 +1,11 @@ package fr.xephi.authme.task; +import fr.xephi.authme.DelayedInject; +import fr.xephi.authme.DelayedInjectionRunner; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; -import fr.xephi.authme.initialization.FieldInjection; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.settings.NewSetting; @@ -21,15 +22,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Set; import java.util.UUID; @@ -54,9 +49,10 @@ import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link PurgeService}. */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(DelayedInjectionRunner.class) public class PurgeServiceTest { + @DelayedInject private PurgeService purgeService; @Mock @@ -88,7 +84,6 @@ public class PurgeServiceTest { given(settings.getProperty(PurgeSettings.USE_AUTO_PURGE)).willReturn(false); // when - initPurgeService(); purgeService.runAutoPurge(); // then @@ -102,7 +97,6 @@ public class PurgeServiceTest { given(settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)).willReturn(0); // when - initPurgeService(); purgeService.runAutoPurge(); // then @@ -120,7 +114,6 @@ public class PurgeServiceTest { mockHasBypassPurgePermission("bravo", "delta"); // when - initPurgeService(); purgeService.runAutoPurge(); // then @@ -140,7 +133,6 @@ public class PurgeServiceTest { CommandSender sender = mock(CommandSender.class); // when - initPurgeService(); purgeService.runPurge(sender, delay); // then @@ -162,7 +154,6 @@ public class PurgeServiceTest { given(sender.getUniqueId()).willReturn(uuid); // when - initPurgeService(); purgeService.runPurge(sender, delay); // then @@ -175,7 +166,6 @@ public class PurgeServiceTest { @Test public void shouldRunPurgeIfProcessIsAlreadyRunning() { // given - initPurgeService(); purgeService.setPurging(true); CommandSender sender = mock(CommandSender.class); OfflinePlayer[] players = mockReturnedOfflinePlayers(); @@ -239,35 +229,4 @@ public class PurgeServiceTest { assertThat(senderInTask, Matchers.equalTo(uuid)); assertThat(namesInTask, containsInAnyOrder(names)); } - - // --------------- - // TODO ljacqu 20160618: Create a delayed injection test runner instead - private void initPurgeService() { - FieldInjection injection = FieldInjection.provide(PurgeService.class).get(); - purgeService = injection.instantiateWith(getFields(injection.getDependencies())); - purgeService.reload(); // because annotated with @PostConstruct - } - - private Object[] getFields(Class[] classes) { - Map, Object> mocksByType = orderMocksByType(); - List orderedMocks = new ArrayList<>(classes.length); - for (Class clazz : classes) { - orderedMocks.add(mocksByType.get(clazz)); - } - return orderedMocks.toArray(); - } - - private Map, Object> orderMocksByType() { - Map, Object> mocksByType = new HashMap<>(); - for (Field field : PurgeServiceTest.class.getDeclaredFields()) { - if (field.isAnnotationPresent(Mock.class)) { - try { - mocksByType.put(field.getType(), field.get(this)); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } - } - } - return mocksByType; - } } diff --git a/src/test/java/tools/checktestmocks/CheckTestMocks.java b/src/test/java/tools/checktestmocks/CheckTestMocks.java index 2508cdd6..dd6affc9 100644 --- a/src/test/java/tools/checktestmocks/CheckTestMocks.java +++ b/src/test/java/tools/checktestmocks/CheckTestMocks.java @@ -3,9 +3,8 @@ package tools.checktestmocks; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Sets; -import fr.xephi.authme.initialization.ConstructorInjection; -import fr.xephi.authme.initialization.FieldInjection; import fr.xephi.authme.initialization.Injection; +import fr.xephi.authme.initialization.InjectionHelper; import fr.xephi.authme.util.StringUtils; import org.mockito.Mock; import tools.utils.AutoToolTask; @@ -139,11 +138,7 @@ public class CheckTestMocks implements AutoToolTask { } private static Set> getRealClassDependencies(Class realClass) { - Injection injection = ConstructorInjection.provide(realClass).get(); - if (injection != null) { - return Sets.newHashSet(injection.getDependencies()); - } - injection = FieldInjection.provide(realClass).get(); + Injection injection = InjectionHelper.getInjection(realClass); return injection == null ? Collections.>emptySet() : Sets.newHashSet(injection.getDependencies()); diff --git a/src/test/java/tools/dependencygraph/DrawDependency.java b/src/test/java/tools/dependencygraph/DrawDependency.java index 4f9dd507..3dc003bd 100644 --- a/src/test/java/tools/dependencygraph/DrawDependency.java +++ b/src/test/java/tools/dependencygraph/DrawDependency.java @@ -5,9 +5,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.converter.Converter; -import fr.xephi.authme.initialization.ConstructorInjection; -import fr.xephi.authme.initialization.FieldInjection; import fr.xephi.authme.initialization.Injection; +import fr.xephi.authme.initialization.InjectionHelper; import fr.xephi.authme.process.AsynchronousProcess; import fr.xephi.authme.process.SynchronousProcess; import fr.xephi.authme.security.crypts.EncryptionMethod; @@ -144,11 +143,7 @@ public class DrawDependency implements ToolTask { } private List getDependencies(Class clazz) { - Injection injection = ConstructorInjection.provide(clazz).get(); - if (injection != null) { - return formatInjectionDependencies(injection); - } - injection = FieldInjection.provide(clazz).get(); + Injection injection = InjectionHelper.getInjection(clazz); return injection == null ? null : formatInjectionDependencies(injection); } From fb5e7d40c6edc471e9232a4314778e95c8fd442f Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 18 Jun 2016 15:31:11 +0200 Subject: [PATCH 018/217] Change delayed injection to only change behavior of its own elements - Introduce new BeforeInjecting annotation to not modify the (expected) order of annotations that do not belong to us - Avoids using hacky way of first initializing field to an Answer that will delegate on demand to the proper class... - Remove PostConstruct support for Mockito's InjectMocks: we should not change the established behavior of external elements --- .../xephi/authme/DelayedInjectionRunner.java | 154 ------------------ .../authme/command/CommandMapperTest.java | 10 +- .../authme/listener/ListenerServiceTest.java | 13 +- .../xephi/authme/runner/BeforeInjecting.java | 14 ++ .../authme/runner/DelayedInjectionRunner.java | 139 ++++++++++++++++ .../InjectDelayed.java} | 6 +- .../xephi/authme/runner/PendingInjection.java | 67 ++++++++ .../authme/runner/RunBeforeInjectings.java | 33 ++++ .../authme/runner/RunDelayedInjects.java | 33 ++++ .../xephi/authme/task/PurgeServiceTest.java | 11 +- 10 files changed, 307 insertions(+), 173 deletions(-) delete mode 100644 src/test/java/fr/xephi/authme/DelayedInjectionRunner.java create mode 100644 src/test/java/fr/xephi/authme/runner/BeforeInjecting.java create mode 100644 src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java rename src/test/java/fr/xephi/authme/{DelayedInject.java => runner/InjectDelayed.java} (63%) create mode 100644 src/test/java/fr/xephi/authme/runner/PendingInjection.java create mode 100644 src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java create mode 100644 src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java diff --git a/src/test/java/fr/xephi/authme/DelayedInjectionRunner.java b/src/test/java/fr/xephi/authme/DelayedInjectionRunner.java deleted file mode 100644 index 8eb66b8d..00000000 --- a/src/test/java/fr/xephi/authme/DelayedInjectionRunner.java +++ /dev/null @@ -1,154 +0,0 @@ -package fr.xephi.authme; - -import fr.xephi.authme.initialization.Injection; -import fr.xephi.authme.initialization.InjectionHelper; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.BlockJUnit4ClassRunner; -import org.junit.runners.model.FrameworkField; -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.Statement; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.mockito.internal.runners.util.FrameworkUsageValidator; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Custom JUnit runner which adds support for {@link DelayedInject}, along with Mockito's - * {@link Mock}, {@link org.mockito.Spy} and {@link org.mockito.InjectMocks}. - *

- * Unlike Mockito's @InjectMocks, fields annotated with {@link DelayedInject} will be - * instantiated only right before a method is invoked on them. This allows a developer to - * define the behavior of mocks the test class depends on. With {@link org.mockito.InjectMocks}, - * fields are instantiated even before {@link org.junit.Before} methods, making it impossible - * to define behavior before the class is instantiated. - *

- * Note that it is required to declare all dependencies of classes annotated with - * {@link DelayedInject} as {@link Mock} fields. If a dependency is missing, an exception - * will be thrown. - *

- * Additionally, this runner adds support for {@link javax.annotation.PostConstruct} methods, - * both for Mockito's @InjectMocks and the custom @DelayedInject. - */ -public class DelayedInjectionRunner extends BlockJUnit4ClassRunner { - - public DelayedInjectionRunner(Class clazz) throws InitializationError { - super(clazz); - } - - @Override - public Statement withBefores(FrameworkMethod method, Object target, Statement statement) { - // Initialize all mocks - MockitoAnnotations.initMocks(target); - - // Add support for @DelayedInject and @PostConstruct - runPostConstructOnInjectMocksFields(target); - initializeDelayedMocks(target); - - // Send to parent - return super.withBefores(method, target, statement); - } - - @Override - public void run(final RunNotifier notifier) { - // add listener that validates framework usage at the end of each test - notifier.addListener(new FrameworkUsageValidator(notifier)); - super.run(notifier); - } - - private void runPostConstructOnInjectMocksFields(Object target) { - List delayedFields = getTestClass().getAnnotatedFields(InjectMocks.class); - for (FrameworkField field : delayedFields) { - Object o = ReflectionTestUtils.getFieldValue(field.getField(), target); - executePostConstructMethod(o); - } - } - - private void initializeDelayedMocks(Object target) { - List delayedFields = getTestClass().getAnnotatedFields(DelayedInject.class); - for (FrameworkField field : delayedFields) { - setUpField(target, field.getField()); - } - } - - private void setUpField(Object target, Field field) { - final Injection injection = InjectionHelper.getInjection(field.getType()); - if (injection == null) { - throw new IllegalStateException("No injection method available for field '" + field.getName() + "'"); - } - final Object[] dependencies = fulfillDependencies(target, injection.getDependencies()); - - Object delayedInjectionMock = Mockito.mock(field.getType(), - new DelayedInstantiatingAnswer(injection, dependencies)); - ReflectionTestUtils.setField(field, target, delayedInjectionMock); - } - - private Object[] fulfillDependencies(Object target, Class[] dependencies) { - List availableMocks = getTestClass().getAnnotatedFields(Mock.class); - Map, Object> mocksByType = new HashMap<>(); - for (FrameworkField frameworkField : availableMocks) { - Field field = frameworkField.getField(); - Object fieldValue = ReflectionTestUtils.getFieldValue(field, target); - mocksByType.put(field.getType(), fieldValue); - } - - Object[] resolvedValues = new Object[dependencies.length]; - for (int i = 0; i < dependencies.length; ++i) { - Object o = mocksByType.get(dependencies[i]); - if (o == null) { - throw new IllegalStateException("No mock found for '" + dependencies[i] + "'. " - + "All dependencies of @DelayedInject must be provided as @Mock fields"); - } - resolvedValues[i] = o; - } - return resolvedValues; - } - - /** - * Executes the class' PostConstruct method if available. Validates that all rules for - * {@link javax.annotation.PostConstruct} are met. - * - * @param object the object whose PostConstruct method should be run, if available - * @see InjectionHelper#getAndValidatePostConstructMethod - */ - private static void executePostConstructMethod(Object object) { - Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass()); - if (postConstructMethod != null) { - ReflectionTestUtils.invokeMethod(postConstructMethod, object); - } - } - - private static final class DelayedInstantiatingAnswer implements Answer { - - private final Injection injection; - private final Object[] dependencies; - private Object realObject; - - public DelayedInstantiatingAnswer(Injection injection, Object... dependencies) { - this.injection = injection; - this.dependencies = dependencies; - } - - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - if (realObject == null) { - Object realObject = injection.instantiateWith(dependencies); - executePostConstructMethod(realObject); - this.realObject = realObject; - } - - Method method = invocation.getMethod(); - return ReflectionTestUtils.invokeMethod(method, realObject, invocation.getArguments()); - } - } - -} diff --git a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java index 4bf022bd..472ffa47 100644 --- a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java @@ -1,15 +1,15 @@ package fr.xephi.authme.command; -import fr.xephi.authme.DelayedInject; -import fr.xephi.authme.DelayedInjectionRunner; import fr.xephi.authme.command.TestCommandsUtil.TestLoginCommand; import fr.xephi.authme.command.TestCommandsUtil.TestRegisterCommand; import fr.xephi.authme.command.TestCommandsUtil.TestUnregisterCommand; import fr.xephi.authme.command.executable.HelpCommand; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.runner.BeforeInjecting; +import fr.xephi.authme.runner.InjectDelayed; +import fr.xephi.authme.runner.DelayedInjectionRunner; import org.bukkit.command.CommandSender; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,7 +41,7 @@ public class CommandMapperTest { private static Set commands; - @DelayedInject + @InjectDelayed private CommandMapper mapper; @Mock @@ -55,7 +55,7 @@ public class CommandMapperTest { commands = TestCommandsUtil.generateCommands(); } - @Before + @BeforeInjecting public void setUpMocks() { given(commandInitializer.getCommands()).willReturn(commands); } diff --git a/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java b/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java index 5ace33c4..e742c5c4 100644 --- a/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java +++ b/src/test/java/fr/xephi/authme/listener/ListenerServiceTest.java @@ -1,10 +1,11 @@ package fr.xephi.authme.listener; -import fr.xephi.authme.DelayedInject; -import fr.xephi.authme.DelayedInjectionRunner; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.runner.BeforeInjecting; +import fr.xephi.authme.runner.InjectDelayed; +import fr.xephi.authme.runner.DelayedInjectionRunner; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; @@ -13,7 +14,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.entity.EntityEvent; import org.bukkit.event.player.PlayerEvent; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -33,7 +33,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; @RunWith(DelayedInjectionRunner.class) public class ListenerServiceTest { - @DelayedInject + @InjectDelayed private ListenerService listenerService; @Mock @@ -48,8 +48,8 @@ public class ListenerServiceTest { @Mock private PlayerCache playerCache; - @Before - public void initializeTestSetup() { + @BeforeInjecting + public void initializeDefaultSettings() { given(settings.getProperty(RegistrationSettings.FORCE)).willReturn(true); given(settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES)).willReturn( Arrays.asList("npc1", "npc2", "npc3")); @@ -127,6 +127,7 @@ public class ListenerServiceTest { given(settings.getProperty(RegistrationSettings.FORCE)).willReturn(false); EntityEvent event = mock(EntityEvent.class); given(event.getEntity()).willReturn(player); + listenerService.loadSettings(settings); // when boolean result = listenerService.shouldCancelEvent(event); diff --git a/src/test/java/fr/xephi/authme/runner/BeforeInjecting.java b/src/test/java/fr/xephi/authme/runner/BeforeInjecting.java new file mode 100644 index 00000000..349964af --- /dev/null +++ b/src/test/java/fr/xephi/authme/runner/BeforeInjecting.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.runner; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks methods to run before {@link InjectDelayed} fields are instantiated. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface BeforeInjecting { +} diff --git a/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java b/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java new file mode 100644 index 00000000..27f328fb --- /dev/null +++ b/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java @@ -0,0 +1,139 @@ +package fr.xephi.authme.runner; + +import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.initialization.Injection; +import fr.xephi.authme.initialization.InjectionHelper; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkField; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.internal.runners.util.FrameworkUsageValidator; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Custom JUnit runner which adds support for {@link InjectDelayed} and {@link BeforeInjecting}. + * This runner also initializes fields with Mockito's {@link Mock}, {@link org.mockito.Spy} and + * {@link org.mockito.InjectMocks}. + *

+ * Mockito's {@link Mock} and {@link org.mockito.InjectMocks} are initialized before + * {@link org.junit.Before} methods are run. This leaves no possibility to initialize some mock + * behavior before {@link org.mockito.InjectMocks} fields get instantiated. + *

+ * The runner fills this gap by introducing {@link BeforeInjecting}. At the time these methods + * are run Mockito's annotation will have taken effect but not {@link InjectDelayed}. Fields with + * this annotation are initialized after {@link BeforeInjecting} methods have been run. + *

+ * Additionally, after a field annotated with {@link InjectDelayed} has been initialized, its + * {@link javax.annotation.PostConstruct} method will be invoked, if available. + *

+ * Important: It is required to declare all dependencies of classes annotated with + * {@link InjectDelayed} as {@link Mock} fields. If a dependency is missing, an exception + * will be thrown. + */ +public class DelayedInjectionRunner extends BlockJUnit4ClassRunner { + + public DelayedInjectionRunner(Class clazz) throws InitializationError { + super(clazz); + } + + @Override + public Statement withBefores(FrameworkMethod method, Object target, Statement statement) { + // Initialize all Mockito annotations + MockitoAnnotations.initMocks(target); + + // Call chain normally: let parent handle @Before methods. + // Note that the chain of statements will be run from the end to the start, + // so @Before will be run AFTER our custom statements below + statement = super.withBefores(method, target, statement); + + // Add support for @BeforeInjecting and @InjectDelayed (again, reverse order) + statement = withDelayedInjects(target, statement); + return withBeforeInjectings(target, statement); + } + + @Override + public void run(final RunNotifier notifier) { + // add listener that validates framework usage at the end of each test + notifier.addListener(new FrameworkUsageValidator(notifier)); + super.run(notifier); + } + + /* Adds a Statement to the chain if @BeforeInjecting methods are present. */ + private Statement withBeforeInjectings(Object target, Statement statement) { + List beforeInjectings = getTestClass().getAnnotatedMethods(BeforeInjecting.class); + return beforeInjectings.isEmpty() + ? statement + : new RunBeforeInjectings(statement, beforeInjectings, target); + } + + /* + * Adds a Statement to the chain if @InjectDelayed methods are present. + * If fields have been found, the injection for the type is resolved and stored with the necessary dependencies. + */ + private Statement withDelayedInjects(Object target, Statement statement) { + List delayedFields = getTestClass().getAnnotatedFields(InjectDelayed.class); + if (delayedFields.isEmpty()) { + return statement; + } + + List pendingInjections = new ArrayList<>(delayedFields.size()); + for (FrameworkField field : delayedFields) { + pendingInjections.add(createPendingInjection(target, field.getField())); + } + return new RunDelayedInjects(statement, pendingInjections, target); + } + + /** + * Creates a {@link PendingInjection} for the given field's type, using the target's values. + * + * @param target the target to get dependencies from + * @param field the field to prepare an injection for + * @return the resulting object + */ + private PendingInjection createPendingInjection(Object target, Field field) { + final Injection injection = InjectionHelper.getInjection(field.getType()); + if (injection == null) { + throw new IllegalStateException("No injection method available for field '" + field.getName() + "'"); + } + final Object[] dependencies = fulfillDependencies(target, injection.getDependencies()); + return new PendingInjection(field, injection, dependencies); + } + + /** + * Returns a list of all objects for the given list of dependencies, retrieved from the given + * target's {@link @Mock} fields. + * + * @param target the target to get the required dependencies from + * @param dependencies the required dependency types + * @return the resolved dependencies + */ + private Object[] fulfillDependencies(Object target, Class[] dependencies) { + List availableMocks = getTestClass().getAnnotatedFields(Mock.class); + Map, Object> mocksByType = new HashMap<>(); + for (FrameworkField frameworkField : availableMocks) { + Field field = frameworkField.getField(); + Object fieldValue = ReflectionTestUtils.getFieldValue(field, target); + mocksByType.put(field.getType(), fieldValue); + } + + Object[] resolvedValues = new Object[dependencies.length]; + for (int i = 0; i < dependencies.length; ++i) { + Object o = mocksByType.get(dependencies[i]); + if (o == null) { + throw new IllegalStateException("No mock found for '" + dependencies[i] + "'. " + + "All dependencies of @InjectDelayed must be provided as @Mock fields"); + } + resolvedValues[i] = o; + } + return resolvedValues; + } +} diff --git a/src/test/java/fr/xephi/authme/DelayedInject.java b/src/test/java/fr/xephi/authme/runner/InjectDelayed.java similarity index 63% rename from src/test/java/fr/xephi/authme/DelayedInject.java rename to src/test/java/fr/xephi/authme/runner/InjectDelayed.java index eccd7b7c..b40bddb3 100644 --- a/src/test/java/fr/xephi/authme/DelayedInject.java +++ b/src/test/java/fr/xephi/authme/runner/InjectDelayed.java @@ -1,4 +1,4 @@ -package fr.xephi.authme; +package fr.xephi.authme.runner; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -6,11 +6,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Marks fields to be instantiated right before a method is invoked on them for the first time. + * Marks fields to instantiate with mocks after {@link BeforeInjecting} methods. * * @see DelayedInjectionRunner */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -public @interface DelayedInject { +public @interface InjectDelayed { } diff --git a/src/test/java/fr/xephi/authme/runner/PendingInjection.java b/src/test/java/fr/xephi/authme/runner/PendingInjection.java new file mode 100644 index 00000000..4eded71d --- /dev/null +++ b/src/test/java/fr/xephi/authme/runner/PendingInjection.java @@ -0,0 +1,67 @@ +package fr.xephi.authme.runner; + +import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.initialization.Injection; +import fr.xephi.authme.initialization.InjectionHelper; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * Contains all necessary information to initialize a {@link InjectDelayed} field. + */ +public class PendingInjection { + + private Field field; + private Object[] dependencies; + private Injection injection; + + public PendingInjection(Field field, Injection injection, Object[] dependencies) { + this.field = field; + this.injection = injection; + this.dependencies = dependencies; + } + + /** + * Constructs an object with the stored injection information. + * + * @return the constructed object + */ + public Object instantiate() { + Object object = injection.instantiateWith(dependencies); + executePostConstructMethod(object); + return object; + } + + /** + * Returns the field the constructed object should be assigned to. + * + * @return the field in the test class + */ + public Field getField() { + return field; + } + + /** + * Clears all fields (avoids keeping a reference to all dependencies). + */ + public void clearFields() { + field = null; + dependencies = null; + injection = null; + } + + /** + * Executes the class' PostConstruct method if available. Validates that all rules for + * {@link javax.annotation.PostConstruct} are met. + * + * @param object the object whose PostConstruct method should be run, if available + * @see InjectionHelper#getAndValidatePostConstructMethod + */ + private static void executePostConstructMethod(Object object) { + Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass()); + if (postConstructMethod != null) { + ReflectionTestUtils.invokeMethod(postConstructMethod, object); + } + } +} diff --git a/src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java b/src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java new file mode 100644 index 00000000..46085cea --- /dev/null +++ b/src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java @@ -0,0 +1,33 @@ +package fr.xephi.authme.runner; + +import fr.xephi.authme.ReflectionTestUtils; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +import java.util.List; + +/** + * Statement for running {@link BeforeInjecting} methods. Such methods are run + * after Mockito's @Mock, @Spy and @InjectMocks have taken effect, + * but before {@link InjectDelayed} fields are handled. + */ +public class RunBeforeInjectings extends Statement { + + private final Statement next; + private final List beforeInjectings; + private final Object target; + + public RunBeforeInjectings(Statement next, List beforeInjectings, Object target) { + this.next = next; + this.beforeInjectings = beforeInjectings; + this.target = target; + } + + @Override + public void evaluate() throws Throwable { + for (FrameworkMethod method : beforeInjectings) { + ReflectionTestUtils.invokeMethod(method.getMethod(), target); + } + next.evaluate(); + } +} diff --git a/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java b/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java new file mode 100644 index 00000000..0fcf8304 --- /dev/null +++ b/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java @@ -0,0 +1,33 @@ +package fr.xephi.authme.runner; + +import fr.xephi.authme.ReflectionTestUtils; +import org.junit.runners.model.Statement; + +import java.util.List; + +/** + * Statement for initializing {@link InjectDelayed} fields. These fields are + * constructed after {@link BeforeInjecting} and before JUnit's @Before. + */ +public class RunDelayedInjects extends Statement { + + private final Statement next; + private final Object target; + private final List pendingInjections; + + public RunDelayedInjects(Statement next, List pendingInjections, Object target) { + this.next = next; + this.pendingInjections = pendingInjections; + this.target = target; + } + + @Override + public void evaluate() throws Throwable { + for (PendingInjection pendingInjection : pendingInjections) { + Object object = pendingInjection.instantiate(); + ReflectionTestUtils.setField(pendingInjection.getField(), target, object); + pendingInjection.clearFields(); + } + next.evaluate(); + } +} diff --git a/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java index 8e87d91d..3eb4bac4 100644 --- a/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java +++ b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java @@ -1,13 +1,14 @@ package fr.xephi.authme.task; -import fr.xephi.authme.DelayedInject; -import fr.xephi.authme.DelayedInjectionRunner; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; +import fr.xephi.authme.runner.BeforeInjecting; +import fr.xephi.authme.runner.InjectDelayed; +import fr.xephi.authme.runner.DelayedInjectionRunner; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.util.BukkitService; @@ -16,7 +17,6 @@ import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.hamcrest.Matchers; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,7 +52,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; @RunWith(DelayedInjectionRunner.class) public class PurgeServiceTest { - @DelayedInject + @InjectDelayed private PurgeService purgeService; @Mock @@ -73,7 +73,7 @@ public class PurgeServiceTest { TestHelper.setupLogger(); } - @Before + @BeforeInjecting public void initSettingDefaults() { given(settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)).willReturn(60); } @@ -95,6 +95,7 @@ public class PurgeServiceTest { // given given(settings.getProperty(PurgeSettings.USE_AUTO_PURGE)).willReturn(true); given(settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)).willReturn(0); + purgeService.reload(); // when purgeService.runAutoPurge(); From 12533a90f67fb8891eb802b76943e512ce8c617a Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 19 Jun 2016 10:40:20 +0200 Subject: [PATCH 019/217] Join/PreLogin event listener changes --- .../authme/listener/AuthMePlayerListener.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 84fff695..dfd519e1 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -192,31 +192,28 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerJoin(PlayerJoinEvent event) { final Player player = event.getPlayer(); - if (player != null) { - // Schedule login task so works after the prelogin - // (Fix found by Koolaid5000) - bukkitService.runTask(new Runnable() { - @Override - public void run() { - management.performJoin(player); - } - }); - } + management.performJoin(player); } // Note ljacqu 20160528: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode // e.g. CraftBukkit does not. So we need to run crucial things in onPlayerLogin, too + + // Note sgdc3 20160619: No performance improvements if we do the same thing on the Sync method + // let's try to remove this, about the single session issue, + // i tried to use the low priority to the sync handler + + /* @EventHandler(priority = EventPriority.HIGHEST) public void onPreLogin(AsyncPlayerPreLoginEvent event) { final String name = event.getName().toLowerCase(); - final boolean isAuthAvailable = dataSource.isAuthAvailable(event.getName()); + //final boolean isAuthAvailable = dataSource.isAuthAvailable(event.getName()); try { // Potential performance improvement: make checkAntiBot not require `isAuthAvailable` info and use // "checkKickNonRegistered" as last -> no need to query the DB before checking antibot / name - onJoinVerifier.checkAntibot(name, isAuthAvailable); - onJoinVerifier.checkKickNonRegistered(isAuthAvailable); - onJoinVerifier.checkIsValidName(name); + // onJoinVerifier.checkAntibot(name, isAuthAvailable); + // onJoinVerifier.checkKickNonRegistered(isAuthAvailable); + // onJoinVerifier.checkIsValidName(name); // Note #760: Single session must be checked here - checking with PlayerLoginEvent is too late and // the first connection will have been kicked. This means this feature doesn't work on CraftBukkit. onJoinVerifier.checkSingleSession(name); @@ -225,8 +222,9 @@ public class AuthMePlayerListener implements Listener { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); } } + */ - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.LOW) public void onPlayerLogin(PlayerLoginEvent event) { final Player player = event.getPlayer(); if (Utils.isUnrestricted(player)) { @@ -242,6 +240,7 @@ public class AuthMePlayerListener implements Listener { final boolean isAuthAvailable = (auth != null); try { + onJoinVerifier.checkSingleSession(name); onJoinVerifier.checkAntibot(name, isAuthAvailable); onJoinVerifier.checkKickNonRegistered(isAuthAvailable); onJoinVerifier.checkIsValidName(name); From e1d697d386a1cd94fd09a02654cd7d9eaf854cfe Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 19 Jun 2016 11:07:17 +0200 Subject: [PATCH 020/217] Fix #780 --- .../fr/xephi/authme/listener/AuthMePlayerListener.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index dfd519e1..ec0368a6 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -235,13 +235,14 @@ public class AuthMePlayerListener implements Listener { return; } - final String name = player.getName().toLowerCase(); + final String name = player.getName(); + final String lowerName = name.toLowerCase(); final PlayerAuth auth = dataSource.getAuth(player.getName()); final boolean isAuthAvailable = (auth != null); try { - onJoinVerifier.checkSingleSession(name); - onJoinVerifier.checkAntibot(name, isAuthAvailable); + onJoinVerifier.checkSingleSession(lowerName); + onJoinVerifier.checkAntibot(lowerName, isAuthAvailable); onJoinVerifier.checkKickNonRegistered(isAuthAvailable); onJoinVerifier.checkIsValidName(name); onJoinVerifier.checkNameCasing(player, auth); From 03fa0e1fece2136dc27aa0482a4acb6859e37468 Mon Sep 17 00:00:00 2001 From: games647 Date: Sun, 19 Jun 2016 12:40:15 +0200 Subject: [PATCH 021/217] Fix disabling tablist adapter on old versions (Fixes #775) --- .../listener/AuthMeTablistPacketAdapter.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index 17b4a60a..01be3235 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -14,20 +14,24 @@ 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; +import javax.inject.Inject; + +import org.bukkit.entity.Player; + public class AuthMeTablistPacketAdapter extends PacketAdapter { private final BukkitService bukkitService; + private boolean isRegistered; @Inject public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) { @@ -50,6 +54,10 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } public void sendTablist(Player receiver) { + if (!isRegistered) { + return; + } + WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(receiver); ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); @@ -85,6 +93,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { public void register() { if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) { ProtocolLibrary.getProtocolManager().addPacketListener(this); + isRegistered = true; } else { ConsoleLogger.info("The hideTablist feature is not compatible with your minecraft version"); ConsoleLogger.info("It requires 1.8+. Disabling the hideTablist feature..."); @@ -93,5 +102,6 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { public void unregister() { ProtocolLibrary.getProtocolManager().removePacketListener(this); + isRegistered = false; } } From d848a2ad1686ba5b45032ef371676425bb9444a4 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 19 Jun 2016 15:14:12 +0200 Subject: [PATCH 022/217] Fix #645 #783 --- .../process/logout/ProcessSynchronousPlayerLogout.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java index c70f4cd0..88a13e30 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java @@ -49,9 +49,10 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { } private void restoreSpeedEffect(Player player) { - if (service.getProperty(RestrictionSettings.REMOVE_SPEED)) { - player.setWalkSpeed(0.0F); - player.setFlySpeed(0.0F); + if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) + && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { + player.setFlySpeed(0.0f); + player.setWalkSpeed(0.0f); } } From a0abe3d19d6f924e08b52ba4fa475a458623c864 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 19 Jun 2016 16:13:00 +0200 Subject: [PATCH 023/217] Minor householding - Remove getter for NewSetting - Reduce visibility of classes used by DelayedRunner --- src/main/java/fr/xephi/authme/AuthMe.java | 8 -------- .../java/fr/xephi/authme/hooks/BungeeCordMessage.java | 10 +++++++--- .../java/fr/xephi/authme/runner/PendingInjection.java | 2 +- .../fr/xephi/authme/runner/RunBeforeInjectings.java | 2 +- .../java/fr/xephi/authme/runner/RunDelayedInjects.java | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index a5f329cf..75606f3e 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -709,14 +709,6 @@ public class AuthMe extends JavaPlugin { // Service getters (deprecated) // Use @Inject fields instead // ------------- - /** - * @return NewSetting - * @deprecated should be used in API classes only (temporarily) - */ - @Deprecated - public NewSetting getSettings() { - return newSettings; - } /** * @return permission manager diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 47e7d17d..5c145bbf 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -9,6 +9,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.BukkitService; import org.bukkit.entity.Player; @@ -30,6 +31,9 @@ public class BungeeCordMessage implements PluginMessageListener { @Inject private AuthMe plugin; + + @Inject + private NewSetting settings; BungeeCordMessage() { } @@ -63,17 +67,17 @@ public class BungeeCordMessage implements PluginMessageListener { } //END - if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { + if (!settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("Player " + auth.getNickname() + " has logged in from one of your server!"); } } else if ("logout".equals(act)) { playerCache.removePlayer(name); dataSource.setUnlogged(name); - if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { + if (!settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("Player " + auth.getNickname() + " has logged out from one of your server!"); } } else if ("register".equals(act)) { - if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { + if (!settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("Player " + auth.getNickname() + " has registered out from one of your server!"); } } else if ("changepassword".equals(act)) { diff --git a/src/test/java/fr/xephi/authme/runner/PendingInjection.java b/src/test/java/fr/xephi/authme/runner/PendingInjection.java index 4eded71d..f326d3cc 100644 --- a/src/test/java/fr/xephi/authme/runner/PendingInjection.java +++ b/src/test/java/fr/xephi/authme/runner/PendingInjection.java @@ -10,7 +10,7 @@ import java.lang.reflect.Method; /** * Contains all necessary information to initialize a {@link InjectDelayed} field. */ -public class PendingInjection { +class PendingInjection { private Field field; private Object[] dependencies; diff --git a/src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java b/src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java index 46085cea..7a6ba70b 100644 --- a/src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java +++ b/src/test/java/fr/xephi/authme/runner/RunBeforeInjectings.java @@ -11,7 +11,7 @@ import java.util.List; * after Mockito's @Mock, @Spy and @InjectMocks have taken effect, * but before {@link InjectDelayed} fields are handled. */ -public class RunBeforeInjectings extends Statement { +class RunBeforeInjectings extends Statement { private final Statement next; private final List beforeInjectings; diff --git a/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java b/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java index 0fcf8304..ec0026df 100644 --- a/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java +++ b/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java @@ -9,7 +9,7 @@ import java.util.List; * Statement for initializing {@link InjectDelayed} fields. These fields are * constructed after {@link BeforeInjecting} and before JUnit's @Before. */ -public class RunDelayedInjects extends Statement { +class RunDelayedInjects extends Statement { private final Statement next; private final Object target; From ff2f8a63bb3dcbe5358e67c7caa81900ba5a46a6 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 19 Jun 2016 17:56:50 +0200 Subject: [PATCH 024/217] Fix bugs in purge classes, cleanup - OfflinePlayer objects were never mapped to names - Essentials purge was run even if setting was disabled - Console user saw messages twice - Misc: trivial field reorderings, change DefaultPermission to be null safe - Permissions: do not expose PermissionHandler just to get its type --- src/main/java/fr/xephi/authme/AuthMe.java | 10 ++-------- .../java/fr/xephi/authme/cache/limbo/LimboPlayer.java | 6 +++--- .../fr/xephi/authme/permission/DefaultPermission.java | 5 ++--- .../fr/xephi/authme/permission/PermissionsManager.java | 8 ++++---- src/main/java/fr/xephi/authme/task/PurgeService.java | 6 ++++-- src/main/java/fr/xephi/authme/task/PurgeTask.java | 8 +++----- 6 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 75606f3e..a4a13b98 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -234,11 +234,6 @@ public class AuthMe extends JavaPlugin { // Some statically injected things initializer.register(PlayerCache.class, PlayerCache.getInstance()); - // Note ljacqu 20160612: Instantiate LimboCache first to make sure it is instantiated - // (because sometimes it's used via LimboCache.getInstance()) - // Once LimboCache#getInstance() no longer exists this can be removed! - initializer.get(LimboCache.class); - permsMan = initializer.get(PermissionsManager.class); bukkitService = initializer.get(BukkitService.class); pluginHooks = initializer.get(PluginHooks.class); @@ -296,8 +291,7 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!"); // If server is using PermissionsBukkit, print a warning that some features may not be supported - if (permsMan.isEnabled() && - permsMan.getHandler().getPermissionSystem() == PermissionsSystemType.PERMISSIONS_BUKKIT) { + if (PermissionsSystemType.PERMISSIONS_BUKKIT.equals(permsMan.getPermissionSystem())) { ConsoleLogger.info("Warning! This server uses PermissionsBukkit for permissions! Some permissions features may not be supported!"); } @@ -497,7 +491,7 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.showError("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!"); getServer().shutdown(); } else { - getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + getServer().getPluginManager().disablePlugin(this); } } diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java index 6295bbb7..6029e6da 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java @@ -11,11 +11,11 @@ public class LimboPlayer { private final String name; private final boolean fly; - private Location loc = null; + private final boolean operator; + private final String group; + private final Location loc; private BukkitTask timeoutTask = null; private BukkitTask messageTask = null; - private boolean operator = false; - private String group; public LimboPlayer(String name, Location loc, boolean operator, String group, boolean fly) { diff --git a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java index 31838b6a..d4b542cd 100644 --- a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java +++ b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java @@ -1,6 +1,5 @@ package fr.xephi.authme.permission; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; /** @@ -30,8 +29,8 @@ public enum DefaultPermission { @Override public boolean evaluateOffline(String name) { - // TODO Gnat008 20160617: Is this safe? - return Bukkit.getOfflinePlayer(name).isOp(); + // TODO #784: Check if there is an elegant way to evaluate OP status + return false; } }, diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index 90199958..0e3d57b3 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -217,12 +217,12 @@ public class PermissionsManager { } /** - * Get the current permissions system handler. + * Return the permissions system that is hooked into. * - * @return The permissions system handler. + * @return The permissions system, or null. */ - public PermissionHandler getHandler() { - return handler; + public PermissionsSystemType getPermissionSystem() { + return isEnabled() ? handler.getPermissionSystem() : null; } /** diff --git a/src/main/java/fr/xephi/authme/task/PurgeService.java b/src/main/java/fr/xephi/authme/task/PurgeService.java index baa4e9eb..7549371b 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeService.java +++ b/src/main/java/fr/xephi/authme/task/PurgeService.java @@ -15,6 +15,7 @@ import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.Server; import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; import javax.annotation.PostConstruct; import javax.inject.Inject; @@ -238,7 +239,7 @@ public class PurgeService implements Reloadable { * @param cleared List of String */ synchronized void purgeEssentials(Set cleared) { - if (!settings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES) && !pluginHooks.isEssentialsAvailable()) { + if (!settings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES)) { return; } @@ -281,7 +282,8 @@ public class PurgeService implements Reloadable { private static void logAndSendMessage(CommandSender sender, String message) { ConsoleLogger.info(message); - if (sender != null) { + // Make sure sender is not console user, which will see the message from ConsoleLogger already + if (sender != null && !(sender instanceof ConsoleCommandSender)) { sender.sendMessage(message); } } diff --git a/src/main/java/fr/xephi/authme/task/PurgeTask.java b/src/main/java/fr/xephi/authme/task/PurgeTask.java index e2252da8..d0636759 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeTask.java +++ b/src/main/java/fr/xephi/authme/task/PurgeTask.java @@ -14,11 +14,10 @@ import java.util.UUID; public class PurgeTask extends BukkitRunnable { - private PurgeService purgeService; - //how many players we should check for each tick private static final int INTERVALL_CHECK = 5; + private final PurgeService purgeService; private final UUID sender; private final Set toPurge; @@ -52,15 +51,14 @@ public class PurgeTask extends BukkitRunnable { Set namePortion = new HashSet(INTERVALL_CHECK); for (int i = 0; i < INTERVALL_CHECK; i++) { int nextPosition = (currentPage * INTERVALL_CHECK) + i; - if (offlinePlayers.length >= nextPosition) { + if (offlinePlayers.length <= nextPosition) { //no more offline players on this page break; } OfflinePlayer offlinePlayer = offlinePlayers[nextPosition]; - String offlineName = offlinePlayer.getName(); //remove to speed up later lookups - if (toPurge.remove(offlineName.toLowerCase())) { + if (toPurge.remove(offlinePlayer.getName().toLowerCase())) { playerPortion.add(offlinePlayer); namePortion.add(offlinePlayer.getName()); } From 1377b10c243e19fa84e360888f942172f67b378b Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 14 Jun 2016 19:09:45 +0200 Subject: [PATCH 025/217] Simplify instantiation of permission handlers - Change permission handler to retrieve the services it needs, instead of getting them from the PermissionsManager - Reduce visibility of some methods - Add Reloadable interface --- .../authme/permission/PermissionsManager.java | 133 ++++++------------ .../handlers/PermissionHandlerException.java | 11 ++ .../handlers/PermissionsExHandler.java | 7 +- .../permission/handlers/VaultHandler.java | 22 ++- .../handlers/ZPermissionsHandler.java | 7 +- 5 files changed, 87 insertions(+), 93 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index 0e3d57b3..efa1c66e 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -1,25 +1,22 @@ package fr.xephi.authme.permission; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.permission.handlers.BPermissionsHandler; import fr.xephi.authme.permission.handlers.GroupManagerHandler; import fr.xephi.authme.permission.handlers.PermissionHandler; +import fr.xephi.authme.permission.handlers.PermissionHandlerException; import fr.xephi.authme.permission.handlers.PermissionsBukkitHandler; import fr.xephi.authme.permission.handlers.PermissionsExHandler; import fr.xephi.authme.permission.handlers.VaultHandler; import fr.xephi.authme.permission.handlers.ZPermissionsHandler; import fr.xephi.authme.util.StringUtils; -import net.milkbowl.vault.permission.Permission; import org.anjocaido.groupmanager.GroupManager; -import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; -import ru.tehkode.permissions.bukkit.PermissionsEx; import javax.annotation.PostConstruct; import javax.inject.Inject; @@ -38,7 +35,7 @@ import java.util.List; * @author Tim Visée, http://timvisee.com * @version 0.3 */ -public class PermissionsManager { +public class PermissionsManager implements Reloadable { private final Server server; private final PluginManager pluginManager; @@ -74,90 +71,17 @@ public class PermissionsManager { * Setup and hook into the permissions systems. */ @PostConstruct - public void setup() { - // Force-unhook from current hooked permissions systems - unhook(); - + private void setup() { // Loop through all the available permissions system types for (PermissionsSystemType type : PermissionsSystemType.values()) { - // Try to find and hook the current plugin if available, print an error if failed try { - // Try to find the plugin for the current permissions system - Plugin plugin = pluginManager.getPlugin(type.getPluginName()); - - // Make sure a plugin with this name was found - if (plugin == null) - continue; - - // Make sure the plugin is enabled before hooking - if (!plugin.isEnabled()) { - ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!"); - continue; + PermissionHandler handler = getPermissionHandler(type); + if (handler != null) { + // Show a success message and return + this.handler = handler; + ConsoleLogger.info("Hooked into " + type.getName() + "!"); + return; } - - // Use the proper method to hook this plugin - switch (type) { - case PERMISSIONS_EX: - // Get the permissions manager for PermissionsEx and make sure it isn't null - if (PermissionsEx.getPermissionManager() == null) { - ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); - continue; - } - - handler = new PermissionsExHandler(PermissionsEx.getPermissionManager()); - break; - - case ESSENTIALS_GROUP_MANAGER: - // Set the plugin instance - handler = new GroupManagerHandler((GroupManager) plugin); - break; - - case Z_PERMISSIONS: - // Set the zPermissions service and make sure it's valid - ZPermissionsService zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class); - if (zPermissionsService == null) { - ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); - continue; - } - - handler = new ZPermissionsHandler(zPermissionsService); - break; - - case VAULT: - // Get the permissions provider service - RegisteredServiceProvider permissionProvider = this.server.getServicesManager().getRegistration(Permission.class); - if (permissionProvider == null) { - ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); - continue; - } - - // Get the Vault provider and make sure it's valid - Permission vaultPerms = permissionProvider.getProvider(); - if (vaultPerms == null) { - ConsoleLogger.info("Not using " + type.getName() + " because it's disabled!"); - continue; - } - - handler = new VaultHandler(vaultPerms); - break; - - case B_PERMISSIONS: - handler = new BPermissionsHandler(); - break; - - case PERMISSIONS_BUKKIT: - handler = new PermissionsBukkitHandler(); - break; - - default: - } - - // Show a success message - ConsoleLogger.info("Hooked into " + type.getName() + "!"); - - // Return the used permissions system type - return; - } catch (Exception ex) { // An error occurred, show a warning message ConsoleLogger.logException("Error while hooking into " + type.getName(), ex); @@ -168,10 +92,42 @@ public class PermissionsManager { ConsoleLogger.info("No supported permissions system found! Permissions are disabled!"); } + private PermissionHandler getPermissionHandler(PermissionsSystemType type) throws PermissionHandlerException { + // Try to find the plugin for the current permissions system + Plugin plugin = pluginManager.getPlugin(type.getPluginName()); + + if (plugin == null) { + return null; + } + + // Make sure the plugin is enabled before hooking + if (!plugin.isEnabled()) { + ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!"); + return null; + } + + switch (type) { + case PERMISSIONS_EX: + return new PermissionsExHandler(); + case ESSENTIALS_GROUP_MANAGER: + return new GroupManagerHandler((GroupManager) plugin); + case Z_PERMISSIONS: + return new ZPermissionsHandler(); + case VAULT: + return new VaultHandler(server); + case B_PERMISSIONS: + return new BPermissionsHandler(); + case PERMISSIONS_BUKKIT: + return new PermissionsBukkitHandler(); + default: + throw new IllegalStateException("Unhandled permission type '" + type + "'"); + } + } + /** * Break the hook with all permission systems. */ - public void unhook() { + private void unhook() { // Reset the current used permissions system this.handler = null; @@ -182,11 +138,12 @@ public class PermissionsManager { /** * Reload the permissions manager, and re-hook all permission plugins. */ + @Override public void reload() { // Unhook all permission plugins unhook(); - // Set up the permissions manager again, return the result + // Set up the permissions manager again setup(); } diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java new file mode 100644 index 00000000..41b91633 --- /dev/null +++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java @@ -0,0 +1,11 @@ +package fr.xephi.authme.permission.handlers; + +/** + * Exception during the instantiation of a {@link PermissionHandler}. + */ +public class PermissionHandlerException extends Exception { + + public PermissionHandlerException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java index 4c6035b1..15339c4c 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java @@ -15,8 +15,11 @@ public class PermissionsExHandler implements PermissionHandler { private PermissionManager permissionManager; - public PermissionsExHandler(PermissionManager permissionManager) { - this.permissionManager = permissionManager; + public PermissionsExHandler() throws PermissionHandlerException { + permissionManager = PermissionsEx.getPermissionManager(); + if (permissionManager == null) { + throw new PermissionHandlerException("Could not get manager of PermissionsEx"); + } } @Override diff --git a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java index 3a40f974..b680d47e 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java @@ -3,7 +3,9 @@ package fr.xephi.authme.permission.handlers; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsSystemType; import net.milkbowl.vault.permission.Permission; +import org.bukkit.Server; import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; import java.util.Arrays; import java.util.List; @@ -12,8 +14,24 @@ public class VaultHandler implements PermissionHandler { private Permission vaultProvider; - public VaultHandler(Permission vaultProvider) { - this.vaultProvider = vaultProvider; + public VaultHandler(Server server) throws PermissionHandlerException { + this.vaultProvider = getVaultPermission(server); + } + + private static Permission getVaultPermission(Server server) throws PermissionHandlerException { + // Get the permissions provider service + RegisteredServiceProvider permissionProvider = server + .getServicesManager().getRegistration(Permission.class); + if (permissionProvider == null) { + throw new PermissionHandlerException("Could not load permissions provider service"); + } + + // Get the Vault provider and make sure it's valid + Permission vaultPerms = permissionProvider.getProvider(); + if (vaultPerms == null) { + throw new PermissionHandlerException("Could not load Vault permissions provider"); + } + return vaultPerms; } @Override diff --git a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java index 49322109..27dca5a3 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java @@ -14,7 +14,12 @@ public class ZPermissionsHandler implements PermissionHandler { private ZPermissionsService zPermissionsService; - public ZPermissionsHandler(ZPermissionsService zPermissionsService) { + public ZPermissionsHandler() throws PermissionHandlerException { + // Set the zPermissions service and make sure it's valid + ZPermissionsService zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class); + if (zPermissionsService == null) { + throw new PermissionHandlerException("Failed to get the ZPermissions service!"); + } this.zPermissionsService = zPermissionsService; } From 2bdd2504df667aa912aff0eab9df632e94acc39b Mon Sep 17 00:00:00 2001 From: games647 Date: Sun, 19 Jun 2016 20:47:20 +0200 Subject: [PATCH 026/217] Do not hide the info data from NPCs --- .../listener/AuthMeTablistPacketAdapter.java | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index 01be3235..8775959e 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -7,13 +7,13 @@ import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; import com.comphenix.protocol.wrappers.PlayerInfoData; import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedGameProfile; +import com.google.common.collect.Lists; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; @@ -22,10 +22,14 @@ import fr.xephi.authme.util.BukkitService; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; import java.util.logging.Level; import javax.inject.Inject; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; public class AuthMeTablistPacketAdapter extends PacketAdapter { @@ -40,15 +44,28 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } @Override - public void onPacketSending(PacketEvent event) { - if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) { + public void onPacketSending(PacketEvent packetEvent) { + if (packetEvent.getPacketType() == PacketType.Play.Server.PLAYER_INFO + && PlayerCache.getInstance().isAuthenticated(packetEvent.getPlayer().getName().toLowerCase())) { //this hides the tablist for the new joining players. Already playing users will see the new player try { - if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) { - event.setCancelled(true); + PacketContainer packet = packetEvent.getPacket(); + PlayerInfoAction playerInfoAction = packet.getPlayerInfoAction().read(0); + if (playerInfoAction == PlayerInfoAction.ADD_PLAYER) { + List playerInfoList = Lists.newArrayList(packet.getPlayerInfoDataLists().read(0)); + for (Iterator iterator = playerInfoList.iterator(); iterator.hasNext();) { + PlayerInfoData current = iterator.next(); + UUID uuid = current.getProfile().getUUID(); + if (Bukkit.getPlayer(uuid) == null) { + //player is not online -> a NPC + iterator.remove(); + } + } + + packet.getPlayerInfoDataLists().write(0, playerInfoList); } - } catch (FieldAccessException e) { - ConsoleLogger.logException("Couldn't access field", e); + } catch (Exception ex) { + ConsoleLogger.logException("Couldn't modify outgoing tablist packet", ex); } } } From 4b3ab4b116d67bb8e9ec5908ff2140d94cd86462 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 14 Jun 2016 19:09:45 +0200 Subject: [PATCH 027/217] #769 Create integration test for service initialization in onEnable() - Test that services can be instantiated (e.g. no circular dependencies) - Instantiate Messages via injection instead of manually --- src/main/java/fr/xephi/authme/AuthMe.java | 55 ++- .../java/fr/xephi/authme/output/Messages.java | 16 +- .../authme/AuthMeInitializationTest.java | 127 ++++++ .../output/MessagesIntegrationTest.java | 9 +- .../resources/initialization/config.test.yml | 389 ++++++++++++++++++ 5 files changed, 568 insertions(+), 28 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/AuthMeInitializationTest.java create mode 100644 src/test/resources/initialization/config.test.yml diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index a4a13b98..afd97494 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -1,5 +1,6 @@ package fr.xephi.authme; +import com.google.common.annotations.VisibleForTesting; import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.cache.auth.PlayerAuth; @@ -36,7 +37,6 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsSystemType; import fr.xephi.authme.process.Management; -import fr.xephi.authme.task.PurgeService; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.settings.NewSetting; @@ -51,6 +51,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.propertymap.PropertyMap; +import fr.xephi.authme.task.PurgeService; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.FileUtils; import fr.xephi.authme.util.GeoLiteAPI; @@ -64,6 +65,8 @@ import org.bukkit.Server; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginLoader; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; @@ -127,6 +130,22 @@ public class AuthMe extends JavaPlugin { private BukkitService bukkitService; private AuthMeServiceInitializer initializer; + /** + * Constructor. + */ + public AuthMe() { + } + + /* + * Constructor for unit testing. + */ + @VisibleForTesting + @SuppressWarnings("deprecation") // the super constructor is deprecated to mark it for unit testing only + protected AuthMe(final PluginLoader loader, final Server server, final PluginDescriptionFile description, + final File dataFolder, final File file) { + super(loader, server, description, dataFolder, file); + } + /** * Get the plugin's instance. * @@ -204,8 +223,6 @@ public class AuthMe extends JavaPlugin { return; } - messages = new Messages(newSettings.getMessagesFile(), newSettings.getDefaultMessagesFile()); - // Connect to the database and setup tables try { setupDatabase(newSettings); @@ -228,21 +245,9 @@ public class AuthMe extends JavaPlugin { // 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()); - - 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); - initializer.get(API.class); + instantiateServices(initializer); // Set up Metrics MetricsStarter.setupMetrics(this, newSettings); @@ -300,6 +305,22 @@ public class AuthMe extends JavaPlugin { purgeService.runAutoPurge(); } + protected void instantiateServices(AuthMeServiceInitializer initializer) { + // Some statically injected things + initializer.register(PlayerCache.class, PlayerCache.getInstance()); + + messages = initializer.get(Messages.class); + 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); + initializer.get(API.class); + } + /** * Set up the mail API, if enabled. */ @@ -329,7 +350,7 @@ public class AuthMe extends JavaPlugin { /** * Register all event listeners. */ - private void registerEventListeners(AuthMeServiceInitializer initializer) { + protected void registerEventListeners(AuthMeServiceInitializer initializer) { // Get the plugin manager instance PluginManager pluginManager = getServer().getPluginManager(); diff --git a/src/main/java/fr/xephi/authme/output/Messages.java b/src/main/java/fr/xephi/authme/output/Messages.java index 61bf3d7d..2dc2562a 100644 --- a/src/main/java/fr/xephi/authme/output/Messages.java +++ b/src/main/java/fr/xephi/authme/output/Messages.java @@ -9,6 +9,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import javax.inject.Inject; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; @@ -26,12 +27,12 @@ public class Messages implements SettingsDependent { /** * Constructor. * - * @param messageFile The messages file to use - * @param defaultFile The file with messages to use as default if missing + * @param settings The settings */ - public Messages(File messageFile, String defaultFile) { - initializeFile(messageFile); - this.defaultFile = defaultFile; + @Inject + Messages(NewSetting settings) { + loadSettings(settings); + this.defaultFile = settings.getDefaultMessagesFile(); } /** @@ -118,10 +119,7 @@ public class Messages implements SettingsDependent { @Override public void loadSettings(NewSetting settings) { - initializeFile(settings.getMessagesFile()); - } - - private void initializeFile(File messageFile) { + File messageFile = settings.getMessagesFile(); this.configuration = YamlConfiguration.loadConfiguration(messageFile); this.fileName = messageFile.getName(); } diff --git a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java new file mode 100644 index 00000000..1fcf7ff4 --- /dev/null +++ b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java @@ -0,0 +1,127 @@ +package fr.xephi.authme; + +import com.google.common.io.Files; +import fr.xephi.authme.api.NewAPI; +import fr.xephi.authme.command.CommandHandler; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; +import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.listener.AuthMeBlockListener; +import fr.xephi.authme.output.Messages; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.process.Management; +import fr.xephi.authme.process.login.ProcessSyncPlayerLogin; +import fr.xephi.authme.security.PasswordSecurity; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.task.PurgeService; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginLoader; +import org.bukkit.plugin.PluginManager; +import org.bukkit.scheduler.BukkitScheduler; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Logger; + +import static fr.xephi.authme.settings.TestSettingsMigrationServices.alwaysFulfilled; +import static fr.xephi.authme.settings.properties.SettingsFieldRetriever.getAllPropertyFields; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Integration test verifying that all services can be initialized in {@link AuthMe} + * with the {@link AuthMeServiceInitializer}. + */ +@RunWith(MockitoJUnitRunner.class) +public class AuthMeInitializationTest { + + @Mock + private PluginLoader pluginLoader; + + @Mock + private Server server; + + @Mock + private PluginManager pluginManager; + + private AuthMe authMe; + private File dataFolder; + private File settingsFile; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @BeforeClass + public static void setUpLogger() { + TestHelper.setupLogger(); + } + + @Before + public void initAuthMe() throws IOException { + dataFolder = temporaryFolder.newFolder(); + settingsFile = new File(dataFolder, "config.yml"); + Files.copy(TestHelper.getJarFile("/initialization/config.test.yml"), settingsFile); + + // Mock / wire various Bukkit components + given(server.getLogger()).willReturn(mock(Logger.class)); + ReflectionTestUtils.setField(Bukkit.class, null, "server", server); + given(server.getScheduler()).willReturn(mock(BukkitScheduler.class)); + given(server.getPluginManager()).willReturn(pluginManager); + + // PluginDescriptionFile is final: need to create a sample one + PluginDescriptionFile descriptionFile = new PluginDescriptionFile( + "AuthMe", "N/A", AuthMe.class.getCanonicalName()); + + // Initialize AuthMe + authMe = new AuthMe(pluginLoader, server, descriptionFile, dataFolder, null); + } + + @Test + public void shouldInitializeAllServices() { + // given + NewSetting settings = new NewSetting(settingsFile, dataFolder, getAllPropertyFields(), alwaysFulfilled()); + + // TODO ljacqu 20160619: At some point setting the "plugin" field should not longer be necessary + // We only require it right now because of usages of AuthMe#getInstance() + ReflectionTestUtils.setField(AuthMe.class, null, "plugin", authMe); + + AuthMeServiceInitializer initializer = new AuthMeServiceInitializer("fr.xephi.authme"); + initializer.provide(DataFolder.class, dataFolder); + initializer.register(Server.class, server); + initializer.register(PluginManager.class, pluginManager); + + initializer.register(AuthMe.class, authMe); + initializer.register(NewSetting.class, settings); + initializer.register(DataSource.class, mock(DataSource.class)); + initializer.register(Messages.class, mock(Messages.class)); + + // when + authMe.instantiateServices(initializer); + authMe.registerEventListeners(initializer); + + // then + // Take a few samples and ensure that they are not null + assertThat(initializer.getIfAvailable(AuthMeBlockListener.class), not(nullValue())); + assertThat(initializer.getIfAvailable(CommandHandler.class), not(nullValue())); + assertThat(initializer.getIfAvailable(Management.class), not(nullValue())); + assertThat(initializer.getIfAvailable(NewAPI.class), not(nullValue())); + assertThat(initializer.getIfAvailable(PasswordSecurity.class), not(nullValue())); + assertThat(initializer.getIfAvailable(PermissionsManager.class), not(nullValue())); + assertThat(initializer.getIfAvailable(ProcessSyncPlayerLogin.class), not(nullValue())); + assertThat(initializer.getIfAvailable(PurgeService.class), not(nullValue())); + } + +} diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index 5777d1d4..61eea6a9 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -53,7 +53,10 @@ public class MessagesIntegrationTest { @Before public void setUpMessages() { File testFile = TestHelper.getJarFile(YML_TEST_FILE); - messages = new Messages(testFile, YML_DEFAULT_TEST_FILE); + NewSetting settings = mock(NewSetting.class); + given(settings.getMessagesFile()).willReturn(testFile); + given(settings.getDefaultMessagesFile()).willReturn(YML_DEFAULT_TEST_FILE); + messages = new Messages(settings); } @Test @@ -232,7 +235,9 @@ public class MessagesIntegrationTest { @Test public void shouldAllowNullAsDefaultFile() { // given - Messages testMessages = new Messages(TestHelper.getJarFile(YML_TEST_FILE), null); + NewSetting settings = mock(NewSetting.class); + given(settings.getMessagesFile()).willReturn(TestHelper.getJarFile(YML_TEST_FILE)); + Messages testMessages = new Messages(settings); // Key not present in test file MessageKey key = MessageKey.TWO_FACTOR_CREATE; diff --git a/src/test/resources/initialization/config.test.yml b/src/test/resources/initialization/config.test.yml new file mode 100644 index 00000000..37cc50b9 --- /dev/null +++ b/src/test/resources/initialization/config.test.yml @@ -0,0 +1,389 @@ +# Copy of config.yml for integration testing the initialization of AuthMe components +# Removed DataSource section: DataSource is not concretely instantiated so they should be largely unused + +settings: + # The name shown in the help messages. + helpHeader: AuthMeReloaded + sessions: + # Do you want to enable the session feature? + # If enabled, when a player authenticates successfully, + # his IP and his nickname is saved. + # The next time the player joins the server, if his IP + # is the same of the last time, and the timeout time + # hasn't expired, he will not need to authenticate. + enabled: false + # After how many minutes a session should expire? + # 0 for unlimited time (Very dangerous, use it at your own risk!) + # Consider that session will end only after the timeout time, and + # if the player's ip has changed but the timeout hasn't expired, + # player will be kicked out of sever due to invalidSession! + timeout: 10 + # Should the session expire if the player try to login with an + # another IP Address? + sessionExpireOnIpChange: true + restrictions: + # Can not authenticated players chat and see the chat log? + # Care that this feature blocks also all the commands not + # listed in the list below. + allowChat: false + # Can not authenticated players see the chat log? + hideChat: false + # Commands allowed when a player is not authenticated + allowCommands: + - /login + - /register + - /l + - /reg + - /email + - /captcha + # Max number of allowed registrations per IP (default: 1) + maxRegPerIp: 1 + # Max allowed username length + maxNicknameLength: 16 + # When this setting is enabled, online players can't be kicked out + # due to "Logged in from another Location" + # This setting will prevent potetial security exploits. + ForceSingleSession: true + ForceSpawnLocOnJoin: + # If enabled, every player will be teleported to the world spawnpoint + # after successful authentication. + # The quit location of the player will be overwritten. + # This is different from "teleportUnAuthedToSpawn" that teleport player + # back to his quit location after the authentication. + enabled: false + # WorldNames where we need to force the spawn location + # Case-sensitive! + worlds: + - 'world' + - 'world_nether' + - 'world_the_end' + # This option will save the quit location of the players. + SaveQuitLocation: false + # To activate the restricted user feature you need + # to enable this option and configure the + # AllowedRestrctedUser field. + AllowRestrictedUser: false + # The restricted user feature will kick players listed below + # if they don't match of the defined ip address. + # Example: + # AllowedRestrictedUser: + # - playername;127.0.0.1 + AllowedRestrictedUser: [] + # Should unregistered players be kicked immediately? + kickNonRegistered: false + # Should players be kicked on wrong password? + kickOnWrongPassword: false + # Should not logged in players be teleported to the spawn? + # After the authentication they will be teleported back to + # their normal position. + teleportUnAuthedToSpawn: false + # Minimum allowed nick length + minNicknameLength: 4 + # Can unregistered players walk around? + allowMovement: false + # Should not authenticated players have speed = 0? + # This will reset the fly/walk speed to default value after the login. + removeSpeed: true + # After how many time players who fail to login or register + # should be kicked? Set to 0 to disable. + timeout: 30 + # Regex sintax of allowed characters in the player name. + allowedNicknameCharacters: '[a-zA-Z0-9_]*' + # How far can unregistered players walk? Set to 0 + # for unlimited radius + allowedMovementRadius: 100 + # Enable double check of password when you register + # when it's true, registration require that kind of command: + # /register + enablePasswordConfirmation: true + # Should we protect the player inventory before logging in? Requires ProtocolLib. + ProtectInventoryBeforeLogIn: true + # Should we deny the tabcomplete feature before logging in? Requires ProtocolLib. + DenyTabCompleteBeforeLogin: true + # Should we hide the tablist before logging in? Requires ProtocolLib. + HideTablistBeforeLogin: true + # Should we display all other accounts from a player when he joins? + # permission: /authme.admin.accounts + displayOtherAccounts: true + # Ban ip when the ip is not the ip registered in database + banUnsafedIP: false + # Spawn Priority, Values : authme, essentials, multiverse, default + spawnPriority: authme,essentials,multiverse,default + # Maximum Login authorized by IP + maxLoginPerIp: 0 + # Maximum Join authorized by IP + maxJoinPerIp: 0 + # AuthMe will NEVER teleport players ! + noTeleport: false + # Regex syntax for allowed Chars in passwords. + allowedPasswordCharacters: '[\x21-\x7E]*' + # Keeps collisions disabled for logged players + # Works only with MC 1.9 + keepCollisionsDisabled: false + GameMode: + # ForceSurvivalMode to player when join ? + ForceSurvivalMode: false + security: + # Minimum length of password + minPasswordLength: 5 + # Maximum length of password + passwordMaxLength: 30 + # this is very important options, + # every time player join the server, + # if they are registered, AuthMe will switch him + # to unLoggedInGroup, this + # should prevent all major exploit. + # So you can set up on your Permission Plugin + # this special group with 0 permissions, or permissions to chat, + # or permission to + # send private message or all other perms that you want, + # the better way is to set up + # this group with few permissions, + # so if player try to exploit some account, + # they can + # do anything except what you set in perm Group. + # After a correct logged-in player will be + # moved to his correct permissions group! + # Pay attention group name is case sensitive, + # so Admin is different from admin, + # otherwise your group will be wiped, + # and player join in default group []! + # Example unLoggedinGroup: NotLogged + unLoggedinGroup: unLoggedinGroup + # possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB, + # MYBB, IPB3, IPB4, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512, + # DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM(for developpers only) + passwordHash: SHA256 + # salt length for the SALTED2MD5 MD5(MD5(password)+salt) + doubleMD5SaltLength: 8 + # If password checking return false, do we need to check with all + # other password algorithm to check an old password? + # AuthMe will update the password to the new passwordHash! + supportOldPasswordHash: false + # Cancel unsafe passwords for being used, put them on lowercase! + #unsafePasswords: + #- '123456' + #- 'password' + unsafePasswords: + - '123456' + - 'password' + - 'qwerty' + - '12345' + - '54321' + registration: + # enable registration on the server? + enabled: true + # Send every X seconds a message to a player to + # remind him that he has to login/register + messageInterval: 5 + # Only registered and logged in players can play. + # See restrictions for exceptions + force: true + # Do we replace password registration by an email registration method? + enableEmailRegistrationSystem: false + # Enable double check of email when you register + # when it's true, registration require that kind of command: + # /register + doubleEmailCheck: false + # Do we force kicking player after a successful registration? + # Do not use with login feature below + forceKickAfterRegister: false + # Does AuthMe need to enforce a /login after a successful registration? + forceLoginAfterRegister: false + unrestrictions: + # below you can list all account names that + # AuthMe will ignore for registration or login, configure it + # at your own risk!! Remember that if you are going to add + # nickname with [], you have to delimit name with ' '. + # this option add compatibility with BuildCraft and some + # other mods. + # It is CaseSensitive! + UnrestrictedName: [] + # Message language, available : en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt + messagesLanguage: en + # Force these commands after /login, without any '/', use %p for replace with player name + forceCommands: [] + # Force these commands after /login as a server console, without any '/', use %p for replace with player name + forceCommandsAsConsole: [] + # Force these commands after /register, without any '/', use %p for replace with player name + forceRegisterCommands: [] + # Force these commands after /register as a server console, without any '/', use %p for replace with player name + forceRegisterCommandsAsConsole: [] + # Do we need to display the welcome message (welcome.txt) after a login? + # You can use colors in this welcome.txt + some replaced strings: + # {PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots, + # {IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name + # {VERSION}: get current bukkit version, {COUNTRY}: player country + useWelcomeMessage: true + # Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player + broadcastWelcomeMessage: false + # Should we delay the join message and display it once the player has logged in? + delayJoinMessage: false + # Should we remove join messages altogether? + removeJoinMessage: false + # Should we remove leave messages? + removeLeaveMessage: false + # Do we need to add potion effect Blinding before login/register? + applyBlindEffect: false + # Do we need to prevent people to login with another case? + # If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI + preventOtherCase: false +ExternalBoardOptions: + # MySQL column for the salt, needed for some forum/cms support + mySQLColumnSalt: '' + # MySQL column for the group, needed for some forum/cms support + mySQLColumnGroup: '' + # -1 mean disabled. If u want that only + # activated player can login in your server + # u can put in this options the group number + # of unactivated user, needed for some forum/cms support + nonActivedUserGroup: -1 + # Other MySQL columns where we need to put the Username (case sensitive) + mySQLOtherUsernameColumns: [] + # How much Log to Round needed in BCrypt(do not change it if you do not know what's your doing) + bCryptLog2Round: 10 + # phpBB prefix defined during phpbb installation process + phpbbTablePrefix: 'phpbb_' + # phpBB activated group id, 2 is default registered group defined by phpbb + phpbbActivatedGroupId: 2 + # WordPress prefix defined during WordPress installation process + wordpressTablePrefix: 'wp_' +permission: + # Take care with this options, if you dont want + # to use Vault and Group Switching of + # AuthMe for unloggedIn players put true + # below, default is false. + EnablePermissionCheck: false +BackupSystem: + # Enable or Disable Automatic Backup + ActivateBackup: false + # set Backup at every start of Server + OnServerStart: false + # set Backup at every stop of Server + OnServerStop: true + # Windows only mysql installation Path + MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\' +Security: + SQLProblem: + # Stop the server if we can't contact the sql database + # Take care with this, if you set that to false, + # AuthMe automatically disable and the server is not protected! + stopServer: true + ReloadCommand: + # /reload support + useReloadCommandSupport: true + console: + # Remove spam console + noConsoleSpam: false + # Replace passwords in the console when player type a command like /login + removePassword: true + # Copy AuthMe log output in a separate file as well? + logConsole: true + captcha: + # Enable captcha when a player uses wrong password too many times + useCaptcha: false + # Max allowed tries before a captcha is required + maxLoginTry: 5 + # Captcha length + captchaLength: 5 + stop: + # Kick players before stopping the server, that allow us to save position of players, and all needed + # information correctly without any corruption. + kickPlayersBeforeStopping: true + tempban: + # Tempban a user's IP address if they enter the wrong password too many times + enableTempban: false + # How many times a user can attempt to login before their IP being tempbanned + maxLoginTries: 10 + # The length of time a IP address will be tempbanned in minutes + # Default: 480 minutes, or 8 hours + tempbanLength: 480 +Converter: + Rakamak: + # Rakamak file name + fileName: users.rak + # Rakamak use ip ? + useIP: false + # IP file name for rakamak + ipFileName: UsersIp.rak + CrazyLogin: + # CrazyLogin database file + fileName: accounts.db +Email: + # Email SMTP server host + mailSMTP: smtp.gmail.com + # Email SMTP server port + mailPort: 465 + # Email account that send the mail + mailAccount: '' + # Email account password + mailPassword: '' + # Custom SenderName, that replace the mailAccount name in the email + mailSenderName: '' + # Random password length + RecoveryPasswordLength: 8 + # Email subject of password get + mailSubject: 'Your new AuthMe password' + # Like maxRegPerIp but with email + maxRegPerEmail: 1 + # Recall players to add an email? + recallPlayers: false + # Delay in minute for the recall scheduler + delayRecall: 5 + # Blacklist these domains for emails + emailBlacklisted: + - 10minutemail.com + # WhiteList only these domains for emails + emailWhitelisted: [] + # Do we need to send new password draw in an image? + generateImage: false + # The email OAuth 2 token (leave empty if not used) + emailOauth2Token: '' +Hooks: + # Do we need to hook with multiverse for spawn checking? + multiverse: true + # Do we need to hook with BungeeCord ? + bungeecord: false + # Send player to this BungeeCord server after register/login + sendPlayerTo: '' + # Do we need to disable Essentials SocialSpy on join? + disableSocialSpy: true + # Do we need to force /motd Essentials command on join? + useEssentialsMotd: false + # Do we need to cache custom Attributes? + customAttributes: false +Purge: + # If enabled, AuthMe automatically purges old, unused accounts + useAutoPurge: false + # Number of Days an account become Unused + daysBeforeRemovePlayer: 60 + # Do we need to remove the player.dat file during purge process? + removePlayerDat: false + # Do we need to remove the Essentials/users/player.yml file during purge process? + removeEssentialsFile: false + # World where are players.dat stores + defaultWorld: 'world' + # Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ? + removeLimitedCreativesInventories: false + # Do we need to remove the AntiXRayData/PlayerData/player file during purge process? + removeAntiXRayFile: false + # Do we need to remove permissions? + removePermissions: false +Protection: + # Enable some servers protection ( country based login, antibot ) + enableProtection: false + # Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes + # PLEASE USE QUOTES! + countries: + - 'US' + - 'GB' + # Countries blacklisted automatically (without any needed to enable protection) + # PLEASE USE QUOTES! + countriesBlacklist: + - 'A1' + # Do we need to enable automatic antibot system? + enableAntiBot: true + # Max number of player allowed to login in 5 secs before enable AntiBot system automatically + antiBotSensibility: 10 + # Duration in minutes of the antibot automatic system + antiBotDuration: 10 From e7ba579960a5ca24dc21b95df07fe1ca849c3fa1 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 19 Jun 2016 22:54:12 +0200 Subject: [PATCH 028/217] #778 Delayed runner: add support for annotations, add validation - Add support for dependencies identified by annotations - Add some more usage validation - Change a few test classes to use the DelayedInjectionRunner --- .../authme/AuthMeInitializationTest.java | 2 - .../authme/command/CommandHandlerTest.java | 15 +-- .../converter/CrazyLoginConverterTest.java | 14 +-- .../authme/runner/DelayedInjectionRunner.java | 53 ++------- .../DelayedInjectionRunnerValidator.java | 36 ++++++ .../authme/runner/InjectionResolver.java | 104 ++++++++++++++++++ .../xephi/authme/runner/PendingInjection.java | 45 ++------ .../authme/runner/RunDelayedInjects.java | 15 ++- .../authme/settings/SpawnLoaderTest.java | 27 ++++- 9 files changed, 203 insertions(+), 108 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/runner/DelayedInjectionRunnerValidator.java create mode 100644 src/test/java/fr/xephi/authme/runner/InjectionResolver.java diff --git a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java index 1fcf7ff4..25e95f83 100644 --- a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java +++ b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java @@ -7,7 +7,6 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.initialization.AuthMeServiceInitializer; import fr.xephi.authme.initialization.DataFolder; import fr.xephi.authme.listener.AuthMeBlockListener; -import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.process.Management; import fr.xephi.authme.process.login.ProcessSyncPlayerLogin; @@ -106,7 +105,6 @@ public class AuthMeInitializationTest { initializer.register(AuthMe.class, authMe); initializer.register(NewSetting.class, settings); initializer.register(DataSource.class, mock(DataSource.class)); - initializer.register(Messages.class, mock(Messages.class)); // when authMe.instantiateServices(initializer); diff --git a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java index 137d9f1f..85ae92a7 100644 --- a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java @@ -7,14 +7,15 @@ import fr.xephi.authme.command.TestCommandsUtil.TestUnregisterCommand; import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.initialization.AuthMeServiceInitializer; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.runner.BeforeInjecting; +import fr.xephi.authme.runner.DelayedInjectionRunner; +import fr.xephi.authme.runner.InjectDelayed; 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.Mock; import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import java.util.Collections; @@ -48,9 +49,10 @@ import static org.mockito.Mockito.verify; // Justification: It's more readable to use asList() everywhere in the test when we often generated two lists where one // often consists of only one element, e.g. myMethod(asList("authme"), asList("my", "args"), ...) @SuppressWarnings("ArraysAsListWithZeroOrOneArgument") -@RunWith(MockitoJUnitRunner.class) +@RunWith(DelayedInjectionRunner.class) public class CommandHandlerTest { + @InjectDelayed private CommandHandler handler; @Mock @@ -64,13 +66,12 @@ public class CommandHandlerTest { private Map, ExecutableCommand> mockedCommands = new HashMap<>(); - @Before + @BeforeInjecting @SuppressWarnings("unchecked") public void initializeCommandMapper() { - given(commandMapper.getCommandClasses()).willReturn(Sets.newHashSet(ExecutableCommand.class, - TestLoginCommand.class, TestRegisterCommand.class, TestUnregisterCommand.class)); + given(commandMapper.getCommandClasses()).willReturn(Sets.newHashSet( + ExecutableCommand.class, TestLoginCommand.class, TestRegisterCommand.class, TestUnregisterCommand.class)); setInjectorToMockExecutableCommandClasses(); - handler = new CommandHandler(initializer, commandMapper, permissionsManager, helpProvider); } /** diff --git a/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java b/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java index e64fb97c..0183c613 100644 --- a/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java +++ b/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java @@ -3,16 +3,17 @@ package fr.xephi.authme.converter; import fr.xephi.authme.TestHelper; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.runner.DelayedInjectionRunner; +import fr.xephi.authme.runner.InjectDelayed; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.ConverterSettings; import org.bukkit.command.CommandSender; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import java.io.File; import java.util.List; @@ -31,9 +32,10 @@ import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link CrazyLoginConverter}. */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(DelayedInjectionRunner.class) public class CrazyLoginConverterTest { + @InjectDelayed private CrazyLoginConverter crazyLoginConverter; @Mock @@ -42,6 +44,7 @@ public class CrazyLoginConverterTest { @Mock private NewSetting settings; + @DataFolder private File dataFolder = TestHelper.getJarFile("/converter/"); @BeforeClass @@ -49,11 +52,6 @@ public class CrazyLoginConverterTest { TestHelper.setupLogger(); } - @Before - public void instantiateConverter() { - crazyLoginConverter = new CrazyLoginConverter(dataFolder, dataSource, settings); - } - @Test public void shouldImportUsers() { // given diff --git a/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java b/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java index 27f328fb..6d072e5f 100644 --- a/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java +++ b/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunner.java @@ -1,6 +1,5 @@ package fr.xephi.authme.runner; -import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.initialization.Injection; import fr.xephi.authme.initialization.InjectionHelper; import org.junit.runner.notification.RunNotifier; @@ -11,13 +10,9 @@ import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.internal.runners.util.FrameworkUsageValidator; -import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * Custom JUnit runner which adds support for {@link InjectDelayed} and {@link BeforeInjecting}. @@ -63,7 +58,7 @@ public class DelayedInjectionRunner extends BlockJUnit4ClassRunner { @Override public void run(final RunNotifier notifier) { // add listener that validates framework usage at the end of each test - notifier.addListener(new FrameworkUsageValidator(notifier)); + notifier.addListener(new DelayedInjectionRunnerValidator(notifier, getTestClass())); super.run(notifier); } @@ -87,53 +82,23 @@ public class DelayedInjectionRunner extends BlockJUnit4ClassRunner { List pendingInjections = new ArrayList<>(delayedFields.size()); for (FrameworkField field : delayedFields) { - pendingInjections.add(createPendingInjection(target, field.getField())); + pendingInjections.add(new PendingInjection(field.getField(), getInjection(field))); } - return new RunDelayedInjects(statement, pendingInjections, target); + InjectionResolver injectionResolver = new InjectionResolver(getTestClass(), target); + return new RunDelayedInjects(statement, pendingInjections, target, injectionResolver); } /** - * Creates a {@link PendingInjection} for the given field's type, using the target's values. + * Gets the injection method for the given field's type and ensures an injection method has been found. * - * @param target the target to get dependencies from - * @param field the field to prepare an injection for - * @return the resulting object + * @param field the field to get the injection for + * @return the injection */ - private PendingInjection createPendingInjection(Object target, Field field) { + private static Injection getInjection(FrameworkField field) { final Injection injection = InjectionHelper.getInjection(field.getType()); if (injection == null) { throw new IllegalStateException("No injection method available for field '" + field.getName() + "'"); } - final Object[] dependencies = fulfillDependencies(target, injection.getDependencies()); - return new PendingInjection(field, injection, dependencies); - } - - /** - * Returns a list of all objects for the given list of dependencies, retrieved from the given - * target's {@link @Mock} fields. - * - * @param target the target to get the required dependencies from - * @param dependencies the required dependency types - * @return the resolved dependencies - */ - private Object[] fulfillDependencies(Object target, Class[] dependencies) { - List availableMocks = getTestClass().getAnnotatedFields(Mock.class); - Map, Object> mocksByType = new HashMap<>(); - for (FrameworkField frameworkField : availableMocks) { - Field field = frameworkField.getField(); - Object fieldValue = ReflectionTestUtils.getFieldValue(field, target); - mocksByType.put(field.getType(), fieldValue); - } - - Object[] resolvedValues = new Object[dependencies.length]; - for (int i = 0; i < dependencies.length; ++i) { - Object o = mocksByType.get(dependencies[i]); - if (o == null) { - throw new IllegalStateException("No mock found for '" + dependencies[i] + "'. " - + "All dependencies of @InjectDelayed must be provided as @Mock fields"); - } - resolvedValues[i] = o; - } - return resolvedValues; + return injection; } } diff --git a/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunnerValidator.java b/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunnerValidator.java new file mode 100644 index 00000000..654dc90f --- /dev/null +++ b/src/test/java/fr/xephi/authme/runner/DelayedInjectionRunnerValidator.java @@ -0,0 +1,36 @@ +package fr.xephi.authme.runner; + +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.TestClass; +import org.mockito.InjectMocks; +import org.mockito.Mockito; + +/** + * Validates that {@link DelayedInjectionRunner} is used as intended. + */ +class DelayedInjectionRunnerValidator extends RunListener { + + private final RunNotifier notifier; + private final TestClass testClass; + + public DelayedInjectionRunnerValidator(RunNotifier notifier, TestClass testClass) { + this.notifier = notifier; + this.testClass = testClass; + } + + @Override + public void testFinished(Description description) throws Exception { + try { + Mockito.validateMockitoUsage(); + if (!testClass.getAnnotatedFields(InjectMocks.class).isEmpty()) { + throw new IllegalStateException("Do not use @InjectMocks with the DelayedInjectionRunner:" + + " use @InjectDelayed or change runner"); + } + } catch (Throwable t) { + notifier.fireTestFailure(new Failure(description, t)); + } + } +} diff --git a/src/test/java/fr/xephi/authme/runner/InjectionResolver.java b/src/test/java/fr/xephi/authme/runner/InjectionResolver.java new file mode 100644 index 00000000..37477ee0 --- /dev/null +++ b/src/test/java/fr/xephi/authme/runner/InjectionResolver.java @@ -0,0 +1,104 @@ +package fr.xephi.authme.runner; + +import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.initialization.Injection; +import fr.xephi.authme.initialization.InjectionHelper; +import org.junit.runners.model.FrameworkField; +import org.junit.runners.model.TestClass; +import org.mockito.Mock; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Resolves the dependencies of an injection based on the provided {@link TestClass} and {@link #target target}. + */ +class InjectionResolver { + + private final TestClass testClass; + private final Object target; + private final Map, Object> mocksByType; + + public InjectionResolver(TestClass testClass, Object target) { + this.testClass = testClass; + this.target = target; + this.mocksByType = gatherAvailableMocks(); + } + + public Object instantiate(Injection injection) { + Object[] dependencies = resolveDependencies(injection); + Object object = injection.instantiateWith(dependencies); + executePostConstructMethod(object); + return object; + } + + /** + * Returns a list of all objects for the given list of dependencies, retrieved from the given + * target's {@link Mock} fields. + * + * @param injection the injection whose dependencies to gather + * @return the resolved dependencies + */ + private Object[] resolveDependencies(Injection injection) { + final Class[] dependencies = injection.getDependencies(); + final Class[] annotations = injection.getDependencyAnnotations(); + Object[] resolvedValues = new Object[dependencies.length]; + for (int i = 0; i < dependencies.length; ++i) { + Object dependency = (annotations[i] == null) + ? resolveDependency(dependencies[i]) + : resolveAnnotation(annotations[i]); + resolvedValues[i] = dependency; + } + return resolvedValues; + } + + private Object resolveDependency(Class clazz) { + Object o = mocksByType.get(clazz); + if (o == null) { + throw new IllegalStateException("No mock found for '" + clazz + "'. " + + "All dependencies of @InjectDelayed must be provided as @Mock fields"); + } + return o; + } + + private Object resolveAnnotation(Class clazz) { + Class annotation = (Class) clazz; + List matches = testClass.getAnnotatedFields(annotation); + if (matches.isEmpty()) { + throw new IllegalStateException("No field found with @" + annotation.getSimpleName() + " in test class," + + "but a dependency in an @InjectDelayed field is using it"); + } else if (matches.size() > 1) { + throw new IllegalStateException("You cannot have multiple fields with @" + annotation.getSimpleName()); + } + return ReflectionTestUtils.getFieldValue(matches.get(0).getField(), target); + } + + /** + * Executes the class' PostConstruct method if available. Validates that all rules for + * {@link javax.annotation.PostConstruct} are met. + * + * @param object the object whose PostConstruct method should be run, if available + * @see InjectionHelper#getAndValidatePostConstructMethod + */ + private static void executePostConstructMethod(Object object) { + Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass()); + if (postConstructMethod != null) { + ReflectionTestUtils.invokeMethod(postConstructMethod, object); + } + } + + private Map, Object> gatherAvailableMocks() { + List availableMocks = testClass.getAnnotatedFields(Mock.class); + Map, Object> mocksByType = new HashMap<>(); + for (FrameworkField frameworkField : availableMocks) { + Field field = frameworkField.getField(); + Object fieldValue = ReflectionTestUtils.getFieldValue(field, target); + mocksByType.put(field.getType(), fieldValue); + } + return mocksByType; + } +} diff --git a/src/test/java/fr/xephi/authme/runner/PendingInjection.java b/src/test/java/fr/xephi/authme/runner/PendingInjection.java index f326d3cc..25d33f47 100644 --- a/src/test/java/fr/xephi/authme/runner/PendingInjection.java +++ b/src/test/java/fr/xephi/authme/runner/PendingInjection.java @@ -1,36 +1,29 @@ package fr.xephi.authme.runner; -import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.initialization.Injection; -import fr.xephi.authme.initialization.InjectionHelper; import java.lang.reflect.Field; -import java.lang.reflect.Method; /** - * Contains all necessary information to initialize a {@link InjectDelayed} field. + * Contains an injection and the field it's for. */ class PendingInjection { - private Field field; - private Object[] dependencies; - private Injection injection; + private final Field field; + private final Injection injection; - public PendingInjection(Field field, Injection injection, Object[] dependencies) { + public PendingInjection(Field field, Injection injection) { this.field = field; this.injection = injection; - this.dependencies = dependencies; } /** - * Constructs an object with the stored injection information. + * Returns the injection to perform. * - * @return the constructed object + * @return the injection */ - public Object instantiate() { - Object object = injection.instantiateWith(dependencies); - executePostConstructMethod(object); - return object; + public Injection getInjection() { + return injection; } /** @@ -42,26 +35,4 @@ class PendingInjection { return field; } - /** - * Clears all fields (avoids keeping a reference to all dependencies). - */ - public void clearFields() { - field = null; - dependencies = null; - injection = null; - } - - /** - * Executes the class' PostConstruct method if available. Validates that all rules for - * {@link javax.annotation.PostConstruct} are met. - * - * @param object the object whose PostConstruct method should be run, if available - * @see InjectionHelper#getAndValidatePostConstructMethod - */ - private static void executePostConstructMethod(Object object) { - Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass()); - if (postConstructMethod != null) { - ReflectionTestUtils.invokeMethod(postConstructMethod, object); - } - } } diff --git a/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java b/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java index ec0026df..b59d7158 100644 --- a/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java +++ b/src/test/java/fr/xephi/authme/runner/RunDelayedInjects.java @@ -13,21 +13,28 @@ class RunDelayedInjects extends Statement { private final Statement next; private final Object target; - private final List pendingInjections; + private List pendingInjections; + private InjectionResolver injectionResolver; - public RunDelayedInjects(Statement next, List pendingInjections, Object target) { + public RunDelayedInjects(Statement next, List pendingInjections, Object target, + InjectionResolver injectionResolver) { this.next = next; this.pendingInjections = pendingInjections; this.target = target; + this.injectionResolver = injectionResolver; } @Override public void evaluate() throws Throwable { for (PendingInjection pendingInjection : pendingInjections) { - Object object = pendingInjection.instantiate(); + if (ReflectionTestUtils.getFieldValue(pendingInjection.getField(), target) != null) { + throw new IllegalStateException("Field with @InjectDelayed must be null on startup"); + } + Object object = injectionResolver.instantiate(pendingInjection.getInjection()); ReflectionTestUtils.setField(pendingInjection.getField(), target, object); - pendingInjection.clearFields(); } + this.pendingInjections = null; + this.injectionResolver = null; next.evaluate(); } } diff --git a/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java b/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java index 06088e19..c489e785 100644 --- a/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java +++ b/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java @@ -4,14 +4,19 @@ import com.google.common.io.Files; import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.runner.BeforeInjecting; +import fr.xephi.authme.runner.DelayedInjectionRunner; +import fr.xephi.authme.runner.InjectDelayed; import fr.xephi.authme.settings.properties.RestrictionSettings; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.file.YamlConfiguration; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; import java.io.File; import java.io.IOException; @@ -24,15 +29,28 @@ import static org.mockito.Mockito.mock; /** * Test for {@link SpawnLoader}. */ +@RunWith(DelayedInjectionRunner.class) public class SpawnLoaderTest { + @InjectDelayed + private SpawnLoader spawnLoader; + + @Mock + private NewSetting settings; + + @Mock + private DataSource dataSource; + + @Mock + private PluginHooks pluginHooks; + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @DataFolder private File testFolder; - private NewSetting settings; - @Before + @BeforeInjecting public void setup() throws IOException { // Copy test config into a new temporary folder testFolder = temporaryFolder.newFolder(); @@ -41,7 +59,6 @@ public class SpawnLoaderTest { Files.copy(source, destination); // Create a settings mock with default values - settings = mock(NewSetting.class); given(settings.getProperty(RestrictionSettings.SPAWN_PRIORITY)) .willReturn("authme, essentials, multiverse, default"); } @@ -49,8 +66,6 @@ public class SpawnLoaderTest { @Test public void shouldSetSpawn() { // given - SpawnLoader spawnLoader = - new SpawnLoader(testFolder, settings, mock(PluginHooks.class), mock(DataSource.class)); World world = mock(World.class); given(world.getName()).willReturn("new_world"); Location newSpawn = new Location(world, 123, 45.0, -67.89); From 44702c48324423343eca9dc7d05cdbeb02305cd3 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 21 Jun 2016 21:40:55 +0200 Subject: [PATCH 029/217] Update fr #781 Thanks to @Twonox --- src/main/resources/messages/messages_fr.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/resources/messages/messages_fr.yml b/src/main/resources/messages/messages_fr.yml index 09691261..a98f21da 100644 --- a/src/main/resources/messages/messages_fr.yml +++ b/src/main/resources/messages/messages_fr.yml @@ -12,7 +12,6 @@ login: '&aConnexion effectuée !' vb_nonActiv: '&fCe compte n''est pas actif, consultez vos emails !' user_regged: '&cCe nom est déjà utilisé.' usage_reg: '&cUtilisez la commande /register motdepasse confirmermotdepasse' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names max_reg: '&fLimite d''enregistrement atteinte pour ce compte' no_perm: '&cVous n''avez pas la permission.' password_error_nick: '&fTu ne peux pas utiliser ton pseudo comme mot de passe.' @@ -66,4 +65,8 @@ not_owner_error: 'Vous n''êtes pas le propriétaire de ce compte. Veuillez util invalid_name_case: 'Veuillez vous connecter avec %valid et non pas avec %invalid.' denied_chat: 'Vous devez être connecté pour pouvoir parler !' same_ip_online: 'Un joueur avec la même adresse IP joue déjà !' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' \ No newline at end of file +max_reg: '&cVous ne pouvez pas enregistrer plus de %max_acc compte(s). &o(Compte(s): %reg_names)' +tempban_max_logins: '&cVous êtes temporairement banni suite à plusieurs échecs de connexions !' +accounts_owned_self: '&fVous avez %count comptes:' +accounts_owned_other: '&fLe joueur %name a %count comptes:' +denied_command: '&cVous devez être connecté pour pouvoir utiliser cette commande.' From 74095fec710acccec9b0aeaeb8a581dd53194322 Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Wed, 22 Jun 2016 17:40:25 -0400 Subject: [PATCH 030/217] Update docs --- docs/commands.md | 9 +++++---- docs/hash_algorithms.md | 5 +++-- docs/permission_nodes.md | 6 ++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index ba38674d..edb4a3b9 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,5 +1,5 @@ - + ## AuthMe Commands You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >` @@ -55,9 +55,9 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`). - **/register** [password] [verifyPassword]: Command to register using AuthMeReloaded.
Requires `authme.player.register` - **/register help** [query]: View detailed help for /register commands. -- **/unreg** <password>: Command to unregister using AuthMeReloaded. +- **/unregister** <password>: Command to unregister using AuthMeReloaded.
Requires `authme.player.unregister` -- **/unreg help** [query]: View detailed help for /unreg commands. +- **/unregister help** [query]: View detailed help for /unregister commands. - **/changepassword** <oldPassword> <newPassword>: Command to change your password using AuthMeReloaded.
Requires `authme.player.changepassword` - **/changepassword help** [query]: View detailed help for /changepassword commands. @@ -73,6 +73,7 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
Requires `authme.player.captcha` - **/captcha help** [query]: View detailed help for /captcha commands. + --- -This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Thu Apr 07 17:17:20 CEST 2016 +This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Wed Jun 22 17:39:14 EDT 2016 diff --git a/docs/hash_algorithms.md b/docs/hash_algorithms.md index 6bc2a24f..457cd23f 100644 --- a/docs/hash_algorithms.md +++ b/docs/hash_algorithms.md @@ -1,5 +1,5 @@ - + ## Hash Algorithms AuthMe supports the following hash algorithms for storing your passwords safely. @@ -35,6 +35,7 @@ WHIRLPOOL | Do not use | 128 | | | None | | WORDPRESS | Acceptable | 34 | | | Text | 9 | XAUTH | Recommended | 140 | | | Text | 12 | XFBCRYPT | | 60 | | | | | + CUSTOM | | | | | | | | @@ -82,4 +83,4 @@ or bad. --- -This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Thu Apr 07 17:17:22 CEST 2016 +This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Wed Jun 22 17:39:16 EDT 2016 diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md index 0591b97a..e501736c 100644 --- a/docs/permission_nodes.md +++ b/docs/permission_nodes.md @@ -1,5 +1,5 @@ - + ## AuthMe Permission Nodes The following are the permission nodes that are currently supported by the latest dev builds. @@ -28,6 +28,7 @@ The following are the permission nodes that are currently supported by the lates - **authme.allowmultipleaccounts** – Permission to be able to register multiple accounts. - **authme.bypassantibot** – Permission node to bypass AntiBot protection. - **authme.bypassforcesurvival** – Permission for users to bypass force-survival mode. +- **authme.bypasspurge** – Permission to bypass the purging process - **authme.player.*** – Permission to use all player (non-admin) commands. - **authme.player.canbeforced** – Permission for users a login can be forced to. - **authme.player.captcha** – Command permission to use captcha. @@ -42,6 +43,7 @@ The following are the permission nodes that are currently supported by the lates - **authme.player.unregister** – Command permission to unregister. - **authme.vip** – Permission node to identify VIP users. + --- -This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Thu Apr 07 17:17:24 CEST 2016 +This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Wed Jun 22 17:39:29 EDT 2016 From 54ababdd288c20cd98519a77b39ef97998063d9e Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 24 Jun 2016 18:59:25 +0200 Subject: [PATCH 031/217] #788 remove duplicate FR message + #772 update missing message comments --- docs/hash_algorithms.md | 1 - src/main/resources/messages/messages_bg.yml | 21 ++++--- src/main/resources/messages/messages_br.yml | 7 ++- src/main/resources/messages/messages_cz.yml | 19 ++++--- src/main/resources/messages/messages_es.yml | 17 +++--- src/main/resources/messages/messages_eu.yml | 29 +++++----- src/main/resources/messages/messages_fi.yml | 25 +++++---- src/main/resources/messages/messages_fr.yml | 3 +- src/main/resources/messages/messages_gl.yml | 19 ++++--- src/main/resources/messages/messages_hu.yml | 2 + src/main/resources/messages/messages_id.yml | 21 ++++--- src/main/resources/messages/messages_ko.yml | 19 ++++--- src/main/resources/messages/messages_lt.yml | 41 +++++++------- src/main/resources/messages/messages_nl.yml | 15 +++-- src/main/resources/messages/messages_pl.yml | 25 +++++---- src/main/resources/messages/messages_pt.yml | 19 ++++--- src/main/resources/messages/messages_ru.yml | 19 ++++--- src/main/resources/messages/messages_sk.yml | 55 ++++++++++--------- src/main/resources/messages/messages_tr.yml | 9 ++- src/main/resources/messages/messages_uk.yml | 19 ++++--- src/main/resources/messages/messages_vn.yml | 8 +++ src/main/resources/messages/messages_zhcn.yml | 11 ++-- src/main/resources/messages/messages_zhhk.yml | 11 ++-- src/main/resources/messages/messages_zhtw.yml | 11 ++-- 24 files changed, 247 insertions(+), 179 deletions(-) diff --git a/docs/hash_algorithms.md b/docs/hash_algorithms.md index 457cd23f..8c141a27 100644 --- a/docs/hash_algorithms.md +++ b/docs/hash_algorithms.md @@ -35,7 +35,6 @@ WHIRLPOOL | Do not use | 128 | | | None | | WORDPRESS | Acceptable | 34 | | | Text | 9 | XAUTH | Recommended | 140 | | | Text | 12 | XFBCRYPT | | 60 | | | | | - CUSTOM | | | | | | | | diff --git a/src/main/resources/messages/messages_bg.yml b/src/main/resources/messages/messages_bg.yml index e174e7b9..6c3a2061 100644 --- a/src/main/resources/messages/messages_bg.yml +++ b/src/main/resources/messages/messages_bg.yml @@ -54,16 +54,19 @@ email_send: '[AuthMe] Изпраен е имейл !' country_banned: Твоята държава е забранена в този сървър! antibot_auto_enabled: '[AuthMe] AntiBotMod автоматично включен, открита е потенциална атака!' antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично изключване след %m Минути.' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' # TODO invalid_session: '&cYour IP has been changed and your session data has expired!' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' diff --git a/src/main/resources/messages/messages_br.yml b/src/main/resources/messages/messages_br.yml index 4f1c2f11..2f3e0ac7 100644 --- a/src/main/resources/messages/messages_br.yml +++ b/src/main/resources/messages/messages_br.yml @@ -64,7 +64,10 @@ two_factor_create: '&2Seu código secreto é %code. Você pode escanear ele daqu email_already_used: '&4Este endereço de email já está em uso' not_owner_error: 'Você não é o dono desta conta. Por favor, tente outro nome!' invalid_name_case: 'Você deve entrar usando %valid, não %invalid.' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' # TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_cz.yml b/src/main/resources/messages/messages_cz.yml index 2937cef7..fb75416b 100644 --- a/src/main/resources/messages/messages_cz.yml +++ b/src/main/resources/messages/messages_cz.yml @@ -26,7 +26,7 @@ reload: '&cZnovu nacteni nastaveni AuthMe probehlo uspesne.' timeout: '&cCas pro prihlaseni vyprsel!' unsafe_spawn: '&cTvoje pozice pri odpojeni byla nebezpecna, teleportuji na spawn!' invalid_session: '&cChybna data pri cteni pockejte do vyprseni.' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&cJiz jsi prekrocil(a) limit pro pocet uctu z jedne IP.' password_error: '&cHesla se neshoduji!' pass_len: '&cTvoje heslo nedosahuje minimalni delky (4).' @@ -55,14 +55,17 @@ country_banned: 'Vase zeme je na tomto serveru zakazana' antibot_auto_enabled: '[AuthMe] AntiBotMod automaticky spusten z duvodu masivnich pripojeni!' antibot_auto_disabled: '[AuthMe] AntiBotMod automaticky ukoncen po %m minutach, doufejme v konec invaze' # TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml index da7b4beb..ad9fb1a2 100644 --- a/src/main/resources/messages/messages_es.yml +++ b/src/main/resources/messages/messages_es.yml @@ -12,7 +12,7 @@ login: '&c¡Sesión iniciada!' vb_nonActiv: '&fTu cuenta no está activada aún, ¡revisa tu correo!' user_regged: '&cUsuario ya registrado' usage_reg: '&cUso: /register Contraseña ConfirmarContraseña' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&fHas excedido la cantidad máxima de registros para tu cuenta' no_perm: '&cNo tienes permiso' error: '&fHa ocurrido un error. Por favor contacta al administrador.' @@ -57,13 +57,16 @@ country_banned: 'Tu país ha sido baneado de este servidor!' antibot_auto_enabled: '[AuthMe] AntiBotMod activado automáticamente debido a conexiones masivas!' antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automáticamente luego de %m minutos. Esperamos que haya terminado' # TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_eu.yml b/src/main/resources/messages/messages_eu.yml index d761ffec..720d7abb 100644 --- a/src/main/resources/messages/messages_eu.yml +++ b/src/main/resources/messages/messages_eu.yml @@ -11,7 +11,7 @@ login: '&cOngi etorri!' vb_nonActiv: '&fZure kontua aktibatu gabe dago, konfirmatu zure emaila!' user_regged: '&cErabiltzailea dagoeneko erregistratua' usage_reg: '&cErabili: /register pasahitza pasahitza' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&fKontuko 2 erabiltzaile bakarrik izan ditzakezu' no_perm: '&cBaimenik ez' error: '&fErrorea; Mesedez jarri kontaktuan administratzaile batekin' @@ -48,21 +48,24 @@ email_confirm: '[AuthMe] Konfirmatu zure emaila !' email_changed: '[AuthMe] Emaila aldatua!' email_send: '[AuthMe] Berreskuratze emaila bidalita !' country_banned: '[AuthMe] Zure herrialdea blokeatuta dago zerbitzari honetan' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' -# TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!' +# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' # TODO invalid_session: '&cYour IP has been changed and your session data has expired!' # TODO usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' +# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +# TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!' # TODO valid_captcha: '&2Captcha code solved correctly!' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_fi.yml b/src/main/resources/messages/messages_fi.yml index 2a4beacf..2902a45f 100644 --- a/src/main/resources/messages/messages_fi.yml +++ b/src/main/resources/messages/messages_fi.yml @@ -11,7 +11,7 @@ login: '&cKirjauduit onnistuneesti' vb_nonActiv: '&fKäyttäjäsi ei ole vahvistettu!' user_regged: '&cPelaaja on jo rekisteröity' usage_reg: '&cKäyttötapa: /register salasana salasana' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&fSinulla ei ole oikeuksia tehdä enempää pelaajatilejä!' no_perm: '&cEi oikeuksia' error: '&fVirhe: Ota yhteys palveluntarjoojaan!' @@ -51,18 +51,21 @@ email_added: '[AuthMe] Sähköposti lisätty!' email_confirm: '[AuthMe] Vahvistuta sähköposti!' email_changed: '[AuthMe] Sähköposti vaihdettu!' email_send: '[AuthMe] Palautus sähköposti lähetetty!' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' -# TODO country_banned: '&4Your country is banned from this server!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' # TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' # TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' +# TODO country_banned: '&4Your country is banned from this server!' +# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_fr.yml b/src/main/resources/messages/messages_fr.yml index a98f21da..848090e8 100644 --- a/src/main/resources/messages/messages_fr.yml +++ b/src/main/resources/messages/messages_fr.yml @@ -12,7 +12,7 @@ login: '&aConnexion effectuée !' vb_nonActiv: '&fCe compte n''est pas actif, consultez vos emails !' user_regged: '&cCe nom est déjà utilisé.' usage_reg: '&cUtilisez la commande /register motdepasse confirmermotdepasse' -max_reg: '&fLimite d''enregistrement atteinte pour ce compte' +max_reg: '&cVous ne pouvez pas enregistrer plus de %max_acc compte(s). &o(Compte(s): %reg_names)' no_perm: '&cVous n''avez pas la permission.' password_error_nick: '&fTu ne peux pas utiliser ton pseudo comme mot de passe.' password_error_unsafe: '&fCe mot de passe n''est pas accepté, choisis en un autre.' @@ -65,7 +65,6 @@ not_owner_error: 'Vous n''êtes pas le propriétaire de ce compte. Veuillez util invalid_name_case: 'Veuillez vous connecter avec %valid et non pas avec %invalid.' denied_chat: 'Vous devez être connecté pour pouvoir parler !' same_ip_online: 'Un joueur avec la même adresse IP joue déjà !' -max_reg: '&cVous ne pouvez pas enregistrer plus de %max_acc compte(s). &o(Compte(s): %reg_names)' tempban_max_logins: '&cVous êtes temporairement banni suite à plusieurs échecs de connexions !' accounts_owned_self: '&fVous avez %count comptes:' accounts_owned_other: '&fLe joueur %name a %count comptes:' diff --git a/src/main/resources/messages/messages_gl.yml b/src/main/resources/messages/messages_gl.yml index 01c14292..72e50144 100644 --- a/src/main/resources/messages/messages_gl.yml +++ b/src/main/resources/messages/messages_gl.yml @@ -12,7 +12,7 @@ login: '&cIdentificación con éxito!' vb_nonActiv: '&fA túa conta aínda non está activada, comproba a túa bandexa de correo!!' user_regged: '&cEse nome de usuario xa está rexistrado' usage_reg: '&cUso: /register contrasinal confirmarContrasinal' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&fExcediches o máximo de rexistros para a túa Conta' no_perm: '&cNon tes o permiso' error: '&fOcurriu un erro; contacta cun administrador' @@ -57,14 +57,17 @@ antibot_auto_enabled: '[AuthMe] AntiBotMod conectouse automáticamente debido a antibot_auto_disabled: '[AuthMe] AntiBotMod desactivouse automáticamente despois de %m minutos, esperemos que a invasión se detivera' # TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml index 7dd9cca1..3e07a4b0 100644 --- a/src/main/resources/messages/messages_hu.yml +++ b/src/main/resources/messages/messages_hu.yml @@ -66,3 +66,5 @@ denied_command: '&cAmíg nem vagy bejelentkezve, nem használhatod ezt a parancs same_ip_online: 'Már valaki csatlakozott a szerverhez ezzel az IP címmel!' password_error_chars: '&4A választott jelszó nem engedélyezett karaktereket tartalmaz. Engedélyezett karakterek: REG_EX' tempban_max_logins: '&cIdeiglenesen ki lettél tiltva mert túl sok alkalommal rontottad el a jelszavad!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO accounts_owned_self: 'You own %count accounts:' \ No newline at end of file diff --git a/src/main/resources/messages/messages_id.yml b/src/main/resources/messages/messages_id.yml index 88b45933..cb81f855 100644 --- a/src/main/resources/messages/messages_id.yml +++ b/src/main/resources/messages/messages_id.yml @@ -10,7 +10,7 @@ valid_session: '&2Otomatis login, karena sesi masih terhubung.' login: '&2Login berhasil!' vb_nonActiv: '&cAkunmu belum diaktifkan, silahkan periksa email kamu!' user_regged: '&cKamu telah mendaftarkan username ini!' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&Kamu telah mencapai batas maksimum pendaftaran di server ini!' no_perm: '&4Kamu tidak mempunyai izin melakukan ini!' error: '&4Terjadi kesalahan tak dikenal, silahkan hubungi Administrator!' @@ -54,15 +54,18 @@ email_send: '&2Email pemulihan akun telah dikirim! Silahkan periksa kotak masuk email_exists: '&cEmail pemulihan sudah dikirim! kamu bisa membatalkan dan mengirimkan yg baru dengan command dibawah:' antibot_auto_enabled: '&4[AntiBotService] AntiBot diaktifkan dikarenakan banyak koneksi yg diterima!' antibot_auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO usage_unreg: '&cUsage: /unregister ' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' # TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' # TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' # TODO country_banned: '&4Your country is banned from this server!' -# TODO usage_unreg: '&cUsage: /unregister ' -# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO usage_reg: '&cUsage: /register ' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' +# TODO usage_reg: '&cUsage: /register ' \ No newline at end of file diff --git a/src/main/resources/messages/messages_ko.yml b/src/main/resources/messages/messages_ko.yml index 17dd47c9..19a30f17 100644 --- a/src/main/resources/messages/messages_ko.yml +++ b/src/main/resources/messages/messages_ko.yml @@ -14,7 +14,7 @@ login: '&c성공적인 접속입니다!' vb_nonActiv: '&f당신의 계정은 아직 활성화되어있지 않습니다, 당신의 이메일을 확인해보세요!' user_regged: '&c사용자이름은 이미 가입했습니다' usage_reg: '&c사용법: /register 비밀번호 비밀번호확인' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&f당신은 가입할 수 있는 계정의 최대 한도를 초과했습니다' no_perm: '&c권한이 없습니다' error: '&f오류가 발생했습니다; 관리자에게 문의해주세요' @@ -59,13 +59,16 @@ country_banned: '당신의 국가는 이 서버에서 차단당했습니다' antibot_auto_enabled: '[AuthMe] 봇차단모드가 연결 개수 때문에 자동적으로 활성화됩니다!' antibot_auto_disabled: '[AuthMe] 봇차단모드가 %m 분 후에 자동적으로 비활성화됩니다' # TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_lt.yml b/src/main/resources/messages/messages_lt.yml index 7c06429f..0a9117f7 100644 --- a/src/main/resources/messages/messages_lt.yml +++ b/src/main/resources/messages/messages_lt.yml @@ -11,7 +11,7 @@ login: '&aSekmingai prisijungete' vb_nonActiv: '&aJusu vartotojas nera patvirtintas, patikrinkite el.pasta.' user_regged: '&cVartotojo vardas jau uzregistruotas' usage_reg: '&eNaudojimas: /register slaptazodis pakartotiSlaptazodi' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&cJus pasiekete maksimalu registraciju skaiciu.' no_perm: '&cNera leidimo' error: '&cAtsirado klaida, praneskite adminstratoriui.' @@ -41,28 +41,31 @@ wrong_captcha: '&cNeteisinga Captcha, naudokite : /captcha THE_CAPTCHA' valid_captcha: '&cJusu captcha Teisinga!' kick_forvip: '&cA VIP prisijunge i pilna serveri!' kick_fullserver: '&cServeris yra pilnas, Atsiprasome.' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -# TODO email_changed: '&2Email address changed correctly!' -# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' -# TODO new_email_invalid: '&cInvalid new email, try again!' +# TODO usage_email_change: '&cUsage: /email change ' +# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' -# TODO usage_email_recovery: '&cUsage: /email recovery ' +# TODO new_email_invalid: '&cInvalid new email, try again!' +# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO old_email_invalid: '&cInvalid old email, try again!' +# TODO email_changed: '&2Email address changed correctly!' +# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' # TODO country_banned: '&4Your country is banned from this server!' # TODO usage_email_add: '&cUsage: /email add ' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' -# TODO email_invalid: '&cInvalid email address, try again!' -# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO email_added: '&2Email address successfully added to your account!' -# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' -# TODO email_send: '&2Recovery email sent successfully! Please check your email inbox!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO usage_email_change: '&cUsage: /email change ' # TODO invalid_name_case: 'You should join using username %valid, not %invalid.' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' +# TODO email_send: '&2Recovery email sent successfully! Please check your email inbox!' +# TODO usage_email_recovery: '&cUsage: /email recovery ' # TODO email_confirm: '&cPlease confirm your email address!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO email_added: '&2Email address successfully added to your account!' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO old_email_invalid: '&cInvalid old email, try again!' \ No newline at end of file +# TODO email_invalid: '&cInvalid email address, try again!' +# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_nl.yml b/src/main/resources/messages/messages_nl.yml index db7a9baf..7198c205 100644 --- a/src/main/resources/messages/messages_nl.yml +++ b/src/main/resources/messages/messages_nl.yml @@ -13,7 +13,7 @@ password_error_unsafe: '&fJe kunt geen onveilige wachtwoorden gebruiken' vb_nonActiv: Je accound is nog niet geactiveerd, controleer je mailbox! user_regged: '&cGebruikersnaam is al geregistreerd' usage_reg: '&cGebruik: /register ' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: Je hebt de maximale registraties van jouw account overschreden. no_perm: '&cGeen toegang!' error: 'Error: neem contact op met een administrator!' @@ -59,11 +59,14 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod automatisch uitgezet na %m minuten, kick_antibot: 'AntiBot is aangezet! Wacht alsjeblieft enkele minuten voor je met de server verbindt.' # TODO two_factor_create: Missing tag %url two_factor_create: '&2Je geheime code is %code' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO reg_email_msg: '&3Please, register to the server with the command "/register "' # TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO reg_email_msg: '&3Please, register to the server with the command "/register "' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_pl.yml b/src/main/resources/messages/messages_pl.yml index 7630ca94..b3a44d6d 100644 --- a/src/main/resources/messages/messages_pl.yml +++ b/src/main/resources/messages/messages_pl.yml @@ -26,7 +26,7 @@ error: '&fBlad prosimy napisac do aministracji' unknown_user: '&fUzytkownika nie ma w bazie danych' unsafe_spawn: '&fTwoje pozycja jest niebezpieczna. Zostaniesz przeniesiony na bezpieczny spawn.' invalid_session: '&fSesja zakonczona!' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&fPrzekroczyles limit zarejestrowanych kont na serwerze.' password_error: '&fHaslo niepoprawne!' pass_len: '&fTwoje haslo jest za krotkie lub za dlugie! Sprobuj ponownie...' @@ -51,18 +51,21 @@ email_added: '[AuthMe] Email dodany!' email_confirm: '[AuthMe] Potwierdz swoj email!' email_changed: '[AuthMe] Email zmieniony!' email_send: '[AuthMe] Email z odzyskaniem wyslany!' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' -# TODO country_banned: '&4Your country is banned from this server!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' # TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' # TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' +# TODO country_banned: '&4Your country is banned from this server!' +# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_pt.yml b/src/main/resources/messages/messages_pt.yml index d35ab6b9..5b47ab6c 100644 --- a/src/main/resources/messages/messages_pt.yml +++ b/src/main/resources/messages/messages_pt.yml @@ -11,7 +11,7 @@ login: '&cAutenticado com sucesso!' vb_nonActiv: '&fA sua conta não foi ainda activada, verifique o seu email onde irá receber indicações para activação de conta. ' user_regged: '&cUtilizador já registado' usage_reg: '&cUse: /register seu@email.com seu@email.com' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&cAtingiu o numero máximo de registos permitidos' no_perm: '&cSem Permissões' error: '&fOcorreu um erro; Por favor contacte um admin' @@ -56,14 +56,17 @@ country_banned: 'O seu país está banido deste servidor' antibot_auto_enabled: '[AuthMe] AntiBotMod activado automaticamente devido a um aumento anormal de tentativas de ligação!' antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automaticamente após %m minutos, esperamos que a invasão tenha parado' # TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_ru.yml b/src/main/resources/messages/messages_ru.yml index b615d868..1cebb8b2 100644 --- a/src/main/resources/messages/messages_ru.yml +++ b/src/main/resources/messages/messages_ru.yml @@ -11,7 +11,7 @@ login: '&a&lВы успешно вошли!' vb_nonActiv: '&6Ваш аккаунт еще не активирован! Проверьте вашу почту!' user_regged: '&c&lТакой игрок уже зарегистрирован' usage_reg: '&c&lИспользование: &e&l/reg ПАРОЛЬ ПОВТОР_ПАРОЛЯ' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&c&lВы превысили макс количество регистраций на ваш IP' no_perm: '&c&lНедостаточно прав' error: '&c&lПроизошла ошибка. Свяжитесь с администратором' @@ -57,13 +57,16 @@ email_send: '[AuthMe] Письмо с инструкциями для восст country_banned: 'Вход с IP-адресов вашей страны воспрещен на этом сервере' antibot_auto_enabled: '&a[AuthMe] AntiBot-режим автоматически включен из-за большого количества входов!' antibot_auto_disabled: '&a[AuthMe] AntiBot-режим автоматичски отключен после %m мин. Надеюсь атака закончилась' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_sk.yml b/src/main/resources/messages/messages_sk.yml index 56adb408..5f00e610 100644 --- a/src/main/resources/messages/messages_sk.yml +++ b/src/main/resources/messages/messages_sk.yml @@ -29,7 +29,7 @@ error: '&fNastala chyba; Kontaktujte administrátora' unknown_user: '&fHrac nie je v databázi' unsafe_spawn: '&fTvoj pozícia bol nebezpecná, teleportujem hraca na spawn' invalid_session: '&fZapamätane casove data nie su doveryhodne. Cakaj na ukoncenie spojenia' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&fDosiahol si maximum registrovanych uctov.' password_error: '&fHeslá sa nezhodujú' pass_len: '&fHeslo je velmi kratke alebo dlhe' @@ -39,33 +39,36 @@ name_len: '&cTvoje meno je velmi krátke alebo dlhé' regex: '&cTvoje meno obsahuje zakázané znaky. Povolené znaky: REG_EX' add_email: '&cPridaj svoj e-mail príkazom "/email add email zopakujEmail"' recovery_email: '&cZabudol si heslo? Pouzi príkaz /email recovery ' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -# TODO email_changed: '&2Email address changed correctly!' -# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' -# TODO new_email_invalid: '&cInvalid new email, try again!' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' -# TODO kick_fullserver: '&4The server is full, try again later!' -# TODO usage_email_recovery: '&cUsage: /email recovery ' +# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' +# TODO usage_email_change: '&cUsage: /email change ' +# TODO new_email_invalid: '&cInvalid new email, try again!' +# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO old_email_invalid: '&cInvalid old email, try again!' +# TODO email_changed: '&2Email address changed correctly!' +# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' # TODO country_banned: '&4Your country is banned from this server!' # TODO usage_email_add: '&cUsage: /email add ' -# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' -# TODO email_invalid: '&cInvalid email address, try again!' -# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -# TODO email_added: '&2Email address successfully added to your account!' -# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!' -# TODO email_send: '&2Recovery email sent successfully! Please check your email inbox!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO kick_forvip: '&3A VIP player has joined the server when it was full!' -# TODO usage_email_change: '&cUsage: /email change ' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO email_confirm: '&cPlease confirm your email address!' # TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!' -# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO old_email_invalid: '&cInvalid old email, try again!' +# TODO valid_captcha: '&2Captcha code solved correctly!' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO email_send: '&2Recovery email sent successfully! Please check your email inbox!' # TODO usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "' -# TODO valid_captcha: '&2Captcha code solved correctly!' \ No newline at end of file +# TODO usage_email_recovery: '&cUsage: /email recovery ' +# TODO email_confirm: '&cPlease confirm your email address!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO kick_fullserver: '&4The server is full, try again later!' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO email_added: '&2Email address successfully added to your account!' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' +# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +# TODO kick_forvip: '&3A VIP player has joined the server when it was full!' +# TODO email_invalid: '&cInvalid email address, try again!' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_tr.yml b/src/main/resources/messages/messages_tr.yml index 2f1992ef..4c19c6a2 100644 --- a/src/main/resources/messages/messages_tr.yml +++ b/src/main/resources/messages/messages_tr.yml @@ -62,7 +62,10 @@ email_already_used: '&4Eposta adresi zaten kullaniliyor.' two_factor_create: '&2Gizli kodunuz %code. Buradan test edebilirsin, %url' not_owner_error: 'Bu hesabin sahibi degilsin. Lutfen farkli bir isim sec!' invalid_name_case: 'Oyuna %valid isminde katilmalisin. %invalid ismini kullanarak katilamazsin.' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' \ No newline at end of file +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' \ No newline at end of file diff --git a/src/main/resources/messages/messages_uk.yml b/src/main/resources/messages/messages_uk.yml index 6c84e72a..27223a6e 100644 --- a/src/main/resources/messages/messages_uk.yml +++ b/src/main/resources/messages/messages_uk.yml @@ -11,7 +11,7 @@ login: '&2Успішна авторизація!' vb_nonActiv: '&fВаш акаунт не активований. Перевірте свою електронну адресу!' user_regged: '&cТакий користувач вже зареєстрований' usage_reg: '&cВикористовуйте: /reg Пароль Повтор_Пароля' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&fВи перевищили максимальне число реєстрацій на ваш IP' no_perm: '&cУ Вас недостатньо прав' error: '&fЩось пішло не так; Будь ласка зв`яжіться з адміністратором' @@ -57,13 +57,16 @@ country_banned: 'Сервер не доступний для вашої краї antibot_auto_enabled: '[AuthMe] AntiBotMod автоматично увімкнений (забагато одначасних з`єднань)!' # TODO antibot_auto_disabled: Missing tag %m antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично вимкнувся, сподіваємось атака зупинена' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' # TODO email_already_used: '&4The email address is already being used' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' \ No newline at end of file +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' \ No newline at end of file diff --git a/src/main/resources/messages/messages_vn.yml b/src/main/resources/messages/messages_vn.yml index a3939aee..64cfc66d 100644 --- a/src/main/resources/messages/messages_vn.yml +++ b/src/main/resources/messages/messages_vn.yml @@ -35,6 +35,7 @@ reload: '&2Cấu hình và cơ sở dử liệu đã được nạp lại!' timeout: '&4Thời gian đăng nhập đã hết, bạn đã bị văng khỏi máy chủ. Xin vui lòng thử lại!' usage_changepassword: '&cSử dụng: /changepassword ' name_len: '&4Tên đăng nhập của bạn quá ngắn hoặc quá dài!' +# TODO regex: Missing tag REG_EX regex: '&4Tên nhân vật có chứa ký tự không hợp lệ hoặc chữ Hoa, vui lòng đặt lại chử thường, số hoặc _' add_email: '&eVui lòng thêm email của bạn với lệnh "/email add "' recovery_email: '&aBạn quên mật khẩu? Vui lòng gõ lệnh "/email recovery "' @@ -61,3 +62,10 @@ email_already_used: '&4Địa chỉ email đã được sử dụng' two_factor_create: '&2Mã bí mật của bạn là %code. Bạn có thể quét nó tại đây %url' not_owner_error: 'Bạn không phải là chủ sở hữu tài khoảng này, hãy chọn tên khác!' invalid_name_case: 'Bạn nên vào máy chủ với tên đăng nhập là %valid, không phải là %invalid.' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' +# TODO same_ip_online: 'A player with the same IP is already in game!' +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' \ No newline at end of file diff --git a/src/main/resources/messages/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml index 349787c5..8e3d9629 100644 --- a/src/main/resources/messages/messages_zhcn.yml +++ b/src/main/resources/messages/messages_zhcn.yml @@ -15,7 +15,7 @@ login: '&8[&6玩家系统&8] &c已成功登录!' vb_nonActiv: '&8[&6玩家系统&8] &f你的帐号还未激活,请查看你的邮箱!' user_regged: '&8[&6玩家系统&8] &c此用户已经在此服务器注册过' usage_reg: '&8[&6玩家系统&8] &c正确用法:“/register <密码> <再输入一次以确定密码>”' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&8[&6玩家系统&8] &f你不允许再为你的IP在服务器注册更多用户了!' no_perm: '&8[&6玩家系统&8] &c没有权限' error: '&8[&6玩家系统&8] &f发现错误,请联系管理员' @@ -65,7 +65,10 @@ email_exists: '&8[&6玩家系统&8] &c恢复邮件已发送 ! 你可以丢弃它 two_factor_create: '&8[&6玩家系统&8] &2你的代码是 %code,你可以使用 %url 来扫描' not_owner_error: '&8[&6玩家系统&8] &4警告! &c你并不是此帐户持有人,请立即登出。 ' invalid_name_case: '&8[&6玩家系统&8] &c你应该使用「%valid」而并非「%invalid」登入游戏。 ' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' \ No newline at end of file +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' \ No newline at end of file diff --git a/src/main/resources/messages/messages_zhhk.yml b/src/main/resources/messages/messages_zhhk.yml index 7001604c..84c27343 100644 --- a/src/main/resources/messages/messages_zhhk.yml +++ b/src/main/resources/messages/messages_zhhk.yml @@ -15,7 +15,7 @@ login: '&8[&6用戶系統&8] &c你成功登入了。' vb_nonActiv: '&8[&6用戶系統&8] &f你的帳戶還沒有經過電郵驗證 !' user_regged: '&8[&6用戶系統&8] &c此用戶名已經註冊過了。' usage_reg: '&8[&6用戶系統&8] &f用法: 《 /register <密碼> <重覆密碼> 》' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&8[&6用戶系統&8] &f你的IP地址已達到註冊數上限。' no_perm: '&8[&6用戶系統&8] &b嗯~你想幹甚麼?' error: '&8[&6用戶系統&8] &f發生錯誤,請與管理員聯絡。' @@ -65,7 +65,10 @@ email_exists: '&8[&6用戶系統&8] &c訊息已發送!如果你收不到該封 two_factor_create: '&8[&6用戶系統 - 兩步驗證碼&8] &b你的登入金鑰為&9「%c%code&9」&b,掃描連結為:&c %url' not_owner_error: '&8[&6用戶系統&8] &4警告!&c你並不是此帳戶持有人,請立即登出。' invalid_name_case: '&8[&6用戶系統&8] &4警告!&c你應該使用「%valid」而並非「%invalid」登入遊戲。' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' \ No newline at end of file +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' \ No newline at end of file diff --git a/src/main/resources/messages/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml index f50208b0..100a3957 100644 --- a/src/main/resources/messages/messages_zhtw.yml +++ b/src/main/resources/messages/messages_zhtw.yml @@ -15,7 +15,7 @@ login: '&b【AuthMe】&6密碼正確,你已成功登入!' vb_nonActiv: '&b【AuthMe】&6你的帳號還沒有經過驗證! 檢查看看你的電子信箱 (Email) 吧!' user_regged: '&b【AuthMe】&6這個帳號已經被註冊過了!' usage_reg: '&b【AuthMe】&6用法: &c"/register <密碼> <確認密碼>"' -# TODO max_reg: Missing tags %reg_count, %max_acc, %reg_names +# TODO max_reg: Missing tags %reg_count, %reg_names, %max_acc max_reg: '&b【AuthMe】&6你的 IP 位置所註冊的帳號數量已經達到最大。' no_perm: '&b【AuthMe】&6你沒有使用該指令的權限。' error: '&b【AuthMe】&6發生錯誤,請聯繫管理員' @@ -65,7 +65,10 @@ email_exists: '&b【AuthMe】&6這個帳戶已經有設定電子郵件了' two_factor_create: '&b【AuthMe - 兩步驗證碼】&b你的登入金鑰為&9「%c%code&9」&b,掃描連結為:&c %url' not_owner_error: '&b【AuthMe】&4警告!&c你並不是此帳戶持有人,請立即登出。' invalid_name_case: '&b【AuthMe】&4警告!&c你應該使用「%valid」而並非「%invalid」登入遊戲。' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO denied_chat: '&cIn order to chat you must be authenticated!' # TODO same_ip_online: 'A player with the same IP is already in game!' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' \ No newline at end of file +# TODO denied_command: '&cIn order to use this command you must be authenticated!' +# TODO accounts_owned_other: 'The player %name has %count accounts:' +# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +# TODO accounts_owned_self: 'You own %count accounts:' +# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' \ No newline at end of file From 6812cfa4db10298f9bf5dd45cd56472097387af6 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 24 Jun 2016 23:50:11 +0200 Subject: [PATCH 032/217] Add utility for safe pattern compiling --- .../xephi/authme/listener/OnJoinVerifier.java | 9 +- src/main/java/fr/xephi/authme/util/Utils.java | 10 ++ .../xephi/authme/util/ValidationService.java | 2 +- .../java/fr/xephi/authme/util/UtilsTest.java | 93 +++++++++++++++++++ 4 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/util/UtilsTest.java diff --git a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java index 297e74c6..38dd7d9c 100644 --- a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java +++ b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java @@ -15,6 +15,7 @@ import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.StringUtils; +import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.ValidationService; import org.bukkit.Server; import org.bukkit.entity.Player; @@ -56,13 +57,7 @@ class OnJoinVerifier implements Reloadable { @Override public void reload() { String nickRegEx = settings.getProperty(RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS); - try { - nicknamePattern = Pattern.compile(nickRegEx); - } catch (Exception e) { - nicknamePattern = Pattern.compile(".*?"); - ConsoleLogger.showError("Nickname pattern is not a valid regular expression! " - + "Fallback to allowing all nicknames"); - } + nicknamePattern = Utils.safePatternCompile(nickRegEx); } /** diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index ae940656..d26ae366 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -10,6 +10,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import java.util.Arrays; +import java.util.regex.Pattern; /** * Utility class for various operations used in the codebase. @@ -79,6 +80,15 @@ public final class Utils { } } + public static Pattern safePatternCompile(String pattern) { + try { + return Pattern.compile(pattern); + } catch (Exception e) { + ConsoleLogger.showError("Failed to compile pattern '" + pattern + "' - defaulting to allowing everything"); + return Pattern.compile(".*?"); + } + } + /** * Returns the IP of the given player. * diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java index 8e72f852..615095d0 100644 --- a/src/main/java/fr/xephi/authme/util/ValidationService.java +++ b/src/main/java/fr/xephi/authme/util/ValidationService.java @@ -38,7 +38,7 @@ public class ValidationService implements Reloadable { @Override public void reload() { - passwordRegex = Pattern.compile(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)); + passwordRegex = Utils.safePatternCompile(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)); } /** diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java new file mode 100644 index 00000000..58af9b7c --- /dev/null +++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java @@ -0,0 +1,93 @@ +package fr.xephi.authme.util; + +import fr.xephi.authme.TestHelper; +import org.bukkit.entity.Player; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.UUID; +import java.util.regex.Pattern; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link Utils}. + */ +public class UtilsTest { + + @BeforeClass + public static void setAuthmeInstance() { + TestHelper.setupLogger(); + } + + @Test + public void shouldCompilePattern() { + // given + String pattern = "gr(a|e)ys?"; + + // when + Pattern result = Utils.safePatternCompile(pattern); + + // then + assertThat(result.toString(), equalTo(pattern)); + } + + @Test + public void shouldDefaultToAllAllowedPattern() { + // given + String invalidPattern = "gr(a|eys?"; // missing closing ')' + + // when + Pattern result = Utils.safePatternCompile(invalidPattern); + + // then + assertThat(result.toString(), equalTo(".*?")); + } + + @Test + public void shouldGetPlayerIp() { + // given + Player player = mock(Player.class); + String ip = "124.86.248.62"; + TestHelper.mockPlayerIp(player, ip); + + // when + String result = Utils.getPlayerIp(player); + + // then + assertThat(result, equalTo(ip)); + } + + @Test + public void shouldGetUuid() { + // given + UUID uuid = UUID.randomUUID(); + Player player = mock(Player.class); + given(player.getUniqueId()).willReturn(uuid); + + // when + String result = Utils.getUUIDorName(player); + + // then + assertThat(result, equalTo(uuid.toString())); + } + + @Test + public void shouldFallbackToName() { + // given + Player player = mock(Player.class); + doThrow(RuntimeException.class).when(player).getUniqueId(); + String name = "Bobby12"; + given(player.getName()).willReturn(name); + + // when + String result = Utils.getUUIDorName(player); + + // then + assertThat(result, equalTo(name)); + } +} From df060ff29c32b0bfef553b32471270e0c33e699a Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 25 Jun 2016 01:05:07 +0200 Subject: [PATCH 033/217] Remove legacy setting + remove obsolete todo comment (wontfix #492) - Remove migrated legacy setting - Remove months old todo comment - Remove large chunk of commented out code and merge two explanations --- .../authme/listener/AuthMePlayerListener.java | 31 ++----------------- .../process/register/AsyncRegister.java | 6 +--- .../fr/xephi/authme/settings/Settings.java | 3 -- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index ec0368a6..59e01376 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -23,7 +23,6 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerBedEnterEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerDropItemEvent; @@ -195,34 +194,10 @@ public class AuthMePlayerListener implements Listener { management.performJoin(player); } - // Note ljacqu 20160528: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode + // Note: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode // e.g. CraftBukkit does not. So we need to run crucial things in onPlayerLogin, too - - // Note sgdc3 20160619: No performance improvements if we do the same thing on the Sync method - // let's try to remove this, about the single session issue, - // i tried to use the low priority to the sync handler - - /* - @EventHandler(priority = EventPriority.HIGHEST) - public void onPreLogin(AsyncPlayerPreLoginEvent event) { - final String name = event.getName().toLowerCase(); - //final boolean isAuthAvailable = dataSource.isAuthAvailable(event.getName()); - - try { - // Potential performance improvement: make checkAntiBot not require `isAuthAvailable` info and use - // "checkKickNonRegistered" as last -> no need to query the DB before checking antibot / name - // onJoinVerifier.checkAntibot(name, isAuthAvailable); - // onJoinVerifier.checkKickNonRegistered(isAuthAvailable); - // onJoinVerifier.checkIsValidName(name); - // Note #760: Single session must be checked here - checking with PlayerLoginEvent is too late and - // the first connection will have been kicked. This means this feature doesn't work on CraftBukkit. - onJoinVerifier.checkSingleSession(name); - } catch (FailedVerificationException e) { - event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs())); - event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); - } - } - */ + // We have no performance improvements if we do the same thing on two different events + // Important: the single session feature works if we use the low priority to the sync handler @EventHandler(priority = EventPriority.LOW) public void onPlayerLogin(PlayerLoginEvent event) { diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java index 44f0fd0b..9c792fe6 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -13,7 +13,6 @@ import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.TwoFactor; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; @@ -159,10 +158,7 @@ public class AsyncRegister implements AsynchronousProcess { return; } - if (!Settings.forceRegLogin && autoLogin) { - //PlayerCache.getInstance().addPlayer(auth); - //database.setLogged(name); - // TODO: check this... + if (!service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER) && autoLogin) { plugin.getManagement().performLogin(player, "dontneed", true); } syncProcessManager.processSyncPasswordRegister(player); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 23580155..6e843001 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -3,7 +3,6 @@ package fr.xephi.authme.settings; import fr.xephi.authme.AuthMe; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.configuration.file.FileConfiguration; @@ -25,7 +24,6 @@ public final class Settings { public static boolean protectInventoryBeforeLogInEnabled; public static boolean isStopEnabled; public static boolean reloadSupport; - public static boolean forceRegLogin; public static boolean noTeleport; public static boolean isRemoveSpeedEnabled; public static String getUnloggedinGroup; @@ -64,7 +62,6 @@ public final class Settings { isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true); reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); defaultWorld = configFile.getString("Purge.defaultWorld", "world"); - forceRegLogin = load(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER); noTeleport = load(RestrictionSettings.NO_TELEPORT); crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db"); } From d72d6ddf5ae8be7f8222d19a964b8c81e9aa094f Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 26 Jun 2016 09:25:52 +0200 Subject: [PATCH 034/217] AntiBot - make public field private --- src/main/java/fr/xephi/authme/AntiBot.java | 23 +++++++++- .../authme/listener/AuthMePlayerListener.java | 4 +- .../xephi/authme/listener/OnJoinVerifier.java | 2 +- .../authme/listener/OnJoinVerifierTest.java | 46 +++++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AntiBot.java b/src/main/java/fr/xephi/authme/AntiBot.java index d85cc784..37f04872 100644 --- a/src/main/java/fr/xephi/authme/AntiBot.java +++ b/src/main/java/fr/xephi/authme/AntiBot.java @@ -24,7 +24,7 @@ public class AntiBot { private final Messages messages; private final PermissionsManager permissionsManager; private final BukkitService bukkitService; - public final CopyOnWriteArrayList antibotKicked = new CopyOnWriteArrayList(); + private final CopyOnWriteArrayList antibotKicked = new CopyOnWriteArrayList(); private final CopyOnWriteArrayList antibotPlayers = new CopyOnWriteArrayList(); private AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED; @@ -112,6 +112,27 @@ public class AntiBot { }, 15 * TICKS_PER_SECOND); } + /** + * Returns whether the player was kicked because of activated antibot. The list is reset + * when antibot is deactivated. + * + * @param name the name to check + * @return true if the given name has been kicked because of Antibot + */ + public boolean wasPlayerKicked(String name) { + return antibotKicked.contains(name.toLowerCase()); + } + + /** + * Adds a name to the list of players kicked by antibot. Should only be used when a player + * is determined to be kicked because of failed antibot verification. + * + * @param name the name to add + */ + public void addPlayerKick(String name) { + antibotKicked.addIfAbsent(name.toLowerCase()); + } + public enum AntiBotStatus { LISTENING, DISABLED, diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 59e01376..fba9e6fc 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -239,7 +239,7 @@ public class AuthMePlayerListener implements Listener { event.setQuitMessage(null); } - if (antiBot.antibotKicked.contains(player.getName())) { + if (antiBot.wasPlayerKicked(player.getName())) { return; } @@ -250,7 +250,7 @@ public class AuthMePlayerListener implements Listener { public void onPlayerKick(PlayerKickEvent event) { Player player = event.getPlayer(); - if (!antiBot.antibotKicked.contains(player.getName())) { + if (!antiBot.wasPlayerKicked(player.getName())) { management.performQuit(player, true); } } diff --git a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java index 38dd7d9c..73bf93e3 100644 --- a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java +++ b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java @@ -68,7 +68,7 @@ class OnJoinVerifier implements Reloadable { */ public void checkAntibot(String playerName, boolean isAuthAvailable) throws FailedVerificationException { if (antiBot.getAntiBotStatus() == AntiBot.AntiBotStatus.ACTIVE && !isAuthAvailable) { - antiBot.antibotKicked.addIfAbsent(playerName); + antiBot.addPlayerKick(playerName); throw new FailedVerificationException(MessageKey.KICK_ANTIBOT); } } diff --git a/src/test/java/fr/xephi/authme/listener/OnJoinVerifierTest.java b/src/test/java/fr/xephi/authme/listener/OnJoinVerifierTest.java index 6d5d27e4..436f62f5 100644 --- a/src/test/java/fr/xephi/authme/listener/OnJoinVerifierTest.java +++ b/src/test/java/fr/xephi/authme/listener/OnJoinVerifierTest.java @@ -36,6 +36,7 @@ import java.util.List; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -377,6 +378,51 @@ public class OnJoinVerifierTest { verifyZeroInteractions(bukkitService); } + @Test + public void shouldCheckAntiBot() throws FailedVerificationException { + // given + String name = "user123"; + boolean hasAuth = false; + given(antiBot.getAntiBotStatus()).willReturn(AntiBot.AntiBotStatus.LISTENING); + + // when + onJoinVerifier.checkAntibot(name, hasAuth); + + // then + verify(antiBot).getAntiBotStatus(); + } + + @Test + public void shouldAllowUserWithAuth() throws FailedVerificationException { + // given + String name = "Bobby"; + boolean hasAuth = true; + given(antiBot.getAntiBotStatus()).willReturn(AntiBot.AntiBotStatus.ACTIVE); + + // when + onJoinVerifier.checkAntibot(name, hasAuth); + + // then + verify(antiBot).getAntiBotStatus(); + } + + @Test + public void shouldThrowForActiveAntiBot() { + // given + String name = "Bobby"; + boolean hasAuth = false; + given(antiBot.getAntiBotStatus()).willReturn(AntiBot.AntiBotStatus.ACTIVE); + + // when / then + try { + onJoinVerifier.checkAntibot(name, hasAuth); + fail("Expected exception to be thrown"); + } catch (FailedVerificationException e) { + assertThat(e, exceptionWithData(MessageKey.KICK_ANTIBOT)); + verify(antiBot).addPlayerKick(name); + } + } + private static Player newPlayerWithName(String name) { Player player = mock(Player.class); given(player.getName()).willReturn(name); From a998354fa2c9a26ec9b785d3210a2ab2bbe77cf7 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 26 Jun 2016 16:19:55 +0200 Subject: [PATCH 035/217] Project cleanup --- pom.xml | 125 ++++++++---------- src/main/java/fr/xephi/authme/AuthMe.java | 113 ++++++++-------- .../fr/xephi/authme/output/Log4JFilter.java | 57 ++++---- .../process/login/ProcessSyncPlayerLogin.java | 24 ++-- src/main/resources/plugin.yml | 2 +- 5 files changed, 149 insertions(+), 172 deletions(-) diff --git a/pom.xml b/pom.xml index a644b229..458f8360 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,6 @@ fr.xephi authme 5.2-SNAPSHOT - jar AuthMeReloaded The first authentication plugin for the Bukkit API! @@ -44,10 +43,6 @@ - - 3.3.3 - - UTF-8 @@ -62,6 +57,7 @@ ${project.outputName} + ${project.versionCode} ${project.groupId}.${project.artifactId}.${bukkitplugin.name} Xephi, sgdc3, DNx5, timvisee, games647, ljacqu, Gnat008 @@ -69,8 +65,9 @@ 1.10-R0.1-SNAPSHOT - + + jenkins @@ -82,6 +79,7 @@ ${env.BUILD_NUMBER} + skipLongHashTests @@ -96,7 +94,7 @@ - + ${project.finalName}-noshade @@ -135,6 +133,7 @@ maven-surefire-plugin 2.19.1 + -Dfile.encoding=${project.build.sourceEncoding} @{argLine} ${project.skipExtendedHashTests} @@ -143,20 +142,16 @@ - org.apache.maven.plugins maven-shade-plugin 2.4.3 false - + @@ -173,36 +168,36 @@ - + com.google.gson - fr.xephi.authme.libs.google - - - com.zaxxer.hikari - fr.xephi.authme.libs.hikari - - - org.slf4j - fr.xephi.authme.libs.slf4j - - - com.maxmind.geoip - fr.xephi.authme.libs.geoip - - - net.ricecode.similarity - fr.xephi.authme.libs.similarity - - - javax.inject - fr.xephi.authme.libs.inject - - - - org.mcstats - fr.xephi.authme + fr.xephi.authme.libs.google.gson + + com.zaxxer.hikari + fr.xephi.authme.libs.zaxxer.hikari + + + org.slf4j + fr.xephi.authme.libs.slf4j.slf4j + + + com.maxmind.geoip + fr.xephi.authme.libs.maxmind.geoip + + + net.ricecode.similarity + fr.xephi.authme.libs.ricecode.similarity + + + javax.inject + fr.xephi.authme.libs.javax.inject + + + + org.mcstats + fr.xephi.authme + target/${project.finalName}-spigot.jar @@ -215,31 +210,31 @@ shade - + com.google fr.xephi.authme.libs.google com.zaxxer.hikari - fr.xephi.authme.libs.hikari + fr.xephi.authme.libs.zaxxer.hikari org.slf4j - fr.xephi.authme.libs.slf4j + fr.xephi.authme.libs.slf4j.slf4j com.maxmind.geoip - fr.xephi.authme.libs.geoip + fr.xephi.authme.libs.maxmind.geoip net.ricecode.similarity - fr.xephi.authme.libs.similarity + fr.xephi.authme.libs.ricecode.similarity javax.inject - fr.xephi.authme.libs.inject + fr.xephi.authme.libs.javax.inject @@ -252,7 +247,7 @@ - + org.codehaus.mojo exec-maven-plugin @@ -267,7 +262,7 @@ true - + org.jacoco jacoco-maven-plugin @@ -281,7 +276,7 @@ - + org.eluder.coveralls coveralls-maven-plugin @@ -289,9 +284,9 @@ false - + - + org.apache.maven.plugins maven-javadoc-plugin @@ -305,9 +300,9 @@ - + - spigot-repo + spigotmc-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots @@ -319,7 +314,7 @@ - minelink-thirdparty + minelink-repo http://repo.minelink.net/content/repositories/public @@ -331,33 +326,27 @@ - onarandombox + onarandombox-repo http://repo.onarandombox.com/content/groups/public - vault-repo + theyeticave-repo http://nexus.theyeticave.net/content/repositories/pub_releases - luricos-releases + luricos-repo http://repo.luricos.de/content/repositories/releases - + xephi-repo http://ci.xephi.fr/plugin/repository/everything/ - - - - pex-repo - https://pex-repo.aoeu.xyz/ - @@ -375,6 +364,7 @@ true + org.slf4j slf4j-simple @@ -387,8 +377,7 @@ org.apache.logging.log4j log4j-core - - 2.0-beta9 + 2.5 provided diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index afd97494..8156d2c1 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -69,6 +69,7 @@ import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginLoader; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.messaging.Messenger; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; @@ -90,39 +91,26 @@ import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS; */ public class AuthMe extends JavaPlugin { - // Defines the name of the plugin. + // Name of the plugin. private static final String PLUGIN_NAME = "AuthMeReloaded"; // Default version and build number values; private static String pluginVersion = "N/D"; private static String pluginBuildNumber = "Unknown"; - // Private Instances - private static AuthMe plugin; - /* - * Maps and stuff - */ - public final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); - - /* - * Public instances - */ - public NewAPI api; - // TODO #655: Encapsulate mail - public SendMailSSL mail; /* * Private instances */ - // TODO #604: Encapsulate ProtocolLib members - public AuthMeInventoryPacketAdapter inventoryProtector; - public AuthMeTabCompletePacketAdapter tabComplete; - public AuthMeTablistPacketAdapter tablistHider; + + // Plugin instance + private static AuthMe plugin; + + private NewAPI api; private Management management; private CommandHandler commandHandler; private PermissionsManager permsMan; private NewSetting newSettings; private Messages messages; - private JsonCache playerBackup; private PasswordSecurity passwordSecurity; private DataSource database; private PluginHooks pluginHooks; @@ -130,6 +118,19 @@ public class AuthMe extends JavaPlugin { private BukkitService bukkitService; private AuthMeServiceInitializer initializer; + /* + * Public instances + */ + + // TODO: Encapsulate session management + public final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); + // TODO #655: Encapsulate mail + public SendMailSSL mail; + // TODO #604: Encapsulate ProtocolLib members + public AuthMeInventoryPacketAdapter inventoryProtector; + public AuthMeTabCompletePacketAdapter tabComplete; + public AuthMeTablistPacketAdapter tablistHider; + /** * Constructor. */ @@ -184,7 +185,7 @@ public class AuthMe extends JavaPlugin { } // Get version and build number of the plugin - private void setPluginInfos() { + private void loadPluginInfo() { String versionRaw = this.getDescription().getVersion(); int index = versionRaw.lastIndexOf("-"); if (index != -1) { @@ -201,19 +202,24 @@ public class AuthMe extends JavaPlugin { */ @Override public void onEnable() { - // Set various instances + // Set the plugin instance and load plugin info from the plugin description. plugin = this; + loadPluginInfo(); + + // Set the Logger instance and log file path ConsoleLogger.setLogger(getLogger()); - setPluginInfos(); + ConsoleLogger.setLogFile(new File(getDataFolder(), "authme.log")); // Load settings and custom configurations, if it fails, stop the server due to security reasons. newSettings = createNewSetting(); if (newSettings == null) { getLogger().warning("Could not load configuration. Aborting."); getServer().shutdown(); + setEnabled(false); return; } - ConsoleLogger.setLogFile(new File(getDataFolder(), "authme.log")); + + // Apply settings to the logger ConsoleLogger.setLoggingOptions(newSettings); // Old settings manager @@ -232,10 +238,12 @@ public class AuthMe extends JavaPlugin { stopOrUnload(); return; } + // Convert deprecated PLAINTEXT hash entries MigrationService.changePlainTextToSha256(newSettings, database, new SHA256()); - + // Injector initialization initializer = new AuthMeServiceInitializer("fr.xephi.authme"); + // Register elements of the Bukkit / JavaPlugin environment initializer.register(AuthMe.class, this); initializer.register(Server.class, getServer()); @@ -261,21 +269,15 @@ public class AuthMe extends JavaPlugin { // Set up the mail API setupMailApi(); - // Check if the ProtocolLib is available. If so we could listen for - // inventory protection + // Check if the ProtocolLib is available checkProtocolLib(); - // End of Hooks // Do a backup on start + // TODO: maybe create a backup manager? new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.START); - - // Setup the inventory backup - playerBackup = new JsonCache(); - - // Set up the BungeeCord hook - setupBungeeCordHook(newSettings, initializer); + setupBungeeCordHook(); // Reload support hook reloadSupportHook(); @@ -396,11 +398,11 @@ public class AuthMe extends JavaPlugin { /** * Set up the BungeeCord hook. */ - private void setupBungeeCordHook(NewSetting settings, AuthMeServiceInitializer initializer) { - if (settings.getProperty(HooksSettings.BUNGEECORD)) { - Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); - Bukkit.getMessenger().registerIncomingPluginChannel( - this, "BungeeCord", initializer.get(BungeeCordMessage.class)); + private void setupBungeeCordHook() { + if (newSettings.getProperty(HooksSettings.BUNGEECORD)) { + Messenger messenger = Bukkit.getMessenger(); + messenger.registerOutgoingPluginChannel(plugin, "BungeeCord"); + messenger.registerIncomingPluginChannel(plugin, "BungeeCord", initializer.get(BungeeCordMessage.class)); } } @@ -434,18 +436,20 @@ public class AuthMe extends JavaPlugin { * Set up the console filter. */ private void setupConsoleFilter() { - if (newSettings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) { + if (!newSettings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) { + return; + } + // Try to set the log4j filter + try { + Class.forName("org.apache.logging.log4j.core.filter.AbstractFilter"); + setLog4JFilter(); + } catch (ClassNotFoundException | NoClassDefFoundError e) { + // log4j is not available + ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled"); ConsoleFilter filter = new ConsoleFilter(); getLogger().setFilter(filter); Bukkit.getLogger().setFilter(filter); Logger.getLogger("Minecraft").setFilter(filter); - // Set Log4J Filter - try { - Class.forName("org.apache.logging.log4j.core.Filter"); - setLog4JFilter(); - } catch (ClassNotFoundException | NoClassDefFoundError e) { - ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled"); - } } } @@ -570,16 +574,9 @@ public class AuthMe extends JavaPlugin { // Set the console filter to remove the passwords private void setLog4JFilter() { - Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { - @Override - public void run() { - org.apache.logging.log4j.core.Logger logger; - logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger(); - logger.addFilter(new Log4JFilter()); - logger = (org.apache.logging.log4j.core.Logger) LogManager.getLogger("net.minecraft"); - logger.addFilter(new Log4JFilter()); - } - }); + org.apache.logging.log4j.core.Logger logger; + logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger(); + logger.addFilter(new Log4JFilter()); } // Check the presence of the ProtocolLib plugin @@ -640,9 +637,6 @@ public class AuthMe extends JavaPlugin { player.setOp(limbo.isOperator()); limbo.getTimeoutTask().cancel(); limboCache.deleteLimboPlayer(name); - if (this.playerBackup.doesCacheExist(player)) { - this.playerBackup.removeCache(player); - } } PlayerCache.getInstance().removePlayer(name); } @@ -719,7 +713,6 @@ public class AuthMe extends JavaPlugin { return commandHandler.processCommand(sender, commandLabel, args); } - // ------------- // Service getters (deprecated) // Use @Inject fields instead diff --git a/src/main/java/fr/xephi/authme/output/Log4JFilter.java b/src/main/java/fr/xephi/authme/output/Log4JFilter.java index 8bc52452..90b9f0fb 100644 --- a/src/main/java/fr/xephi/authme/output/Log4JFilter.java +++ b/src/main/java/fr/xephi/authme/output/Log4JFilter.java @@ -2,9 +2,9 @@ package fr.xephi.authme.output; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.filter.AbstractFilter; import org.apache.logging.log4j.message.Message; /** @@ -12,7 +12,8 @@ import org.apache.logging.log4j.message.Message; * * @author Xephi59 */ -public class Log4JFilter implements Filter { +@SuppressWarnings("serial") +public class Log4JFilter extends AbstractFilter { /** * Constructor. @@ -50,42 +51,30 @@ public class Log4JFilter implements Filter { } @Override - public Result filter(LogEvent record) { - if (record == null) { - return Result.NEUTRAL; + public Result filter(LogEvent event) { + Message candidate = null; + if(event != null) { + candidate = event.getMessage(); } - return validateMessage(record.getMessage()); + return validateMessage(candidate); } @Override - public Result filter(Logger arg0, Level arg1, Marker arg2, String message, Object... arg4) { - if (message == null) { - return Result.NEUTRAL; + public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) { + return validateMessage(msg); + } + + @Override + public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) { + return validateMessage(msg); + } + + @Override + public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) { + String candidate = null; + if(msg != null) { + candidate = msg.toString(); } - return validateMessage(message); + return validateMessage(candidate); } - - @Override - public Result filter(Logger arg0, Level arg1, Marker arg2, Object message, Throwable arg4) { - if (message == null) { - return Result.NEUTRAL; - } - return validateMessage(message.toString()); - } - - @Override - public Result filter(Logger arg0, Level arg1, Marker arg2, Message message, Throwable arg4) { - return validateMessage(message); - } - - @Override - public Result getOnMatch() { - return Result.NEUTRAL; - } - - @Override - public Result getOnMismatch() { - return Result.NEUTRAL; - } - } diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 28304e00..8f8f32ec 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -135,9 +135,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { // The Login event now fires (as intended) after everything is processed bukkitService.callEvent(new LoginEvent(player)); player.saveData(); - if (service.getProperty(HooksSettings.BUNGEECORD)) { - sendBungeeMessage(player); - } + sendBungeeMessage(player); // Login is done, display welcome message if (service.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { if (service.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) { @@ -162,15 +160,24 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { } private void sendTo(Player player) { - if (!service.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) { - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF("Connect"); - out.writeUTF(service.getProperty(HooksSettings.BUNGEECORD_SERVER)); - player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); + if(!service.getProperty(HooksSettings.BUNGEECORD)) { + return; } + if(service.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) { + return; + } + + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("Connect"); + out.writeUTF(service.getProperty(HooksSettings.BUNGEECORD_SERVER)); + player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); } private void sendBungeeMessage(Player player) { + if(!service.getProperty(HooksSettings.BUNGEECORD)) { + return; + } + ByteArrayDataOutput out = ByteStreams.newDataOutput(); out.writeUTF("Forward"); out.writeUTF("ALL"); @@ -178,5 +185,4 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { out.writeUTF("login;" + player.getName()); player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); } - } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ef48d2e2..cb915889 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -3,7 +3,7 @@ authors: [${bukkitplugin.authors}] website: ${project.url} description: ${project.description} main: ${bukkitplugin.main} -version: ${project.versionCode} +version: ${bukkitplugin.versionCode} softdepend: - Vault - PermissionsBukkit From 99704e7c294b2485dea1b1e0cb780e545b1e7b8b Mon Sep 17 00:00:00 2001 From: DNx5 Date: Mon, 27 Jun 2016 16:50:45 +0700 Subject: [PATCH 036/217] - Quick fix. Safely update player's inventory. * because it bugs me when i have items with custom NBT Tag --- .../fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 8f8f32ec..52192833 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -70,8 +70,8 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { private void restoreInventory(Player player) { RestoreInventoryEvent event = new RestoreInventoryEvent(player); pluginManager.callEvent(event); - if (!event.isCancelled() && plugin.inventoryProtector != null) { - plugin.inventoryProtector.sendInventoryPacket(player); + if (!event.isCancelled()) { + player.updateInventory(); } } From 0c96a3113bf6e1aa3207641408fa2cb8c741054f Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Mon, 27 Jun 2016 11:25:12 -0400 Subject: [PATCH 037/217] Encapsulate fields in main class; see #762 #655 #604 --- src/main/java/fr/xephi/authme/AuthMe.java | 71 ++++++++++++++++--- .../executable/email/RecoverEmailCommand.java | 4 +- .../xephi/authme/hooks/BungeeCordMessage.java | 6 +- .../authme/listener/AuthMeServerListener.java | 4 +- .../authme/process/join/AsynchronousJoin.java | 10 +-- .../process/login/ProcessSyncPlayerLogin.java | 4 +- .../ProcessSynchronousPlayerLogout.java | 8 +-- .../authme/process/quit/AsynchronousQuit.java | 4 +- .../process/register/AsyncRegister.java | 2 +- .../register/ProcessSyncPasswordRegister.java | 8 +-- 10 files changed, 84 insertions(+), 37 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 8156d2c1..b7474222 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -5,7 +5,6 @@ import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.command.CommandHandler; @@ -119,17 +118,13 @@ public class AuthMe extends JavaPlugin { private AuthMeServiceInitializer initializer; /* - * Public instances + * Private instances (sessions, mail, and ProtocolLib) */ - - // TODO: Encapsulate session management - public final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); - // TODO #655: Encapsulate mail - public SendMailSSL mail; - // TODO #604: Encapsulate ProtocolLib members - public AuthMeInventoryPacketAdapter inventoryProtector; - public AuthMeTabCompletePacketAdapter tabComplete; - public AuthMeTablistPacketAdapter tablistHider; + private final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); + private SendMailSSL mail; + private AuthMeInventoryPacketAdapter inventoryProtector; + private AuthMeTabCompletePacketAdapter tabComplete; + private AuthMeTablistPacketAdapter tablistHider; /** * Constructor. @@ -713,6 +708,60 @@ public class AuthMe extends JavaPlugin { return commandHandler.processCommand(sender, commandLabel, args); } + /** + * Get all current player sessions. + * + * @return A concurrent hashmap containing the sessions. + */ + public ConcurrentHashMap getSessions() { + return this.sessions; + } + + /** + * Get the mailing instance. + * + * @return The send mail instance. + */ + public SendMailSSL getMail() { + return this.mail; + } + + /** + * Get the ProtocolLib inventory packet adapter. + * + * @return The inventory packet adapter. + */ + public AuthMeInventoryPacketAdapter getInventoryProtector() { + return inventoryProtector; + } + + /** + * Get the ProtocolLib tab complete packet adapter. + * + * @return The tab complete packet adapter. + */ + public AuthMeTabCompletePacketAdapter getTabComplete() { + return tabComplete; + } + + /** + * Get the ProtocolLib tab list packet adapter. + * + * @return The tab list packet adapter. + */ + public AuthMeTablistPacketAdapter getTablistHider() { + return tablistHider; + } + + /** + * Disables instances should the ProtocolLib plugin be disabled on the server. + */ + public void disableProtocolLib() { + this.inventoryProtector = null; + this.tablistHider = null; + this.tabComplete = null; + } + // ------------- // Service getters (deprecated) // Use @Inject fields instead diff --git a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java index fac517ea..636027bb 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 @@ -41,7 +41,7 @@ public class RecoverEmailCommand extends PlayerCommand { final String playerMail = arguments.get(0); final String playerName = player.getName(); - if (plugin.mail == null) { + if (plugin.getMail() == null) { ConsoleLogger.showError("Mail API is not set"); commandService.send(player, MessageKey.ERROR); return; @@ -76,7 +76,7 @@ public class RecoverEmailCommand extends PlayerCommand { } auth.setPassword(hashNew); dataSource.updatePassword(auth); - plugin.mail.main(auth, thePass); + plugin.getMail().main(auth, thePass); commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE); } else { commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE); diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 5c145bbf..ff67b4ec 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -61,9 +61,9 @@ public class BungeeCordMessage implements PluginMessageListener { playerCache.updatePlayer(auth); dataSource.setLogged(name); //START 03062016 sgdc3: should fix #731 but we need to recode this mess - if (plugin.sessions.containsKey(name)) { - plugin.sessions.get(name).cancel(); - plugin.sessions.remove(name); + if (plugin.getSessions().containsKey(name)) { + plugin.getSessions().get(name).cancel(); + plugin.getSessions().remove(name); } //END diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index b627ed6d..d545ef10 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -75,9 +75,7 @@ public class AuthMeServerListener implements Listener { } if (pluginName.equalsIgnoreCase("ProtocolLib")) { - plugin.inventoryProtector = null; - plugin.tablistHider = null; - plugin.tabComplete = null; + plugin.disableProtocolLib(); ConsoleLogger.showError("ProtocolLib has been disabled, unhook packet inventory protection!"); } } diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java index cf1741c1..0eedd802 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -122,11 +122,11 @@ public class AsynchronousJoin implements AsynchronousProcess { limboCache.updateLimboPlayer(player); // Protect inventory - if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.inventoryProtector != null) { + if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.getInventoryProtector() != null) { ProtectInventoryEvent ev = new ProtectInventoryEvent(player); bukkitService.callEvent(ev); if (ev.isCancelled()) { - plugin.inventoryProtector.sendInventoryPacket(player); + plugin.getInventoryProtector().sendInventoryPacket(player); if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + "..."); } @@ -135,9 +135,9 @@ public class AsynchronousJoin implements AsynchronousProcess { // Session logic if (service.getProperty(PluginSettings.SESSIONS_ENABLED) && (playerCache.isAuthenticated(name) || database.isLogged(name))) { - if (plugin.sessions.containsKey(name)) { - plugin.sessions.get(name).cancel(); - plugin.sessions.remove(name); + if (plugin.getSessions().containsKey(name)) { + plugin.getSessions().get(name).cancel(); + plugin.getSessions().remove(name); } PlayerAuth auth = database.getAuth(name); database.setUnlogged(name); diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 52192833..e4ded1de 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -106,8 +106,8 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { restoreInventory(player); } - if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) { - plugin.tablistHider.sendTablist(player); + if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.getTablistHider() != null) { + plugin.getTablistHider().sendTablist(player); } // Clean up no longer used temporary data diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java index 88a13e30..6fb337f9 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java @@ -58,12 +58,12 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { public void processSyncLogout(Player player) { final String name = player.getName().toLowerCase(); - if (plugin.sessions.containsKey(name)) { - plugin.sessions.get(name).cancel(); - plugin.sessions.remove(name); + if (plugin.getSessions().containsKey(name)) { + plugin.getSessions().get(name).cancel(); + plugin.getSessions().remove(name); } if (service.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { - plugin.inventoryProtector.sendBlankInventoryPacket(player); + plugin.getInventoryProtector().sendBlankInventoryPacket(player); } limboPlayerTaskManager.registerTimeoutTask(player); diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index d31f305c..675a40ff 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -94,7 +94,7 @@ public class AsynchronousQuit implements AsynchronousProcess { }, Settings.getSessionTimeout * TICKS_PER_MINUTE); - plugin.sessions.put(name, task); + plugin.getSessions().put(name, task); } else { //plugin is disabled; we cannot schedule more tasks so run it directly here postLogout(name); @@ -117,6 +117,6 @@ public class AsynchronousQuit implements AsynchronousProcess { private void postLogout(String name) { PlayerCache.getInstance().removePlayer(name); database.setUnlogged(name); - plugin.sessions.remove(name); + plugin.getSessions().remove(name); } } diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java index 9c792fe6..4ddaff5e 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -137,7 +137,7 @@ public class AsyncRegister implements AsynchronousProcess { } database.updateEmail(auth); database.updateSession(auth); - plugin.mail.main(auth, password); + plugin.getMail().main(auth, password); syncProcessManager.processSyncEmailRegister(player); } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 3076e7f1..2ac8d027 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -92,17 +92,17 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { final String name = player.getName().toLowerCase(); LimboPlayer limbo = limboCache.getLimboPlayer(name); if (limbo != null) { - if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) { - plugin.tablistHider.sendTablist(player); + if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.getTablistHider() != null) { + plugin.getTablistHider().sendTablist(player); } Utils.teleportToSpawn(player); - if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.inventoryProtector != null) { + if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.getInventoryProtector() != null) { RestoreInventoryEvent event = new RestoreInventoryEvent(player); bukkitService.callEvent(event); if (!event.isCancelled()) { - plugin.inventoryProtector.sendInventoryPacket(player); + plugin.getInventoryProtector().sendInventoryPacket(player); } } From 1326606f37ccd14a23b87d5f4033bb8014d46d09 Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Mon, 27 Jun 2016 13:50:16 -0400 Subject: [PATCH 038/217] #762 - Move all sessions stuff to new SessionManager class --- src/main/java/fr/xephi/authme/AuthMe.java | 13 +-- .../fr/xephi/authme/cache/SessionManager.java | 75 ++++++++++++++ .../xephi/authme/hooks/BungeeCordMessage.java | 9 +- .../authme/process/join/AsynchronousJoin.java | 9 +- .../ProcessSynchronousPlayerLogout.java | 9 +- .../authme/process/quit/AsynchronousQuit.java | 32 +++--- .../authme/cache/SessionManagerTest.java | 98 +++++++++++++++++++ 7 files changed, 209 insertions(+), 36 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/cache/SessionManager.java create mode 100644 src/test/java/fr/xephi/authme/cache/SessionManagerTest.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index b7474222..5f493516 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -78,7 +78,6 @@ import java.util.ArrayList; 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; @@ -118,9 +117,8 @@ public class AuthMe extends JavaPlugin { private AuthMeServiceInitializer initializer; /* - * Private instances (sessions, mail, and ProtocolLib) + * Private instances (mail and ProtocolLib) */ - private final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); private SendMailSSL mail; private AuthMeInventoryPacketAdapter inventoryProtector; private AuthMeTabCompletePacketAdapter tabComplete; @@ -708,15 +706,6 @@ public class AuthMe extends JavaPlugin { return commandHandler.processCommand(sender, commandLabel, args); } - /** - * Get all current player sessions. - * - * @return A concurrent hashmap containing the sessions. - */ - public ConcurrentHashMap getSessions() { - return this.sessions; - } - /** * Get the mailing instance. * diff --git a/src/main/java/fr/xephi/authme/cache/SessionManager.java b/src/main/java/fr/xephi/authme/cache/SessionManager.java new file mode 100644 index 00000000..0c03dc0f --- /dev/null +++ b/src/main/java/fr/xephi/authme/cache/SessionManager.java @@ -0,0 +1,75 @@ +package fr.xephi.authme.cache; + +import fr.xephi.authme.initialization.SettingsDependent; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.PluginSettings; +import org.bukkit.scheduler.BukkitTask; + +import javax.inject.Inject; +import java.util.concurrent.ConcurrentHashMap; + +public class SessionManager implements SettingsDependent { + + private final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); + + private boolean enabled; + private int sessionTimeout; + + @Inject + SessionManager(NewSetting settings) { + loadSettings(settings); + } + + /** + * Check if a session for a player is currently being cached. + * + * @param name The name to check. + * @return True if a session is found. + */ + public boolean hasSession(String name) { + return sessions.containsKey(name); + } + + /** + * Add a player session to the cache. + * + * @param name The name of the player. + * @param task The task to run. + */ + public void addSession(String name, BukkitTask task) { + if (!enabled || sessionTimeout == 0) { + return; + } + + this.sessions.put(name, task); + } + + /** + * Cancels a player's session. After the task is cancelled, it will be removed from + * the cache. + * + * @param name The name of the player who's session to cancel. + */ + public void cancelSession(String name) { + BukkitTask task = sessions.get(name); + if (task != null) { + task.cancel(); + removeSession(name); + } + } + + /** + * Remove a player's session from the cache. + * + * @param name The name of the player. + */ + public void removeSession(String name) { + this.sessions.remove(name); + } + + @Override + public void loadSettings(NewSetting settings) { + this.enabled = settings.getProperty(PluginSettings.SESSIONS_ENABLED); + this.sessionTimeout = settings.getProperty(PluginSettings.SESSIONS_TIMEOUT); + } +} diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index ff67b4ec..2d05d5ce 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -5,6 +5,7 @@ import com.google.common.io.ByteStreams; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; @@ -29,6 +30,9 @@ public class BungeeCordMessage implements PluginMessageListener { @Inject private PlayerCache playerCache; + @Inject + private SessionManager sessionManager; + @Inject private AuthMe plugin; @@ -61,9 +65,8 @@ public class BungeeCordMessage implements PluginMessageListener { playerCache.updatePlayer(auth); dataSource.setLogged(name); //START 03062016 sgdc3: should fix #731 but we need to recode this mess - if (plugin.getSessions().containsKey(name)) { - plugin.getSessions().get(name).cancel(); - plugin.getSessions().remove(name); + if (sessionManager.hasSession(name)) { + sessionManager.cancelSession(name); } //END 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 0eedd802..709a9dac 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -2,6 +2,7 @@ package fr.xephi.authme.process.join; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; @@ -55,6 +56,9 @@ public class AsynchronousJoin implements AsynchronousProcess { @Inject private LimboCache limboCache; + @Inject + private SessionManager sessionManager; + @Inject private PluginHooks pluginHooks; @@ -135,9 +139,8 @@ public class AsynchronousJoin implements AsynchronousProcess { // Session logic if (service.getProperty(PluginSettings.SESSIONS_ENABLED) && (playerCache.isAuthenticated(name) || database.isLogged(name))) { - if (plugin.getSessions().containsKey(name)) { - plugin.getSessions().get(name).cancel(); - plugin.getSessions().remove(name); + if (sessionManager.hasSession(name)) { + sessionManager.cancelSession(name); } PlayerAuth auth = database.getAuth(name); database.setUnlogged(name); diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java index 6fb337f9..38514567 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java @@ -4,6 +4,7 @@ import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.events.LogoutEvent; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.ProcessService; @@ -36,6 +37,9 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { @Inject private LimboPlayerTaskManager limboPlayerTaskManager; + @Inject + private SessionManager sessionManager; + ProcessSynchronousPlayerLogout() { } @@ -58,9 +62,8 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { public void processSyncLogout(Player player) { final String name = player.getName().toLowerCase(); - if (plugin.getSessions().containsKey(name)) { - plugin.getSessions().get(name).cancel(); - plugin.getSessions().remove(name); + if (sessionManager.hasSession(name)) { + sessionManager.cancelSession(name); } if (service.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { plugin.getInventoryProtector().sendBlankInventoryPacket(player); diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index 675a40ff..a157287b 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -1,6 +1,7 @@ package fr.xephi.authme.process.quit; import fr.xephi.authme.AuthMe; +import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; @@ -42,6 +43,9 @@ public class AsynchronousQuit implements AsynchronousProcess { @Inject private SyncProcessManager syncProcessManager; + @Inject + private SessionManager sessionManager; + AsynchronousQuit() { } @@ -82,23 +86,21 @@ public class AsynchronousQuit implements AsynchronousProcess { isOp = limbo.isOperator(); limboCache.deleteLimboPlayer(name); } - if (Settings.isSessionsEnabled && !isKick) { - if (Settings.getSessionTimeout != 0) { - if (plugin.isEnabled()) { - BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { + if (!isKick) { + if (plugin.isEnabled()) { + BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { - @Override - public void run() { - postLogout(name); - } + @Override + public void run() { + postLogout(name); + } - }, Settings.getSessionTimeout * TICKS_PER_MINUTE); + }, Settings.getSessionTimeout * TICKS_PER_MINUTE); - plugin.getSessions().put(name, task); - } else { - //plugin is disabled; we cannot schedule more tasks so run it directly here - postLogout(name); - } + sessionManager.addSession(name, task); + } else { + //plugin is disabled; we cannot schedule more tasks so run it directly here + postLogout(name); } } else { playerCache.removePlayer(name); @@ -117,6 +119,6 @@ public class AsynchronousQuit implements AsynchronousProcess { private void postLogout(String name) { PlayerCache.getInstance().removePlayer(name); database.setUnlogged(name); - plugin.getSessions().remove(name); + sessionManager.removeSession(name); } } diff --git a/src/test/java/fr/xephi/authme/cache/SessionManagerTest.java b/src/test/java/fr/xephi/authme/cache/SessionManagerTest.java new file mode 100644 index 00000000..6e03b312 --- /dev/null +++ b/src/test/java/fr/xephi/authme/cache/SessionManagerTest.java @@ -0,0 +1,98 @@ +package fr.xephi.authme.cache; + +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.PluginSettings; +import org.bukkit.scheduler.BukkitTask; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link SessionManager}. + */ +@RunWith(MockitoJUnitRunner.class) +public class SessionManagerTest { + + @Test + public void shouldHaveSession() { + // given + NewSetting settings = mockSettings(true, 10); + SessionManager manager = new SessionManager(settings); + String player = "playah"; + BukkitTask task = mock(BukkitTask.class); + + // when + manager.addSession(player, task); + + // then + assertThat(manager.hasSession(player), equalTo(true)); + } + + @Test + public void shouldNotHaveSession() { + // given + NewSetting settings = mockSettings(true, 10); + SessionManager manager = new SessionManager(settings); + String player = "playah"; + + // when/then + assertThat(manager.hasSession(player), equalTo(false)); + } + + @Test + public void shouldAddSession() { + // given + NewSetting settings = mockSettings(true, 10); + SessionManager manager = new SessionManager(settings); + String player = "playah"; + BukkitTask task = mock(BukkitTask.class); + + // when + manager.addSession(player, task); + + // then + assertThat(manager.hasSession(player), equalTo(true)); + } + + @Test + public void shouldNotAddSessionBecauseDisabled() { + // given + NewSetting settings = mockSettings(false, 10); + SessionManager manager = new SessionManager(settings); + String player = "playah"; + BukkitTask task = mock(BukkitTask.class); + + // when + manager.addSession(player, task); + + // then + assertThat(manager.hasSession(player), equalTo(false)); + } + + @Test + public void shouldNotAddSessionBecauseTimeoutIsZero() { + // given + NewSetting settings = mockSettings(true, 0); + SessionManager manager = new SessionManager(settings); + String player = "playah"; + BukkitTask task = mock(BukkitTask.class); + + // when + manager.addSession(player, task); + + // then + assertThat(manager.hasSession(player), equalTo(false)); + } + + private static NewSetting mockSettings(boolean isEnabled, int sessionTimeout) { + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(PluginSettings.SESSIONS_ENABLED)).willReturn(isEnabled); + given(settings.getProperty(PluginSettings.SESSIONS_TIMEOUT)).willReturn(sessionTimeout); + return settings; + } +} From 1361174892dd6df0f71be24d48a6551c97d42b14 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 26 Jun 2016 23:09:27 +0200 Subject: [PATCH 039/217] Encapsulate GeoLiteAPI class --- src/main/java/fr/xephi/authme/AuthMe.java | 7 +- .../fr/xephi/authme/settings/SpawnLoader.java | 4 +- .../java/fr/xephi/authme/util/GeoLiteAPI.java | 51 ++++++--- .../xephi/authme/util/ValidationService.java | 24 ++-- .../fr/xephi/authme/util/GeoLiteAPITest.java | 104 ++++++++++++++++++ .../authme/util/ValidationServiceTest.java | 13 ++- 6 files changed, 163 insertions(+), 40 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/util/GeoLiteAPITest.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 5f493516..bd9b58d4 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -115,6 +115,7 @@ public class AuthMe extends JavaPlugin { private SpawnLoader spawnLoader; private BukkitService bukkitService; private AuthMeServiceInitializer initializer; + private GeoLiteAPI geoLiteApi; /* * Private instances (mail and ProtocolLib) @@ -256,9 +257,6 @@ public class AuthMe extends JavaPlugin { // Set console filter setupConsoleFilter(); - // Download and load GeoIp.dat file if absent - GeoLiteAPI.isDataAvailable(); - // Set up the mail API setupMailApi(); @@ -313,6 +311,7 @@ public class AuthMe extends JavaPlugin { commandHandler = initializer.get(CommandHandler.class); api = initializer.get(NewAPI.class); management = initializer.get(Management.class); + geoLiteApi = initializer.get(GeoLiteAPI.class); initializer.get(API.class); } @@ -678,7 +677,7 @@ public class AuthMe extends JavaPlugin { .replace("{WORLD}", player.getWorld().getName()) .replace("{SERVER}", server.getServerName()) .replace("{VERSION}", server.getBukkitVersion()) - .replace("{COUNTRY}", GeoLiteAPI.getCountryName(ipAddress)); + .replace("{COUNTRY}", geoLiteApi.getCountryName(ipAddress)); } diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java index ecb1d379..684e74aa 100644 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java @@ -1,6 +1,5 @@ package fr.xephi.authme.settings; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; @@ -145,8 +144,7 @@ public class SpawnLoader implements Reloadable { * @see RestrictionSettings#SPAWN_PRIORITY */ public Location getSpawnLocation(Player player) { - AuthMe plugin = AuthMe.getInstance(); - if (plugin == null || player == null || player.getWorld() == null) { + if (player == null || player.getWorld() == null) { return null; } diff --git a/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java b/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java index 49a57cf3..ec66d508 100644 --- a/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java +++ b/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java @@ -1,9 +1,11 @@ package fr.xephi.authme.util; +import com.google.common.annotations.VisibleForTesting; import com.maxmind.geoip.LookupService; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.initialization.DataFolder; +import javax.inject.Inject; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -19,10 +21,22 @@ public class GeoLiteAPI { "[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com"; private static final String GEOIP_URL = "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"; - private static LookupService lookupService; - private static Thread downloadTask; + private LookupService lookupService; + private Thread downloadTask; - private GeoLiteAPI() { + private final File dataFile; + + @Inject + GeoLiteAPI(@DataFolder File dataFolder) { + this.dataFile = new File(dataFolder, "GeoIP.dat"); + // Fires download of recent data or the initialization of the look up service + isDataAvailable(); + } + + @VisibleForTesting + GeoLiteAPI(@DataFolder File dataFolder, LookupService lookupService) { + this.dataFile = dataFolder; + this.lookupService = lookupService; } /** @@ -30,20 +44,19 @@ public class GeoLiteAPI { * * @return True if the data is available, false otherwise. */ - public synchronized static boolean isDataAvailable() { + private synchronized boolean isDataAvailable() { if (downloadTask != null && downloadTask.isAlive()) { return false; } if (lookupService != null) { return true; } - final File pluginFolder = AuthMe.getInstance().getDataFolder(); - final File data = new File(pluginFolder, "GeoIP.dat"); - if (data.exists()) { - boolean dataIsOld = (System.currentTimeMillis() - data.lastModified()) > TimeUnit.DAYS.toMillis(30); + + if (dataFile.exists()) { + boolean dataIsOld = (System.currentTimeMillis() - dataFile.lastModified()) > TimeUnit.DAYS.toMillis(30); if (!dataIsOld) { try { - lookupService = new LookupService(data); + lookupService = new LookupService(dataFile); ConsoleLogger.info(LICENSE); return true; } catch (IOException e) { @@ -51,13 +64,19 @@ public class GeoLiteAPI { return false; } } else { - if (!data.delete()) { + if (!dataFile.delete()) { ConsoleLogger.showError("Failed to delete GeoLiteAPI database"); } } } // Ok, let's try to download the data file! - downloadTask = new Thread(new Runnable() { + downloadTask = createDownloadTask(); + downloadTask.start(); + return false; + } + + private Thread createDownloadTask() { + return new Thread(new Runnable() { @Override public void run() { try { @@ -69,7 +88,7 @@ public class GeoLiteAPI { if (conn.getURL().toString().endsWith(".gz")) { input = new GZIPInputStream(input); } - OutputStream output = new FileOutputStream(data); + OutputStream output = new FileOutputStream(dataFile); byte[] buffer = new byte[2048]; int length = input.read(buffer); while (length >= 0) { @@ -83,8 +102,6 @@ public class GeoLiteAPI { } } }); - downloadTask.start(); - return false; } /** @@ -94,7 +111,7 @@ public class GeoLiteAPI { * * @return two-character ISO 3166-1 alpha code for the country. */ - public static String getCountryCode(String ip) { + public String getCountryCode(String ip) { if (!"127.0.0.1".equals(ip) && isDataAvailable()) { return lookupService.getCountry(ip).getCode(); } @@ -108,7 +125,7 @@ public class GeoLiteAPI { * * @return The name of the country. */ - public static String getCountryName(String ip) { + public String getCountryName(String ip) { if (!"127.0.0.1".equals(ip) && isDataAvailable()) { return lookupService.getCountry(ip).getName(); } diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java index 615095d0..f2f1b0e5 100644 --- a/src/main/java/fr/xephi/authme/util/ValidationService.java +++ b/src/main/java/fr/xephi/authme/util/ValidationService.java @@ -13,6 +13,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.CommandSender; +import javax.annotation.PostConstruct; import javax.inject.Inject; import java.util.Collection; import java.util.List; @@ -23,19 +24,20 @@ import java.util.regex.Pattern; */ public class ValidationService implements Reloadable { - private final NewSetting settings; - private final DataSource dataSource; - private final PermissionsManager permissionsManager; + @Inject + private NewSetting settings; + @Inject + private DataSource dataSource; + @Inject + private PermissionsManager permissionsManager; + @Inject + private GeoLiteAPI geoLiteApi; + private Pattern passwordRegex; - @Inject - public ValidationService(NewSetting settings, DataSource dataSource, PermissionsManager permissionsManager) { - this.settings = settings; - this.dataSource = dataSource; - this.permissionsManager = permissionsManager; - reload(); - } + ValidationService() { } + @PostConstruct @Override public void reload() { passwordRegex = Utils.safePatternCompile(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)); @@ -105,7 +107,7 @@ public class ValidationService implements Reloadable { return true; } - String countryCode = GeoLiteAPI.getCountryCode(hostAddress); + String countryCode = geoLiteApi.getCountryCode(hostAddress); return validateWhitelistAndBlacklist(countryCode, ProtectionSettings.COUNTRIES_WHITELIST, ProtectionSettings.COUNTRIES_BLACKLIST); diff --git a/src/test/java/fr/xephi/authme/util/GeoLiteAPITest.java b/src/test/java/fr/xephi/authme/util/GeoLiteAPITest.java new file mode 100644 index 00000000..c932ddbb --- /dev/null +++ b/src/test/java/fr/xephi/authme/util/GeoLiteAPITest.java @@ -0,0 +1,104 @@ +package fr.xephi.authme.util; + +import com.maxmind.geoip.Country; +import com.maxmind.geoip.LookupService; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +/** + * Test for {@link GeoLiteAPI}. + */ +@RunWith(MockitoJUnitRunner.class) +public class GeoLiteAPITest { + + private GeoLiteAPI geoLiteApi; + private File dataFolder; + @Mock + private LookupService lookupService; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void initializeGeoLiteApi() throws IOException { + dataFolder = temporaryFolder.newFolder(); + geoLiteApi = new GeoLiteAPI(dataFolder, lookupService); + } + + @Test + public void shouldGetCountry() { + // given + String ip = "123.45.67.89"; + String countryCode = "XX"; + Country country = mock(Country.class); + given(country.getCode()).willReturn(countryCode); + given(lookupService.getCountry(ip)).willReturn(country); + + // when + String result = geoLiteApi.getCountryCode(ip); + + // then + assertThat(result, equalTo(countryCode)); + verify(lookupService).getCountry(ip); + } + + @Test + public void shouldNotLookUpCountryForLocalhostIp() { + // given + String ip = "127.0.0.1"; + + // when + String result = geoLiteApi.getCountryCode(ip); + + // then + assertThat(result, equalTo("--")); + verify(lookupService, never()).getCountry(anyString()); + } + + @Test + public void shouldLookUpCountryName() { + // given + String ip = "24.45.167.89"; + String countryName = "Ecuador"; + Country country = mock(Country.class); + given(country.getName()).willReturn(countryName); + given(lookupService.getCountry(ip)).willReturn(country); + + // when + String result = geoLiteApi.getCountryName(ip); + + // then + assertThat(result, equalTo(countryName)); + verify(lookupService).getCountry(ip); + } + + @Test + public void shouldNotLookUpCountryNameForLocalhostIp() { + // given + String ip = "127.0.0.1"; + + // when + String result = geoLiteApi.getCountryName(ip); + + // then + assertThat(result, equalTo("N/A")); + verify(lookupService, never()).getCountry(ip); + } + +} diff --git a/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java b/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java index 0d52f775..ddfc9c16 100644 --- a/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java +++ b/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java @@ -5,17 +5,18 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; +import fr.xephi.authme.runner.BeforeInjecting; +import fr.xephi.authme.runner.DelayedInjectionRunner; +import fr.xephi.authme.runner.InjectDelayed; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.ValidationService.ValidationResult; import org.bukkit.command.CommandSender; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import java.util.Arrays; import java.util.Collections; @@ -28,9 +29,10 @@ import static org.mockito.Mockito.mock; /** * Test for {@link ValidationService}. */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(DelayedInjectionRunner.class) public class ValidationServiceTest { + @InjectDelayed private ValidationService validationService; @Mock private NewSetting settings; @@ -38,8 +40,10 @@ public class ValidationServiceTest { private DataSource dataSource; @Mock private PermissionsManager permissionsManager; + @Mock + private GeoLiteAPI geoLiteApi; - @Before + @BeforeInjecting public void createService() { given(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)).willReturn("[a-zA-Z]+"); given(settings.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)).willReturn(3); @@ -47,7 +51,6 @@ public class ValidationServiceTest { given(settings.getProperty(SecuritySettings.UNSAFE_PASSWORDS)) .willReturn(Arrays.asList("unsafe", "other-unsafe")); given(settings.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).willReturn(3); - validationService = new ValidationService(settings, dataSource, permissionsManager); } @Test From 23836cda6aaff3bd7300f34e00bec2eae42047a5 Mon Sep 17 00:00:00 2001 From: Gnat008 Date: Mon, 27 Jun 2016 15:38:43 -0400 Subject: [PATCH 040/217] #604 - Move ProtocolLib adapters to new package and add ProtocolLibService --- src/main/java/fr/xephi/authme/AuthMe.java | 80 ---------- .../authme/listener/AuthMeServerListener.java | 9 +- .../AuthMeInventoryPacketAdapter.java | 15 +- .../AuthMeTabCompletePacketAdapter.java | 2 +- .../AuthMeTablistPacketAdapter.java | 11 +- .../protocollib/ProtocolLibService.java | 146 ++++++++++++++++++ .../authme/process/join/AsynchronousJoin.java | 8 +- .../process/login/ProcessSyncPlayerLogin.java | 8 +- .../ProcessSynchronousPlayerLogout.java | 6 +- .../register/ProcessSyncPasswordRegister.java | 12 +- 10 files changed, 188 insertions(+), 109 deletions(-) rename src/main/java/fr/xephi/authme/listener/{ => protocollib}/AuthMeInventoryPacketAdapter.java (99%) rename src/main/java/fr/xephi/authme/listener/{ => protocollib}/AuthMeTabCompletePacketAdapter.java (96%) rename src/main/java/fr/xephi/authme/listener/{ => protocollib}/AuthMeTablistPacketAdapter.java (99%) create mode 100644 src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index bd9b58d4..181e0da3 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -21,13 +21,10 @@ 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; import fr.xephi.authme.listener.AuthMePlayerListener18; import fr.xephi.authme.listener.AuthMeServerListener; -import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter; -import fr.xephi.authme.listener.AuthMeTablistPacketAdapter; import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.output.ConsoleFilter; import fr.xephi.authme.output.Log4JFilter; @@ -121,9 +118,6 @@ public class AuthMe extends JavaPlugin { * Private instances (mail and ProtocolLib) */ private SendMailSSL mail; - private AuthMeInventoryPacketAdapter inventoryProtector; - private AuthMeTabCompletePacketAdapter tabComplete; - private AuthMeTablistPacketAdapter tablistHider; /** * Constructor. @@ -260,9 +254,6 @@ public class AuthMe extends JavaPlugin { // Set up the mail API setupMailApi(); - // Check if the ProtocolLib is available - checkProtocolLib(); - // Do a backup on start // TODO: maybe create a backup manager? new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.START); @@ -571,41 +562,6 @@ public class AuthMe extends JavaPlugin { logger.addFilter(new Log4JFilter()); } - // Check the presence of the ProtocolLib plugin - public void checkProtocolLib() { - 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; - newSettings.setProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN, false); - newSettings.save(); - } - return; - } - - if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN) && inventoryProtector == null) { - inventoryProtector = new AuthMeInventoryPacketAdapter(this); - inventoryProtector.register(); - } else if (inventoryProtector != null) { - inventoryProtector.unregister(); - inventoryProtector = null; - } - if (newSettings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN) && tabComplete == null) { - tabComplete = new AuthMeTabCompletePacketAdapter(this); - tabComplete.register(); - } else if (tabComplete != null) { - tabComplete.unregister(); - tabComplete = null; - } - if (newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && tablistHider == null) { - tablistHider = new AuthMeTablistPacketAdapter(this, bukkitService); - tablistHider.register(); - } else if (tablistHider != null) { - tablistHider.unregister(); - tablistHider = null; - } - } - // Save Player Data private void savePlayer(Player player, LimboCache limboCache) { if (safeIsNpc(player) || Utils.isUnrestricted(player)) { @@ -714,42 +670,6 @@ public class AuthMe extends JavaPlugin { return this.mail; } - /** - * Get the ProtocolLib inventory packet adapter. - * - * @return The inventory packet adapter. - */ - public AuthMeInventoryPacketAdapter getInventoryProtector() { - return inventoryProtector; - } - - /** - * Get the ProtocolLib tab complete packet adapter. - * - * @return The tab complete packet adapter. - */ - public AuthMeTabCompletePacketAdapter getTabComplete() { - return tabComplete; - } - - /** - * Get the ProtocolLib tab list packet adapter. - * - * @return The tab list packet adapter. - */ - public AuthMeTablistPacketAdapter getTablistHider() { - return tablistHider; - } - - /** - * Disables instances should the ProtocolLib plugin be disabled on the server. - */ - public void disableProtocolLib() { - this.inventoryProtector = null; - this.tablistHider = null; - this.tabComplete = null; - } - // ------------- // Service getters (deprecated) // Use @Inject fields instead diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index d545ef10..a851b5e9 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -3,6 +3,7 @@ package fr.xephi.authme.listener; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; @@ -34,6 +35,8 @@ public class AuthMeServerListener implements Listener { @Inject private SpawnLoader spawnLoader; @Inject + private ProtocolLibService protocolLibService; + @Inject private ValidationService validationService; @Inject private PermissionsManager permissionsManager; @@ -75,8 +78,8 @@ public class AuthMeServerListener implements Listener { } if (pluginName.equalsIgnoreCase("ProtocolLib")) { - plugin.disableProtocolLib(); - ConsoleLogger.showError("ProtocolLib has been disabled, unhook packet inventory protection!"); + protocolLibService.disable(); + ConsoleLogger.showError("ProtocolLib has been disabled, unhooking packet adapters!"); } } @@ -103,7 +106,7 @@ public class AuthMeServerListener implements Listener { } if (pluginName.equalsIgnoreCase("ProtocolLib")) { - plugin.checkProtocolLib(); + protocolLibService.setup(); } } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java similarity index 99% rename from src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java rename to src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java index c6bb0967..a8179b74 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package fr.xephi.authme.listener; +package fr.xephi.authme.listener.protocollib; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -22,22 +22,19 @@ import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.settings.Settings; - -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.Collections; -import java.util.logging.Level; - +import org.apache.commons.lang.reflect.MethodUtils; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; -import org.apache.commons.lang.reflect.MethodUtils; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Collections; +import java.util.logging.Level; public class AuthMeInventoryPacketAdapter extends PacketAdapter { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTabCompletePacketAdapter.java similarity index 96% rename from src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java rename to src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTabCompletePacketAdapter.java index ae6c47bc..ad4d1e0b 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTabCompletePacketAdapter.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.listener; +package fr.xephi.authme.listener.protocollib; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java similarity index 99% rename from src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java rename to src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java index 8775959e..dd24bdb1 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.listener; +package fr.xephi.authme.listener.protocollib; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -14,12 +14,14 @@ import com.comphenix.protocol.wrappers.PlayerInfoData; import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.google.common.collect.Lists; - 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.Bukkit; +import org.bukkit.entity.Player; +import javax.inject.Inject; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Iterator; @@ -27,11 +29,6 @@ import java.util.List; import java.util.UUID; import java.util.logging.Level; -import javax.inject.Inject; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - public class AuthMeTablistPacketAdapter extends PacketAdapter { private final BukkitService bukkitService; diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java new file mode 100644 index 00000000..b1f5573a --- /dev/null +++ b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java @@ -0,0 +1,146 @@ +package fr.xephi.authme.listener.protocollib; + +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.initialization.SettingsDependent; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.util.BukkitService; +import org.bukkit.entity.Player; + +import javax.inject.Inject; + +public class ProtocolLibService implements SettingsDependent { + + /* Packet Adapters */ + private AuthMeInventoryPacketAdapter inventoryPacketAdapter; + private AuthMeTabCompletePacketAdapter tabCompletePacketAdapter; + private AuthMeTablistPacketAdapter tablistPacketAdapter; + + /* Settings */ + private boolean protectInvBeforeLogin; + private boolean denyTabCompleteBeforeLogin; + private boolean hideTablistBeforeLogin; + + /* Service */ + private boolean isEnabled; + private AuthMe plugin; + private BukkitService bukkitService; + + @Inject + ProtocolLibService(AuthMe plugin, BukkitService bukkitService, NewSetting settings) { + this.plugin = plugin; + this.bukkitService = bukkitService; + loadSettings(settings); + setup(); + } + + /** + * Set up the ProtocolLib packet adapters. + */ + public void setup() { + // Check if ProtocolLib is enabled on the server. + if (!plugin.getServer().getPluginManager().isPluginEnabled("ProtocolLib")) { + if (protectInvBeforeLogin) { + ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it..."); + } + if (denyTabCompleteBeforeLogin) { + ConsoleLogger.showError("WARNING! The denyTabComplete feature requires ProtocolLib! Disabling it..."); + } + if (hideTablistBeforeLogin) { + ConsoleLogger.showError("WARNING! The hideTablist feature requires ProtocolLib! Disabling it..."); + } + + this.isEnabled = false; + return; + } + + // Set up packet adapters + if (protectInvBeforeLogin && inventoryPacketAdapter == null) { + inventoryPacketAdapter = new AuthMeInventoryPacketAdapter(plugin); + inventoryPacketAdapter.register(); + } else if (inventoryPacketAdapter != null) { + inventoryPacketAdapter.unregister(); + inventoryPacketAdapter = null; + } + if (denyTabCompleteBeforeLogin && tabCompletePacketAdapter == null) { + tabCompletePacketAdapter = new AuthMeTabCompletePacketAdapter(plugin); + tabCompletePacketAdapter.register(); + } else if (tabCompletePacketAdapter != null) { + tabCompletePacketAdapter.unregister(); + tabCompletePacketAdapter = null; + } + if (hideTablistBeforeLogin && tablistPacketAdapter == null) { + tablistPacketAdapter = new AuthMeTablistPacketAdapter(plugin, bukkitService); + tablistPacketAdapter.register(); + } else if (tablistPacketAdapter != null) { + tablistPacketAdapter.unregister(); + tablistPacketAdapter = null; + } + + this.isEnabled = true; + } + + public void disable() { + isEnabled = false; + + if (inventoryPacketAdapter != null) { + inventoryPacketAdapter.unregister(); + inventoryPacketAdapter = null; + } + if (tabCompletePacketAdapter != null) { + tabCompletePacketAdapter.unregister(); + tabCompletePacketAdapter = null; + } + if (tablistPacketAdapter != null) { + tablistPacketAdapter.unregister(); + tablistPacketAdapter = null; + } + } + + /** + * Send a packet to the player to give them an inventory. + * + * @param player The player to send the packet to. + */ + public void sendInventoryPacket(Player player) { + if (!isEnabled || inventoryPacketAdapter == null) { + return; + } + + inventoryPacketAdapter.sendInventoryPacket(player); + } + + /** + * Send a packet to the player to give them a blank inventory. + * + * @param player The player to send the packet to. + */ + public void sendBlankInventoryPacket(Player player) { + if (!isEnabled || inventoryPacketAdapter == null) { + return; + } + + inventoryPacketAdapter.sendBlankInventoryPacket(player); + } + + /** + * Send a tab list packet to a player. + * + * @param player The player to send the packet to. + */ + public void sendTabList(Player player) { + if (!isEnabled || tablistPacketAdapter == null) { + return; + } + + tablistPacketAdapter.sendTablist(player); + } + + @Override + public void loadSettings(NewSetting settings) { + this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN); + this.denyTabCompleteBeforeLogin = settings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN); + this.hideTablistBeforeLogin = settings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN); + } +} 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 709a9dac..5551b9b8 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.cache.limbo.LimboCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.ProtectInventoryEvent; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.permission.PlayerStatePermission; @@ -68,6 +69,9 @@ public class AsynchronousJoin implements AsynchronousProcess { @Inject private BukkitService bukkitService; + @Inject + private ProtocolLibService protocolLibService; + @Inject private LimboPlayerTaskManager limboPlayerTaskManager; @@ -126,11 +130,11 @@ public class AsynchronousJoin implements AsynchronousProcess { limboCache.updateLimboPlayer(player); // Protect inventory - if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.getInventoryProtector() != null) { + if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { ProtectInventoryEvent ev = new ProtectInventoryEvent(player); bukkitService.callEvent(ev); if (ev.isCancelled()) { - plugin.getInventoryProtector().sendInventoryPacket(player); + protocolLibService.sendInventoryPacket(player); if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + "..."); } diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index e4ded1de..14a4f8e0 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -10,6 +10,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.LoginEvent; import fr.xephi.authme.events.RestoreInventoryEvent; import fr.xephi.authme.listener.AuthMePlayerListener; +import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SynchronousProcess; @@ -50,6 +51,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { @Inject private BukkitService bukkitService; + @Inject + private ProtocolLibService protocolLibService; + @Inject private PluginManager pluginManager; @@ -106,8 +110,8 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { restoreInventory(player); } - if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.getTablistHider() != null) { - plugin.getTablistHider().sendTablist(player); + if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN)) { + protocolLibService.sendTabList(player); } // Clean up no longer used temporary data diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java index 38514567..6a36ab44 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java @@ -6,6 +6,7 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.events.LogoutEvent; +import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SynchronousProcess; @@ -34,6 +35,9 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { @Inject private BukkitService bukkitService; + @Inject + private ProtocolLibService protocolLibService; + @Inject private LimboPlayerTaskManager limboPlayerTaskManager; @@ -66,7 +70,7 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { sessionManager.cancelSession(name); } if (service.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { - plugin.getInventoryProtector().sendBlankInventoryPacket(player); + protocolLibService.sendBlankInventoryPacket(player); } limboPlayerTaskManager.registerTimeoutTask(player); diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 2ac8d027..524d6b1c 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -8,6 +8,7 @@ import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.events.LoginEvent; import fr.xephi.authme.events.RestoreInventoryEvent; +import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.process.ProcessService; @@ -42,6 +43,9 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { @Inject private BukkitService bukkitService; + @Inject + private ProtocolLibService protocolLibService; + @Inject private LimboCache limboCache; @@ -92,17 +96,17 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { final String name = player.getName().toLowerCase(); LimboPlayer limbo = limboCache.getLimboPlayer(name); if (limbo != null) { - if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.getTablistHider() != null) { - plugin.getTablistHider().sendTablist(player); + if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN)) { + protocolLibService.sendTabList(player); } Utils.teleportToSpawn(player); - if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.getInventoryProtector() != null) { + if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { RestoreInventoryEvent event = new RestoreInventoryEvent(player); bukkitService.callEvent(event); if (!event.isCancelled()) { - plugin.getInventoryProtector().sendInventoryPacket(player); + protocolLibService.sendInventoryPacket(player); } } From 2f341029a6f4817daf0cc5672ef6c9d06eed8a54 Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 28 Jun 2016 11:22:30 +0200 Subject: [PATCH 041/217] Use bukkit's updateInventory method for restoring NBT data --- .../AuthMeInventoryPacketAdapter.java | 45 +------------------ .../process/login/ProcessSyncPlayerLogin.java | 4 +- 2 files changed, 4 insertions(+), 45 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java index a8179b74..980f3ccb 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java @@ -33,7 +33,6 @@ import org.bukkit.inventory.PlayerInventory; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; -import java.util.Collections; import java.util.logging.Level; public class AuthMeInventoryPacketAdapter extends PacketAdapter { @@ -75,49 +74,7 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter { } public void sendInventoryPacket(Player player) { - ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); - PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS); - - // we are sending our own inventory - inventoryPacket.getIntegers().write(0, PLAYER_INVENTORY); - - ItemStack[] playerCrafting = new ItemStack[CRAFTING_SIZE]; - Arrays.fill(playerCrafting, new ItemStack(Material.AIR)); - ItemStack[] armorContents = player.getInventory().getArmorContents(); - ItemStack[] mainInventory = player.getInventory().getContents(); - - // bukkit saves the armor in reversed order - Collections.reverse(Arrays.asList(armorContents)); - - // same main inventory. The hotbar is at the beginning but it should be at the end of the array - ItemStack[] hotbar = Arrays.copyOfRange(mainInventory, 0, HOTBAR_SIZE); - ItemStack[] storedInventory = Arrays.copyOfRange(mainInventory, HOTBAR_SIZE, mainInventory.length); - - // concat all parts of the inventory together - int inventorySize = CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE + HOTBAR_SIZE; - if (offHandSupported) { - inventorySize++; - } - - ItemStack[] completeInventory = new ItemStack[inventorySize]; - - System.arraycopy(playerCrafting, 0, completeInventory, 0, CRAFTING_SIZE); - System.arraycopy(armorContents, 0, completeInventory, CRAFTING_SIZE, ARMOR_SIZE); - - // storedInventory and hotbar - System.arraycopy(storedInventory, 0, completeInventory, CRAFTING_SIZE + ARMOR_SIZE, MAIN_SIZE); - System.arraycopy(hotbar, 0, completeInventory, CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE, HOTBAR_SIZE); - - if (offHandSupported) { - completeInventory[OFF_HAND_POSITION] = player.getInventory().getItemInOffHand(); - } - - inventoryPacket.getItemArrayModifier().write(0, completeInventory); - try { - protocolManager.sendServerPacket(player, inventoryPacket, false); - } catch (InvocationTargetException invocationExc) { - plugin.getLogger().log(Level.WARNING, "Error during inventory recovery", invocationExc); - } + player.updateInventory(); } public void sendBlankInventoryPacket(Player player) { diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 14a4f8e0..783a4ed3 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -2,6 +2,7 @@ package fr.xephi.authme.process.login; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; + import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.limbo.LimboCache; @@ -19,6 +20,7 @@ import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.TeleportationService; + import org.apache.commons.lang.reflect.MethodUtils; import org.bukkit.Bukkit; import org.bukkit.entity.LivingEntity; @@ -75,7 +77,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { RestoreInventoryEvent event = new RestoreInventoryEvent(player); pluginManager.callEvent(event); if (!event.isCancelled()) { - player.updateInventory(); + protocolLibService.sendInventoryPacket(player); } } From 874869cef8012df4cbc8568d685820a54bacd4e1 Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 28 Jun 2016 12:25:46 +0200 Subject: [PATCH 042/217] Fix NPC showing when authenticated (Fixes #791) --- .../listener/protocollib/AuthMeTablistPacketAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java index dd24bdb1..a26bec83 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java @@ -42,8 +42,9 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { @Override public void onPacketSending(PacketEvent packetEvent) { + Player receiver = packetEvent.getPlayer(); if (packetEvent.getPacketType() == PacketType.Play.Server.PLAYER_INFO - && PlayerCache.getInstance().isAuthenticated(packetEvent.getPlayer().getName().toLowerCase())) { + && !PlayerCache.getInstance().isAuthenticated(receiver.getName().toLowerCase())) { //this hides the tablist for the new joining players. Already playing users will see the new player try { PacketContainer packet = packetEvent.getPacket(); From 70b57b389ef4413f78c5cbae69e778e3cdd662c5 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 28 Jun 2016 14:28:37 +0200 Subject: [PATCH 043/217] Cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 3 +-- src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java | 4 ---- .../fr/xephi/authme/listener/AuthMeServerListener.java | 3 --- .../listener/protocollib/AuthMeInventoryPacketAdapter.java | 7 ------- .../permission/handlers/PermissionHandlerException.java | 1 + 5 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 181e0da3..4fc05f9c 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -100,7 +100,6 @@ public class AuthMe extends JavaPlugin { // Plugin instance private static AuthMe plugin; - private NewAPI api; private Management management; private CommandHandler commandHandler; private PermissionsManager permsMan; @@ -300,9 +299,9 @@ public class AuthMe extends JavaPlugin { 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); geoLiteApi = initializer.get(GeoLiteAPI.class); + initializer.get(NewAPI.class); initializer.get(API.class); } diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 2d05d5ce..7d4aa774 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -3,7 +3,6 @@ package fr.xephi.authme.hooks; import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteStreams; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.cache.auth.PlayerAuth; @@ -32,9 +31,6 @@ public class BungeeCordMessage implements PluginMessageListener { @Inject private SessionManager sessionManager; - - @Inject - private AuthMe plugin; @Inject private NewSetting settings; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index a851b5e9..79c1c3be 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -1,6 +1,5 @@ package fr.xephi.authme.listener; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.listener.protocollib.ProtocolLibService; @@ -24,8 +23,6 @@ import javax.inject.Inject; */ public class AuthMeServerListener implements Listener { - @Inject - private AuthMe plugin; @Inject private Messages messages; @Inject diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java index 980f3ccb..64ad7cf3 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java @@ -25,12 +25,9 @@ import com.comphenix.protocol.events.PacketEvent; import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.settings.Settings; -import org.apache.commons.lang.reflect.MethodUtils; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; - import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.logging.Level; @@ -44,10 +41,6 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter { private static final int ARMOR_SIZE = 4; private static final int MAIN_SIZE = 27; private static final int HOTBAR_SIZE = 9; - private static final int OFF_HAND_POSITION = 45; - - private final boolean offHandSupported = MethodUtils - .getAccessibleMethod(PlayerInventory.class, "getItemInOffHand", new Class[]{}) != null; public AuthMeInventoryPacketAdapter(AuthMe plugin) { super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS); diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java index 41b91633..3037c4dd 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java @@ -3,6 +3,7 @@ package fr.xephi.authme.permission.handlers; /** * Exception during the instantiation of a {@link PermissionHandler}. */ +@SuppressWarnings("serial") public class PermissionHandlerException extends Exception { public PermissionHandlerException(String message) { From 469e8d3a48535b9342a35a0df162ecf365eeba7b Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 28 Jun 2016 16:03:04 +0200 Subject: [PATCH 044/217] Refactor sessions a bit to fix #419 --- .../fr/xephi/authme/cache/SessionManager.java | 3 +- .../authme/process/join/AsynchronousJoin.java | 7 ++-- .../authme/process/quit/AsynchronousQuit.java | 34 +++++++++---------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/SessionManager.java b/src/main/java/fr/xephi/authme/cache/SessionManager.java index 0c03dc0f..ff448f3f 100644 --- a/src/main/java/fr/xephi/authme/cache/SessionManager.java +++ b/src/main/java/fr/xephi/authme/cache/SessionManager.java @@ -51,10 +51,9 @@ public class SessionManager implements SettingsDependent { * @param name The name of the player who's session to cancel. */ public void cancelSession(String name) { - BukkitTask task = sessions.get(name); + BukkitTask task = sessions.remove(name); if (task != null) { task.cancel(); - removeSession(name); } } 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 5551b9b8..b242f1c3 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -142,10 +142,9 @@ public class AsynchronousJoin implements AsynchronousProcess { } // Session logic - if (service.getProperty(PluginSettings.SESSIONS_ENABLED) && (playerCache.isAuthenticated(name) || database.isLogged(name))) { - if (sessionManager.hasSession(name)) { - sessionManager.cancelSession(name); - } + if (service.getProperty(PluginSettings.SESSIONS_ENABLED) && (sessionManager.hasSession(name) || database.isLogged(name))) { + sessionManager.cancelSession(name); + PlayerAuth auth = database.getAuth(name); database.setUnlogged(name); playerCache.removePlayer(name); diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index a157287b..d331cf77 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -86,27 +86,29 @@ public class AsynchronousQuit implements AsynchronousProcess { isOp = limbo.isOperator(); limboCache.deleteLimboPlayer(name); } - if (!isKick) { - if (plugin.isEnabled()) { - BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { - @Override - public void run() { - postLogout(name); - } + //always unauthenticate the player - use session only for auto logins on the same ip + playerCache.removePlayer(name); - }, Settings.getSessionTimeout * TICKS_PER_MINUTE); + if (plugin.isEnabled() && Settings.isSessionsEnabled) { + BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { - sessionManager.addSession(name, task); - } else { - //plugin is disabled; we cannot schedule more tasks so run it directly here - postLogout(name); - } + @Override + public void run() { + postLogout(name); + } + + }, Settings.getSessionTimeout * TICKS_PER_MINUTE); + + sessionManager.addSession(name, task); } else { - playerCache.removePlayer(name); - database.setUnlogged(name); + //plugin is disabled; we cannot schedule more tasks so run it directly here + postLogout(name); } + //always update the database when the player quit the game + database.setUnlogged(name); + if (plugin.isEnabled()) { syncProcessManager.processSyncPlayerQuit(player, isOp, needToChange); } @@ -117,8 +119,6 @@ public class AsynchronousQuit implements AsynchronousProcess { } private void postLogout(String name) { - PlayerCache.getInstance().removePlayer(name); - database.setUnlogged(name); sessionManager.removeSession(name); } } From 837bbd69ac6bfb963b88383b9bc406f443bfd113 Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 28 Jun 2016 16:09:32 +0200 Subject: [PATCH 045/217] Remove the debug code as the source for random-logouts is found --- src/main/java/fr/xephi/authme/ConsoleLogger.java | 14 -------------- .../fr/xephi/authme/cache/auth/PlayerCache.java | 4 ---- .../xephi/authme/datasource/CacheDataSource.java | 1 - 3 files changed, 19 deletions(-) diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index 284a7442..130919aa 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -11,7 +11,6 @@ import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.logging.Level; import java.util.logging.Logger; /** @@ -67,19 +66,6 @@ public final class ConsoleLogger { } - public static void debug(String message) { - if (enableDebug) { - //creating and filling an exception is a expensive call - //TODO #419 20160601: ->so it should be removed as soon #419 is fixed - //logger.isLoggable does not work because the plugin logger is always ALL - logger.log(Level.FINE, message + ' ' + Thread.currentThread().getName(), new Exception()); - - if (useLogging) { - writeLog("Debug: " + Thread.currentThread().getName() + ':' + message); - } - } - } - /** * Print an error message. * diff --git a/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java b/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java index 9914ee3f..60040575 100644 --- a/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java +++ b/src/main/java/fr/xephi/authme/cache/auth/PlayerCache.java @@ -1,6 +1,5 @@ package fr.xephi.authme.cache.auth; -import fr.xephi.authme.ConsoleLogger; import java.util.concurrent.ConcurrentHashMap; @@ -34,7 +33,6 @@ public class PlayerCache { * @param auth PlayerAuth */ public void addPlayer(PlayerAuth auth) { - ConsoleLogger.debug("ADDED PLAYER TO CACHE " + auth.getNickname()); cache.put(auth.getNickname().toLowerCase(), auth); } @@ -44,7 +42,6 @@ public class PlayerCache { * @param auth PlayerAuth */ public void updatePlayer(PlayerAuth auth) { - ConsoleLogger.debug("UPDATE PLAYER " + auth.getNickname()); cache.put(auth.getNickname(), auth); } @@ -54,7 +51,6 @@ public class PlayerCache { * @param user String */ public void removePlayer(String user) { - ConsoleLogger.debug("REMOVE PLAYER " + user); cache.remove(user.toLowerCase()); } diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 473633e4..79cc6ae6 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -54,7 +54,6 @@ public class CacheDataSource implements DataSource { return executorService.submit(new Callable>() { @Override public Optional call() { - ConsoleLogger.debug("REFRESH " + key); return load(key); } }); From c383c072ff12d15242a1f60f2d6907af00d3b252 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 28 Jun 2016 16:12:14 +0200 Subject: [PATCH 046/217] Remove my stupid code --- src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 2d05d5ce..c4d54e58 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -64,11 +64,6 @@ public class BungeeCordMessage implements PluginMessageListener { if ("login".equals(act)) { playerCache.updatePlayer(auth); dataSource.setLogged(name); - //START 03062016 sgdc3: should fix #731 but we need to recode this mess - if (sessionManager.hasSession(name)) { - sessionManager.cancelSession(name); - } - //END if (!settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("Player " + auth.getNickname() + " has logged in from one of your server!"); @@ -76,6 +71,7 @@ public class BungeeCordMessage implements PluginMessageListener { } else if ("logout".equals(act)) { playerCache.removePlayer(name); dataSource.setUnlogged(name); + if (!settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("Player " + auth.getNickname() + " has logged out from one of your server!"); } From 451a570c73f002d95adb03b3279620f4adb61fdb Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 28 Jun 2016 16:17:01 +0200 Subject: [PATCH 047/217] Cleanup --- src/main/java/fr/xephi/authme/ConsoleLogger.java | 2 -- src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index 130919aa..b26a8625 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -21,7 +21,6 @@ public final class ConsoleLogger { private static final String NEW_LINE = System.getProperty("line.separator"); private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]"); private static Logger logger; - private static boolean enableDebug = false; private static boolean useLogging = false; private static File logFile; private static FileWriter fileWriter; @@ -39,7 +38,6 @@ public final class ConsoleLogger { public static void setLoggingOptions(NewSetting settings) { ConsoleLogger.useLogging = settings.getProperty(SecuritySettings.USE_LOGGING); - ConsoleLogger.enableDebug = !settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE); if (useLogging) { if (fileWriter == null) { try { diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 53409375..1fda06ba 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -28,9 +28,6 @@ public class BungeeCordMessage implements PluginMessageListener { @Inject private PlayerCache playerCache; - - @Inject - private SessionManager sessionManager; @Inject private NewSetting settings; From 145747505f82d004f8f04347575f7774248876a3 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Tue, 28 Jun 2016 21:36:58 +0700 Subject: [PATCH 048/217] Use JsonCache correctly, couldn't list all changes. --- src/main/java/fr/xephi/authme/AuthMe.java | 7 +- .../xephi/authme/cache/backup/JsonCache.java | 140 ++++++++++++------ .../xephi/authme/cache/backup/PlayerData.java | 26 ---- .../xephi/authme/cache/limbo/LimboCache.java | 25 ++-- .../xephi/authme/cache/limbo/LimboPlayer.java | 16 +- .../AuthMeInventoryPacketAdapter.java | 4 - .../protocollib/ProtocolLibService.java | 13 -- .../authme/permission/AuthGroupHandler.java | 7 +- .../authme/process/SyncProcessManager.java | 4 +- .../authme/process/join/AsynchronousJoin.java | 2 +- .../process/login/AsynchronousLogin.java | 7 +- .../process/login/ProcessSyncPlayerLogin.java | 18 +-- .../process/logout/AsynchronousLogout.java | 2 +- .../authme/process/quit/AsynchronousQuit.java | 16 +- .../quit/ProcessSyncronousPlayerQuit.java | 22 ++- .../register/ProcessSyncPasswordRegister.java | 4 +- .../java/fr/xephi/authme/util/FileUtils.java | 24 ++- 17 files changed, 185 insertions(+), 152 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/cache/backup/PlayerData.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 181e0da3..5ce8ba34 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -580,11 +580,12 @@ public class AuthMe extends JavaPlugin { if (!Settings.noTeleport) { player.teleport(limbo.getLoc()); } - Utils.addNormal(player, limbo.getGroup()); player.setOp(limbo.isOperator()); - limbo.getTimeoutTask().cancel(); - limboCache.deleteLimboPlayer(name); + player.setAllowFlight(limbo.isCanFly()); + player.setWalkSpeed(limbo.getWalkSpeed()); + limbo.clearTasks(); + limboCache.deleteLimboPlayer(player); } PlayerCache.getInstance().removePlayer(name); } diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index d9735491..90cb013d 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -12,8 +12,17 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.limbo.LimboPlayer; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.settings.SpawnLoader; +import fr.xephi.authme.util.BukkitService; +import fr.xephi.authme.util.FileUtils; +import fr.xephi.authme.util.Utils; +import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.lang.reflect.Type; @@ -22,110 +31,145 @@ public class JsonCache { private final Gson gson; private final File cacheDir; + @Inject + private AuthMe plugin; + @Inject + private PermissionsManager permissionsManager; + @Inject + private SpawnLoader spawnLoader; + @Inject + private BukkitService bukkitService; public JsonCache() { - cacheDir = new File(AuthMe.getInstance().getDataFolder(), "cache"); + cacheDir = new File(plugin.getDataFolder(), "cache"); if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { ConsoleLogger.showError("Failed to create cache directory."); } gson = new GsonBuilder() - .registerTypeAdapter(PlayerData.class, new PlayerDataSerializer()) - .registerTypeAdapter(PlayerData.class, new PlayerDataDeserializer()) + .registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer()) + .registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer()) .setPrettyPrinting() .create(); } - public PlayerData readCache(Player player) { - String name = player.getName().toLowerCase(); - File file = new File(cacheDir, name + File.separator + "cache.json"); + public LimboPlayer readCache(Player player) { + String id = Utils.getUUIDorName(player); + File file = new File(cacheDir, id + File.separator + "cache.json"); if (!file.exists()) { return null; } try { String str = Files.toString(file, Charsets.UTF_8); - return gson.fromJson(str, PlayerData.class); + return gson.fromJson(str, LimboPlayer.class); } catch (IOException e) { ConsoleLogger.writeStackTrace(e); return null; } } - public void removeCache(Player player) { + public void writeCache(Player player) { + String id = Utils.getUUIDorName(player); String name = player.getName().toLowerCase(); - File file = new File(cacheDir, name); + Location location = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation(); + String group = permissionsManager.getPrimaryGroup(player); + boolean operator = player.isOp(); + boolean canFly = player.getAllowFlight(); + float walkSpeed = player.getWalkSpeed(); + LimboPlayer limboPlayer = new LimboPlayer(name, location, operator, group, canFly, walkSpeed); + try { + File file = new File(cacheDir, id + File.separator + "cache.json"); + Files.write(gson.toJson(limboPlayer), file, Charsets.UTF_8); + } catch (IOException e) { + ConsoleLogger.logException("Failed to write " + player.getName() + " cache.", e); + } + } + + public void removeCache(Player player) { + String id = Utils.getUUIDorName(player); + File file = new File(cacheDir, id); if (file.exists()) { - purgeDirectory(file); + FileUtils.purgeDirectory(file); if (!file.delete()) { - ConsoleLogger.showError("Failed to remove" + player.getName() + "cache."); + ConsoleLogger.showError("Failed to remove " + player.getName() + " cache."); } } } public boolean doesCacheExist(Player player) { - String name = player.getName().toLowerCase(); - File file = new File(cacheDir, name + File.separator + "cache.json"); + String id = Utils.getUUIDorName(player); + File file = new File(cacheDir, id + File.separator + "cache.json"); return file.exists(); } - private class PlayerDataDeserializer implements JsonDeserializer { + private class LimboPlayerDeserializer implements JsonDeserializer { @Override - public PlayerData deserialize(JsonElement jsonElement, Type type, - JsonDeserializationContext context) { + public LimboPlayer deserialize(JsonElement jsonElement, Type type, + JsonDeserializationContext context) { JsonObject jsonObject = jsonElement.getAsJsonObject(); if (jsonObject == null) { return null; } - String group = null; + + Location loc = null; + String group = ""; boolean operator = false; - boolean fly = false; + boolean canFly = false; + float walkSpeed = 0.2f; JsonElement e; + if ((e = jsonObject.getAsJsonObject("location")) != null) { + JsonObject obj = e.getAsJsonObject(); + World world = bukkitService.getWorld(obj.get("world").getAsString()); + if (world != null) { + double x = obj.get("x").getAsDouble(); + double y = obj.get("y").getAsDouble(); + double z = obj.get("z").getAsDouble(); + float yaw = obj.get("yaw").getAsFloat(); + float pitch = obj.get("pitch").getAsFloat(); + loc = new Location(world, x, y, z, yaw, pitch); + } + } if ((e = jsonObject.get("group")) != null) { group = e.getAsString(); } if ((e = jsonObject.get("operator")) != null) { operator = e.getAsBoolean(); } - if ((e = jsonObject.get("fly")) != null) { - fly = e.getAsBoolean(); + if ((e = jsonObject.get("can-fly")) != null) { + canFly = e.getAsBoolean(); + } + if ((e = jsonObject.get("walk-speed")) != null) { + walkSpeed = e.getAsFloat(); } - return new PlayerData(group, operator, fly); + return new LimboPlayer("", loc, operator, group, canFly, walkSpeed); } } - private class PlayerDataSerializer implements JsonSerializer { + private class LimboPlayerSerializer implements JsonSerializer { @Override - public JsonElement serialize(PlayerData playerData, Type type, + public JsonElement serialize(LimboPlayer limboPlayer, Type type, JsonSerializationContext context) { - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("group", playerData.getGroup()); - jsonObject.addProperty("operator", playerData.getOperator()); - jsonObject.addProperty("fly", playerData.isFlyEnabled()); - return jsonObject; + JsonObject obj = new JsonObject(); + obj.addProperty("group", limboPlayer.getGroup()); + + Location loc = limboPlayer.getLoc(); + JsonObject obj2 = new JsonObject(); + obj2.addProperty("world", loc.getWorld().getName()); + obj2.addProperty("x", loc.getX()); + obj2.addProperty("y", loc.getY()); + obj2.addProperty("z", loc.getZ()); + obj2.addProperty("yaw", loc.getYaw()); + obj2.addProperty("pitch", loc.getPitch()); + obj.add("location", obj2); + + obj.addProperty("operator", limboPlayer.isOperator()); + obj.addProperty("can-fly", limboPlayer.isCanFly()); + obj.addProperty("walk-speed", limboPlayer.getWalkSpeed()); + return obj; } } - /** - * Delete a given directory and all its content. - * - * @param directory The directory to remove - */ - private static void purgeDirectory(File directory) { - if (!directory.isDirectory()) { - return; - } - File[] files = directory.listFiles(); - if (files == null) { - return; - } - for (File target : files) { - if (target.isDirectory()) { - purgeDirectory(target); - } - target.delete(); - } - } } diff --git a/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java b/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java deleted file mode 100644 index a41b8aa9..00000000 --- a/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java +++ /dev/null @@ -1,26 +0,0 @@ -package fr.xephi.authme.cache.backup; - -public class PlayerData { - - private final String group; - private final boolean operator; - private final boolean flyEnabled; - - public PlayerData(String group, boolean operator, boolean flyEnabled) { - this.group = group; - this.operator = operator; - this.flyEnabled = flyEnabled; - } - - public String getGroup() { - return group; - } - - public boolean getOperator() { - return operator; - } - - public boolean isFlyEnabled() { - return flyEnabled; - } -} diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 97670a88..71482c81 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -1,7 +1,6 @@ package fr.xephi.authme.cache.limbo; import fr.xephi.authme.cache.backup.JsonCache; -import fr.xephi.authme.cache.backup.PlayerData; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.settings.SpawnLoader; import org.bukkit.Location; @@ -41,36 +40,40 @@ public class LimboCache { Location location = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation(); boolean operator = player.isOp(); boolean flyEnabled = player.getAllowFlight(); + float walkSpeed = player.getWalkSpeed(); String playerGroup = ""; if (permissionsManager.hasGroupSupport()) { playerGroup = permissionsManager.getPrimaryGroup(player); } if (jsonCache.doesCacheExist(player)) { - PlayerData cache = jsonCache.readCache(player); + LimboPlayer cache = jsonCache.readCache(player); if (cache != null) { + location = cache.getLoc(); playerGroup = cache.getGroup(); - operator = cache.getOperator(); - flyEnabled = cache.isFlyEnabled(); + operator = cache.isOperator(); + flyEnabled = cache.isCanFly(); + walkSpeed = cache.getWalkSpeed(); } + } else { + jsonCache.writeCache(player); } - - cache.put(name, new LimboPlayer(name, location, operator, playerGroup, flyEnabled)); + cache.put(name, new LimboPlayer(name, location, operator, playerGroup, flyEnabled, walkSpeed)); } /** * Method deleteLimboPlayer. * - * @param name String + * @param player Player player to remove. */ - public void deleteLimboPlayer(String name) { - checkNotNull(name); - name = name.toLowerCase(); + public void deleteLimboPlayer(Player player) { + String name = player.getName().toLowerCase(); LimboPlayer cachedPlayer = cache.remove(name); if (cachedPlayer != null) { cachedPlayer.clearTasks(); } + jsonCache.removeCache(player); } /** @@ -104,7 +107,7 @@ public class LimboCache { */ public void updateLimboPlayer(Player player) { checkNotNull(player); - deleteLimboPlayer(player.getName().toLowerCase()); + deleteLimboPlayer(player); addLimboPlayer(player); } diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java index 6029e6da..f8e84e3b 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java @@ -10,20 +10,22 @@ import org.bukkit.scheduler.BukkitTask; public class LimboPlayer { private final String name; - private final boolean fly; + private final boolean canFly; private final boolean operator; private final String group; private final Location loc; + private final float walkSpeed; private BukkitTask timeoutTask = null; private BukkitTask messageTask = null; public LimboPlayer(String name, Location loc, boolean operator, - String group, boolean fly) { + String group, boolean fly, float walkSpeed) { this.name = name; this.loc = loc; this.operator = operator; this.group = group; - this.fly = fly; + this.canFly = fly; + this.walkSpeed = walkSpeed; } /** @@ -62,8 +64,12 @@ public class LimboPlayer { return group; } - public boolean isFly() { - return fly; + public boolean isCanFly() { + return canFly; + } + + public float getWalkSpeed() { + return walkSpeed; } /** diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java index 980f3ccb..05b39377 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java @@ -73,10 +73,6 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter { ProtocolLibrary.getProtocolManager().removePacketListener(this); } - public void sendInventoryPacket(Player player) { - player.updateInventory(); - } - public void sendBlankInventoryPacket(Player player) { ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS); diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java index b1f5573a..8788be9d 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java @@ -98,19 +98,6 @@ public class ProtocolLibService implements SettingsDependent { } } - /** - * Send a packet to the player to give them an inventory. - * - * @param player The player to send the packet to. - */ - public void sendInventoryPacket(Player player) { - if (!isEnabled || inventoryPacketAdapter == null) { - return; - } - - inventoryPacketAdapter.sendInventoryPacket(player); - } - /** * Send a packet to the player to give them a blank inventory. * diff --git a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java index c7557fc2..a33cb7c5 100644 --- a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java +++ b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java @@ -67,14 +67,17 @@ public class AuthGroupHandler { case LOGGED_IN: // Get the limbo player data LimboPlayer limbo = limboCache.getLimboPlayer(player.getName().toLowerCase()); - if (limbo == null) + if (limbo == null) { return false; + } // Get the players group String realGroup = limbo.getGroup(); // Remove the other group types groups, set the real group - permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup, Settings.getUnloggedinGroup)); + permissionsManager.removeGroups(player, + Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup, Settings.getUnloggedinGroup) + ); return permissionsManager.addGroup(player, realGroup); default: return false; diff --git a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java b/src/main/java/fr/xephi/authme/process/SyncProcessManager.java index 221e1e8c..894c3a48 100644 --- a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java +++ b/src/main/java/fr/xephi/authme/process/SyncProcessManager.java @@ -71,11 +71,11 @@ public class SyncProcessManager { }); } - public void processSyncPlayerQuit(final Player player, final boolean isOp, final boolean needToChange) { + public void processSyncPlayerQuit(final Player player) { runTask(new Runnable() { @Override public void run() { - processSyncronousPlayerQuit.processSyncQuit(player, isOp, needToChange); + processSyncronousPlayerQuit.processSyncQuit(player); } }); } diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java index 5551b9b8..139d80bc 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -134,7 +134,7 @@ public class AsynchronousJoin implements AsynchronousProcess { ProtectInventoryEvent ev = new ProtectInventoryEvent(player); bukkitService.callEvent(ev); if (ev.isCancelled()) { - protocolLibService.sendInventoryPacket(player); + player.updateInventory(); if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + "..."); } diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java index 18e7e8e4..8de8c0e8 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -199,12 +199,7 @@ public class AsynchronousLogin implements AsynchronousProcess { // processed in other order. LimboPlayer limboPlayer = limboCache.getLimboPlayer(name); if (limboPlayer != null) { - if (limboPlayer.getTimeoutTask() != null) { - limboPlayer.getTimeoutTask().cancel(); - } - if (limboPlayer.getMessageTask() != null) { - limboPlayer.getMessageTask().cancel(); - } + limboPlayer.clearTasks(); } syncProcessManager.processSyncPlayerLogin(player); } else if (player.isOnline()) { diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 783a4ed3..f1e68cfd 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -2,7 +2,6 @@ package fr.xephi.authme.process.login; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.limbo.LimboCache; @@ -20,7 +19,6 @@ import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.TeleportationService; - import org.apache.commons.lang.reflect.MethodUtils; import org.bukkit.Bukkit; import org.bukkit.entity.LivingEntity; @@ -77,7 +75,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { RestoreInventoryEvent event = new RestoreInventoryEvent(player); pluginManager.callEvent(event); if (!event.isCancelled()) { - protocolLibService.sendInventoryPacket(player); + player.updateInventory(); } } @@ -99,8 +97,13 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { if (limbo != null) { // Restore Op state and Permission Group - restoreOpState(player, limbo); + player.setOp(limbo.isOperator()); + // Restore primary group service.setGroup(player, AuthGroupType.LOGGED_IN); + // Restore can-fly state + player.setAllowFlight(limbo.isCanFly()); + // Restore walk speed + player.setWalkSpeed(limbo.getWalkSpeed()); teleportationService.teleportOnLogin(player, auth, limbo); @@ -117,7 +120,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { } // Clean up no longer used temporary data - limboCache.deleteLimboPlayer(name); + limboCache.deleteLimboPlayer(player); } // We can now display the join message (if delayed) @@ -142,6 +145,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { bukkitService.callEvent(new LoginEvent(player)); player.saveData(); sendBungeeMessage(player); + // Login is done, display welcome message if (service.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { if (service.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) { @@ -161,10 +165,6 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { sendTo(player); } - private void restoreOpState(Player player, LimboPlayer limboPlayer) { - player.setOp(limboPlayer.isOperator()); - } - private void sendTo(Player player) { if(!service.getProperty(HooksSettings.BUNGEECORD)) { return; diff --git a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java index fc81017d..4924b480 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java @@ -60,7 +60,7 @@ public class AsynchronousLogout implements AsynchronousProcess { } }); if (limboCache.hasLimboPlayer(name)) { - limboCache.deleteLimboPlayer(name); + limboCache.deleteLimboPlayer(player); } limboCache.addLimboPlayer(player); service.setGroup(player, AuthGroupType.NOT_LOGGED_IN); diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index a157287b..459452d8 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -5,7 +5,6 @@ import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; -import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.datasource.CacheDataSource; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.process.AsynchronousProcess; @@ -13,7 +12,6 @@ import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SyncProcessManager; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -74,18 +72,6 @@ public class AsynchronousQuit implements AsynchronousProcess { database.updateSession(auth); } - boolean needToChange = false; - boolean isOp = false; - - LimboPlayer limbo = limboCache.getLimboPlayer(name); - if (limbo != null) { - if (!StringUtils.isEmpty(limbo.getGroup())) { - Utils.addNormal(player, limbo.getGroup()); - } - needToChange = true; - isOp = limbo.isOperator(); - limboCache.deleteLimboPlayer(name); - } if (!isKick) { if (plugin.isEnabled()) { BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { @@ -108,7 +94,7 @@ public class AsynchronousQuit implements AsynchronousProcess { } if (plugin.isEnabled()) { - syncProcessManager.processSyncPlayerQuit(player, isOp, needToChange); + syncProcessManager.processSyncPlayerQuit(player); } // remove player from cache if (database instanceof CacheDataSource) { diff --git a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java index c1382c2c..8ed3edbf 100644 --- a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java @@ -1,14 +1,30 @@ package fr.xephi.authme.process.quit; +import fr.xephi.authme.cache.limbo.LimboCache; +import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.process.SynchronousProcess; +import fr.xephi.authme.util.StringUtils; +import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; +import javax.inject.Inject; + public class ProcessSyncronousPlayerQuit implements SynchronousProcess { - public void processSyncQuit(Player player, boolean isOp, boolean needToChange) { - if (needToChange) { - player.setOp(isOp); + @Inject + private LimboCache limboCache; + + public void processSyncQuit(Player player) { + LimboPlayer limbo = limboCache.getLimboPlayer(player.getName().toLowerCase()); + if (limbo != null) { + if (!StringUtils.isEmpty(limbo.getGroup())) { + Utils.addNormal(player, limbo.getGroup()); + } + player.setOp(limbo.isOperator()); + player.setAllowFlight(limbo.isCanFly()); + player.setWalkSpeed(limbo.getWalkSpeed()); + limboCache.deleteLimboPlayer(player); } player.leaveVehicle(); } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 524d6b1c..9e20d49b 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -106,11 +106,11 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { RestoreInventoryEvent event = new RestoreInventoryEvent(player); bukkitService.callEvent(event); if (!event.isCancelled()) { - protocolLibService.sendInventoryPacket(player); + player.updateInventory(); } } - limboCache.deleteLimboPlayer(name); + limboCache.deleteLimboPlayer(player); } if (!Settings.getRegisteredGroup.isEmpty()) { diff --git a/src/main/java/fr/xephi/authme/util/FileUtils.java b/src/main/java/fr/xephi/authme/util/FileUtils.java index d34c41f8..bd9c7fb9 100644 --- a/src/main/java/fr/xephi/authme/util/FileUtils.java +++ b/src/main/java/fr/xephi/authme/util/FileUtils.java @@ -22,7 +22,8 @@ public class FileUtils { * Copy a resource file (from the JAR) to the given file if it doesn't exist. * * @param destinationFile The file to check and copy to (outside of JAR) - * @param resourcePath Absolute path to the resource file (path to file within JAR) + * @param resourcePath Absolute path to the resource file (path to file within JAR) + * * @return False if the file does not exist and could not be copied, true otherwise */ public static boolean copyFileFromResource(File destinationFile, String resourcePath) { @@ -49,4 +50,25 @@ public class FileUtils { } return false; } + + /** + * Delete a given directory and all its content. + * + * @param directory The directory to remove + */ + public static void purgeDirectory(File directory) { + if (!directory.isDirectory()) { + return; + } + File[] files = directory.listFiles(); + if (files == null) { + return; + } + for (File target : files) { + if (target.isDirectory()) { + purgeDirectory(target); + } + target.delete(); + } + } } From ffa92def12192fe36bed823ffce23498db2357e2 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 28 Jun 2016 16:47:58 +0200 Subject: [PATCH 049/217] Create ISSUE_TEMPLATE.MD #801 --- .github/ISSUE_TEMPLATE.MD | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.MD diff --git a/.github/ISSUE_TEMPLATE.MD b/.github/ISSUE_TEMPLATE.MD new file mode 100644 index 00000000..0527d7ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE.MD @@ -0,0 +1,25 @@ +####Before reporting an issue make sure you are running the latest build of the plugin! + +### What behaviour is observed: +What happened? + +### What behaviour is expected: +What did you expect? + +### Steps/models to reproduce: +The actions that cause the issue + +### Plugin list: +This can be found by running `/pl` + +### Environment description +Standalone server/Bungeecord network, SQLite/MYSql, ... + +### AuthMe build number: +This can be found by running `/authme version` + +### Error Log: +Pastebin/Hastebin/Gist link of the error logo or stacktrace (if any) + +### COnfiguration: +Pastebin/Hastebin/Gist link of your config.yml file (remember to delete any sesible data) From 45d8e24350a8d4ec91d68185815687679075cc92 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 00:34:31 +0700 Subject: [PATCH 050/217] - Fix fly speed not get restored after login. - Attempt to fix #592 --- src/main/java/fr/xephi/authme/AuthMe.java | 50 ++++++++++++------- .../xephi/authme/cache/limbo/LimboCache.java | 5 +- .../process/login/ProcessSyncPlayerLogin.java | 19 +++---- .../process/logout/AsynchronousLogout.java | 7 +-- .../ProcessSynchronousPlayerLogout.java | 19 +++---- 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 5ce8ba34..1224aba4 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -293,16 +293,16 @@ public class AuthMe extends JavaPlugin { // Some statically injected things initializer.register(PlayerCache.class, PlayerCache.getInstance()); - messages = initializer.get(Messages.class); - permsMan = initializer.get(PermissionsManager.class); - bukkitService = initializer.get(BukkitService.class); - pluginHooks = initializer.get(PluginHooks.class); + messages = initializer.get(Messages.class); + 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); - geoLiteApi = initializer.get(GeoLiteAPI.class); + spawnLoader = initializer.get(SpawnLoader.class); + commandHandler = initializer.get(CommandHandler.class); + api = initializer.get(NewAPI.class); + management = initializer.get(Management.class); + geoLiteApi = initializer.get(GeoLiteAPI.class); initializer.get(API.class); } @@ -341,7 +341,7 @@ public class AuthMe extends JavaPlugin { // Register event listeners pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this); - pluginManager.registerEvents(initializer.get(AuthMeBlockListener.class), this); + pluginManager.registerEvents(initializer.get(AuthMeBlockListener.class), this); pluginManager.registerEvents(initializer.get(AuthMeEntityListener.class), this); pluginManager.registerEvents(initializer.get(AuthMeServerListener.class), this); @@ -568,16 +568,9 @@ public class AuthMe extends JavaPlugin { return; } String name = player.getName().toLowerCase(); - if (PlayerCache.getInstance().isAuthenticated(name) && !player.isDead() && Settings.isSaveQuitLocationEnabled) { - final PlayerAuth auth = PlayerAuth.builder() - .name(player.getName().toLowerCase()) - .realName(player.getName()) - .location(player.getLocation()).build(); - database.updateQuitLoc(auth); - } if (limboCache.hasLimboPlayer(name)) { LimboPlayer limbo = limboCache.getLimboPlayer(name); - if (!Settings.noTeleport) { + if (!newSettings.getProperty(RestrictionSettings.NO_TELEPORT)) { player.teleport(limbo.getLoc()); } Utils.addNormal(player, limbo.getGroup()); @@ -587,6 +580,21 @@ public class AuthMe extends JavaPlugin { limbo.clearTasks(); limboCache.deleteLimboPlayer(player); } + if (PlayerCache.getInstance().isAuthenticated(name) && !player.isDead()) { + if (Settings.isSaveQuitLocationEnabled) { + + final PlayerAuth auth = PlayerAuth.builder() + .name(player.getName().toLowerCase()) + .realName(player.getName()) + .location(player.getLocation()).build(); + database.updateQuitLoc(auth); + } + if (newSettings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN) + && !newSettings.getProperty(RestrictionSettings.NO_TELEPORT)) { + limboCache.getJsonCache().writeCache(player); + player.teleport(spawnLoader.getSpawnLocation(player)); + } + } PlayerCache.getInstance().removePlayer(name); } @@ -638,7 +646,6 @@ public class AuthMe extends JavaPlugin { } - /** * Handle Bukkit commands. * @@ -678,6 +685,7 @@ public class AuthMe extends JavaPlugin { /** * @return permission manager + * * @deprecated should be used in API classes only (temporarily) */ @Deprecated @@ -687,6 +695,7 @@ public class AuthMe extends JavaPlugin { /** * @return process manager + * * @deprecated should be used in API classes only (temporarily) */ @Deprecated @@ -696,6 +705,7 @@ public class AuthMe extends JavaPlugin { /** * @return the datasource + * * @deprecated should be used in API classes only (temporarily) */ @Deprecated @@ -705,6 +715,7 @@ public class AuthMe extends JavaPlugin { /** * @return password manager + * * @deprecated should be used in API classes only (temporarily) */ @Deprecated @@ -714,6 +725,7 @@ public class AuthMe extends JavaPlugin { /** * @return plugin hooks + * * @deprecated should be used in API classes only (temporarily) */ @Deprecated diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 71482c81..2bc39ded 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -30,6 +30,10 @@ public class LimboCache { this.spawnLoader = spawnLoader; } + public JsonCache getJsonCache() { + return jsonCache; + } + /** * Add a limbo player. * @@ -110,5 +114,4 @@ public class LimboCache { deleteLimboPlayer(player); addLimboPlayer(player); } - } diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index f1e68cfd..7f6e598c 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -62,15 +62,6 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { ProcessSyncPlayerLogin() { } - - private void restoreSpeedEffects(Player player) { - if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) - && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { - player.setWalkSpeed(0.2F); - player.setFlySpeed(0.1F); - } - } - private void restoreInventory(Player player) { RestoreInventoryEvent event = new RestoreInventoryEvent(player); pluginManager.callEvent(event); @@ -102,8 +93,13 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { service.setGroup(player, AuthGroupType.LOGGED_IN); // Restore can-fly state player.setAllowFlight(limbo.isCanFly()); - // Restore walk speed - player.setWalkSpeed(limbo.getWalkSpeed()); + + // Restore speed + if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) + && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { + player.setWalkSpeed(limbo.getWalkSpeed()); + player.setFlySpeed(0.2F); + } teleportationService.teleportOnLogin(player, auth, limbo); @@ -136,7 +132,6 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { AuthMePlayerListener.joinMessage.remove(name); } - restoreSpeedEffects(player); if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { player.removePotionEffect(PotionEffectType.BLINDNESS); } diff --git a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java index 4924b480..25842af0 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java @@ -5,7 +5,6 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.process.AsynchronousProcess; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SyncProcessManager; @@ -59,11 +58,7 @@ public class AsynchronousLogout implements AsynchronousProcess { Utils.teleportToSpawn(player); } }); - if (limboCache.hasLimboPlayer(name)) { - limboCache.deleteLimboPlayer(player); - } - limboCache.addLimboPlayer(player); - service.setGroup(player, AuthGroupType.NOT_LOGGED_IN); + limboCache.updateLimboPlayer(player); syncProcessManager.processSyncPlayerLogout(player); } } diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java index 6a36ab44..c8336262 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java @@ -8,6 +8,7 @@ import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.events.LogoutEvent; import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SynchronousProcess; import fr.xephi.authme.settings.properties.HooksSettings; @@ -56,14 +57,6 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); } - private void restoreSpeedEffect(Player player) { - if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) - && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { - player.setFlySpeed(0.0f); - player.setWalkSpeed(0.0f); - } - } - public void processSyncLogout(Player player) { final String name = player.getName().toLowerCase(); if (sessionManager.hasSession(name)) { @@ -83,8 +76,16 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2)); } + + service.setGroup(player, AuthGroupType.NOT_LOGGED_IN); player.setOp(false); - restoreSpeedEffect(player); + // Remove speed + if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) + && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { + player.setFlySpeed(0.0f); + player.setWalkSpeed(0.0f); + } + // Player is now logout... Time to fire event ! bukkitService.callEvent(new LogoutEvent(player)); if (service.getProperty(HooksSettings.BUNGEECORD)) { From 348e796752904d88267bc4b7c4a799516c43e2dd Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 28 Jun 2016 20:47:13 +0200 Subject: [PATCH 051/217] Switch to the new properties settings --- .../java/fr/xephi/authme/process/quit/AsynchronousQuit.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index d331cf77..c1aac0c6 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -11,7 +11,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.process.AsynchronousProcess; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SyncProcessManager; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; @@ -90,7 +90,7 @@ public class AsynchronousQuit implements AsynchronousProcess { //always unauthenticate the player - use session only for auto logins on the same ip playerCache.removePlayer(name); - if (plugin.isEnabled() && Settings.isSessionsEnabled) { + if (plugin.isEnabled() && service.getProperty(PluginSettings.SESSIONS_ENABLED)) { BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { @Override @@ -98,7 +98,7 @@ public class AsynchronousQuit implements AsynchronousProcess { postLogout(name); } - }, Settings.getSessionTimeout * TICKS_PER_MINUTE); + }, service.getProperty(PluginSettings.SESSIONS_TIMEOUT) * TICKS_PER_MINUTE); sessionManager.addSession(name, task); } else { From 6b13f9d370453f35d1b81e486530e894431d6055 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 28 Jun 2016 22:14:30 +0200 Subject: [PATCH 052/217] Fix plugin version in plugin.yml --- src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index cb915889..6491849b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -3,7 +3,7 @@ authors: [${bukkitplugin.authors}] website: ${project.url} description: ${project.description} main: ${bukkitplugin.main} -version: ${bukkitplugin.versionCode} +version: ${bukkitplugin.version} softdepend: - Vault - PermissionsBukkit From ad068ffba0fd0cf229f6670c0da769e4490ea393 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 04:49:10 +0700 Subject: [PATCH 053/217] - Make JsonCache injectable - Only inject needed field --- src/main/java/fr/xephi/authme/AuthMe.java | 8 ++++++-- .../java/fr/xephi/authme/cache/backup/JsonCache.java | 9 ++++----- .../java/fr/xephi/authme/cache/limbo/LimboCache.java | 9 ++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 1224aba4..ddd0df7e 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -5,6 +5,7 @@ import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.command.CommandHandler; @@ -591,8 +592,11 @@ public class AuthMe extends JavaPlugin { } if (newSettings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN) && !newSettings.getProperty(RestrictionSettings.NO_TELEPORT)) { - limboCache.getJsonCache().writeCache(player); - player.teleport(spawnLoader.getSpawnLocation(player)); + JsonCache jsonCache = initializer.getIfAvailable(JsonCache.class); + if (jsonCache != null) { + jsonCache.writeCache(player); + player.teleport(spawnLoader.getSpawnLocation(player)); + } } } PlayerCache.getInstance().removePlayer(name); diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 90cb013d..6f56e2c4 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -10,9 +10,9 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.limbo.LimboPlayer; +import fr.xephi.authme.initialization.DataFolder; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.util.BukkitService; @@ -32,16 +32,15 @@ public class JsonCache { private final Gson gson; private final File cacheDir; @Inject - private AuthMe plugin; - @Inject private PermissionsManager permissionsManager; @Inject private SpawnLoader spawnLoader; @Inject private BukkitService bukkitService; - public JsonCache() { - cacheDir = new File(plugin.getDataFolder(), "cache"); + @Inject + public JsonCache(@DataFolder File dataFolder) { + cacheDir = new File(dataFolder, "cache"); if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { ConsoleLogger.showError("Failed to create cache directory."); } diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 2bc39ded..2bd4c669 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -17,10 +17,13 @@ import static com.google.common.base.Preconditions.checkNotNull; public class LimboCache { private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); - private final JsonCache jsonCache = new JsonCache(); + + @Inject + private JsonCache jsonCache; @Inject private PermissionsManager permissionsManager; + @Inject private SpawnLoader spawnLoader; @@ -30,10 +33,6 @@ public class LimboCache { this.spawnLoader = spawnLoader; } - public JsonCache getJsonCache() { - return jsonCache; - } - /** * Add a limbo player. * From 392b8ac19e8349d123cb1a907c449921531b15e0 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 05:17:56 +0700 Subject: [PATCH 054/217] Sync with master. --- .../xephi/authme/process/quit/AsynchronousQuit.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index 57e6552e..cad276a0 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -44,7 +44,8 @@ public class AsynchronousQuit implements AsynchronousProcess { @Inject private SessionManager sessionManager; - AsynchronousQuit() { } + AsynchronousQuit() { + } public void processQuit(Player player, boolean isKick) { @@ -72,9 +73,11 @@ public class AsynchronousQuit implements AsynchronousProcess { database.updateSession(auth); } - if (!isKick) { - if (plugin.isEnabled()) { - BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { + //always unauthenticate the player - use session only for auto logins on the same ip + playerCache.removePlayer(name); + + if (plugin.isEnabled() && service.getProperty(PluginSettings.SESSIONS_ENABLED)) { + BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { @Override public void run() { From b455e20811de71916bc4562f41e77f334c87c36e Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 06:06:54 +0700 Subject: [PATCH 055/217] - Fix NPE in JsonCache. --- src/main/java/fr/xephi/authme/cache/backup/JsonCache.java | 7 ++++++- src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 6f56e2c4..6de1ec9c 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -39,7 +39,12 @@ public class JsonCache { private BukkitService bukkitService; @Inject - public JsonCache(@DataFolder File dataFolder) { + public JsonCache(@DataFolder File dataFolder, PermissionsManager permsMan, + SpawnLoader spawnLoader, BukkitService bukkitService) { + this.permissionsManager = permsMan; + this.spawnLoader = spawnLoader; + this.bukkitService = bukkitService; + cacheDir = new File(dataFolder, "cache"); if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { ConsoleLogger.showError("Failed to create cache directory."); diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 2bd4c669..902270d2 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -28,9 +28,10 @@ public class LimboCache { private SpawnLoader spawnLoader; @Inject - LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader) { + LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader, JsonCache jsonCache) { this.permissionsManager = permissionsManager; this.spawnLoader = spawnLoader; + this.jsonCache = jsonCache; } /** From 609b14815732950e74cd0eecaae656d98561d2c6 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 06:19:49 +0700 Subject: [PATCH 056/217] Touch the file, it works fine now. --- src/main/java/fr/xephi/authme/cache/backup/JsonCache.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 6de1ec9c..57bf7051 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -83,6 +83,8 @@ public class JsonCache { LimboPlayer limboPlayer = new LimboPlayer(name, location, operator, group, canFly, walkSpeed); try { File file = new File(cacheDir, id + File.separator + "cache.json"); + Files.createParentDirs(file); + Files.touch(file); Files.write(gson.toJson(limboPlayer), file, Charsets.UTF_8); } catch (IOException e) { ConsoleLogger.logException("Failed to write " + player.getName() + " cache.", e); From 22a4ef93bf2d21369ea9b4ec28d027e4206c34bc Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 20:25:01 +0700 Subject: [PATCH 057/217] - Remove unnecessary @Inject on field. - Teleport player to spawn immediately on PlayerLoginEvent. - Only save authenticated player's location on quit. - Fix player's last location get reset if fail to login. --- src/main/java/fr/xephi/authme/AuthMe.java | 36 ++++++++-------- .../xephi/authme/cache/backup/JsonCache.java | 10 ++--- .../xephi/authme/cache/limbo/LimboCache.java | 20 +++++---- .../authme/listener/AuthMePlayerListener.java | 4 ++ .../authme/process/join/AsynchronousJoin.java | 28 +++++-------- .../authme/process/quit/AsynchronousQuit.java | 11 +++-- .../quit/ProcessSyncronousPlayerQuit.java | 41 +++++++++++++++---- 7 files changed, 88 insertions(+), 62 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 64595834..ca5df4fa 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -293,15 +293,15 @@ public class AuthMe extends JavaPlugin { // Some statically injected things initializer.register(PlayerCache.class, PlayerCache.getInstance()); - messages = initializer.get(Messages.class); - permsMan = initializer.get(PermissionsManager.class); - bukkitService = initializer.get(BukkitService.class); - pluginHooks = initializer.get(PluginHooks.class); + messages = initializer.get(Messages.class); + 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); - management = initializer.get(Management.class); - geoLiteApi = initializer.get(GeoLiteAPI.class); + spawnLoader = initializer.get(SpawnLoader.class); + commandHandler = initializer.get(CommandHandler.class); + management = initializer.get(Management.class); + geoLiteApi = initializer.get(GeoLiteAPI.class); initializer.get(NewAPI.class); initializer.get(API.class); } @@ -577,24 +577,26 @@ public class AuthMe extends JavaPlugin { player.setOp(limbo.isOperator()); player.setAllowFlight(limbo.isCanFly()); player.setWalkSpeed(limbo.getWalkSpeed()); - limbo.clearTasks(); - limboCache.deleteLimboPlayer(player); - } - if (PlayerCache.getInstance().isAuthenticated(name) && !player.isDead()) { - if (Settings.isSaveQuitLocationEnabled) { - + if (newSettings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)) { + limboCache.removeLimboPlayer(player); + } else { + limboCache.deleteLimboPlayer(player); + } + } else { + if (newSettings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { + Location loc = + player.isOnline() && player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation(); final PlayerAuth auth = PlayerAuth.builder() .name(player.getName().toLowerCase()) .realName(player.getName()) - .location(player.getLocation()).build(); + .location(loc).build(); database.updateQuitLoc(auth); } if (newSettings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN) && !newSettings.getProperty(RestrictionSettings.NO_TELEPORT)) { JsonCache jsonCache = initializer.getIfAvailable(JsonCache.class); - if (jsonCache != null) { + if (jsonCache != null && !jsonCache.doesCacheExist(player)) { jsonCache.writeCache(player); - player.teleport(spawnLoader.getSpawnLocation(player)); } } } diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index 57bf7051..39b2d48f 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -31,16 +31,13 @@ public class JsonCache { private final Gson gson; private final File cacheDir; - @Inject private PermissionsManager permissionsManager; - @Inject private SpawnLoader spawnLoader; - @Inject private BukkitService bukkitService; @Inject - public JsonCache(@DataFolder File dataFolder, PermissionsManager permsMan, - SpawnLoader spawnLoader, BukkitService bukkitService) { + JsonCache(@DataFolder File dataFolder, PermissionsManager permsMan, + SpawnLoader spawnLoader, BukkitService bukkitService) { this.permissionsManager = permsMan; this.spawnLoader = spawnLoader; this.bukkitService = bukkitService; @@ -75,7 +72,8 @@ public class JsonCache { public void writeCache(Player player) { String id = Utils.getUUIDorName(player); String name = player.getName().toLowerCase(); - Location location = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation(); + Location location = + player.isOnline() && player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation(); String group = permissionsManager.getPrimaryGroup(player); boolean operator = player.isOp(); boolean canFly = player.getAllowFlight(); diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java index 902270d2..7553630e 100644 --- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java +++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java @@ -18,13 +18,8 @@ public class LimboCache { private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); - @Inject private JsonCache jsonCache; - - @Inject private PermissionsManager permissionsManager; - - @Inject private SpawnLoader spawnLoader; @Inject @@ -67,17 +62,26 @@ public class LimboCache { } /** - * Method deleteLimboPlayer. + * Remove LimboPlayer and delete cache.json from disk. * * @param player Player player to remove. */ public void deleteLimboPlayer(Player player) { + removeLimboPlayer(player); + jsonCache.removeCache(player); + } + + /** + * Remove LimboPlayer from cache, without deleting cache.json file. + * + * @param player Player player to remove. + */ + public void removeLimboPlayer(Player player) { String name = player.getName().toLowerCase(); LimboPlayer cachedPlayer = cache.remove(name); if (cachedPlayer != null) { cachedPlayer.clearTasks(); } - jsonCache.removeCache(player); } /** @@ -111,7 +115,7 @@ public class LimboCache { */ public void updateLimboPlayer(Player player) { checkNotNull(player); - deleteLimboPlayer(player); + removeLimboPlayer(player); addLimboPlayer(player); } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index fba9e6fc..5320a72a 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -12,6 +12,7 @@ import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.BukkitService; +import fr.xephi.authme.util.TeleportationService; import fr.xephi.authme.util.Utils; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -72,6 +73,8 @@ public class AuthMePlayerListener implements Listener { private OnJoinVerifier onJoinVerifier; @Inject private ListenerService listenerService; + @Inject + private TeleportationService teleportationService; @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { @@ -229,6 +232,7 @@ public class AuthMePlayerListener implements Listener { } antiBot.handlePlayerJoin(player); + teleportationService.teleportOnJoin(player); } @EventHandler(priority = EventPriority.HIGHEST) 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 0e3540db..f63973e3 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -22,7 +22,6 @@ import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.task.LimboPlayerTaskManager; import fr.xephi.authme.util.BukkitService; -import fr.xephi.authme.util.TeleportationService; import fr.xephi.authme.util.Utils; import org.apache.commons.lang.reflect.MethodUtils; import org.bukkit.GameMode; @@ -63,9 +62,6 @@ public class AsynchronousJoin implements AsynchronousProcess { @Inject private PluginHooks pluginHooks; - @Inject - private TeleportationService teleportationService; - @Inject private BukkitService bukkitService; @@ -75,7 +71,8 @@ public class AsynchronousJoin implements AsynchronousProcess { @Inject private LimboPlayerTaskManager limboPlayerTaskManager; - AsynchronousJoin() { } + AsynchronousJoin() { + } public void processJoin(final Player player) { @@ -122,12 +119,12 @@ public class AsynchronousJoin implements AsynchronousProcess { return; } + limboCache.updateLimboPlayer(player); + final boolean isAuthAvailable = database.isAuthAvailable(name); if (isAuthAvailable) { service.setGroup(player, AuthGroupType.NOT_LOGGED_IN); - teleportationService.teleportOnJoin(player); - limboCache.updateLimboPlayer(player); // Protect inventory if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { @@ -166,13 +163,6 @@ public class AsynchronousJoin implements AsynchronousProcess { if (!service.getProperty(RegistrationSettings.FORCE)) { return; } - - teleportationService.teleportOnJoin(player); - } - // The user is not logged in - - if (!limboCache.hasLimboPlayer(name)) { - limboCache.addLimboPlayer(player); } final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; @@ -211,11 +201,12 @@ public class AsynchronousJoin implements AsynchronousProcess { /** * Returns whether the name is restricted based on the restriction settings. * - * @param name The name to check - * @param ip The IP address of the player + * @param name The name to check + * @param ip The IP address of the player * @param domain The hostname of the IP address + * * @return True if the name is restricted (IP/domain is not allowed for the given name), - * false if the restrictions are met or if the name has no restrictions to it + * false if the restrictions are met or if the name has no restrictions to it */ private boolean isNameRestricted(String name, String ip, String domain) { if (!service.getProperty(RestrictionSettings.ENABLE_RESTRICTED_USERS)) { @@ -242,7 +233,8 @@ public class AsynchronousJoin implements AsynchronousProcess { * settings and permissions). If this is the case, the player is kicked. * * @param player the player to verify - * @param ip the ip address of the player + * @param ip the ip address of the player + * * @return true if the verification is OK (no infraction), false if player has been kicked */ private boolean validatePlayerCountForIp(final Player player, String ip) { diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index cad276a0..726fc1a2 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -4,12 +4,12 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.datasource.CacheDataSource; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.process.AsynchronousProcess; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SyncProcessManager; +import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.Utils; @@ -35,15 +35,15 @@ public class AsynchronousQuit implements AsynchronousProcess { @Inject private PlayerCache playerCache; - @Inject - private LimboCache limboCache; - @Inject private SyncProcessManager syncProcessManager; @Inject private SessionManager sessionManager; + @Inject + private SpawnLoader spawnLoader; + AsynchronousQuit() { } @@ -55,10 +55,9 @@ public class AsynchronousQuit implements AsynchronousProcess { final String name = player.getName().toLowerCase(); String ip = Utils.getPlayerIp(player); - if (playerCache.isAuthenticated(name)) { if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { - Location loc = player.getLocation(); + Location loc = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation(); PlayerAuth auth = PlayerAuth.builder() .name(name).location(loc) .realName(player.getName()).build(); diff --git a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java index 8ed3edbf..2ed9bb1f 100644 --- a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java @@ -1,8 +1,12 @@ package fr.xephi.authme.process.quit; +import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SynchronousProcess; +import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; @@ -12,20 +16,43 @@ import javax.inject.Inject; public class ProcessSyncronousPlayerQuit implements SynchronousProcess { + @Inject + private JsonCache jsonCache; + + @Inject + private DataSource database; + + @Inject + private ProcessService service; + @Inject private LimboCache limboCache; public void processSyncQuit(Player player) { LimboPlayer limbo = limboCache.getLimboPlayer(player.getName().toLowerCase()); - if (limbo != null) { - if (!StringUtils.isEmpty(limbo.getGroup())) { - Utils.addNormal(player, limbo.getGroup()); + if (limbo != null) { // it mean player is not authenticated + // Only delete if we don't need player's last location + if (service.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)) { + limboCache.removeLimboPlayer(player); + } else { + // Restore data if its about to delete LimboPlayer + if (!StringUtils.isEmpty(limbo.getGroup())) { + Utils.addNormal(player, limbo.getGroup()); + } + player.setOp(limbo.isOperator()); + player.setAllowFlight(limbo.isCanFly()); + player.setWalkSpeed(limbo.getWalkSpeed()); + limboCache.deleteLimboPlayer(player); + } + } else { + // Write player's location, so we could retrieve it later on player next join + if (service.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)) { + if (!jsonCache.doesCacheExist(player)) { + jsonCache.writeCache(player); + } } - player.setOp(limbo.isOperator()); - player.setAllowFlight(limbo.isCanFly()); - player.setWalkSpeed(limbo.getWalkSpeed()); - limboCache.deleteLimboPlayer(player); } + player.leaveVehicle(); } } From b1b56f2d515f76a2e528a7ba06b7e614812873b4 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 29 Jun 2016 15:56:55 +0200 Subject: [PATCH 058/217] Cleanup, updated some settings --- .../protocollib/AuthMeInventoryPacketAdapter.java | 4 +--- .../fr/xephi/authme/process/join/AsynchronousJoin.java | 3 --- .../authme/process/quit/ProcessSyncronousPlayerQuit.java | 3 --- src/main/java/fr/xephi/authme/settings/Settings.java | 8 -------- src/test/java/fr/xephi/authme/task/PurgeServiceTest.java | 1 + 5 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java index 50c6cdfb..88d83f61 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java @@ -24,7 +24,6 @@ import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.settings.Settings; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -52,8 +51,7 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter { PacketContainer packet = packetEvent.getPacket(); byte windowId = packet.getIntegers().read(0).byteValue(); - if (windowId == PLAYER_INVENTORY && Settings.protectInventoryBeforeLogInEnabled - && !PlayerCache.getInstance().isAuthenticated(player.getName())) { + if (windowId == PLAYER_INVENTORY && !PlayerCache.getInstance().isAuthenticated(player.getName())) { packetEvent.setCancelled(true); } } 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 f63973e3..7c83ec28 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -65,9 +65,6 @@ public class AsynchronousJoin implements AsynchronousProcess { @Inject private BukkitService bukkitService; - @Inject - private ProtocolLibService protocolLibService; - @Inject private LimboPlayerTaskManager limboPlayerTaskManager; diff --git a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java index 2ed9bb1f..13a6a7b3 100644 --- a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java @@ -19,9 +19,6 @@ public class ProcessSyncronousPlayerQuit implements SynchronousProcess { @Inject private JsonCache jsonCache; - @Inject - private DataSource database; - @Inject private ProcessService service; diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 6e843001..7c128d99 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -18,10 +18,7 @@ public final class Settings { public static List getUnrestrictedName; public static boolean isPermissionCheckEnabled; public static boolean isTeleportToSpawnEnabled; - public static boolean isSessionsEnabled; public static boolean isAllowRestrictedIp; - public static boolean isSaveQuitLocationEnabled; - public static boolean protectInventoryBeforeLogInEnabled; public static boolean isStopEnabled; public static boolean reloadSupport; public static boolean noTeleport; @@ -31,7 +28,6 @@ public final class Settings { public static String getRegisteredGroup; public static String defaultWorld; public static String crazyloginFileName; - public static int getSessionTimeout; public static int getNonActivatedGroup; private static FileConfiguration configFile; @@ -48,17 +44,13 @@ public final class Settings { private static void loadVariables() { isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK); isTeleportToSpawnEnabled = load(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN); - isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED); - getSessionTimeout = configFile.getInt("settings.sessions.timeout", 10); isAllowRestrictedIp = load(RestrictionSettings.ENABLE_RESTRICTED_USERS); isRemoveSpeedEnabled = load(RestrictionSettings.REMOVE_SPEED); - isSaveQuitLocationEnabled = load(RestrictionSettings.SAVE_QUIT_LOCATION); getUnloggedinGroup = load(SecuritySettings.UNLOGGEDIN_GROUP); getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1); unRegisteredGroup = configFile.getString("GroupOptions.UnregisteredPlayerGroup", ""); getUnrestrictedName = load(RestrictionSettings.UNRESTRICTED_NAMES); getRegisteredGroup = configFile.getString("GroupOptions.RegisteredPlayerGroup", ""); - protectInventoryBeforeLogInEnabled = load(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN); isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true); reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); defaultWorld = configFile.getString("Purge.defaultWorld", "world"); diff --git a/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java index 3eb4bac4..a631476e 100644 --- a/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java +++ b/src/test/java/fr/xephi/authme/task/PurgeServiceTest.java @@ -126,6 +126,7 @@ public class PurgeServiceTest { verifyScheduledPurgeTask(null, "alpha", "charlie"); } + @SuppressWarnings("unchecked") @Test public void shouldRecognizeNoPlayersToPurge() { // given From 56d6fd81b41d8499b6441c66d52b8e304df8b6b6 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 29 Jun 2016 16:18:12 +0200 Subject: [PATCH 059/217] Cleanup --- .../java/fr/xephi/authme/hooks/BungeeCordMessage.java | 1 - .../fr/xephi/authme/permission/AuthGroupHandler.java | 10 ++++++---- .../fr/xephi/authme/process/join/AsynchronousJoin.java | 1 - .../process/quit/ProcessSyncronousPlayerQuit.java | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 1fda06ba..758d0446 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -4,7 +4,6 @@ import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteStreams; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.cache.SessionManager; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; diff --git a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java index a33cb7c5..bbad6f0f 100644 --- a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java +++ b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java @@ -6,6 +6,8 @@ import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.PluginSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; + import org.bukkit.entity.Player; import javax.inject.Inject; @@ -51,18 +53,18 @@ public class AuthGroupHandler { switch (group) { case UNREGISTERED: // Remove the other group type groups, set the current group - permissionsManager.removeGroups(player, Arrays.asList(Settings.getRegisteredGroup, Settings.getUnloggedinGroup)); + permissionsManager.removeGroups(player, Arrays.asList(Settings.getRegisteredGroup, settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP))); return permissionsManager.addGroup(player, Settings.unRegisteredGroup); case REGISTERED: // Remove the other group type groups, set the current group - permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getUnloggedinGroup)); + permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP))); return permissionsManager.addGroup(player, Settings.getRegisteredGroup); case NOT_LOGGED_IN: // Remove the other group type groups, set the current group permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup)); - return permissionsManager.addGroup(player, Settings.getUnloggedinGroup); + return permissionsManager.addGroup(player, settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP)); case LOGGED_IN: // Get the limbo player data @@ -76,7 +78,7 @@ public class AuthGroupHandler { // Remove the other group types groups, set the real group permissionsManager.removeGroups(player, - Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup, Settings.getUnloggedinGroup) + Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup, settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP)) ); return permissionsManager.addGroup(player, realGroup); default: 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 7c83ec28..390a3f9b 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -9,7 +9,6 @@ import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.ProtectInventoryEvent; import fr.xephi.authme.hooks.PluginHooks; -import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.permission.PlayerStatePermission; diff --git a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java index 13a6a7b3..88153345 100644 --- a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java @@ -3,7 +3,6 @@ package fr.xephi.authme.process.quit; import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; -import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SynchronousProcess; import fr.xephi.authme.settings.properties.RestrictionSettings; From 5726b0d326c3b7a6e225b1af45cf6f2c37cc6f40 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 22:02:45 +0700 Subject: [PATCH 060/217] Fix player always teleport to spawn on join. --- .../authme/listener/AuthMePlayerListener.java | 3 +- .../process/logout/AsynchronousLogout.java | 30 ++++++-------- .../ProcessSynchronousPlayerLogout.java | 41 +++++++++++-------- .../authme/util/TeleportationService.java | 23 +++++++---- 4 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 5320a72a..fc92e1e8 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -194,6 +194,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerJoin(PlayerJoinEvent event) { final Player player = event.getPlayer(); + teleportationService.teleportOnJoin(player); management.performJoin(player); } @@ -232,7 +233,7 @@ public class AuthMePlayerListener implements Listener { } antiBot.handlePlayerJoin(player); - teleportationService.teleportOnJoin(player); + teleportationService.teleportOnLoginEvent(player); } @EventHandler(priority = EventPriority.HIGHEST) diff --git a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java index 25842af0..f58cd359 100644 --- a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java @@ -8,8 +8,7 @@ import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.AsynchronousProcess; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.process.SyncProcessManager; -import fr.xephi.authme.util.BukkitService; -import fr.xephi.authme.util.Utils; +import fr.xephi.authme.settings.properties.RestrictionSettings; import org.bukkit.entity.Player; import javax.inject.Inject; @@ -31,10 +30,8 @@ public class AsynchronousLogout implements AsynchronousProcess { @Inject private SyncProcessManager syncProcessManager; - @Inject - private BukkitService bukkitService; - - AsynchronousLogout() { } + AsynchronousLogout() { + } public void logout(final Player player) { final String name = player.getName().toLowerCase(); @@ -42,23 +39,20 @@ public class AsynchronousLogout implements AsynchronousProcess { service.send(player, MessageKey.NOT_LOGGED_IN); return; } + PlayerAuth auth = playerCache.getAuth(name); database.updateSession(auth); - auth.setQuitLocX(player.getLocation().getX()); - auth.setQuitLocY(player.getLocation().getY()); - auth.setQuitLocZ(player.getLocation().getZ()); - auth.setWorld(player.getWorld().getName()); - database.updateQuitLoc(auth); + if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { + auth.setQuitLocX(player.getLocation().getX()); + auth.setQuitLocY(player.getLocation().getY()); + auth.setQuitLocZ(player.getLocation().getZ()); + auth.setWorld(player.getWorld().getName()); + database.updateQuitLoc(auth); + } + limboCache.updateLimboPlayer(player); playerCache.removePlayer(name); database.setUnlogged(name); - bukkitService.scheduleSyncDelayedTask(new Runnable() { - @Override - public void run() { - Utils.teleportToSpawn(player); - } - }); - limboCache.updateLimboPlayer(player); syncProcessManager.processSyncPlayerLogout(player); } } diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java index c8336262..4c168a6b 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java @@ -69,22 +69,7 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { limboPlayerTaskManager.registerTimeoutTask(player); limboPlayerTaskManager.registerMessageTask(name, true); - if (player.isInsideVehicle() && player.getVehicle() != null) { - player.getVehicle().eject(); - } - final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; - if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { - player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2)); - } - - service.setGroup(player, AuthGroupType.NOT_LOGGED_IN); - player.setOp(false); - // Remove speed - if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) - && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { - player.setFlySpeed(0.0f); - player.setWalkSpeed(0.0f); - } + applyLogoutEffect(player); // Player is now logout... Time to fire event ! bukkitService.callEvent(new LogoutEvent(player)); @@ -95,4 +80,28 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess { ConsoleLogger.info(player.getName() + " logged out"); } + private void applyLogoutEffect(Player player) { + // dismount player + if (player.isInsideVehicle() && player.getVehicle() != null) { + player.getVehicle().eject(); + } + + // Apply Blindness effect + final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; + if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { + player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2)); + } + + // Set player's data to unauthenticated + service.setGroup(player, AuthGroupType.NOT_LOGGED_IN); + player.setOp(false); + player.setAllowFlight(false); + // Remove speed + if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) + && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { + player.setFlySpeed(0.0f); + player.setWalkSpeed(0.0f); + } + } + } diff --git a/src/main/java/fr/xephi/authme/util/TeleportationService.java b/src/main/java/fr/xephi/authme/util/TeleportationService.java index 06c7558d..53e77421 100644 --- a/src/main/java/fr/xephi/authme/util/TeleportationService.java +++ b/src/main/java/fr/xephi/authme/util/TeleportationService.java @@ -41,8 +41,12 @@ public class TeleportationService implements Reloadable { private Set spawnOnLoginWorlds; - TeleportationService() { } + TeleportationService() { + } + private static boolean isEventValid(AbstractTeleportEvent event) { + return !event.isCancelled() && event.getTo() != null && event.getTo().getWorld() != null; + } @PostConstruct @Override @@ -51,11 +55,9 @@ public class TeleportationService implements Reloadable { spawnOnLoginWorlds = new HashSet<>(settings.getProperty(RestrictionSettings.FORCE_SPAWN_ON_WORLDS)); } - public void teleportOnJoin(final Player player) { + public void teleportOnLoginEvent(final Player player) { if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { return; - } else if (teleportToFirstSpawn(player)) { - return; } if (settings.getProperty(TELEPORT_UNAUTHED_TO_SPAWN) || mustForceSpawnAfterLogin(player.getWorld().getName())) { @@ -63,6 +65,13 @@ public class TeleportationService implements Reloadable { } } + public void teleportOnJoin(final Player player) { + if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { + return; + } + teleportToFirstSpawn(player); + } + public void teleportOnLogin(final Player player, PlayerAuth auth, LimboPlayer limbo) { if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { return; @@ -122,7 +131,7 @@ public class TeleportationService implements Reloadable { * by external listeners). Note that not teleportation is performed if the event's location is empty. * * @param player the player to teleport - * @param event the event to emit and according to which to teleport + * @param event the event to emit and according to which to teleport */ private void performTeleportation(final Player player, final AbstractTeleportEvent event) { bukkitService.scheduleSyncDelayedTask(new Runnable() { @@ -135,8 +144,4 @@ public class TeleportationService implements Reloadable { } }); } - - private static boolean isEventValid(AbstractTeleportEvent event) { - return !event.isCancelled() && event.getTo() != null && event.getTo().getWorld() != null; - } } From abf6645620e92539c8c70533d1ea01a3002b5c94 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Wed, 29 Jun 2016 22:31:10 +0700 Subject: [PATCH 061/217] Fix test --- .../authme/util/TeleportationServiceTest.java | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java b/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java index ad9d9620..de8d286f 100644 --- a/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java +++ b/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link TeleportationService}. */ +// TODO: Correct me! @RunWith(MockitoJUnitRunner.class) public class TeleportationServiceTest { @@ -56,6 +57,20 @@ public class TeleportationServiceTest { @Mock private PlayerCache playerCache; + // We check that the World in Location is set, this method creates a mock World in Location for us + private static Location mockLocation() { + Location location = mock(Location.class); + given(location.getWorld()).willReturn(mock(World.class)); + return location; + } + + private static PlayerAuth createAuthWithLocation() { + return PlayerAuth.builder() + .name("bobby") + .locX(123.45).locY(23.4).locZ(-4.567) + .build(); + } + @Before public void setUpForcedWorlds() { given(settings.getProperty(RestrictionSettings.FORCE_SPAWN_ON_WORLDS)) @@ -113,7 +128,7 @@ public class TeleportationServiceTest { given(spawnLoader.getSpawnLocation(player)).willReturn(spawn); // when - teleportationService.teleportOnJoin(player); + teleportationService.teleportOnLoginEvent(player); runSyncDelayedTask(bukkitService); // then @@ -135,6 +150,7 @@ public class TeleportationServiceTest { given(spawnLoader.getFirstSpawn()).willReturn(null); // when + teleportationService.teleportOnLoginEvent(player); teleportationService.teleportOnJoin(player); // then @@ -161,6 +177,7 @@ public class TeleportationServiceTest { given(spawnLoader.getSpawnLocation(player)).willReturn(spawn); // when + teleportationService.teleportOnLoginEvent(player); teleportationService.teleportOnJoin(player); runSyncDelayedTask(bukkitService); @@ -189,6 +206,7 @@ public class TeleportationServiceTest { }).when(bukkitService).callEvent(any(SpawnTeleportEvent.class)); // when + teleportationService.teleportOnLoginEvent(player); teleportationService.teleportOnJoin(player); runSyncDelayedTask(bukkitService); @@ -216,6 +234,7 @@ public class TeleportationServiceTest { }).when(bukkitService).callEvent(any(SpawnTeleportEvent.class)); // when + teleportationService.teleportOnLoginEvent(player); teleportationService.teleportOnJoin(player); runSyncDelayedTask(bukkitService); @@ -224,7 +243,6 @@ public class TeleportationServiceTest { verify(player, never()).teleport(any(Location.class)); } - // --------- // LOGIN // --------- @@ -397,21 +415,6 @@ public class TeleportationServiceTest { verify(player).teleport(location); } - - // We check that the World in Location is set, this method creates a mock World in Location for us - private static Location mockLocation() { - Location location = mock(Location.class); - given(location.getWorld()).willReturn(mock(World.class)); - return location; - } - - private static PlayerAuth createAuthWithLocation() { - return PlayerAuth.builder() - .name("bobby") - .locX(123.45).locY(23.4).locZ(-4.567) - .build(); - } - private void assertCorrectLocation(Location location, PlayerAuth auth, World world) { assertThat(location.getX(), equalTo(auth.getQuitLocX())); assertThat(location.getY(), equalTo(auth.getQuitLocY())); From a02c1c4e60ab79a257f9dee81562ce77ff2587b3 Mon Sep 17 00:00:00 2001 From: games647 Date: Wed, 29 Jun 2016 17:48:33 +0200 Subject: [PATCH 062/217] Change to a total task timeout instead of individual one --- src/main/java/fr/xephi/authme/AuthMe.java | 55 +++++++++++++++-------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 4fc05f9c..0d994cc7 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -67,7 +67,6 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.messaging.Messenger; import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; import java.io.File; import java.sql.SQLException; @@ -80,6 +79,9 @@ 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; +import java.util.Iterator; +import java.util.logging.Level; +import org.bukkit.scheduler.BukkitWorker; /** * The AuthMe main class. @@ -452,35 +454,50 @@ public class AuthMe extends JavaPlugin { if (newSettings != null) { 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(pluginInstance) && !pendingTask.isSync()) { + //returns only the async takss + for (BukkitWorker pendingTask : getServer().getScheduler().getActiveWorkers()) { + if (pendingTask.getOwner().equals(AuthMe.this) + //it's not a peridic task + && !getServer().getScheduler().isQueued(pendingTask.getTaskId())) { pendingTasks.add(pendingTask.getTaskId()); } } - getLogger().info("Waiting for " + pendingTasks.size() + " tasks to finish"); + + getLogger().log(Level.INFO, "Waiting for {0} tasks to finish", pendingTasks.size()); int progress = 0; - for (int taskId : pendingTasks) { - int maxTries = 5; - while (getServer().getScheduler().isCurrentlyRunning(taskId)) { - if (maxTries <= 0) { - getLogger().info("Async task " + taskId + " times out after to many tries"); - break; - } - try { - Thread.sleep(1000); - } catch (InterruptedException ignored) { - } - maxTries--; + + //one minute + some time checking the running state + int tries = 60; + while (!pendingTasks.isEmpty()) { + if (tries <= 0) { + getLogger().log(Level.INFO, "Async tasks times out after to many tries {0}", pendingTasks); + break; } - progress++; - getLogger().info("Progress: " + progress + " / " + pendingTasks.size()); + try { + Thread.sleep(1000); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + break; + } + + for (Iterator iterator = pendingTasks.iterator(); iterator.hasNext();) { + int taskId = iterator.next(); + if (!getServer().getScheduler().isCurrentlyRunning(taskId)) { + iterator.remove(); + progress++; + getLogger().log(Level.INFO, "Progress: {0} / {1}", new Object[]{progress, pendingTasks.size()}); + } + } + + tries--; } + if (database != null) { database.close(); } From 1cadbd2345bb3a504f6524dca253fbb542bafd6c Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 30 Jun 2016 20:50:13 +0200 Subject: [PATCH 063/217] Minor code householding Various neglectable changes while looking at recent commits - Remove Inject annotation on ProtocolLib adapters that are no longer created via injection - Reduce ProtocolLib adapters to package private - interaction always goes via ProtocolLibService - Fix typos --- .github/ISSUE_TEMPLATE.MD | 4 ++-- src/main/java/fr/xephi/authme/AuthMe.java | 10 +++------- .../AuthMeInventoryPacketAdapter.java | 2 +- .../AuthMeTabCompletePacketAdapter.java | 6 +----- .../AuthMeTablistPacketAdapter.java | 4 +--- .../protocollib/ProtocolLibService.java | 18 ++++++------------ 6 files changed, 14 insertions(+), 30 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.MD b/.github/ISSUE_TEMPLATE.MD index 0527d7ff..c3a5da7a 100644 --- a/.github/ISSUE_TEMPLATE.MD +++ b/.github/ISSUE_TEMPLATE.MD @@ -21,5 +21,5 @@ This can be found by running `/authme version` ### Error Log: Pastebin/Hastebin/Gist link of the error logo or stacktrace (if any) -### COnfiguration: -Pastebin/Hastebin/Gist link of your config.yml file (remember to delete any sesible data) +### Configuration: +Pastebin/Hastebin/Gist link of your config.yml file (remember to delete any sensible data) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 0d994cc7..a81619d9 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -67,21 +67,21 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.messaging.Messenger; import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitWorker; import java.io.File; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.Iterator; import java.util.List; +import java.util.logging.Level; 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; -import java.util.Iterator; -import java.util.logging.Level; -import org.bukkit.scheduler.BukkitWorker; /** * The AuthMe main class. @@ -114,10 +114,6 @@ public class AuthMe extends JavaPlugin { private BukkitService bukkitService; private AuthMeServiceInitializer initializer; private GeoLiteAPI geoLiteApi; - - /* - * Private instances (mail and ProtocolLib) - */ private SendMailSSL mail; /** diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java index 64ad7cf3..a155538e 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeInventoryPacketAdapter.java @@ -32,7 +32,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.logging.Level; -public class AuthMeInventoryPacketAdapter extends PacketAdapter { +class AuthMeInventoryPacketAdapter extends PacketAdapter { private static final int PLAYER_INVENTORY = 0; // http://wiki.vg/Inventory#Inventory (0-4 crafting, 5-8 armor, 9-35 main inventory, 36-44 hotbar, 45 off hand) diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTabCompletePacketAdapter.java index ad4d1e0b..2aef7d06 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTabCompletePacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTabCompletePacketAdapter.java @@ -6,16 +6,12 @@ import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.FieldAccessException; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; -import javax.inject.Inject; +class AuthMeTabCompletePacketAdapter extends PacketAdapter { -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/protocollib/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java index a26bec83..75e06cd5 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java @@ -21,7 +21,6 @@ import fr.xephi.authme.util.BukkitService; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import javax.inject.Inject; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Iterator; @@ -29,12 +28,11 @@ import java.util.List; import java.util.UUID; import java.util.logging.Level; -public class AuthMeTablistPacketAdapter extends PacketAdapter { +class AuthMeTablistPacketAdapter extends PacketAdapter { private final BukkitService bukkitService; private boolean isRegistered; - @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/listener/protocollib/ProtocolLibService.java b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java index b1f5573a..a3859527 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java @@ -104,11 +104,9 @@ public class ProtocolLibService implements SettingsDependent { * @param player The player to send the packet to. */ public void sendInventoryPacket(Player player) { - if (!isEnabled || inventoryPacketAdapter == null) { - return; + if (isEnabled && inventoryPacketAdapter != null) { + inventoryPacketAdapter.sendInventoryPacket(player); } - - inventoryPacketAdapter.sendInventoryPacket(player); } /** @@ -117,11 +115,9 @@ public class ProtocolLibService implements SettingsDependent { * @param player The player to send the packet to. */ public void sendBlankInventoryPacket(Player player) { - if (!isEnabled || inventoryPacketAdapter == null) { - return; + if (isEnabled && inventoryPacketAdapter != null) { + inventoryPacketAdapter.sendBlankInventoryPacket(player); } - - inventoryPacketAdapter.sendBlankInventoryPacket(player); } /** @@ -130,11 +126,9 @@ public class ProtocolLibService implements SettingsDependent { * @param player The player to send the packet to. */ public void sendTabList(Player player) { - if (!isEnabled || tablistPacketAdapter == null) { - return; + if (isEnabled && tablistPacketAdapter != null) { + tablistPacketAdapter.sendTablist(player); } - - tablistPacketAdapter.sendTablist(player); } @Override From 6585b68749b0cb843b57f81517e08aae3ebdd65b Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 30 Jun 2016 22:38:36 +0200 Subject: [PATCH 064/217] Fix TeleportationService tests + rename methods - Fix and supplement unit tests for TeleportationService - Rename methods as to avoid confusion (login vs. LoginEvent when player joins) - Add javadoc with note about Player#hasPlayedBefore always being false --- .../authme/listener/AuthMePlayerListener.java | 4 +- .../authme/util/TeleportationService.java | 57 ++++++++------ .../authme/util/TeleportationServiceTest.java | 75 ++++++++++++------- 3 files changed, 86 insertions(+), 50 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index fc92e1e8..0e5915e1 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -194,7 +194,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerJoin(PlayerJoinEvent event) { final Player player = event.getPlayer(); - teleportationService.teleportOnJoin(player); + teleportationService.teleportNewPlayerToFirstSpawn(player); management.performJoin(player); } @@ -233,7 +233,7 @@ public class AuthMePlayerListener implements Listener { } antiBot.handlePlayerJoin(player); - teleportationService.teleportOnLoginEvent(player); + teleportationService.teleportOnJoin(player); } @EventHandler(priority = EventPriority.HIGHEST) diff --git a/src/main/java/fr/xephi/authme/util/TeleportationService.java b/src/main/java/fr/xephi/authme/util/TeleportationService.java index 53e77421..a7cffb35 100644 --- a/src/main/java/fr/xephi/authme/util/TeleportationService.java +++ b/src/main/java/fr/xephi/authme/util/TeleportationService.java @@ -44,10 +44,6 @@ public class TeleportationService implements Reloadable { TeleportationService() { } - private static boolean isEventValid(AbstractTeleportEvent event) { - return !event.isCancelled() && event.getTo() != null && event.getTo().getWorld() != null; - } - @PostConstruct @Override public void reload() { @@ -55,7 +51,18 @@ public class TeleportationService implements Reloadable { spawnOnLoginWorlds = new HashSet<>(settings.getProperty(RestrictionSettings.FORCE_SPAWN_ON_WORLDS)); } - public void teleportOnLoginEvent(final Player player) { + /** + * Teleports the player according to the settings when he joins. + *

+ * Note: this is triggered by Bukkit's PlayerLoginEvent, during which you cannot use + * {@link Player#hasPlayedBefore()}: it always returns {@code false}. We trigger teleportation + * from the PlayerLoginEvent and not the PlayerJoinEvent to ensure that the location is overridden + * as fast as possible (cf. AuthMe #682). + * + * @param player the player to process + * @see BUKKIT-3521: Player.hasPlayedBefore() always false + */ + public void teleportOnJoin(final Player player) { if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { return; } @@ -65,13 +72,30 @@ public class TeleportationService implements Reloadable { } } - public void teleportOnJoin(final Player player) { - if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { + /** + * Teleports the player to the first spawn if he is new and the first spawn is configured. + * + * @param player the player to process + */ + public void teleportNewPlayerToFirstSpawn(final Player player) { + if (settings.getProperty(RestrictionSettings.NO_TELEPORT) || player.hasPlayedBefore()) { return; } - teleportToFirstSpawn(player); + Location firstSpawn = spawnLoader.getFirstSpawn(); + if (firstSpawn == null) { + return; + } + + performTeleportation(player, new FirstSpawnTeleportEvent(player, firstSpawn)); } + /** + * Teleports the player according to the settings after having successfully logged in. + * + * @param player the player + * @param auth corresponding PlayerAuth object + * @param limbo corresponding LimboPlayer object + */ public void teleportOnLogin(final Player player, PlayerAuth auth, LimboPlayer limbo) { if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { return; @@ -104,19 +128,6 @@ public class TeleportationService implements Reloadable { return new Location(world, auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ()); } - private boolean teleportToFirstSpawn(final Player player) { - if (player.hasPlayedBefore()) { - return false; - } - Location firstSpawn = spawnLoader.getFirstSpawn(); - if (firstSpawn == null) { - return false; - } - - performTeleportation(player, new FirstSpawnTeleportEvent(player, firstSpawn)); - return true; - } - private void teleportBackFromSpawn(final Player player, final Location location) { performTeleportation(player, new AuthMeTeleportEvent(player, location)); } @@ -144,4 +155,8 @@ public class TeleportationService implements Reloadable { } }); } + + private static boolean isEventValid(AbstractTeleportEvent event) { + return !event.isCancelled() && event.getTo() != null && event.getTo().getWorld() != null; + } } diff --git a/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java b/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java index de8d286f..84e1a1de 100644 --- a/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java +++ b/src/test/java/fr/xephi/authme/util/TeleportationServiceTest.java @@ -38,7 +38,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link TeleportationService}. */ -// TODO: Correct me! @RunWith(MockitoJUnitRunner.class) public class TeleportationServiceTest { @@ -57,20 +56,6 @@ public class TeleportationServiceTest { @Mock private PlayerCache playerCache; - // We check that the World in Location is set, this method creates a mock World in Location for us - private static Location mockLocation() { - Location location = mock(Location.class); - given(location.getWorld()).willReturn(mock(World.class)); - return location; - } - - private static PlayerAuth createAuthWithLocation() { - return PlayerAuth.builder() - .name("bobby") - .locX(123.45).locY(23.4).locZ(-4.567) - .build(); - } - @Before public void setUpForcedWorlds() { given(settings.getProperty(RestrictionSettings.FORCE_SPAWN_ON_WORLDS)) @@ -107,7 +92,7 @@ public class TeleportationServiceTest { given(spawnLoader.getFirstSpawn()).willReturn(firstSpawn); // when - teleportationService.teleportOnJoin(player); + teleportationService.teleportNewPlayerToFirstSpawn(player); runSyncDelayedTask(bukkitService); // then @@ -122,13 +107,12 @@ public class TeleportationServiceTest { // given given(settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)).willReturn(true); Player player = mock(Player.class); - given(player.hasPlayedBefore()).willReturn(true); given(player.isOnline()).willReturn(true); Location spawn = mockLocation(); given(spawnLoader.getSpawnLocation(player)).willReturn(spawn); // when - teleportationService.teleportOnLoginEvent(player); + teleportationService.teleportOnJoin(player); runSyncDelayedTask(bukkitService); // then @@ -150,8 +134,7 @@ public class TeleportationServiceTest { given(spawnLoader.getFirstSpawn()).willReturn(null); // when - teleportationService.teleportOnLoginEvent(player); - teleportationService.teleportOnJoin(player); + teleportationService.teleportNewPlayerToFirstSpawn(player); // then verify(player, never()).teleport(any(Location.class)); @@ -161,10 +144,39 @@ public class TeleportationServiceTest { } @Test - public void shouldTeleportPlayerDueToForcedWorld() { + public void shouldNotTeleportPlayerToFirstSpawnIfNoTeleportEnabled() { + // given + Player player = mock(Player.class); + given(player.hasPlayedBefore()).willReturn(false); + given(settings.getProperty(RestrictionSettings.NO_TELEPORT)).willReturn(true); + + // when + teleportationService.teleportNewPlayerToFirstSpawn(player); + + // then + verify(player, never()).teleport(any(Location.class)); + verifyZeroInteractions(bukkitService); + } + + @Test + public void shouldNotTeleportNotNewPlayerToFirstSpawn() { // given Player player = mock(Player.class); given(player.hasPlayedBefore()).willReturn(true); + given(settings.getProperty(RestrictionSettings.NO_TELEPORT)).willReturn(false); + + // when + teleportationService.teleportNewPlayerToFirstSpawn(player); + + // then + verify(player, never()).teleport(any(Location.class)); + verifyZeroInteractions(bukkitService); + } + + @Test + public void shouldTeleportPlayerDueToForcedWorld() { + // given + Player player = mock(Player.class); given(player.isOnline()).willReturn(true); World playerWorld = mock(World.class); @@ -177,7 +189,6 @@ public class TeleportationServiceTest { given(spawnLoader.getSpawnLocation(player)).willReturn(spawn); // when - teleportationService.teleportOnLoginEvent(player); teleportationService.teleportOnJoin(player); runSyncDelayedTask(bukkitService); @@ -191,7 +202,6 @@ public class TeleportationServiceTest { public void shouldNotTeleportPlayerForRemovedLocationInEvent() { // given final Player player = mock(Player.class); - given(player.hasPlayedBefore()).willReturn(true); Location spawn = mockLocation(); given(spawnLoader.getSpawnLocation(player)).willReturn(spawn); given(settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)).willReturn(true); @@ -206,7 +216,6 @@ public class TeleportationServiceTest { }).when(bukkitService).callEvent(any(SpawnTeleportEvent.class)); // when - teleportationService.teleportOnLoginEvent(player); teleportationService.teleportOnJoin(player); runSyncDelayedTask(bukkitService); @@ -219,7 +228,6 @@ public class TeleportationServiceTest { public void shouldNotTeleportPlayerForCanceledEvent() { // given final Player player = mock(Player.class); - given(player.hasPlayedBefore()).willReturn(true); Location spawn = mockLocation(); given(spawnLoader.getSpawnLocation(player)).willReturn(spawn); given(settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)).willReturn(true); @@ -234,7 +242,6 @@ public class TeleportationServiceTest { }).when(bukkitService).callEvent(any(SpawnTeleportEvent.class)); // when - teleportationService.teleportOnLoginEvent(player); teleportationService.teleportOnJoin(player); runSyncDelayedTask(bukkitService); @@ -415,11 +422,25 @@ public class TeleportationServiceTest { verify(player).teleport(location); } - private void assertCorrectLocation(Location location, PlayerAuth auth, World world) { + private static void assertCorrectLocation(Location location, PlayerAuth auth, World world) { assertThat(location.getX(), equalTo(auth.getQuitLocX())); assertThat(location.getY(), equalTo(auth.getQuitLocY())); assertThat(location.getZ(), equalTo(auth.getQuitLocZ())); assertThat(location.getWorld(), equalTo(world)); } + // We check that the World in Location is set, this method creates a mock World in Location for us + private static Location mockLocation() { + Location location = mock(Location.class); + given(location.getWorld()).willReturn(mock(World.class)); + return location; + } + + private static PlayerAuth createAuthWithLocation() { + return PlayerAuth.builder() + .name("bobby") + .locX(123.45).locY(23.4).locZ(-4.567) + .build(); + } + } From 73a9b5ce0c03b08fdf2b82db0e87d885de882496 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 08:06:17 +0200 Subject: [PATCH 065/217] Cleanup - reduce duplication in MySQL class --- .../fr/xephi/authme/datasource/MySQL.java | 120 +++++++----------- 1 file changed, 48 insertions(+), 72 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index fbf51eb9..17cb3202 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -31,34 +31,23 @@ import java.util.Set; public class MySQL implements DataSource { - private final String host; - private final String port; - private final String username; - private final String password; - private final String database; - private final String tableName; - private final List columnOthers; - private final Columns col; - private final HashAlgorithm hashAlgorithm; + private String host; + private String port; + private String username; + private String password; + private String database; + private String tableName; + private List columnOthers; + private Columns col; + private HashAlgorithm hashAlgorithm; private HikariDataSource ds; - private final String phpBbPrefix; - private final int phpBbGroup; - private final String wordpressPrefix; + private String phpBbPrefix; + private int phpBbGroup; + private String wordpressPrefix; public MySQL(NewSetting settings) throws ClassNotFoundException, SQLException, PoolInitializationException { - this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST); - this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT); - this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME); - this.password = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD); - this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS); - this.col = new Columns(settings); - this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); - this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX); - this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID); - this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); + setParameters(settings); // Set the connection arguments (and check if connection is ok) try { @@ -67,7 +56,7 @@ public class MySQL implements DataSource { if (e instanceof IllegalArgumentException) { ConsoleLogger.showError("Invalid database arguments! Please check your configuration!"); ConsoleLogger.showError("If this error persists, please report it to the developer!"); - throw new IllegalArgumentException(e); + throw e; } if (e instanceof PoolInitializationException) { ConsoleLogger.showError("Can't initialize database connection! Please check your configuration!"); @@ -91,6 +80,11 @@ public class MySQL implements DataSource { @VisibleForTesting MySQL(NewSetting settings, HikariDataSource hikariDataSource) { + ds = hikariDataSource; + setParameters(settings); + } + + private void setParameters(NewSetting settings) { this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST); this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT); this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME); @@ -103,7 +97,6 @@ public class MySQL implements DataSource { this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX); this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID); this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); - ds = hikariDataSource; } private void setConnectionArguments() throws RuntimeException { @@ -148,9 +141,7 @@ public class MySQL implements DataSource { } private void setupConnection() throws SQLException { - try (Connection con = getConnection()) { - Statement st = con.createStatement(); - DatabaseMetaData md = con.getMetaData(); + try (Connection con = getConnection(); Statement st = con.createStatement()) { // Create table if not exists. String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" + col.ID + " INTEGER AUTO_INCREMENT," @@ -169,96 +160,77 @@ public class MySQL implements DataSource { + ");"; st.executeUpdate(sql); - ResultSet rs = md.getColumns(null, null, tableName, col.NAME); - if (!rs.next()) { + DatabaseMetaData md = con.getMetaData(); + if (isColumnMissing(md, col.NAME)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.NAME + " VARCHAR(255) NOT NULL UNIQUE AFTER " + col.ID + ";"); } - rs.close(); - rs = md.getColumns(null, null, tableName, col.REAL_NAME); - if (!rs.next()) { + if (isColumnMissing(md, col.REAL_NAME)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL AFTER " + col.NAME + ";"); } - rs.close(); - rs = md.getColumns(null, null, tableName, col.PASSWORD); - if (!rs.next()) { + if (isColumnMissing(md, col.PASSWORD)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;"); } - rs.close(); - if (!col.SALT.isEmpty()) { - rs = md.getColumns(null, null, tableName, col.SALT); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); - } - rs.close(); + if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { + st.executeUpdate("ALTER TABLE " + tableName + + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); } - rs = md.getColumns(null, null, tableName, col.IP); - if (!rs.next()) { + if (isColumnMissing(md, col.IP)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;"); } - rs.close(); - rs = md.getColumns(null, null, tableName, col.LAST_LOGIN); - if (!rs.next()) { + if (isColumnMissing(md, col.LAST_LOGIN)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0;"); } else { - migrateLastLoginColumnToBigInt(con, rs); + migrateLastLoginColumnToBigInt(con, md); } - rs.close(); - rs = md.getColumns(null, null, tableName, col.LASTLOC_X); - if (!rs.next()) { + if (isColumnMissing(md, col.LASTLOC_X)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LAST_LOGIN + " , ADD " + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_X + " , ADD " + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_Y); - } - rs.close(); - - rs = md.getColumns(null, null, tableName, col.LASTLOC_X); - if (rs.next()) { + } else { st.executeUpdate("ALTER TABLE " + tableName + " MODIFY " + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY " + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY " + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';"); } - rs.close(); - rs = md.getColumns(null, null, tableName, col.LASTLOC_WORLD); - if (!rs.next()) { + if (isColumnMissing(md, col.LASTLOC_WORLD)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world' AFTER " + col.LASTLOC_Z); } - rs.close(); - rs = md.getColumns(null, null, tableName, col.EMAIL); - if (!rs.next()) { + if (isColumnMissing(md, col.EMAIL)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com' AFTER " + col.LASTLOC_WORLD); } - rs.close(); - rs = md.getColumns(null, null, tableName, col.IS_LOGGED); - if (!rs.next()) { + if (isColumnMissing(md, col.IS_LOGGED)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.EMAIL); } - rs.close(); st.close(); } ConsoleLogger.info("MySQL setup finished"); } + private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException { + try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) { + return !rs.next(); + } + } + @Override public boolean isAuthAvailable(String user) { String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; @@ -933,10 +905,14 @@ public class MySQL implements DataSource { * Check if the lastlogin column is of type timestamp and, if so, revert it to the bigint format. * * @param con Connection to the database - * @param rs ResultSet containing meta data for the lastlogin column + * @param metaData metaData meta data of the database */ - private void migrateLastLoginColumnToBigInt(Connection con, ResultSet rs) throws SQLException { - final int columnType = rs.getInt("DATA_TYPE"); + private void migrateLastLoginColumnToBigInt(Connection con, DatabaseMetaData metaData) throws SQLException { + final int columnType; + try (ResultSet rs = metaData.getColumns(null, null, tableName, col.LAST_LOGIN)) { + columnType = rs.getInt("DATA_TYPE"); + } + if (columnType == Types.TIMESTAMP) { ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint"); final String lastLoginOld = col.LAST_LOGIN + "_old"; From 1f35ccd841160cbb4d0ee886b97bdf766dd6bec2 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 08:38:23 +0200 Subject: [PATCH 066/217] Improve bat helpers / minor changes to logging and todo messages --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- src/main/java/fr/xephi/authme/task/PurgeService.java | 2 +- .../fr/xephi/authme/security/crypts/CryptPBKDF2Test.java | 2 +- src/test/java/tools/bathelpers/freshen_jar.bat | 5 +++++ src/test/java/tools/bathelpers/move_plugin.bat | 3 +-- src/test/java/tools/bathelpers/quick_build.bat | 2 +- 6 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 src/test/java/tools/bathelpers/freshen_jar.bat diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index a81619d9..3acb8ca8 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -278,7 +278,7 @@ public class AuthMe extends JavaPlugin { // If server is using PermissionsBukkit, print a warning that some features may not be supported if (PermissionsSystemType.PERMISSIONS_BUKKIT.equals(permsMan.getPermissionSystem())) { - ConsoleLogger.info("Warning! This server uses PermissionsBukkit for permissions! Some permissions features may not be supported!"); + ConsoleLogger.showError("Warning! This server uses PermissionsBukkit for permissions. Some permissions features may not be supported!"); } // Purge on start if enabled diff --git a/src/main/java/fr/xephi/authme/task/PurgeService.java b/src/main/java/fr/xephi/authme/task/PurgeService.java index 7549371b..e84fae41 100644 --- a/src/main/java/fr/xephi/authme/task/PurgeService.java +++ b/src/main/java/fr/xephi/authme/task/PurgeService.java @@ -76,7 +76,7 @@ public class PurgeService implements Reloadable { if (!settings.getProperty(PurgeSettings.USE_AUTO_PURGE)) { return; } else if (daysBeforePurge <= 0) { - ConsoleLogger.showError("Configured days before purging must be positive"); + ConsoleLogger.showError("Did not run auto purge: configured days before purging must be positive"); return; } diff --git a/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2Test.java b/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2Test.java index 2e9f6380..36ce7106 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2Test.java @@ -6,7 +6,7 @@ import org.junit.Ignore; * Test for {@link CryptPBKDF2}. */ @Ignore -// TODO #369: This algorithm seems broken +// TODO #685: This algorithm seems broken public class CryptPBKDF2Test extends AbstractEncryptionMethodTest { public CryptPBKDF2Test() { diff --git a/src/test/java/tools/bathelpers/freshen_jar.bat b/src/test/java/tools/bathelpers/freshen_jar.bat new file mode 100644 index 00000000..3eba26db --- /dev/null +++ b/src/test/java/tools/bathelpers/freshen_jar.bat @@ -0,0 +1,5 @@ +: Shortcut for quickbuild / move to plugins / run server + +call quick_build.bat +call move_plugin.bat +call run_server.bat diff --git a/src/test/java/tools/bathelpers/move_plugin.bat b/src/test/java/tools/bathelpers/move_plugin.bat index a8bec501..ac89c05f 100644 --- a/src/test/java/tools/bathelpers/move_plugin.bat +++ b/src/test/java/tools/bathelpers/move_plugin.bat @@ -1,11 +1,10 @@ : Moves the AuthMe JAR file to the plugins folder of the test server -: You will have to hit 'Y' to really replace it if it already exists if "%jarfile%" == "" ( call setvars.bat ) if exist %jarfile% ( - xcopy %jarfile% %plugins% + xcopy %jarfile% %plugins% /y ) else ( echo Target file not found: '%jarfile%' ) diff --git a/src/test/java/tools/bathelpers/quick_build.bat b/src/test/java/tools/bathelpers/quick_build.bat index 2010e00a..543b53b0 100644 --- a/src/test/java/tools/bathelpers/quick_build.bat +++ b/src/test/java/tools/bathelpers/quick_build.bat @@ -3,4 +3,4 @@ if "%jarfile%" == "" ( call setvars.bat ) -mvn install -f "%pomfile%" -Dmaven.test.skip \ No newline at end of file +mvn install -o -f "%pomfile%" -Dmaven.test.skip From de3f3a42ab96a814feb32703df0fd4538861db42 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 10:24:44 +0200 Subject: [PATCH 067/217] #679 Fix compatibility with InnoDB/XtraDB engine - Includes other improvements in collation and data types --- .../fr/xephi/authme/datasource/MySQL.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 17cb3202..3902e3e5 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -69,11 +69,11 @@ public class MySQL implements DataSource { // Initialize the database try { - this.setupConnection(); + setupConnection(); } catch (SQLException e) { - this.close(); - ConsoleLogger.showError("Can't initialize the MySQL database... Please check your database settings in the config.yml file! SHUTDOWN..."); - ConsoleLogger.showError("If this error persists, please report it to the developer!"); + close(); + ConsoleLogger.logException("Can't initialize the MySQL database:", e); + ConsoleLogger.showError("Please check your database settings in the config.yml file!"); throw e; } } @@ -144,11 +144,11 @@ public class MySQL implements DataSource { try (Connection con = getConnection(); Statement st = con.createStatement()) { // Create table if not exists. String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" - + col.ID + " INTEGER AUTO_INCREMENT," + + col.ID + " MEDIUMINT(8) UNSIGNED AUTO_INCREMENT," + col.NAME + " VARCHAR(255) NOT NULL UNIQUE," + col.REAL_NAME + " VARCHAR(255) NOT NULL," - + col.PASSWORD + " VARCHAR(255) NOT NULL," - + col.IP + " VARCHAR(40) NOT NULL DEFAULT '127.0.0.1'," + + col.PASSWORD + " VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL," + + col.IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '127.0.0.1'," + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0," + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0'," @@ -156,8 +156,8 @@ public class MySQL implements DataSource { + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com'," + col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0'," - + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + ")" - + ");"; + + "PRIMARY KEY (" + col.ID + ")" + + ") CHARACTER SET = utf8"; st.executeUpdate(sql); DatabaseMetaData md = con.getMetaData(); @@ -173,7 +173,7 @@ public class MySQL implements DataSource { if (isColumnMissing(md, col.PASSWORD)) { st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;"); + + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;"); } if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { @@ -183,7 +183,7 @@ public class MySQL implements DataSource { if (isColumnMissing(md, col.IP)) { st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;"); + + " ADD COLUMN " + col.IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;"); } if (isColumnMissing(md, col.LAST_LOGIN)) { @@ -909,7 +909,11 @@ public class MySQL implements DataSource { */ private void migrateLastLoginColumnToBigInt(Connection con, DatabaseMetaData metaData) throws SQLException { final int columnType; - try (ResultSet rs = metaData.getColumns(null, null, tableName, col.LAST_LOGIN)) { + try (ResultSet rs = metaData.getColumns(null, null, tableName, col.LAST_LOGIN)) { + if (!rs.next()) { + ConsoleLogger.showError("Could not get LAST_LOGIN meta data. This should never happen!"); + return; + } columnType = rs.getInt("DATA_TYPE"); } From 70226f7ddbfe495cf91d614f2e5712d51d551cbb Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 10:57:30 +0200 Subject: [PATCH 068/217] #813 Move test resources to conform to package structure --- .../java/fr/xephi/authme/AuthMeInitializationTest.java | 2 +- src/test/java/fr/xephi/authme/TestHelper.java | 2 ++ .../fr/xephi/authme/converter/CrazyLoginConverterTest.java | 2 +- .../fr/xephi/authme/converter/ForceFlatToSqliteTest.java | 2 +- .../xephi/authme/datasource/FlatFileIntegrationTest.java | 2 +- .../fr/xephi/authme/datasource/MySqlIntegrationTest.java | 2 +- .../fr/xephi/authme/datasource/SQLiteIntegrationTest.java | 2 +- .../fr/xephi/authme/output/MessagesIntegrationTest.java | 7 ++++--- .../xephi/authme/settings/NewSettingIntegrationTest.java | 6 +++--- .../java/fr/xephi/authme/settings/SpawnLoaderTest.java | 2 +- .../{initialization => fr/xephi/authme}/config.test.yml | 0 .../{ => fr/xephi/authme}/converter/crazylogin.db | 0 .../xephi/authme/datasource}/flatfile-test.txt | 0 .../xephi/authme/datasource}/sql-initialize.sql | 0 .../{ => fr/xephi/authme/output}/messages_default.yml | 0 .../{ => fr/xephi/authme/output}/messages_test.yml | 0 .../{ => fr/xephi/authme/output}/messages_test2.yml | 0 .../xephi/authme/settings}/config-difficult-values.yml | 0 .../xephi/authme/settings}/config-incomplete-sample.yml | 0 .../xephi/authme/settings}/config-sample-values.yml | 0 .../xephi/authme/settings}/spawn-firstspawn.yml | 0 21 files changed, 16 insertions(+), 13 deletions(-) rename src/test/resources/{initialization => fr/xephi/authme}/config.test.yml (100%) rename src/test/resources/{ => fr/xephi/authme}/converter/crazylogin.db (100%) rename src/test/resources/{datasource-integration => fr/xephi/authme/datasource}/flatfile-test.txt (100%) rename src/test/resources/{datasource-integration => fr/xephi/authme/datasource}/sql-initialize.sql (100%) rename src/test/resources/{ => fr/xephi/authme/output}/messages_default.yml (100%) rename src/test/resources/{ => fr/xephi/authme/output}/messages_test.yml (100%) rename src/test/resources/{ => fr/xephi/authme/output}/messages_test2.yml (100%) rename src/test/resources/{ => fr/xephi/authme/settings}/config-difficult-values.yml (100%) rename src/test/resources/{ => fr/xephi/authme/settings}/config-incomplete-sample.yml (100%) rename src/test/resources/{ => fr/xephi/authme/settings}/config-sample-values.yml (100%) rename src/test/resources/{spawn => fr/xephi/authme/settings}/spawn-firstspawn.yml (100%) diff --git a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java index 25e95f83..72208992 100644 --- a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java +++ b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java @@ -72,7 +72,7 @@ public class AuthMeInitializationTest { public void initAuthMe() throws IOException { dataFolder = temporaryFolder.newFolder(); settingsFile = new File(dataFolder, "config.yml"); - Files.copy(TestHelper.getJarFile("/initialization/config.test.yml"), settingsFile); + Files.copy(TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "config.test.yml"), settingsFile); // Mock / wire various Bukkit components given(server.getLogger()).willReturn(mock(Logger.class)); diff --git a/src/test/java/fr/xephi/authme/TestHelper.java b/src/test/java/fr/xephi/authme/TestHelper.java index bef65621..58f3355c 100644 --- a/src/test/java/fr/xephi/authme/TestHelper.java +++ b/src/test/java/fr/xephi/authme/TestHelper.java @@ -28,6 +28,8 @@ import static org.mockito.Mockito.verify; */ public final class TestHelper { + public static final String PROJECT_ROOT = "/fr/xephi/authme/"; + private TestHelper() { } diff --git a/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java b/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java index 0183c613..615ef915 100644 --- a/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java +++ b/src/test/java/fr/xephi/authme/converter/CrazyLoginConverterTest.java @@ -45,7 +45,7 @@ public class CrazyLoginConverterTest { private NewSetting settings; @DataFolder - private File dataFolder = TestHelper.getJarFile("/converter/"); + private File dataFolder = TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "converter/"); @BeforeClass public static void initializeLogger() { diff --git a/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java b/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java index 6f6082ce..903c58ff 100644 --- a/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java +++ b/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java @@ -41,7 +41,7 @@ public class ForceFlatToSqliteTest { @Before public void copyFile() throws IOException { - File source = TestHelper.getJarFile("/datasource-integration/flatfile-test.txt"); + File source = TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "datasource/flatfile-test.txt"); File destination = temporaryFolder.newFile(); Files.copy(source, destination); flatFile = new FlatFile(destination); diff --git a/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java index 0c0ab8e1..853cbd78 100644 --- a/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java @@ -35,7 +35,7 @@ public class FlatFileIntegrationTest { @Before public void copyFileToTemporaryFolder() throws IOException { - File originalFile = TestHelper.getJarFile("/datasource-integration/flatfile-test.txt"); + File originalFile = TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "datasource/flatfile-test.txt"); File copy = temporaryFolder.newFile(); Files.copy(originalFile, copy); dataSource = new FlatFile(copy); diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java index ec90dab0..39769306 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -54,7 +54,7 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { set(DatabaseSettings.MYSQL_TABLE, "authme"); TestHelper.setupLogger(); - Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-initialize.sql"); + Path sqlInitFile = TestHelper.getJarPath(TestHelper.PROJECT_ROOT + "datasource/sql-initialize.sql"); sqlInitialize = new String(Files.readAllBytes(sqlInitFile)); } diff --git a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java index 3cfe9eb2..a654fca6 100644 --- a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java @@ -53,7 +53,7 @@ public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest { set(DatabaseSettings.MYSQL_TABLE, "authme"); TestHelper.setupLogger(); - Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-initialize.sql"); + Path sqlInitFile = TestHelper.getJarPath(TestHelper.PROJECT_ROOT + "datasource/sql-initialize.sql"); // Note ljacqu 20160221: It appears that we can only run one statement per Statement.execute() so we split // the SQL file by ";\n" as to get the individual statements sqlInitialize = new String(Files.readAllBytes(sqlInitFile)).split(";(\\r?)\\n"); diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index 61eea6a9..cea523c4 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -33,8 +33,8 @@ import static org.mockito.Mockito.verify; */ public class MessagesIntegrationTest { - private static final String YML_TEST_FILE = "/messages_test.yml"; - private static final String YML_DEFAULT_TEST_FILE = "/messages_default.yml"; + private static final String YML_TEST_FILE = TestHelper.PROJECT_ROOT + "output/messages_test.yml"; + private static final String YML_DEFAULT_TEST_FILE = TestHelper.PROJECT_ROOT + "output/messages_default.yml"; private Messages messages; @BeforeClass @@ -255,7 +255,8 @@ public class MessagesIntegrationTest { // assumption: message comes back as defined in messages_test.yml assumeThat(messages.retrieveSingle(key), equalTo("§cWrong password!")); NewSetting settings = mock(NewSetting.class); - given(settings.getMessagesFile()).willReturn(TestHelper.getJarFile("/messages_test2.yml")); + given(settings.getMessagesFile()).willReturn(TestHelper.getJarFile( + TestHelper.PROJECT_ROOT + "output/messages_test2.yml")); // when messages.loadSettings(settings); diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java index 1ee5a50c..4663b214 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java @@ -32,11 +32,11 @@ import static org.junit.Assert.assertThat; public class NewSettingIntegrationTest { /** File name of the sample config including all {@link TestConfiguration} values. */ - private static final String COMPLETE_FILE = "/config-sample-values.yml"; + private static final String COMPLETE_FILE = TestHelper.PROJECT_ROOT + "settings/config-sample-values.yml"; /** File name of the sample config missing certain {@link TestConfiguration} values. */ - private static final String INCOMPLETE_FILE = "/config-incomplete-sample.yml"; + private static final String INCOMPLETE_FILE = TestHelper.PROJECT_ROOT + "settings/config-incomplete-sample.yml"; /** File name for testing difficult values. */ - private static final String DIFFICULT_FILE = "/config-difficult-values.yml"; + private static final String DIFFICULT_FILE = TestHelper.PROJECT_ROOT + "settings/config-difficult-values.yml"; private static PropertyMap propertyMap = TestConfiguration.generatePropertyMap(); diff --git a/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java b/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java index c489e785..941c30f1 100644 --- a/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java +++ b/src/test/java/fr/xephi/authme/settings/SpawnLoaderTest.java @@ -54,7 +54,7 @@ public class SpawnLoaderTest { public void setup() throws IOException { // Copy test config into a new temporary folder testFolder = temporaryFolder.newFolder(); - File source = TestHelper.getJarFile("/spawn/spawn-firstspawn.yml"); + File source = TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "settings/spawn-firstspawn.yml"); File destination = new File(testFolder, "spawn.yml"); Files.copy(source, destination); diff --git a/src/test/resources/initialization/config.test.yml b/src/test/resources/fr/xephi/authme/config.test.yml similarity index 100% rename from src/test/resources/initialization/config.test.yml rename to src/test/resources/fr/xephi/authme/config.test.yml diff --git a/src/test/resources/converter/crazylogin.db b/src/test/resources/fr/xephi/authme/converter/crazylogin.db similarity index 100% rename from src/test/resources/converter/crazylogin.db rename to src/test/resources/fr/xephi/authme/converter/crazylogin.db diff --git a/src/test/resources/datasource-integration/flatfile-test.txt b/src/test/resources/fr/xephi/authme/datasource/flatfile-test.txt similarity index 100% rename from src/test/resources/datasource-integration/flatfile-test.txt rename to src/test/resources/fr/xephi/authme/datasource/flatfile-test.txt diff --git a/src/test/resources/datasource-integration/sql-initialize.sql b/src/test/resources/fr/xephi/authme/datasource/sql-initialize.sql similarity index 100% rename from src/test/resources/datasource-integration/sql-initialize.sql rename to src/test/resources/fr/xephi/authme/datasource/sql-initialize.sql diff --git a/src/test/resources/messages_default.yml b/src/test/resources/fr/xephi/authme/output/messages_default.yml similarity index 100% rename from src/test/resources/messages_default.yml rename to src/test/resources/fr/xephi/authme/output/messages_default.yml diff --git a/src/test/resources/messages_test.yml b/src/test/resources/fr/xephi/authme/output/messages_test.yml similarity index 100% rename from src/test/resources/messages_test.yml rename to src/test/resources/fr/xephi/authme/output/messages_test.yml diff --git a/src/test/resources/messages_test2.yml b/src/test/resources/fr/xephi/authme/output/messages_test2.yml similarity index 100% rename from src/test/resources/messages_test2.yml rename to src/test/resources/fr/xephi/authme/output/messages_test2.yml diff --git a/src/test/resources/config-difficult-values.yml b/src/test/resources/fr/xephi/authme/settings/config-difficult-values.yml similarity index 100% rename from src/test/resources/config-difficult-values.yml rename to src/test/resources/fr/xephi/authme/settings/config-difficult-values.yml diff --git a/src/test/resources/config-incomplete-sample.yml b/src/test/resources/fr/xephi/authme/settings/config-incomplete-sample.yml similarity index 100% rename from src/test/resources/config-incomplete-sample.yml rename to src/test/resources/fr/xephi/authme/settings/config-incomplete-sample.yml diff --git a/src/test/resources/config-sample-values.yml b/src/test/resources/fr/xephi/authme/settings/config-sample-values.yml similarity index 100% rename from src/test/resources/config-sample-values.yml rename to src/test/resources/fr/xephi/authme/settings/config-sample-values.yml diff --git a/src/test/resources/spawn/spawn-firstspawn.yml b/src/test/resources/fr/xephi/authme/settings/spawn-firstspawn.yml similarity index 100% rename from src/test/resources/spawn/spawn-firstspawn.yml rename to src/test/resources/fr/xephi/authme/settings/spawn-firstspawn.yml From bc9717d6501fbc639d97e4ad636c47fd3963eacb Mon Sep 17 00:00:00 2001 From: games647 Date: Sat, 2 Jul 2016 12:25:33 +0200 Subject: [PATCH 069/217] Remove tablist hider because it's useless and produces too much issues (Related #810) --- .../AuthMeTablistPacketAdapter.java | 120 ------------------ .../protocollib/ProtocolLibService.java | 29 +---- .../process/login/ProcessSyncPlayerLogin.java | 4 - .../register/ProcessSyncPasswordRegister.java | 5 - .../properties/RestrictionSettings.java | 4 - src/main/resources/config.yml | 2 - 6 files changed, 1 insertion(+), 163 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java deleted file mode 100644 index 75e06cd5..00000000 --- a/src/main/java/fr/xephi/authme/listener/protocollib/AuthMeTablistPacketAdapter.java +++ /dev/null @@ -1,120 +0,0 @@ -package fr.xephi.authme.listener.protocollib; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.events.ListenerPriority; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; -import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; -import com.comphenix.protocol.wrappers.PlayerInfoData; -import com.comphenix.protocol.wrappers.WrappedChatComponent; -import com.comphenix.protocol.wrappers.WrappedGameProfile; -import com.google.common.collect.Lists; -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.Bukkit; -import org.bukkit.entity.Player; - -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; -import java.util.logging.Level; - -class AuthMeTablistPacketAdapter extends PacketAdapter { - - private final BukkitService bukkitService; - private boolean isRegistered; - - public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) { - super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO); - this.bukkitService = bukkitService; - } - - @Override - public void onPacketSending(PacketEvent packetEvent) { - Player receiver = packetEvent.getPlayer(); - if (packetEvent.getPacketType() == PacketType.Play.Server.PLAYER_INFO - && !PlayerCache.getInstance().isAuthenticated(receiver.getName().toLowerCase())) { - //this hides the tablist for the new joining players. Already playing users will see the new player - try { - PacketContainer packet = packetEvent.getPacket(); - PlayerInfoAction playerInfoAction = packet.getPlayerInfoAction().read(0); - if (playerInfoAction == PlayerInfoAction.ADD_PLAYER) { - List playerInfoList = Lists.newArrayList(packet.getPlayerInfoDataLists().read(0)); - for (Iterator iterator = playerInfoList.iterator(); iterator.hasNext();) { - PlayerInfoData current = iterator.next(); - UUID uuid = current.getProfile().getUUID(); - if (Bukkit.getPlayer(uuid) == null) { - //player is not online -> a NPC - iterator.remove(); - } - } - - packet.getPlayerInfoDataLists().write(0, playerInfoList); - } - } catch (Exception ex) { - ConsoleLogger.logException("Couldn't modify outgoing tablist packet", ex); - } - } - } - - public void sendTablist(Player receiver) { - if (!isRegistered) { - return; - } - - WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(receiver); - - ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); - NativeGameMode gamemode = NativeGameMode.fromBukkit(receiver.getGameMode()); - - WrappedChatComponent displayName = WrappedChatComponent.fromText(receiver.getDisplayName()); - PlayerInfoData playerInfoData = new PlayerInfoData(gameProfile, 0, gamemode, displayName); - - //add info containing the skin data - PacketContainer addInfo = protocolManager.createPacket(PacketType.Play.Server.PLAYER_INFO); - addInfo.getPlayerInfoAction().write(0, PlayerInfoAction.ADD_PLAYER); - addInfo.getPlayerInfoDataLists().write(0, Arrays.asList(playerInfoData)); - - try { - //adds the skin - protocolManager.sendServerPacket(receiver, addInfo); - } catch (InvocationTargetException ex) { - plugin.getLogger().log(Level.SEVERE, "Exception sending instant skin change packet", ex); - } - - //triggers an update for others player to see them - for (Player onlinePlayer : bukkitService.getOnlinePlayers()) { - if (onlinePlayer.equals(receiver) || !receiver.canSee(onlinePlayer)) { - continue; - } - - //removes the entity and display them - receiver.hidePlayer(onlinePlayer); - receiver.showPlayer(onlinePlayer); - } - } - - public void register() { - if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) { - ProtocolLibrary.getProtocolManager().addPacketListener(this); - isRegistered = true; - } else { - ConsoleLogger.info("The hideTablist feature is not compatible with your minecraft version"); - ConsoleLogger.info("It requires 1.8+. Disabling the hideTablist feature..."); - } - } - - public void unregister() { - ProtocolLibrary.getProtocolManager().removePacketListener(this); - isRegistered = false; - } -} diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java index a3859527..d0db2664 100644 --- a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java +++ b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java @@ -15,12 +15,10 @@ public class ProtocolLibService implements SettingsDependent { /* Packet Adapters */ private AuthMeInventoryPacketAdapter inventoryPacketAdapter; private AuthMeTabCompletePacketAdapter tabCompletePacketAdapter; - private AuthMeTablistPacketAdapter tablistPacketAdapter; /* Settings */ private boolean protectInvBeforeLogin; private boolean denyTabCompleteBeforeLogin; - private boolean hideTablistBeforeLogin; /* Service */ private boolean isEnabled; @@ -44,12 +42,10 @@ public class ProtocolLibService implements SettingsDependent { if (protectInvBeforeLogin) { ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it..."); } + if (denyTabCompleteBeforeLogin) { ConsoleLogger.showError("WARNING! The denyTabComplete feature requires ProtocolLib! Disabling it..."); } - if (hideTablistBeforeLogin) { - ConsoleLogger.showError("WARNING! The hideTablist feature requires ProtocolLib! Disabling it..."); - } this.isEnabled = false; return; @@ -70,13 +66,6 @@ public class ProtocolLibService implements SettingsDependent { tabCompletePacketAdapter.unregister(); tabCompletePacketAdapter = null; } - if (hideTablistBeforeLogin && tablistPacketAdapter == null) { - tablistPacketAdapter = new AuthMeTablistPacketAdapter(plugin, bukkitService); - tablistPacketAdapter.register(); - } else if (tablistPacketAdapter != null) { - tablistPacketAdapter.unregister(); - tablistPacketAdapter = null; - } this.isEnabled = true; } @@ -92,10 +81,6 @@ public class ProtocolLibService implements SettingsDependent { tabCompletePacketAdapter.unregister(); tabCompletePacketAdapter = null; } - if (tablistPacketAdapter != null) { - tablistPacketAdapter.unregister(); - tablistPacketAdapter = null; - } } /** @@ -120,21 +105,9 @@ public class ProtocolLibService implements SettingsDependent { } } - /** - * Send a tab list packet to a player. - * - * @param player The player to send the packet to. - */ - public void sendTabList(Player player) { - if (isEnabled && tablistPacketAdapter != null) { - tablistPacketAdapter.sendTablist(player); - } - } - @Override public void loadSettings(NewSetting settings) { this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN); this.denyTabCompleteBeforeLogin = settings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN); - this.hideTablistBeforeLogin = settings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN); } } diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 783a4ed3..1752e33b 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -112,10 +112,6 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { restoreInventory(player); } - if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN)) { - protocolLibService.sendTabList(player); - } - // Clean up no longer used temporary data limboCache.deleteLimboPlayer(name); } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 524d6b1c..94b35304 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -17,7 +17,6 @@ import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.task.LimboPlayerTaskManager; import fr.xephi.authme.util.BukkitService; @@ -96,10 +95,6 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { final String name = player.getName().toLowerCase(); LimboPlayer limbo = limboCache.getLimboPlayer(name); if (limbo != null) { - if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN)) { - protocolLibService.sendTabList(player); - } - Utils.teleportToSpawn(player); if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { diff --git a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java index 3fd7b40b..e2b8d039 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java @@ -141,10 +141,6 @@ public class RestrictionSettings implements SettingsClass { public static final Property DENY_TABCOMPLETE_BEFORE_LOGIN = newProperty("settings.restrictions.DenyTabCompleteBeforeLogin", true); - @Comment("Should we hide the tablist before logging in? Requires ProtocolLib.") - public static final Property HIDE_TABLIST_BEFORE_LOGIN = - newProperty("settings.restrictions.HideTablistBeforeLogin", true); - @Comment({ "Should we display all other accounts from a player when he joins?", "permission: /authme.admin.accounts"}) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 99cc3a2b..7c6d0cae 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -141,8 +141,6 @@ settings: ProtectInventoryBeforeLogIn: true # Should we deny the tabcomplete feature before logging in? Requires ProtocolLib. DenyTabCompleteBeforeLogin: true - # Should we hide the tablist before logging in? Requires ProtocolLib. - HideTablistBeforeLogin: true # Should we display all other accounts from a player when he joins? # permission: /authme.admin.accounts displayOtherAccounts: true From f1d5f3df28471702180d6e16e5ebdb704a08fa93 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 15:18:13 +0200 Subject: [PATCH 070/217] Merge conversion classes to one class per conversion type - Fix issues in #736 using service getters --- .../executable/authme/ConverterCommand.java | 7 +- .../authme/converter/vAuthConverter.java | 67 +++++++-- .../authme/converter/vAuthFileReader.java | 83 ----------- .../authme/converter/xAuthConverter.java | 132 ++++++++++++++++- .../xephi/authme/converter/xAuthToFlat.java | 136 ------------------ 5 files changed, 189 insertions(+), 236 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/converter/vAuthFileReader.java delete mode 100644 src/main/java/fr/xephi/authme/converter/xAuthToFlat.java diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java index e18c9dc4..fef7cfb3 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java @@ -1,6 +1,7 @@ package fr.xephi.authme.command.executable.authme; import com.google.common.annotations.VisibleForTesting; +import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.converter.Converter; @@ -51,7 +52,11 @@ public class ConverterCommand implements ExecutableCommand { bukkitService.runTaskAsynchronously(new Runnable() { @Override public void run() { - converter.execute(sender); + try { + converter.execute(sender); + } catch (Exception e) { + ConsoleLogger.logException("Error during conversion:", e); + } } }); diff --git a/src/main/java/fr/xephi/authme/converter/vAuthConverter.java b/src/main/java/fr/xephi/authme/converter/vAuthConverter.java index 7c6f3ea5..9c116f02 100644 --- a/src/main/java/fr/xephi/authme/converter/vAuthConverter.java +++ b/src/main/java/fr/xephi/authme/converter/vAuthConverter.java @@ -1,28 +1,77 @@ package fr.xephi.authme.converter; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.initialization.DataFolder; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Scanner; +import java.util.UUID; + +import static fr.xephi.authme.util.StringUtils.makePath; public class vAuthConverter implements Converter { - private final AuthMe plugin; + private final DataSource dataSource; + private final File vAuthPasswordsFile; @Inject - vAuthConverter(AuthMe plugin) { - this.plugin = plugin; + vAuthConverter(@DataFolder File dataFolder, DataSource dataSource) { + vAuthPasswordsFile = new File(dataFolder.getParent(), makePath("vAuth", "passwords.yml")); + this.dataSource = dataSource; } @Override public void execute(CommandSender sender) { - try { - new vAuthFileReader(plugin).convert(); - } catch (Exception e) { - sender.sendMessage(e.getMessage()); - ConsoleLogger.showError(e.getMessage()); + try (Scanner scanner = new Scanner(vAuthPasswordsFile)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + String name = line.split(": ")[0]; + String password = line.split(": ")[1]; + PlayerAuth auth; + if (isUuidInstance(password)) { + String pname; + try { + pname = Bukkit.getOfflinePlayer(UUID.fromString(name)).getName(); + } catch (Exception | NoSuchMethodError e) { + pname = getName(UUID.fromString(name)); + } + if (pname == null) + continue; + auth = PlayerAuth.builder() + .name(pname.toLowerCase()) + .realName(pname) + .password(password, null).build(); + } else { + auth = PlayerAuth.builder() + .name(name.toLowerCase()) + .realName(name) + .password(password, null).build(); + } + dataSource.saveAuth(auth); + } + } catch (IOException e) { + ConsoleLogger.logException("Error while trying to import some vAuth data", e); } } + private static boolean isUuidInstance(String s) { + return s.length() > 8 && s.charAt(8) == '-'; + } + + private String getName(UUID uuid) { + for (OfflinePlayer op : Bukkit.getOfflinePlayers()) { + if (op.getUniqueId().compareTo(uuid) == 0) { + return op.getName(); + } + } + return null; + } + } diff --git a/src/main/java/fr/xephi/authme/converter/vAuthFileReader.java b/src/main/java/fr/xephi/authme/converter/vAuthFileReader.java deleted file mode 100644 index 4c5b3b4f..00000000 --- a/src/main/java/fr/xephi/authme/converter/vAuthFileReader.java +++ /dev/null @@ -1,83 +0,0 @@ -package fr.xephi.authme.converter; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; - -import java.io.File; -import java.io.IOException; -import java.util.Scanner; -import java.util.UUID; - -import static fr.xephi.authme.util.StringUtils.makePath; - -class vAuthFileReader { - - private final AuthMe plugin; - private final DataSource database; - - /** - * Constructor for vAuthFileReader. - * - * @param plugin AuthMe - */ - public vAuthFileReader(AuthMe plugin) { - this.plugin = plugin; - this.database = plugin.getDataSource(); - } - - public void convert() { - final File file = new File(plugin.getDataFolder().getParent(), makePath("vAuth", "passwords.yml")); - Scanner scanner; - try { - scanner = new Scanner(file); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - String name = line.split(": ")[0]; - String password = line.split(": ")[1]; - PlayerAuth auth; - if (isUuidInstance(password)) { - String pname; - try { - pname = Bukkit.getOfflinePlayer(UUID.fromString(name)).getName(); - } catch (Exception | NoSuchMethodError e) { - pname = getName(UUID.fromString(name)); - } - if (pname == null) - continue; - auth = PlayerAuth.builder() - .name(pname.toLowerCase()) - .realName(pname) - .password(password, null).build(); - } else { - auth = PlayerAuth.builder() - .name(name.toLowerCase()) - .realName(name) - .password(password, null).build(); - } - database.saveAuth(auth); - } - scanner.close(); - } catch (IOException e) { - ConsoleLogger.logException("Error while trying to import some vAuth data", e); - } - - } - - private static boolean isUuidInstance(String s) { - return s.length() > 8 && s.charAt(8) == '-'; - } - - private String getName(UUID uuid) { - for (OfflinePlayer op : Bukkit.getOfflinePlayers()) { - if (op.getUniqueId().compareTo(uuid) == 0) { - return op.getName(); - } - } - return null; - } - -} diff --git a/src/main/java/fr/xephi/authme/converter/xAuthConverter.java b/src/main/java/fr/xephi/authme/converter/xAuthConverter.java index 6fdddbf7..37dfc9fe 100644 --- a/src/main/java/fr/xephi/authme/converter/xAuthConverter.java +++ b/src/main/java/fr/xephi/authme/converter/xAuthConverter.java @@ -1,28 +1,146 @@ package fr.xephi.authme.converter; -import fr.xephi.authme.AuthMe; +import de.luricos.bukkit.xAuth.database.DatabaseTables; +import de.luricos.bukkit.xAuth.utils.xAuthLog; +import de.luricos.bukkit.xAuth.xAuth; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.util.CollectionUtils; import org.bukkit.command.CommandSender; +import org.bukkit.plugin.PluginManager; import javax.inject.Inject; +import java.io.File; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import static fr.xephi.authme.util.StringUtils.makePath; public class xAuthConverter implements Converter { - private final AuthMe plugin; - @Inject - xAuthConverter(AuthMe plugin) { - this.plugin = plugin; + @DataFolder + private File dataFolder; + @Inject + private DataSource database; + @Inject + private PluginManager pluginManager; + + xAuthConverter() { } @Override public void execute(CommandSender sender) { try { Class.forName("de.luricos.bukkit.xAuth.xAuth"); - xAuthToFlat converter = new xAuthToFlat(plugin, sender); - converter.convert(); + convert(sender); } catch (ClassNotFoundException ce) { sender.sendMessage("xAuth has not been found, please put xAuth.jar in your plugin folder and restart!"); } } + private void convert(CommandSender sender) { + if (pluginManager.getPlugin("xAuth") == null) { + sender.sendMessage("[AuthMe] xAuth plugin not found"); + return; + } + // TODO ljacqu 20160702: xAuthDb is not used except for the existence check -- is this intended? + File xAuthDb = new File(dataFolder.getParent(), makePath("xAuth", "xAuth.h2.db")); + if (!xAuthDb.exists()) { + sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data..."); + } + List players = getXAuthPlayers(); + if (CollectionUtils.isEmpty(players)) { + sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players"); + return; + } + sender.sendMessage("[AuthMe] Starting import..."); + + for (int id : players) { + String pl = getIdPlayer(id); + String psw = getPassword(id); + if (psw != null && !psw.isEmpty() && pl != null) { + PlayerAuth auth = PlayerAuth.builder() + .name(pl.toLowerCase()) + .realName(pl) + .password(psw, null).build(); + database.saveAuth(auth); + } + } + sender.sendMessage("[AuthMe] Successfully converted from xAuth database"); + } + + private String getIdPlayer(int id) { + String realPass = ""; + Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = String.format("SELECT `playername` FROM `%s` WHERE `id` = ?", + xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); + ps = conn.prepareStatement(sql); + ps.setInt(1, id); + rs = ps.executeQuery(); + if (!rs.next()) + return null; + realPass = rs.getString("playername").toLowerCase(); + } catch (SQLException e) { + xAuthLog.severe("Failed to retrieve name for account: " + id, e); + return null; + } finally { + xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); + } + return realPass; + } + + private List getXAuthPlayers() { + List xP = new ArrayList<>(); + Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = String.format("SELECT * FROM `%s`", + xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); + ps = conn.prepareStatement(sql); + rs = ps.executeQuery(); + while (rs.next()) { + xP.add(rs.getInt("id")); + } + } catch (SQLException e) { + xAuthLog.severe("Cannot import xAuthPlayers", e); + return new ArrayList<>(); + } finally { + xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); + } + return xP; + } + + private String getPassword(int accountId) { + String realPass = ""; + Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?", + xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); + ps = conn.prepareStatement(sql); + ps.setInt(1, accountId); + rs = ps.executeQuery(); + if (!rs.next()) + return null; + realPass = rs.getString("password"); + } catch (SQLException e) { + xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e); + return null; + } finally { + xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); + } + return realPass; + } + } diff --git a/src/main/java/fr/xephi/authme/converter/xAuthToFlat.java b/src/main/java/fr/xephi/authme/converter/xAuthToFlat.java deleted file mode 100644 index 34ec2a5e..00000000 --- a/src/main/java/fr/xephi/authme/converter/xAuthToFlat.java +++ /dev/null @@ -1,136 +0,0 @@ -package fr.xephi.authme.converter; - -import de.luricos.bukkit.xAuth.database.DatabaseTables; -import de.luricos.bukkit.xAuth.utils.xAuthLog; -import de.luricos.bukkit.xAuth.xAuth; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.util.CollectionUtils; -import org.bukkit.command.CommandSender; - -import java.io.File; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -class xAuthToFlat { - - private final AuthMe instance; - private final DataSource database; - private final CommandSender sender; - - public xAuthToFlat(AuthMe instance, CommandSender sender) { - this.instance = instance; - this.database = instance.getDataSource(); - this.sender = sender; - } - - public boolean convert() { - if (instance.getServer().getPluginManager().getPlugin("xAuth") == null) { - sender.sendMessage("[AuthMe] xAuth plugin not found"); - return false; - } - File xAuthDb = new File(instance.getDataFolder().getParent(), "xAuth" + File.separator + "xAuth.h2.db"); - if (!xAuthDb.exists()) { - sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data..."); - } - List players = getXAuthPlayers(); - if (CollectionUtils.isEmpty(players)) { - sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players"); - return false; - } - sender.sendMessage("[AuthMe] Starting import..."); - try { - for (int id : players) { - String pl = getIdPlayer(id); - String psw = getPassword(id); - if (psw != null && !psw.isEmpty() && pl != null) { - PlayerAuth auth = PlayerAuth.builder() - .name(pl.toLowerCase()) - .realName(pl) - .password(psw, null).build(); - database.saveAuth(auth); - } - } - sender.sendMessage("[AuthMe] Successfully converted from xAuth database"); - } catch (Exception e) { - sender.sendMessage("[AuthMe] An error has occurred while importing the xAuth database." - + " The import may have succeeded partially."); - ConsoleLogger.logException("Error during xAuth database import", e); - } - return true; - } - - private String getIdPlayer(int id) { - String realPass = ""; - Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = String.format("SELECT `playername` FROM `%s` WHERE `id` = ?", - xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); - ps = conn.prepareStatement(sql); - ps.setInt(1, id); - rs = ps.executeQuery(); - if (!rs.next()) - return null; - realPass = rs.getString("playername").toLowerCase(); - } catch (SQLException e) { - xAuthLog.severe("Failed to retrieve name for account: " + id, e); - return null; - } finally { - xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); - } - return realPass; - } - - private List getXAuthPlayers() { - List xP = new ArrayList<>(); - Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = String.format("SELECT * FROM `%s`", - xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); - ps = conn.prepareStatement(sql); - rs = ps.executeQuery(); - while (rs.next()) { - xP.add(rs.getInt("id")); - } - } catch (SQLException e) { - xAuthLog.severe("Cannot import xAuthPlayers", e); - return new ArrayList<>(); - } finally { - xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); - } - return xP; - } - - private String getPassword(int accountId) { - String realPass = ""; - Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?", - xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); - ps = conn.prepareStatement(sql); - ps.setInt(1, accountId); - rs = ps.executeQuery(); - if (!rs.next()) - return null; - realPass = rs.getString("password"); - } catch (SQLException e) { - xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e); - return null; - } finally { - xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); - } - return realPass; - } -} From 22911a0bb9eddb8431164d6c94c8929d7dc4c92e Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 19:16:26 +0200 Subject: [PATCH 071/217] Remove duplicate column initialization code, add datasource integration tests - Drop initialization of all columns on table create in favor of checking each column individually. This is slower but guarantees that each column is only defined once in the code. Columns are only created once so having clean code outweighs performance. - Write more datasource integration tests --- .../fr/xephi/authme/datasource/MySQL.java | 26 +---- .../fr/xephi/authme/datasource/SQLite.java | 106 +++++++++--------- .../fr/xephi/authme/settings/Settings.java | 8 -- .../AbstractDataSourceIntegrationTest.java | 64 +++++++++++ .../datasource/MySqlIntegrationTest.java | 7 +- .../datasource/SQLiteIntegrationTest.java | 55 ++++++++- 6 files changed, 185 insertions(+), 81 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 3902e3e5..d60f867f 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -3,14 +3,12 @@ package fr.xephi.authme.datasource; import com.google.common.annotations.VisibleForTesting; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; - import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.XFBCRYPT; import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.SecuritySettings; @@ -69,7 +67,7 @@ public class MySQL implements DataSource { // Initialize the database try { - setupConnection(); + checkTablesAndColumns(); } catch (SQLException e) { close(); ConsoleLogger.logException("Can't initialize the MySQL database:", e); @@ -140,24 +138,13 @@ public class MySQL implements DataSource { return ds.getConnection(); } - private void setupConnection() throws SQLException { + private void checkTablesAndColumns() throws SQLException { try (Connection con = getConnection(); Statement st = con.createStatement()) { - // Create table if not exists. + // Create table with ID column if it doesn't exist String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" + col.ID + " MEDIUMINT(8) UNSIGNED AUTO_INCREMENT," - + col.NAME + " VARCHAR(255) NOT NULL UNIQUE," - + col.REAL_NAME + " VARCHAR(255) NOT NULL," - + col.PASSWORD + " VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL," - + col.IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '127.0.0.1'," - + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0," - + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0'," - + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0'," - + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0'," - + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," - + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com'," - + col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0'," + "PRIMARY KEY (" + col.ID + ")" - + ") CHARACTER SET = utf8"; + + ") CHARACTER SET = utf8;"; st.executeUpdate(sql); DatabaseMetaData md = con.getMetaData(); @@ -177,8 +164,7 @@ public class MySQL implements DataSource { } if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); + st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); } if (isColumnMissing(md, col.IP)) { @@ -219,8 +205,6 @@ public class MySQL implements DataSource { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.EMAIL); } - - st.close(); } ConsoleLogger.info("MySQL setup finished"); } diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index d5109af2..a60dfd0d 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -5,11 +5,11 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.util.StringUtils; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -69,67 +69,73 @@ public class SQLite implements DataSource { this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); } - private void setup() throws SQLException { - Statement st = null; - ResultSet rs = null; - try { - st = con.createStatement(); - st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" + col.ID + " INTEGER AUTO_INCREMENT," + col.NAME + " VARCHAR(255) NOT NULL UNIQUE," + col.PASSWORD + " VARCHAR(255) NOT NULL," + col.IP + " VARCHAR(40) NOT NULL," + col.LAST_LOGIN + " BIGINT," + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com'," + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));"); - rs = con.getMetaData().getColumns(null, null, tableName, col.PASSWORD); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;"); + @VisibleForTesting + protected void setup() throws SQLException { + try (Statement st = con.createStatement()) { + // Note: cannot add unique fields later on in SQLite, so we add it on initialization + st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" + + col.ID + " INTEGER AUTO_INCREMENT, " + + col.NAME + " VARCHAR(255) NOT NULL UNIQUE, " + + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));"); + + DatabaseMetaData md = con.getMetaData(); + + if (isColumnMissing(md, col.REAL_NAME)) { + st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + + col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';"); } - rs.close(); - if (!col.SALT.isEmpty()) { - rs = con.getMetaData().getColumns(null, null, tableName, col.SALT); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); - } - rs.close(); + + if (isColumnMissing(md, col.PASSWORD)) { + st.executeUpdate("ALTER TABLE " + tableName + + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL DEFAULT '';"); } - rs = con.getMetaData().getColumns(null, null, tableName, col.IP); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;"); + + if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { + st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); } - rs.close(); - rs = con.getMetaData().getColumns(null, null, tableName, col.LAST_LOGIN); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP DEFAULT current_timestamp;"); + + if (isColumnMissing(md, col.IP)) { + st.executeUpdate("ALTER TABLE " + tableName + + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL DEFAULT '';"); } - rs.close(); - rs = con.getMetaData().getColumns(null, null, tableName, col.LASTLOC_X); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0';"); - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0';"); - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';"); + + if (isColumnMissing(md, col.LAST_LOGIN)) { + st.executeUpdate("ALTER TABLE " + tableName + + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP;"); } - rs.close(); - rs = con.getMetaData().getColumns(null, null, tableName, col.LASTLOC_WORLD); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';"); + + if (isColumnMissing(md, col.LASTLOC_X)) { + st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X + + " DOUBLE NOT NULL DEFAULT '0.0';"); + st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Y + + " DOUBLE NOT NULL DEFAULT '0.0';"); + st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Z + + " DOUBLE NOT NULL DEFAULT '0.0';"); } - rs.close(); - rs = con.getMetaData().getColumns(null, null, tableName, col.EMAIL); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';"); + + if (isColumnMissing(md, col.LASTLOC_WORLD)) { + st.executeUpdate("ALTER TABLE " + tableName + + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';"); } - rs.close(); - rs = con.getMetaData().getColumns(null, null, tableName, col.IS_LOGGED); - if (!rs.next()) { + + if (isColumnMissing(md, col.EMAIL)) { + st.executeUpdate("ALTER TABLE " + tableName + + " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';"); + } + + if (isColumnMissing(md, col.IS_LOGGED)) { st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IS_LOGGED + " INT DEFAULT '0';"); } - rs.close(); - rs = con.getMetaData().getColumns(null, null, tableName, col.REAL_NAME); - if (!rs.next()) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';"); - } - } finally { - close(rs); - close(st); } ConsoleLogger.info("SQLite Setup finished"); } + private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException { + try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) { + return !rs.next(); + } + } + @Override public void reload() { close(con); @@ -146,7 +152,7 @@ public class SQLite implements DataSource { PreparedStatement pst = null; ResultSet rs = null; try { - pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"); + pst = con.prepareStatement("SELECT 1 FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"); pst.setString(1, user); rs = pst.executeQuery(); return rs.next(); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 6e843001..d13fc4de 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -18,20 +18,16 @@ public final class Settings { public static List getUnrestrictedName; public static boolean isPermissionCheckEnabled; public static boolean isTeleportToSpawnEnabled; - public static boolean isSessionsEnabled; public static boolean isAllowRestrictedIp; public static boolean isSaveQuitLocationEnabled; public static boolean protectInventoryBeforeLogInEnabled; public static boolean isStopEnabled; public static boolean reloadSupport; public static boolean noTeleport; - public static boolean isRemoveSpeedEnabled; public static String getUnloggedinGroup; public static String unRegisteredGroup; public static String getRegisteredGroup; public static String defaultWorld; - public static String crazyloginFileName; - public static int getSessionTimeout; public static int getNonActivatedGroup; private static FileConfiguration configFile; @@ -48,10 +44,7 @@ public final class Settings { private static void loadVariables() { isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK); isTeleportToSpawnEnabled = load(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN); - isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED); - getSessionTimeout = configFile.getInt("settings.sessions.timeout", 10); isAllowRestrictedIp = load(RestrictionSettings.ENABLE_RESTRICTED_USERS); - isRemoveSpeedEnabled = load(RestrictionSettings.REMOVE_SPEED); isSaveQuitLocationEnabled = load(RestrictionSettings.SAVE_QUIT_LOCATION); getUnloggedinGroup = load(SecuritySettings.UNLOGGEDIN_GROUP); getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1); @@ -63,7 +56,6 @@ public final class Settings { reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); defaultWorld = configFile.getString("Purge.defaultWorld", "world"); noTeleport = load(RestrictionSettings.NO_TELEPORT); - crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db"); } /** diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java index e9488a40..0c0d217b 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java @@ -12,6 +12,9 @@ import java.util.Set; import static fr.xephi.authme.AuthMeMatchers.equalToHash; import static fr.xephi.authme.AuthMeMatchers.hasAuthBasicData; import static fr.xephi.authme.AuthMeMatchers.hasAuthLocation; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; @@ -170,6 +173,22 @@ public abstract class AbstractDataSourceIntegrationTest { assertThat(dataSource.getPassword("user"), equalToHash("new_hash")); } + @Test + public void shouldUpdatePasswordWithPlayerAuth() { + // given + DataSource dataSource = getDataSource("salt"); + PlayerAuth bobbyAuth = PlayerAuth.builder().name("bobby").password(new HashedPassword("tt", "cc")).build(); + PlayerAuth invalidAuth = PlayerAuth.builder().name("invalid").password(new HashedPassword("tt", "cc")).build(); + + // when + boolean response1 = dataSource.updatePassword(bobbyAuth); + boolean response2 = dataSource.updatePassword(invalidAuth); + + // then + assertThat(response1 && response2, equalTo(true)); + assertThat(dataSource.getPassword("bobby"), equalToHash("tt", "cc")); + } + @Test public void shouldRemovePlayerAuth() { // given @@ -321,4 +340,49 @@ public abstract class AbstractDataSourceIntegrationTest { assertThat(dataSource.getAuth("bobby"), hasAuthBasicData("bobby", "BOBBY", "your@email.com", "123.45.67.89")); } + @Test + public void shouldGetRecordsToPurge() { + // given + DataSource dataSource = getDataSource(); + // 1453242857 -> user, 1449136800 -> bobby + + // when + Set records1 = dataSource.getRecordsToPurge(1450000000); + Set records2 = dataSource.getRecordsToPurge(1460000000); + + // then + assertThat(records1, contains("bobby")); + assertThat(records2, containsInAnyOrder("bobby", "user")); + // check that the entry was not deleted because of running this command + assertThat(dataSource.isAuthAvailable("bobby"), equalTo(true)); + } + + @Test + public void shouldPerformOperationsOnIsLoggedColumnSuccessfully() { + DataSource dataSource = getDataSource(); + // on startup no one should be marked as logged + assertThat(dataSource.getLoggedPlayers(), empty()); + + // Mark user as logged + dataSource.setLogged("user"); + // non-existent user should not break database + dataSource.setLogged("does-not-exist"); + + assertThat(dataSource.isLogged("user"), equalTo(true)); + assertThat(dataSource.isLogged("bobby"), equalTo(false)); + + // Set bobby logged and unlog user + dataSource.setLogged("bobby"); + dataSource.setUnlogged("user"); + assertThat(dataSource.getLoggedPlayers(), + contains(hasAuthBasicData("bobby", "Bobby", "your@email.com", "123.45.67.89"))); + + // Set both as logged (even if Bobby already is logged) + dataSource.setLogged("user"); + dataSource.setLogged("bobby"); + dataSource.purgeLogged(); + assertThat(dataSource.isLogged("user"), equalTo(false)); + assertThat(dataSource.getLoggedPlayers(), empty()); + } + } diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java index 39769306..8289d837 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -6,6 +6,7 @@ import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.DatabaseSettings; +import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.mockito.invocation.InvocationOnMock; @@ -60,7 +61,6 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { @Before public void initializeConnectionAndTable() throws SQLException { - silentClose(hikariSource); HikariConfig config = new HikariConfig(); config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); config.setConnectionTestQuery("VALUES 1"); @@ -77,6 +77,11 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { hikariSource = ds; } + @After + public void closeConnection() { + silentClose(hikariSource); + } + @Override protected DataSource getDataSource(String saltColumn) { when(settings.getProperty(DatabaseSettings.MYSQL_COL_SALT)).thenReturn(saltColumn); diff --git a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java index a654fca6..76d01655 100644 --- a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java @@ -1,11 +1,14 @@ package fr.xephi.authme.datasource; import fr.xephi.authme.TestHelper; +import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.DatabaseSettings; +import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -17,6 +20,8 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -61,7 +66,6 @@ public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest { @Before public void initializeConnectionAndTable() throws SQLException { - silentClose(con); Connection connection = DriverManager.getConnection("jdbc:sqlite::memory:"); try (Statement st = connection.createStatement()) { st.execute("DROP TABLE IF EXISTS authme"); @@ -72,6 +76,55 @@ public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest { con = connection; } + @After + public void closeConnection() { + silentClose(con); + } + + @Test + public void shouldSetUpTableIfMissing() throws SQLException { + // given + Statement st = con.createStatement(); + // table is absent + st.execute("DROP TABLE authme"); + SQLite sqLite = new SQLite(settings, con); + + // when + sqLite.setup(); + + // then + // Save some player to verify database is operational + sqLite.saveAuth(PlayerAuth.builder().name("Name").build()); + assertThat(sqLite.getAllAuths(), hasSize(1)); + } + + @Test + public void shouldCreateMissingColumns() throws SQLException { + // given + Statement st = con.createStatement(); + // drop table and create one with only some of the columns: SQLite doesn't support ALTER TABLE t DROP COLUMN c + st.execute("DROP TABLE authme"); + st.execute("CREATE TABLE authme (" + + "id bigint, " + + "username varchar(255) unique, " + + "password varchar(255) not null, " + + "primary key (id));"); + SQLite sqLite = new SQLite(settings, con); + + // when + sqLite.setup(); + + // then + // Save some player to verify database is operational + sqLite.saveAuth(PlayerAuth.builder().name("Name").build()); + assertThat(sqLite.getAllAuths(), hasSize(1)); + } + + @Test + public void shouldCreate2() throws SQLException { + con.createStatement().execute("SELECT 1 from authme"); + } + @Override protected DataSource getDataSource(String saltColumn) { when(settings.getProperty(DatabaseSettings.MYSQL_COL_SALT)).thenReturn(saltColumn); From d2556b8a045eb8de9debb07cc00c158c2ea6d36b Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 19:39:13 +0200 Subject: [PATCH 072/217] #817 Sessions timeout - remove mention of 0 = unlimited in config comments --- .../java/fr/xephi/authme/settings/properties/PluginSettings.java | 1 - src/main/resources/config.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java index cf0f7932..0a3722ac 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java @@ -25,7 +25,6 @@ public class PluginSettings implements SettingsClass { @Comment({ "After how many minutes should a session expire?", - "0 for unlimited time (Very dangerous, use it at your own risk!)", "Remember that sessions will end only after the timeout, and", "if the player's IP has changed but the timeout hasn't expired,", "the player will be kicked from the server due to invalid session" diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7c6d0cae..8d4a0f0f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -54,7 +54,6 @@ settings: # hasn't expired, he will not need to authenticate. enabled: false # After how many minutes a session should expire? - # 0 for unlimited time (Very dangerous, use it at your own risk!) # Consider that session will end only after the timeout time, and # if the player's ip has changed but the timeout hasn't expired, # player will be kicked out of sever due to invalidSession! From 9a5c43250988ca984f75161ff43ff1fa02ee37da Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 20:56:53 +0200 Subject: [PATCH 073/217] #655 Encapsulate mail service - Change SendMailSSL to be injected into classes and created regardless of settings - Various minor cleanups (remove accidentally committed test, add more precise logging statement) --- src/main/java/fr/xephi/authme/AuthMe.java | 26 -------- .../authme/ChangePasswordAdminCommand.java | 2 +- .../executable/email/RecoverEmailCommand.java | 9 ++- .../executable/register/RegisterCommand.java | 12 ++-- .../fr/xephi/authme/datasource/MySQL.java | 2 - .../fr/xephi/authme/mail/SendMailSSL.java | 66 +++++++++++++------ .../process/register/AsyncRegister.java | 6 +- .../register/RegisterCommandTest.java | 24 +++++-- .../datasource/SQLiteIntegrationTest.java | 5 -- 9 files changed, 80 insertions(+), 72 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 3acb8ca8..6959b19e 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -25,7 +25,6 @@ import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.listener.AuthMePlayerListener16; import fr.xephi.authme.listener.AuthMePlayerListener18; import fr.xephi.authme.listener.AuthMeServerListener; -import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.output.ConsoleFilter; import fr.xephi.authme.output.Log4JFilter; import fr.xephi.authme.output.MessageKey; @@ -79,8 +78,6 @@ import java.util.List; import java.util.logging.Level; 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; /** @@ -114,7 +111,6 @@ public class AuthMe extends JavaPlugin { private BukkitService bukkitService; private AuthMeServiceInitializer initializer; private GeoLiteAPI geoLiteApi; - private SendMailSSL mail; /** * Constructor. @@ -248,9 +244,6 @@ public class AuthMe extends JavaPlugin { // Set console filter setupConsoleFilter(); - // Set up the mail API - setupMailApi(); - // Do a backup on start // TODO: maybe create a backup manager? new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.START); @@ -303,16 +296,6 @@ public class AuthMe extends JavaPlugin { initializer.get(API.class); } - /** - * Set up the mail API, if enabled. - */ - private void setupMailApi() { - // Make sure the mail API is enabled - if (!newSettings.getProperty(MAIL_ACCOUNT).isEmpty() && !newSettings.getProperty(MAIL_PASSWORD).isEmpty()) { - this.mail = new SendMailSSL(this, newSettings); - } - } - /** * Show the settings warnings, for various risky settings. */ @@ -673,15 +656,6 @@ public class AuthMe extends JavaPlugin { return commandHandler.processCommand(sender, commandLabel, args); } - /** - * Get the mailing instance. - * - * @return The send mail instance. - */ - public SendMailSSL getMail() { - return this.mail; - } - // ------------- // Service getters (deprecated) // Use @Inject fields instead diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java index 729a4b4e..d55e84ac 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java @@ -75,7 +75,7 @@ public class ChangePasswordAdminCommand implements ExecutableCommand { if (dataSource.updatePassword(auth)) { commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS); - ConsoleLogger.info(playerNameLowerCase + "'s password changed"); + ConsoleLogger.info(sender.getName() + " changed password of " + playerNameLowerCase); } else { commandService.send(sender, MessageKey.ERROR); } diff --git a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java index 636027bb..8a874af7 100644 --- a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java @@ -1,12 +1,12 @@ package fr.xephi.authme.command.executable.email; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.RandomString; @@ -33,15 +33,14 @@ public class RecoverEmailCommand extends PlayerCommand { private PlayerCache playerCache; @Inject - // TODO #655: Remove injected AuthMe instance once Authme#mail is encapsulated - private AuthMe plugin; + private SendMailSSL sendMailSsl; @Override public void runCommand(Player player, List arguments) { final String playerMail = arguments.get(0); final String playerName = player.getName(); - if (plugin.getMail() == null) { + if (!sendMailSsl.hasAllInformation()) { ConsoleLogger.showError("Mail API is not set"); commandService.send(player, MessageKey.ERROR); return; @@ -76,7 +75,7 @@ public class RecoverEmailCommand extends PlayerCommand { } auth.setPassword(hashNew); dataSource.updatePassword(auth); - plugin.getMail().main(auth, thePass); + sendMailSsl.sendPasswordMail(auth, thePass); commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE); } else { commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE); diff --git a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java index ed9f9eef..cb8c1946 100644 --- a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java @@ -3,6 +3,7 @@ package fr.xephi.authme.command.executable.register; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.PlayerCommand; +import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Management; import fr.xephi.authme.security.HashAlgorithm; @@ -27,6 +28,9 @@ public class RegisterCommand extends PlayerCommand { @Inject private CommandService commandService; + @Inject + private SendMailSSL sendMailSsl; + @Override public void runCommand(Player player, List arguments) { if (commandService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) { @@ -63,11 +67,11 @@ public class RegisterCommand extends PlayerCommand { } private void handleEmailRegistration(Player player, List arguments) { - if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { - player.sendMessage("Cannot register: no email address is set for the server. " + if (!sendMailSsl.hasAllInformation()) { + player.sendMessage("Cannot register: not all required settings are set for sending emails. " + "Please contact an administrator"); - ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email is set " - + "to send emails from. Please add one in your config at " + EmailSettings.MAIL_ACCOUNT.getPath()); + ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email or password is set " + + "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath()); return; } diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index d60f867f..e1720f95 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -54,12 +54,10 @@ public class MySQL implements DataSource { if (e instanceof IllegalArgumentException) { ConsoleLogger.showError("Invalid database arguments! Please check your configuration!"); ConsoleLogger.showError("If this error persists, please report it to the developer!"); - throw e; } if (e instanceof PoolInitializationException) { ConsoleLogger.showError("Can't initialize database connection! Please check your configuration!"); ConsoleLogger.showError("If this error persists, please report it to the developer!"); - throw new PoolInitializationException(e); } ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer!"); throw e; diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java index 58b64d6b..949f3777 100644 --- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java +++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java @@ -5,45 +5,72 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.EmailSettings; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.StringUtils; import org.apache.commons.mail.EmailConstants; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.HtmlEmail; -import org.bukkit.Bukkit; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.imageio.ImageIO; +import javax.inject.Inject; import javax.mail.Session; import java.io.File; import java.io.IOException; import java.security.Security; import java.util.Properties; +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT; +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD; + /** * @author Xephi59 */ public class SendMailSSL { - private final AuthMe plugin; - private final NewSetting settings; + @Inject + private AuthMe plugin; + @Inject + private NewSetting settings; + @Inject + private BukkitService bukkitService; - public SendMailSSL(AuthMe plugin, NewSetting settings) { - this.plugin = plugin; - this.settings = settings; + SendMailSSL() { } - public void main(final PlayerAuth auth, final String newPass) { - final String mailText = replaceMailTags(settings.getEmailMessage(), plugin, auth, newPass); - Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { + /** + * Returns whether all necessary settings are set for sending mails. + * + * @return true if the necessary email settings are set, false otherwise + */ + public boolean hasAllInformation() { + return !settings.getProperty(MAIL_ACCOUNT).isEmpty() + && !settings.getProperty(MAIL_PASSWORD).isEmpty(); + } + + /** + * Sends an email to the user with his new password. + * + * @param auth the player auth of the player + * @param newPass the new password + */ + public void sendPasswordMail(final PlayerAuth auth, final String newPass) { + if (!hasAllInformation()) { + ConsoleLogger.showError("Cannot perform email registration: not all email settings are complete"); + return; + } + + final String mailText = replaceMailTags(settings.getEmailMessage(), auth, newPass); + bukkitService.runTaskAsynchronously(new Runnable() { @Override public void run() { Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); HtmlEmail email; try { - email = initializeMail(auth, settings); + email = initializeMail(auth.getEmail()); } catch (EmailException e) { ConsoleLogger.logException("Failed to create email with the given settings:", e); return; @@ -54,7 +81,7 @@ public class SendMailSSL { File file = null; if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) { try { - file = generateImage(auth, plugin, newPass); + file = generateImage(auth.getNickname(), plugin, newPass); content = embedImageIntoEmailContent(file, email, content); } catch (IOException | EmailException e) { ConsoleLogger.logException( @@ -67,13 +94,12 @@ public class SendMailSSL { file.delete(); } } - }); } - private static File generateImage(PlayerAuth auth, AuthMe plugin, String newPass) throws IOException { + private static File generateImage(String name, AuthMe plugin, String newPass) throws IOException { ImageGenerator gen = new ImageGenerator(newPass); - File file = new File(plugin.getDataFolder(), auth.getNickname() + "_new_pass.jpg"); + File file = new File(plugin.getDataFolder(), name + "_new_pass.jpg"); ImageIO.write(gen.generateImage(), "jpg", file); return file; } @@ -85,8 +111,7 @@ public class SendMailSSL { return content.replace("", ""); } - private static HtmlEmail initializeMail(PlayerAuth auth, NewSetting settings) - throws EmailException { + private HtmlEmail initializeMail(String emailAddress) throws EmailException { String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT); String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME)) ? senderMail @@ -98,12 +123,12 @@ public class SendMailSSL { email.setCharset(EmailConstants.UTF_8); email.setSmtpPort(port); email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST)); - email.addTo(auth.getEmail()); + email.addTo(emailAddress); email.setFrom(senderMail, senderName); email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT)); email.setAuthentication(senderMail, mailPassword); - setPropertiesForPort(email, port, settings); + setPropertiesForPort(email, port); return email; } @@ -124,15 +149,14 @@ public class SendMailSSL { } } - private static String replaceMailTags(String mailText, AuthMe plugin, PlayerAuth auth, String newPass) { + private String replaceMailTags(String mailText, PlayerAuth auth, String newPass) { return mailText .replace("", auth.getNickname()) .replace("", plugin.getServer().getServerName()) .replace("", newPass); } - private static void setPropertiesForPort(HtmlEmail email, int port, NewSetting settings) - throws EmailException { + private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException { switch (port) { case 587: String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN); diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java index 4ddaff5e..056ae36c 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -4,6 +4,7 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.process.AsynchronousProcess; @@ -55,6 +56,9 @@ public class AsyncRegister implements AsynchronousProcess { @Inject private ValidationService validationService; + @Inject + private SendMailSSL sendMailSsl; + AsyncRegister() { } private boolean preRegisterCheck(Player player, String password) { @@ -137,7 +141,7 @@ public class AsyncRegister implements AsynchronousProcess { } database.updateEmail(auth); database.updateSession(auth); - plugin.getMail().main(auth, password); + sendMailSsl.sendPasswordMail(auth, password); syncProcessManager.processSyncEmailRegister(player); } diff --git a/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java index 217b74be..683302db 100644 --- a/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java @@ -2,6 +2,7 @@ package fr.xephi.authme.command.executable.register; import fr.xephi.authme.TestHelper; import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Management; import fr.xephi.authme.security.HashAlgorithm; @@ -49,6 +50,8 @@ public class RegisterCommandTest { @Mock private Management management; + @Mock + private SendMailSSL sendMailSsl; @BeforeClass public static void setup() { @@ -72,7 +75,7 @@ public class RegisterCommandTest { // then verify(sender).sendMessage(argThat(containsString("Player only!"))); - verifyZeroInteractions(management); + verifyZeroInteractions(management, sendMailSsl); } @Test @@ -86,6 +89,7 @@ public class RegisterCommandTest { // then verify(management).performRegister(player, "", "", true); + verifyZeroInteractions(sendMailSsl); } @Test @@ -98,7 +102,7 @@ public class RegisterCommandTest { // then verify(commandService).send(player, MessageKey.USAGE_REGISTER); - verifyZeroInteractions(management); + verifyZeroInteractions(management, sendMailSsl); } @Test @@ -112,7 +116,7 @@ public class RegisterCommandTest { // then verify(commandService).send(player, MessageKey.USAGE_REGISTER); - verifyZeroInteractions(management); + verifyZeroInteractions(management, sendMailSsl); } @Test @@ -127,7 +131,7 @@ public class RegisterCommandTest { // then verify(commandService).send(player, MessageKey.USAGE_REGISTER); - verifyZeroInteractions(management); + verifyZeroInteractions(management, sendMailSsl); } @Test @@ -135,14 +139,15 @@ public class RegisterCommandTest { // given given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true); given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(false); - given(commandService.getProperty(EmailSettings.MAIL_ACCOUNT)).willReturn(""); + given(sendMailSsl.hasAllInformation()).willReturn(false); Player player = mock(Player.class); // when command.executeCommand(player, Collections.singletonList("myMail@example.tld")); // then - verify(player).sendMessage(argThat(containsString("no email address"))); + verify(player).sendMessage(argThat(containsString("not all required settings are set for sending emails"))); + verify(sendMailSsl).hasAllInformation(); verifyZeroInteractions(management); } @@ -155,6 +160,7 @@ public class RegisterCommandTest { given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true); given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true); given(commandService.getProperty(EmailSettings.MAIL_ACCOUNT)).willReturn("server@example.com"); + given(sendMailSsl.hasAllInformation()).willReturn(true); Player player = mock(Player.class); // when @@ -175,6 +181,7 @@ public class RegisterCommandTest { given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true); given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true); given(commandService.getProperty(EmailSettings.MAIL_ACCOUNT)).willReturn("server@example.com"); + given(sendMailSsl.hasAllInformation()).willReturn(true); Player player = mock(Player.class); // when @@ -182,6 +189,7 @@ public class RegisterCommandTest { // then verify(commandService).send(player, MessageKey.USAGE_REGISTER); + verify(sendMailSsl).hasAllInformation(); verifyZeroInteractions(management); } @@ -196,6 +204,7 @@ public class RegisterCommandTest { given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true); given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true); given(commandService.getProperty(EmailSettings.MAIL_ACCOUNT)).willReturn("server@example.com"); + given(sendMailSsl.hasAllInformation()).willReturn(true); Player player = mock(Player.class); // when @@ -203,6 +212,7 @@ public class RegisterCommandTest { // then verify(commandService).validateEmail(playerMail); + verify(sendMailSsl).hasAllInformation(); verify(management).performRegister(eq(player), argThat(stringWithLength(passLength)), eq(playerMail), eq(true)); } @@ -217,7 +227,7 @@ public class RegisterCommandTest { // then verify(commandService).send(player, MessageKey.PASSWORD_MATCH_ERROR); - verifyZeroInteractions(management); + verifyZeroInteractions(management, sendMailSsl); } @Test diff --git a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java index 76d01655..e672eb49 100644 --- a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java @@ -120,11 +120,6 @@ public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest { assertThat(sqLite.getAllAuths(), hasSize(1)); } - @Test - public void shouldCreate2() throws SQLException { - con.createStatement().execute("SELECT 1 from authme"); - } - @Override protected DataSource getDataSource(String saltColumn) { when(settings.getProperty(DatabaseSettings.MYSQL_COL_SALT)).thenReturn(saltColumn); From 3984208548cd34f92d80a8b456d01e419424ca2a Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 21:49:01 +0200 Subject: [PATCH 074/217] #797 Make two messages translatable --- .../java/fr/xephi/authme/command/CommandService.java | 10 ++++++++++ .../executable/authme/RegisterAdminCommand.java | 2 +- .../command/executable/email/RecoverEmailCommand.java | 2 +- .../command/executable/register/RegisterCommand.java | 4 ++-- src/main/java/fr/xephi/authme/output/MessageKey.java | 6 +++++- src/main/resources/messages/messages_en.yml | 2 ++ .../executable/authme/RegisterAdminCommandTest.java | 6 +++--- .../executable/register/RegisterCommandTest.java | 2 +- 8 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 5efe79e8..5114d1ff 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -53,6 +53,16 @@ public class CommandService { return messages.retrieve(key); } + /** + * Retrieve a message as a single String by its message key. + * + * @param key The message to retrieve + * @return The message + */ + public String retrieveSingle(MessageKey key) { + return messages.retrieveSingle(key); + } + /** * Retrieve the given property's value. * diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java index a4931e96..deddaf9c 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 @@ -79,7 +79,7 @@ public class RegisterAdminCommand implements ExecutableCommand { bukkitService.scheduleSyncDelayedTask(new Runnable() { @Override public void run() { - player.kickPlayer("An admin just registered you, please log in again"); + player.kickPlayer(commandService.retrieveSingle(MessageKey.KICK_FOR_ADMIN_REGISTER)); } }); } 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 8a874af7..346b9072 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 @@ -42,7 +42,7 @@ public class RecoverEmailCommand extends PlayerCommand { if (!sendMailSsl.hasAllInformation()) { ConsoleLogger.showError("Mail API is not set"); - commandService.send(player, MessageKey.ERROR); + commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS); return; } if (dataSource.isAuthAvailable(playerName)) { diff --git a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java index cb8c1946..be8b1edb 100644 --- a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java @@ -15,6 +15,7 @@ import org.bukkit.entity.Player; import javax.inject.Inject; import java.util.List; +import static fr.xephi.authme.output.MessageKey.INCOMPLETE_EMAIL_SETTINGS; import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH; import static fr.xephi.authme.settings.properties.RegistrationSettings.ENABLE_CONFIRM_EMAIL; import static fr.xephi.authme.settings.properties.RegistrationSettings.USE_EMAIL_REGISTRATION; @@ -68,8 +69,7 @@ public class RegisterCommand extends PlayerCommand { private void handleEmailRegistration(Player player, List arguments) { if (!sendMailSsl.hasAllInformation()) { - player.sendMessage("Cannot register: not all required settings are set for sending emails. " - + "Please contact an administrator"); + commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS); ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email or password is set " + "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath()); return; diff --git a/src/main/java/fr/xephi/authme/output/MessageKey.java b/src/main/java/fr/xephi/authme/output/MessageKey.java index 670366f5..c445b9a2 100644 --- a/src/main/java/fr/xephi/authme/output/MessageKey.java +++ b/src/main/java/fr/xephi/authme/output/MessageKey.java @@ -143,7 +143,11 @@ public enum MessageKey { ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"), - ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"); + ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"), + + KICK_FOR_ADMIN_REGISTER("kicked_admin_registered"), + + INCOMPLETE_EMAIL_SETTINGS("incomplete_email_settings"); private String key; private String[] tags; diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml index f2926eb9..b02a2c98 100644 --- a/src/main/resources/messages/messages_en.yml +++ b/src/main/resources/messages/messages_en.yml @@ -68,3 +68,5 @@ invalid_name_case: 'You should join using username %valid, not %invalid.' tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' accounts_owned_self: 'You own %count accounts:' accounts_owned_other: 'The player %name has %count accounts:' +kicked_admin_registered: 'An admin just registered you; please log in again' +incomplete_email_settings: 'Error: not all required settings are set for sending emails. Please contact an admin.' 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 d6d0924e..441a38a2 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 @@ -22,12 +22,10 @@ import org.mockito.runners.MockitoJUnitRunner; 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; @@ -160,6 +158,8 @@ public class RegisterAdminCommandTest { given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); Player player = mock(Player.class); given(bukkitService.getPlayerExact(user)).willReturn(player); + String kickForAdminRegister = "Admin registered you -- log in again"; + given(commandService.retrieveSingle(MessageKey.KICK_FOR_ADMIN_REGISTER)).willReturn(kickForAdminRegister); CommandSender sender = mock(CommandSender.class); // when @@ -174,7 +174,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"))); + verify(player).kickPlayer(kickForAdminRegister); } private void assertAuthHasInfo(PlayerAuth auth, String name, HashedPassword hashedPassword) { diff --git a/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java index 683302db..dd30d970 100644 --- a/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java @@ -146,7 +146,7 @@ public class RegisterCommandTest { command.executeCommand(player, Collections.singletonList("myMail@example.tld")); // then - verify(player).sendMessage(argThat(containsString("not all required settings are set for sending emails"))); + verify(commandService).send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS); verify(sendMailSsl).hasAllInformation(); verifyZeroInteractions(management); } From a9574d23633b5a5c95d3f9794ca32055762acdbd Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Jul 2016 22:22:03 +0200 Subject: [PATCH 075/217] #819 Email text migration - migrate %tag% style placeholders as well --- .../xephi/authme/settings/SettingsMigrationService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java index fdafea6f..4a4add7b 100644 --- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java +++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java @@ -92,10 +92,10 @@ public class SettingsMigrationService { final File emailFile = new File(pluginFolder, "email.html"); final String mailText = configuration.getString(oldSettingPath) - .replace("", "") - .replace("", "") - .replace("", "") - .replace("", ""); + .replace("", "").replace("%playername%", "") + .replace("", "").replace("%servername%", "") + .replace("", "").replace("%generatedpass%", "") + .replace("", "").replace("%image%", ""); if (!emailFile.exists()) { try (FileWriter fw = new FileWriter(emailFile)) { fw.write(mailText); From 2420a83ec3088472aa10aa1b1160aff67d9fcdb3 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 3 Jul 2016 09:49:38 +0200 Subject: [PATCH 076/217] #797 Add missing French messages - Thanks to @Twonox --- src/main/resources/messages/messages_fr.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/messages/messages_fr.yml b/src/main/resources/messages/messages_fr.yml index 848090e8..e1180ef2 100644 --- a/src/main/resources/messages/messages_fr.yml +++ b/src/main/resources/messages/messages_fr.yml @@ -69,3 +69,5 @@ tempban_max_logins: '&cVous êtes temporairement banni suite à plusieurs échec accounts_owned_self: '&fVous avez %count comptes:' accounts_owned_other: '&fLe joueur %name a %count comptes:' denied_command: '&cVous devez être connecté pour pouvoir utiliser cette commande.' +kicked_admin_registered: 'Un admin vient de vous enregistrer, veuillez vous reconnecter.' +incomplete_email_settings: '&cErreur : Tous les paramètres requis ne sont pas présent pour l''envoi de mail, veuillez contacter un admin.' From 8f5817883ea3fcc5b4b02e8636f83652e9453b7c Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 3 Jul 2016 11:47:37 +0200 Subject: [PATCH 077/217] Testing - check return value of Set#add instead of separately checking Set#contains --- src/test/java/fr/xephi/authme/output/MessageKeyTest.java | 3 +-- .../java/fr/xephi/authme/permission/AdminPermissionTest.java | 3 +-- .../java/fr/xephi/authme/permission/PlayerPermissionTest.java | 3 +-- .../fr/xephi/authme/permission/PlayerStatePermissionTest.java | 3 +-- .../fr/xephi/authme/security/HashAlgorithmIntegrationTest.java | 3 +-- .../settings/properties/SettingsClassConsistencyTest.java | 3 +-- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/test/java/fr/xephi/authme/output/MessageKeyTest.java b/src/test/java/fr/xephi/authme/output/MessageKeyTest.java index 101306bf..dda5eeb9 100644 --- a/src/test/java/fr/xephi/authme/output/MessageKeyTest.java +++ b/src/test/java/fr/xephi/authme/output/MessageKeyTest.java @@ -22,12 +22,11 @@ public class MessageKeyTest { // when / then for (MessageKey messageKey : messageKeys) { String key = messageKey.getKey(); - if (keys.contains(key)) { + if (!keys.add(key)) { fail("Found key '" + messageKey.getKey() + "' twice!"); } else if (StringUtils.isEmpty(key)) { fail("Key for message key '" + messageKey + "' is empty"); } - keys.add(key); } } } diff --git a/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java b/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java index 0c2c2b16..3cfa0e27 100644 --- a/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java +++ b/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java @@ -33,10 +33,9 @@ public class AdminPermissionTest { // when/then for (AdminPermission permission : AdminPermission.values()) { - if (nodes.contains(permission.getNode())) { + if (!nodes.add(permission.getNode())) { fail("More than one enum value defines the node '" + permission.getNode() + "'"); } - nodes.add(permission.getNode()); } } diff --git a/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java b/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java index 632a2cf3..ad8f6fe9 100644 --- a/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java +++ b/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java @@ -33,10 +33,9 @@ public class PlayerPermissionTest { // when/then for (PlayerPermission permission : PlayerPermission.values()) { - if (nodes.contains(permission.getNode())) { + if (!nodes.add(permission.getNode())) { fail("More than one enum value defines the node '" + permission.getNode() + "'"); } - nodes.add(permission.getNode()); } } } diff --git a/src/test/java/fr/xephi/authme/permission/PlayerStatePermissionTest.java b/src/test/java/fr/xephi/authme/permission/PlayerStatePermissionTest.java index 94b6e246..6c3e3d16 100644 --- a/src/test/java/fr/xephi/authme/permission/PlayerStatePermissionTest.java +++ b/src/test/java/fr/xephi/authme/permission/PlayerStatePermissionTest.java @@ -37,10 +37,9 @@ public class PlayerStatePermissionTest { // when/then for (PlayerStatePermission permission : PlayerStatePermission.values()) { - if (nodes.contains(permission.getNode())) { + if (!nodes.add(permission.getNode())) { fail("More than one enum value defines the node '" + permission.getNode() + "'"); } - nodes.add(permission.getNode()); } } diff --git a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java index 79745a33..9f875a00 100644 --- a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java @@ -43,10 +43,9 @@ public class HashAlgorithmIntegrationTest { // when / then for (HashAlgorithm algorithm : HashAlgorithm.values()) { if (!HashAlgorithm.CUSTOM.equals(algorithm)) { - if (classes.contains(algorithm.getClazz())) { + if (!classes.add(algorithm.getClazz())) { fail("Found class '" + algorithm.getClazz() + "' twice!"); } - classes.add(algorithm.getClazz()); } } } diff --git a/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java index 75c1a56a..9e075200 100644 --- a/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java @@ -74,10 +74,9 @@ public class SettingsClassConsistencyTest { if (Property.class.isAssignableFrom(field.getType())) { Property property = (Property) ReflectionTestUtils.getFieldValue(clazz, null, field.getName()); - if (paths.contains(property.getPath())) { + if (!paths.add(property.getPath())) { fail("Path '" + property.getPath() + "' should be used by only one constant"); } - paths.add(property.getPath()); } } } From deffcb3e2b75b88ea568d5ae4d081d3d1fdbf2b8 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Sun, 3 Jul 2016 21:52:46 +0700 Subject: [PATCH 078/217] - Renamed JsonCache to PlayerDataStorage * the methods inside it renamed to fit with class name * cache folder changed into playerdata - Renamed LimboPlayer to PlayerData - Added fly speed to PlayerData - Removed player's name from PlayerData object - Added getPlayerLocationOrSpawn method in spawn loader. --- .idea/codeStyleSettings.xml | 275 +++++++++++++++++- src/main/java/fr/xephi/authme/AuthMe.java | 21 +- .../xephi/authme/cache/auth/PlayerCache.java | 7 +- ...{JsonCache.java => PlayerDataStorage.java} | 98 ++++--- .../xephi/authme/cache/limbo/LimboCache.java | 58 ++-- .../{LimboPlayer.java => PlayerData.java} | 23 +- .../authme/UnregisterAdminCommand.java | 10 +- .../authme/permission/AuthGroupHandler.java | 5 +- .../authme/process/join/AsynchronousJoin.java | 10 +- .../process/login/AsynchronousLogin.java | 14 +- .../process/login/ProcessSyncPlayerLogin.java | 6 +- .../process/logout/AsynchronousLogout.java | 2 +- .../ProcessSynchronousPlayerLogout.java | 8 +- .../authme/process/quit/AsynchronousQuit.java | 2 +- .../quit/ProcessSyncronousPlayerQuit.java | 18 +- .../register/ProcessSyncEmailRegister.java | 8 +- .../register/ProcessSyncPasswordRegister.java | 16 +- .../unregister/AsynchronousUnregister.java | 10 +- .../fr/xephi/authme/settings/Settings.java | 4 - .../fr/xephi/authme/settings/SpawnLoader.java | 36 ++- .../fr/xephi/authme/task/MessageTask.java | 4 +- ...anager.java => PlayerDataTaskManager.java} | 29 +- .../authme/util/TeleportationService.java | 8 +- src/main/java/fr/xephi/authme/util/Utils.java | 16 + ...st.java => PlayerDataTaskManagerTest.java} | 70 ++--- .../authme/util/TeleportationServiceTest.java | 16 +- 26 files changed, 554 insertions(+), 220 deletions(-) rename src/main/java/fr/xephi/authme/cache/backup/{JsonCache.java => PlayerDataStorage.java} (61%) rename src/main/java/fr/xephi/authme/cache/limbo/{LimboPlayer.java => PlayerData.java} (89%) rename src/main/java/fr/xephi/authme/task/{LimboPlayerTaskManager.java => PlayerDataTaskManager.java} (79%) rename src/test/java/fr/xephi/authme/task/{LimboPlayerTaskManagerTest.java => PlayerDataTaskManagerTest.java} (72%) diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml index 26493260..91baa3db 100644 --- a/.idea/codeStyleSettings.xml +++ b/.idea/codeStyleSettings.xml @@ -12,9 +12,280 @@ + + + +

+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + true + + +
+
+ + + true + + +
+
+ + + true + + +
+
+ + + + true + true + + + +
+
+ + + true + + +
+
+ + + + true + true + true + + + +
+
+ + + true + + +
+
+ + + true + + +
+
+ + + + true + true + + + +
+
+ + + true + + +
+ + +