From ff17e4ca6b95ebcc4a30de510baa804d0e00561d Mon Sep 17 00:00:00 2001 From: DNx5 Date: Fri, 1 Apr 2016 13:05:26 +0700 Subject: [PATCH 01/71] Minor improvement. --- src/main/java/fr/xephi/authme/DataManager.java | 13 +------------ .../process/quit/ProcessSyncronousPlayerQuit.java | 5 +---- src/main/java/fr/xephi/authme/util/Utils.java | 2 +- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 0545611d..b518ea99 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -6,7 +6,6 @@ import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; import java.io.File; import java.util.ArrayList; @@ -145,19 +144,9 @@ public class DataManager { } int i = 0; for (String name : cleared) { - permsMan.removeAllGroups(getOnlinePlayerLower(name)); + permsMan.removeAllGroups(Utils.getPlayer(name)); i++; } ConsoleLogger.info("AutoPurge: Removed permissions from " + i + " player(s)."); } - - private Player getOnlinePlayerLower(String name) { - name = name.toLowerCase(); - for (Player player : Utils.getOnlinePlayers()) { - if (player.getName().equalsIgnoreCase(name)) { - return player; - } - } - return null; - } } 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 3193ac49..bf7ab967 100644 --- a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncronousPlayerQuit.java @@ -38,9 +38,6 @@ public class ProcessSyncronousPlayerQuit implements Runnable { if (needToChange) { player.setOp(isOp); } - try { - player.getVehicle().eject(); - } catch (Exception ignored) { - } + player.leaveVehicle(); } } diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index c399f655..c9b472c3 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -236,7 +236,7 @@ public final class Utils { } public static Player getPlayer(String name) { - return wrapper.getServer().getPlayerExact(name); + return wrapper.getServer().getPlayerExact(name); // bukkit will lowercase the input } public static boolean isNPC(Player player) { From c63b9786f863b8e64afb91c487ae2256897f8aed Mon Sep 17 00:00:00 2001 From: DNx5 Date: Fri, 1 Apr 2016 13:28:00 +0700 Subject: [PATCH 02/71] IpAddressManager should work with BungeeCord too. --- .../xephi/authme/cache/IpAddressManager.java | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/main/java/fr/xephi/authme/cache/IpAddressManager.java b/src/main/java/fr/xephi/authme/cache/IpAddressManager.java index 41d1d77f..ff3398a5 100644 --- a/src/main/java/fr/xephi/authme/cache/IpAddressManager.java +++ b/src/main/java/fr/xephi/authme/cache/IpAddressManager.java @@ -1,7 +1,10 @@ package fr.xephi.authme.cache; import com.google.common.base.Charsets; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; import com.google.common.io.Resources; +import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.HooksSettings; @@ -16,10 +19,14 @@ import java.util.concurrent.ConcurrentHashMap; * Stateful manager for looking up IP address appropriately, including caching. */ public class IpAddressManager { - - /** Whether or not to use the VeryGames API for IP lookups. */ + /** + * Whether or not to use the VeryGames API or BungeeCord for IP lookups. + */ private final boolean useVeryGamesIpCheck; - /** Cache for lookups via the VeryGames API. */ + private final boolean useBungee; + /** + * Cache for lookups. + */ private final ConcurrentHashMap ipCache; /** @@ -29,6 +36,7 @@ public class IpAddressManager { */ public IpAddressManager(NewSetting settings) { this.useVeryGamesIpCheck = settings.getProperty(HooksSettings.ENABLE_VERYGAMES_IP_CHECK); + this.useBungee = settings.getProperty(HooksSettings.BUNGEECORD); this.ipCache = new ConcurrentHashMap<>(); } @@ -37,36 +45,40 @@ public class IpAddressManager { * VeryGames API will be returned. * * @param player The player to look up + * * @return The IP address of the player */ public String getPlayerIp(Player player) { - if (useVeryGamesIpCheck) { - final String playerName = player.getName().toLowerCase(); - final String cachedValue = ipCache.get(playerName); - if (cachedValue != null) { - return cachedValue; - } + final String playerName = player.getName().toLowerCase(); + final String cachedValue = ipCache.get(playerName); + if (cachedValue != null) { + return cachedValue; + } - final String plainIp = player.getAddress().getAddress().getHostAddress(); + final String plainIp = player.getAddress().getAddress().getHostAddress(); + if (useBungee) { + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("IP"); + player.sendPluginMessage(AuthMe.getInstance(), "BungeeCord", out.toByteArray()); + } + if (useVeryGamesIpCheck) { String veryGamesResult = getVeryGamesIp(plainIp, player.getAddress().getPort()); if (veryGamesResult != null) { ipCache.put(playerName, veryGamesResult); return veryGamesResult; } } - return player.getAddress().getAddress().getHostAddress(); + return plainIp; } /** * Add a player to the IP address cache. * * @param player The player to add or update the cache entry for - * @param ip The IP address to add + * @param ip The IP address to add */ public void addCache(String player, String ip) { - if (useVeryGamesIpCheck) { - ipCache.put(player.toLowerCase(), ip); - } + ipCache.put(player.toLowerCase(), ip); } /** @@ -75,9 +87,7 @@ public class IpAddressManager { * @param player The player to remove */ public void removeCache(String player) { - if (useVeryGamesIpCheck) { - ipCache.remove(player.toLowerCase()); - } + ipCache.remove(player.toLowerCase()); } // returns null if IP could not be looked up From 46a10da40fecbe2c96179bf4ce337c6e14008983 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Fri, 1 Apr 2016 13:47:35 +0700 Subject: [PATCH 03/71] Fix test --- .../authme/cache/IpAddressManagerTest.java | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java b/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java index 50c73d30..be172f3d 100644 --- a/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java +++ b/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java @@ -18,36 +18,10 @@ import static org.mockito.Mockito.mock; */ public class IpAddressManagerTest { - @Test - public void shouldRetrieveFromCache() { - // given - IpAddressManager ipAddressManager = new IpAddressManager(mockSettings(true)); - ipAddressManager.addCache("Test", "my test IP"); - - // when - String result = ipAddressManager.getPlayerIp(mockPlayer("test", "123.123.123.123")); - - // then - assertThat(result, equalTo("my test IP")); - } - - @Test - public void shouldReturnPlainIp() { - // given - IpAddressManager ipAddressManager = new IpAddressManager(mockSettings(false)); - - // when - String result = ipAddressManager.getPlayerIp(mockPlayer("bobby", "8.8.8.8")); - - // then - assertThat(result, equalTo("8.8.8.8")); - } - - - - private static NewSetting mockSettings(boolean useVeryGames) { + private static NewSetting mockSettings(boolean useVeryGames, boolean useBungee) { NewSetting settings = mock(NewSetting.class); given(settings.getProperty(HooksSettings.ENABLE_VERYGAMES_IP_CHECK)).willReturn(useVeryGames); + given(settings.getProperty(HooksSettings.BUNGEECORD)).willReturn(useBungee); return settings; } @@ -61,4 +35,29 @@ public class IpAddressManagerTest { return player; } + @Test + public void shouldRetrieveFromCache() { + // given + IpAddressManager ipAddressManager = new IpAddressManager(mockSettings(true, true)); + ipAddressManager.addCache("Test", "my test IP"); + + // when + String result = ipAddressManager.getPlayerIp(mockPlayer("test", "123.123.123.123")); + + // then + assertThat(result, equalTo("my test IP")); + } + + @Test + public void shouldReturnPlainIp() { + // given + IpAddressManager ipAddressManager = new IpAddressManager(mockSettings(false, false)); + + // when + String result = ipAddressManager.getPlayerIp(mockPlayer("bobby", "8.8.8.8")); + + // then + assertThat(result, equalTo("8.8.8.8")); + } + } From 997c31a03ecd3aa75913af6a19f167f5819a4313 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 1 Apr 2016 17:02:57 +0200 Subject: [PATCH 04/71] Cleanup warnings --- .../xephi/authme/listener/AuthMeTablistPacketAdapter.java | 1 - .../authme/settings/properties/SettingsFieldRetriever.java | 4 ++-- .../fr/xephi/authme/settings/propertymap/PropertyMap.java | 2 +- .../authme/settings/propertymap/PropertyMapComparator.java | 6 +++--- src/test/java/fr/xephi/authme/AntiBotTest.java | 2 ++ 5 files changed, 8 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 bd32d1b8..ef4d0b93 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -1,7 +1,6 @@ package fr.xephi.authme.listener; import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketEvent; diff --git a/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java b/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java index b4adfa07..ac8d65d9 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java +++ b/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java @@ -38,7 +38,7 @@ public final class SettingsFieldRetriever { for (Class clazz : CONFIGURATION_CLASSES) { Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { - Property property = getPropertyField(field); + Property property = getPropertyField(field); if (property != null) { properties.put(property, getCommentsForField(field)); } @@ -64,7 +64,7 @@ public final class SettingsFieldRetriever { field.setAccessible(true); if (field.isAccessible() && Property.class.equals(field.getType()) && Modifier.isStatic(field.getModifiers())) { try { - return (Property) field.get(null); + return (Property) field.get(null); } catch (IllegalAccessException e) { throw new IllegalStateException("Could not fetch field '" + field.getName() + "' from class '" + field.getDeclaringClass().getSimpleName() + "': " + StringUtils.formatException(e)); diff --git a/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMap.java b/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMap.java index 9cac52d3..aed4ac0e 100644 --- a/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMap.java +++ b/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMap.java @@ -31,7 +31,7 @@ public class PropertyMap { * @param property The property to add * @param comments The comments associated to the property */ - public void put(Property property, String[] comments) { + public void put(Property property, String[] comments) { comparator.add(property); map.put(property, comments); } diff --git a/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMapComparator.java b/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMapComparator.java index a7ec1cb3..e6bd9fb4 100644 --- a/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMapComparator.java +++ b/src/main/java/fr/xephi/authme/settings/propertymap/PropertyMapComparator.java @@ -13,7 +13,7 @@ import java.util.Comparator; * property, then "DataSource" properties will come before the "security" ones. * */ -final class PropertyMapComparator implements Comparator { +final class PropertyMapComparator implements Comparator> { private Node parent = Node.createRoot(); @@ -22,12 +22,12 @@ final class PropertyMapComparator implements Comparator { * * @param property The property that is being added */ - public void add(Property property) { + public void add(Property property) { parent.addNode(property.getPath()); } @Override - public int compare(Property p1, Property p2) { + public int compare(Property p1, Property p2) { return parent.compare(p1.getPath(), p2.getPath()); } diff --git a/src/test/java/fr/xephi/authme/AntiBotTest.java b/src/test/java/fr/xephi/authme/AntiBotTest.java index 4dace294..9950963a 100644 --- a/src/test/java/fr/xephi/authme/AntiBotTest.java +++ b/src/test/java/fr/xephi/authme/AntiBotTest.java @@ -167,6 +167,7 @@ public class AntiBotTest { antiBot.checkAntiBot(player); // then + @SuppressWarnings("unchecked") List playerList = (List) ReflectionTestUtils .getFieldValue(AntiBot.class, antiBot, "antibotPlayers"); assertThat(playerList, hasSize(1)); @@ -196,6 +197,7 @@ public class AntiBotTest { antiBot.checkAntiBot(player); // then + @SuppressWarnings("rawtypes") List playerList = (List) ReflectionTestUtils.getFieldValue(AntiBot.class, antiBot, "antibotPlayers"); assertThat(playerList, empty()); verify(bukkitService, never()).scheduleSyncDelayedTask(any(Runnable.class), anyLong()); From de89244e0eb119d06e859d79c3a93fbde0fd22db Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 1 Apr 2016 18:21:05 +0200 Subject: [PATCH 05/71] #630 Disable collisions for unlogged players --- .../xephi/authme/process/join/AsynchronousJoin.java | 11 +++++++++++ .../authme/process/login/ProcessSyncPlayerLogin.java | 11 +++++++++++ src/main/java/fr/xephi/authme/settings/Settings.java | 4 ++-- .../authme/settings/properties/PluginSettings.java | 6 ++++++ src/main/resources/config.yml | 3 +++ 5 files changed, 33 insertions(+), 2 deletions(-) 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 838ac0e6..900abd4c 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -27,10 +27,14 @@ import fr.xephi.authme.util.Utils.GroupType; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.entity.LivingEntity; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitTask; +import com.comphenix.protocol.reflect.MethodUtils; + /** */ public class AsynchronousJoin implements Process { @@ -42,6 +46,9 @@ public class AsynchronousJoin implements Process { private final ProcessService service; private final PlayerCache playerCache; + private final boolean disableCollisions = MethodUtils + .getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null; + public AsynchronousJoin(Player player, AuthMe plugin, DataSource database, PlayerCache playerCache, ProcessService service) { this.player = player; @@ -89,6 +96,10 @@ public class AsynchronousJoin implements Process { }); return; } + // Prevent player collisions in 1.9 + if (disableCollisions) { + ((LivingEntity) player).setCollidable(false); + } final Location spawnLoc = service.getSpawnLoader().getSpawnLocation(player); final boolean isAuthAvailable = database.isAuthAvailable(name); if (isAuthAvailable) { 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 b454f370..48b4eda4 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -4,12 +4,15 @@ import fr.xephi.authme.settings.NewSetting; 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.PluginSettings; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.plugin.PluginManager; import org.bukkit.potion.PotionEffectType; +import com.comphenix.protocol.reflect.MethodUtils; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; @@ -29,6 +32,7 @@ import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils.GroupType; import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; +import static fr.xephi.authme.settings.properties.PluginSettings.KEEP_COLLISIONS_DISABLED; public class ProcessSyncPlayerLogin implements Runnable { @@ -42,6 +46,9 @@ public class ProcessSyncPlayerLogin implements Runnable { private final JsonCache playerCache; private final NewSetting settings; + private final boolean restoreCollisions = MethodUtils + .getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null; + /** * Constructor for ProcessSyncPlayerLogin. * @@ -148,6 +155,10 @@ public class ProcessSyncPlayerLogin implements Runnable { } } + if (restoreCollisions && !settings.getProperty(KEEP_COLLISIONS_DISABLED)) { + player.setCollidable(true); + } + if (settings.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { restoreInventory(); } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 5989e216..a35c6df8 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -59,7 +59,7 @@ public final class Settings { checkVeryGames, removeJoinMessage, removeLeaveMessage, delayJoinMessage, noTeleport, hideTablistBeforeLogin, denyTabcompleteBeforeLogin, kickPlayersBeforeStopping, allowAllCommandsIfRegIsOptional, - customAttributes, isRemoveSpeedEnabled, preventOtherCase; + customAttributes, isRemoveSpeedEnabled, preventOtherCase, keepCollisionsDisabled; public static String getNickRegex, getUnloggedinGroup, unRegisteredGroup, backupWindowsPath, getRegisteredGroup, @@ -195,7 +195,7 @@ public final class Settings { preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); kickPlayersBeforeStopping = configFile.getBoolean("Security.stop.kickPlayersBeforeStopping", true); sendPlayerTo = configFile.getString("Hooks.sendPlayerTo", ""); - + keepCollisionsDisabled = configFile.getBoolean("settings.keepCollisionsDisabled"); } /** 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 6fea29fb..de858203 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java @@ -53,6 +53,12 @@ public class PluginSettings implements SettingsClass { public static final Property ENABLE_PERMISSION_CHECK = newProperty("permission.EnablePermissionCheck", false); + @Comment({ + "Keeps collisions disabled for logged players", + "Works only with MC 1.9" + }) + public static final Property KEEP_COLLISIONS_DISABLED = + newProperty("settings.KeepCollisionsDisabled", false); private PluginSettings() { } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index dc52379a..5aa33aa7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -159,6 +159,9 @@ settings: 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 From 3a3ea4d228f46eb8414aa58587afb00654672040 Mon Sep 17 00:00:00 2001 From: Ivan Ip Date: Sat, 2 Apr 2016 00:57:21 +0800 Subject: [PATCH 06/71] First repairing commit to fix Chinese Lingual. --- src/main/resources/messages/messages_zhcn.yml | 132 +++++++++-------- src/main/resources/messages/messages_zhhk.yml | 133 +++++++++--------- src/main/resources/messages/messages_zhtw.yml | 6 +- 3 files changed, 134 insertions(+), 137 deletions(-) diff --git a/src/main/resources/messages/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml index 3c7fa1a2..be7e1f9c 100644 --- a/src/main/resources/messages/messages_zhcn.yml +++ b/src/main/resources/messages/messages_zhcn.yml @@ -1,68 +1,66 @@ -# Translator: uSoc_lifehome (http://lifeho.me) # -# Translator: WaterXCubic 水方塊 # +# Translator: Unknown # +# Last modif: 1459528742 UTC # # -------------------------------------------- # -unknown_user: '&8[&6用戶系統&8] &f用戶資料並不存在於資料庫中。' -unsafe_spawn: '&8[&6用戶系統&8] &f你的登出位置不安全,現在將傳送你到重生點。' -not_logged_in: '&8[&6用戶系統&8] &c你還沒有登入 !' -reg_voluntarily: '&8[&6用戶系統&8] &f你可以使用這個的指令來註冊: 《 /register <密碼> <重覆密碼> 》' -usage_log: '&8[&6用戶系統&8] &c用法: 《 /login <密碼> 》' -wrong_pwd: '&8[&6用戶系統&8] &c你輸入了錯誤的密碼。' -unregistered: '&8[&6用戶系統&8] &c你已成功取消會員註冊記錄。' -reg_disabled: '&8[&6用戶系統&8] &c本伺服器已停止新玩家註冊。' -valid_session: '&8[&6用戶系統&8] &b嗨 ! 我記得你,歡迎回來~' -login: '&8[&6用戶系統&8] &c你成功的登入了。' -password_error_nick: '&f你不可以使用你的名字為密碼!' -password_error_unsafe: '&f你不可以使用不安全的密碼' -vb_nonActiv: '&8[&6用戶系統&8] &f你的帳戶還沒有經過電郵驗證 !' -user_regged: '&8[&6用戶系統&8] &c此用戶名已經註冊過了。' -usage_reg: '&8[&6用戶系統&8] &c用法: 《 /register <密碼> <重覆密碼> 》' -max_reg: '&8[&6用戶系統&8] &f你的IP地址已達到註冊數上限。' -no_perm: '&8[&6用戶系統&8] &b你可以到 CraftingHK 玩家百科中查看說明文件。' -error: '&8[&6用戶系統&8] &f發生錯誤,請與管理員聯絡。' -login_msg: '&8[&6用戶系統&8] &c請使用這個指令來登入: 《 /login <密碼> 》' -reg_msg: '&8[&6用戶系統&8] &c請使用這個的指令來註冊: 《 /register <密碼> <重覆密碼> 》' -reg_email_msg: '&8[&6用戶系統&8] &c請使用這個的指令來註冊: 《 /register <電郵> <重覆電郵> 》' -usage_unreg: '&8[&6用戶系統&8] &c用法: 《 /unregister <密碼> 》' -pwd_changed: '&8[&6用戶系統&8] &c你成功的更換了你的密碼 !' -user_unknown: '&8[&6用戶系統&8] &c此用戶名沒有已登記資料。' -password_error: '&8[&6用戶系統&8] &f密碼不符合。' -invalid_session: '&8[&6用戶系統&8] &f登入階段資料已損壞,請等待登入階段結束。' -reg_only: '&8[&6用戶系統&8] &f限已註冊會員,請先到 https://www.example.com/ 註冊。' -logged_in: '&8[&6用戶系統&8] &c你已經登入過了。' -logout: '&8[&6用戶系統&8] &b你成功的登出了。' -same_nick: '&8[&6用戶系統&8] &f同名玩家已在遊玩。' -registered: '&8[&6用戶系統&8] &b你成功的註冊了。' -pass_len: '&8[&6用戶系統&8] &f你的密碼並不符合規定長度。' -reload: '&8[&6用戶系統&8] &b登入系統設定及資料庫重新載入完畢。' -timeout: '&8[&6用戶系統&8] &f登入逾時。' -usage_changepassword: '&8[&6用戶系統&8] &f用法: 《 /changepassword <舊密碼> <新密碼> 》' -name_len: '&8[&6用戶系統&8] &c你的用戶名不符合規定長度。' -regex: '&8[&6用戶系統&8] &c你的用戶名含有不容許之字符。以下為准許之字母: REG_EX' -add_email: '&8[&6用戶系統&8] &b請為你的帳戶立即添加電郵地址: 《 /email add <電郵地址> <重覆電郵地址> 》' -bad_database_email: '&8[&6用戶系統&8] 此指令只適用於使用MySQL或SQLite之伺服器。' -recovery_email: '&8[&6用戶系統&8] &c忘記密碼 ? 請使用這個的指令來更新密碼: 《 /email recovery <電郵地址> 》' -usage_captcha: '&8[&6用戶系統&8] &c用法: 《 /captcha 》' -# TODO wrong_captcha: Missing tag THE_CAPTCHA -wrong_captcha: '&8[&6用戶系統&8] &c你輸入了錯誤的驗證碼,請使用 《 /captcha <驗證碼> 》 再次輸入。' -valid_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼是無效的 !' -kick_forvip: '&c因為有VIP玩家登入了伺服器。' -kick_fullserver: '&c抱歉! 因為伺服器滿人了,所以你目前未能登入伺服器。' -usage_email_add: '&8[&6用戶系統&8] &f用法: 《 /email add <電郵> <重覆電郵> 》' -usage_email_change: '&8[&6用戶系統&8] &f用法: 《 /email change <舊電郵> <新電郵> 》' -usage_email_recovery: '&8[&6用戶系統&8] &f用法: 《 /email recovery <電郵> 》' -new_email_invalid: '&8[&6用戶系統&8] 你所填寫的新電郵地址並不正確。' -old_email_invalid: '&8[&6用戶系統&8] 你所填寫的舊電郵地址並不正確。' -email_invalid: '&8[&6用戶系統&8] 你所填寫的電郵地址並不正確。' -email_added: '&8[&6用戶系統&8] 已加入你的電郵地址記錄。' -email_confirm: '&8[&6用戶系統&8] 請重覆輸入你的電郵地址。' -email_changed: '&8[&6用戶系統&8] 你的電郵地址記錄已更改。' -email_send: '&8[&6用戶系統&8] 忘記密碼信件已寄出,請查收。' -country_banned: '&8[&6用戶系統&8] 本伺服器已停止對你的國家提供遊戲服務。' -antibot_auto_enabled: '&8[&6用戶系統&8] 防止機械人程序已因應現時大量不尋常的連線而啟用。' -antibot_auto_disabled: '&8[&6用戶系統&8] 防止機械人程序檢查到不正常連接數已減少,並於 %m 分鐘後停止運作。' -# TODO email_already_used: '&4The email address is already being used' -# 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 invalid_name_case: 'You should join using username %valid, not %invalid.' -# 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 try another name!' \ No newline at end of file +kick_antibot: '&8[&6玩家系统&8] &f防机器人程序已启用 !请稍等几分钟後才再次进入服务器' +unknown_user: '&8[&6玩家系统&8] &f&f数据库里找不到此用户' +unsafe_spawn: '&8[&6玩家系统&8] &f你退出服务器时的位置不安全,正在传送你到此世界的出生点' +not_logged_in: '&8[&6玩家系统&8] &c你还未登录!' +reg_voluntarily: '&8[&6玩家系统&8] &f你可以在服务器里使用这个指令以注册:“/register <密码> <再输入一次以确定密码>”' +usage_log: '&8[&6玩家系统&8] &c正确用法:“/login <密码>”' +wrong_pwd: '&8[&6玩家系统&8] &c错误的密码' +unregistered: '&8[&6玩家系统&8] &c成功删除此用户!' +reg_disabled: '&8[&6玩家系统&8] &c目前服务器暂时禁止注册,请到服务器论坛以得到更多资讯' +valid_session: '&8[&6玩家系统&8] &c欢迎回来,已帮你自动登录到此服务器' +login: '&8[&6玩家系统&8] &c已成功登录!' +vb_nonActiv: '&8[&6玩家系统&8] &f你的帐号还未激活,请查看你的邮箱!' +user_regged: '&8[&6玩家系统&8] &c此用户已经在此服务器注册过' +usage_reg: '&8[&6玩家系统&8] &c正确用法:“/register <密码> <再输入一次以确定密码>”' +max_reg: '&8[&6玩家系统&8] &f你不允许再为你的IP在服务器注册更多用户了!' +no_perm: '&8[&6玩家系统&8] &c没有权限' +error: '&8[&6玩家系统&8] &f发现错误,请联系管理员' +login_msg: '&8[&6玩家系统&8] &c请输入“/login <密码>”以登录' +reg_msg: '&8[&6玩家系统&8] &c请输入“/register <密码> <再输入一次以确定密码>”以注册' +reg_email_msg: '&8[&6玩家系统&8] &c请输入 "/register <邮箱> <确认电子邮件>"' +usage_unreg: '&8[&6玩家系统&8] &c正确用法:“/unregister <密码>”' +pwd_changed: '&8[&6玩家系统&8] &c密码已成功修改!' +user_unknown: '&8[&6玩家系统&8] &c此用户名还未注册过' +password_error: '&8[&6玩家系统&8] &f密码不相同' +password_error_nick: '&8[&6玩家系统&8] &f你不能使用你的名字作为密码。 ' +password_error_unsafe: '&8[&6玩家系统&8] &f你不能使用安全性过低的码。 ' +invalid_session: '&8[&6玩家系统&8] &f登陆数据异常,请等待登陆结束' +reg_only: '&8[&6玩家系统&8] &f只允许注册过的玩家进服!请到 https://crafting.hk 注册' +logged_in: '&8[&6玩家系统&8] &c你已经登陆过了!' +logout: '&8[&6玩家系统&8] &c已成功登出!' +same_nick: '&8[&6玩家系统&8] &f同样的用户名现在在线且已经登录了!' +registered: '&8[&6玩家系统&8] &c已成功注册!' +pass_len: '&8[&6玩家系统&8] &你的密码没有达到要求!' +reload: '&8[&6玩家系统&8] &f配置以及数据已经重新加载完毕' +timeout: '&8[&6玩家系统&8] &f给你登录的时间已经过了' +usage_changepassword: '&8[&6玩家系统&8] &f正确用法:“/changepassword 旧密码 新密码”' +name_len: '&8[&6玩家系统&8] &c你的用户名太短或者太长了' +regex: '&8[&6玩家系统&8] &c你的用户名包含非法字母,用户名里允许的字母: REG_EX' +add_email: '&8[&6玩家系统&8] &c请输入“/email add <你的邮箱> <再输入一次以确认>”以把你的邮箱添加到此帐号' +recovery_email: '&8[&6玩家系统&8] &c忘了你的密码?请输入:“/email recovery <你的邮箱>”' +usage_captcha: '&8[&6玩家系统&8] &c正确用法:/captcha <验证码>' +wrong_captcha: '&8[&6玩家系统&8] &c错误的验证码,请输入:“/captcha <验证码>”' +valid_captcha: '&8[&6玩家系统&8] &c你的验证码是有效的!' +kick_forvip: '&8[&6玩家系统&8] &cA VIP玩家加入了已满的服务器!' +kick_fullserver: '&8[&6玩家系统&8] &c抱歉,服务器已满!' +usage_email_add: '&8[&6玩家系统&8] &f用法: /email add <邮箱> <确认电子邮件> ' +usage_email_change: '&8[&6玩家系统&8] &f用法: /email change <旧邮箱> <新邮箱> ' +usage_email_recovery: '&8[&6玩家系统&8] &f用法: /email recovery <邮箱>' +new_email_invalid: '&8[&6玩家系统&8] &f新邮箱无效!' +old_email_invalid: '&8[&6玩家系统&8] &f旧邮箱无效!' +email_invalid: '&8[&6玩家系统&8] &f无效的邮箱' +email_added: '&8[&6玩家系统&8] &f邮箱已添加 !' +email_confirm: '&8[&6玩家系统&8] &f确认你的邮箱 !' +email_changed: '&8[&6玩家系统&8] &f邮箱已改变 !' +email_send: '&8[&6玩家系统&8] &f恢复邮件已发送 !' +country_banned: '这个服务器禁止该国家登陆' +antibot_auto_enabled: '&8[&6玩家系统&8] &f防机器人程序由于大量异常连接而启用' +antibot_auto_disabled: '&8[&6玩家系统&8] &f防机器人程序由于异常连接减少而在 %m 分钟后停止' +email_already_used: '&8[&6玩家系统&8] &4邮箱已被使用' +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」登入游戏。 ' \ 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 2eacb1f6..e5cba6b3 100644 --- a/src/main/resources/messages/messages_zhhk.yml +++ b/src/main/resources/messages/messages_zhhk.yml @@ -1,67 +1,66 @@ -#----------------------------------------# -#translated by i998979 -#----------------------------------------# -unknown_user: '&f用戶資料並不存在於資料庫中。' -unsafe_spawn: '&f你的登出的位置不安全,將傳送你至重生點。' -not_logged_in: '&c你並未登入!' -reg_voluntarily: '&f請使用: /register <密碼> <重覆密碼> 來註冊。' -usage_log: '&c用法: /login <密碼>' -wrong_pwd: '&c密碼錯誤。' -unregistered: '&c成功取消該名用戶的註冊記錄。' -reg_disabled: '&c新玩家註冊已停用。' -valid_session: '&cIP記憶,自動登入。' -login: '&c登入成功。' -vb_nonActiv: '&f你的帳戶並未啟用,請檢查你的電郵!' -user_regged: '&c此用戶名已有註冊記錄。' -usage_reg: '&c用法: /register <密碼> <重覆密碼>' -max_reg: '&f你的IP地址已達到註冊帳號上限。' -no_perm: '&c你沒有足夠的權限。' -error: '&f發生錯誤,請與管理員聯絡。' -login_msg: '&c請使用 /login <密碼> 來登入。' -reg_msg: '&c請使用 /register <密碼> <重覆密碼> 來註冊。' -reg_email_msg: '&c請使用 /register <電郵> <重覆電郵> 來註冊。' -usage_unreg: '&c用法: /unregister <密碼>' -pwd_changed: '&c密碼更改成功!' -user_unknown: '&c該用戶並未註冊。' -password_error: '&f密碼不符合。' -password_error_nick: '&f你不能使用你的名字作為密碼。' -password_error_unsafe: '&f你不能使用安全性過低的碼。' -invalid_session: '&f登入階段資料不相同,請等待登入階段結束。' -reg_only: '&f只限已註冊用戶,請先到 https://www.example.com 註冊。' -logged_in: '&c你已經登入過了。' -logout: '&b登出成功。' -same_nick: '&f同名玩家已在遊玩。' -registered: '&b註冊成功。' -pass_len: '&f你的密碼太短或太長。' -reload: '&b系統設定及資料庫已重新載入。' -timeout: '&f登入逾時,請重新登入。' -usage_changepassword: '&f用法: /changepassword <舊密碼> <新密碼>' -name_len: '&c你的用戶名太短或太長。' -regex: '&c你的用戶名含有不容許的字符。以下為准許之字母: REG_EX。' -add_email: '&b請為你的帳戶添加電郵地址: /email add <電郵地址> <重覆電郵地址>。' -bad_database_email: '/email 只適用於使用MySQL或SQLite之伺服器,請聯絡管理員。' -recovery_email: '&c忘記密碼?請使用 /email recovery <電郵地址> 來更新密碼。' -usage_captcha: '&c用法: /captcha ' -wrong_captcha: '&c驗證碼錯誤,請再次輸入 /captcha THE_CAPTCHA。' -valid_captcha: '&c驗證碼無效!' -kick_forvip: '&cVIP玩家登入了滿人的伺服器。' -kick_fullserver: '&c因為伺服器滿人,請稍候再試。' -usage_email_add: '&f用法: /email add <電郵> <重覆電郵>' -usage_email_change: '&f用法: /email change <舊電郵> <新電郵>' -usage_email_recovery: '&f用法: /email recovery <電郵>' -new_email_invalid: '新電郵地址不正確。' -old_email_invalid: '舊電郵地址不正確。' -email_invalid: '電郵地址不正確。' -email_added: '電郵地址已加入。' -email_confirm: '請確認電郵地址。' -email_changed: '電郵地址已更改。' -email_send: '已寄出忘記密碼信件。' -country_banned: '你的國家已被本伺服器封禁。' -antibot_auto_enabled: '防止機械人程序因大量不尋常連線而啟用。' -antibot_auto_disabled: '防止機械人程序將於 %m 分鐘後停止運作。' -email_already_used: '&4邮箱已被使用' -kick_antibot: '[AuthMe] 防机器人程序已启用 !请稍等几分钟後才再次进入服务器' -email_exists: '&c恢复邮件已发送 ! 你可以丢弃它然後使用以下的指令来发送新的邮件:' -two_factor_create: '&2你的代码是 %code,你可以使用 %url 来扫描' -# 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 try another name!' \ No newline at end of file +# Translator: lifehome # +# Last modif: 1459528742 UTC # +# -------------------------------------------- # +kick_antibot: '&8[&6用戶系統&8] &c伺服器錯誤!請稍候再嘗試登入吧。 &7(err: kick_due2_bot)' +unknown_user: '&8[&6用戶系統&8] &f用戶資料並不存在。' +unsafe_spawn: '&8[&6用戶系統&8] &f你的登出位置不安全,現在將傳送你到重生點。' +not_logged_in: '&8[&6用戶系統&8] &c你還沒有登入 !' +reg_voluntarily: '&8[&6用戶系統&8] &f你可以使用這個指令來註冊: 《 /register <密碼> <重覆密碼> 》' +usage_log: '&8[&6用戶系統&8] &f用法: 《 /login <密碼> 》' +wrong_pwd: '&8[&6用戶系統&8] &c你輸入了錯誤的密碼。' +unregistered: '&8[&6用戶系統&8] &c你已成功刪除會員註冊記錄。' +reg_disabled: '&8[&6用戶系統&8] &c本伺服器已停止新玩家註冊。' +valid_session: '&8[&6用戶系統&8] &b嗨 ! 歡迎回來喔~' +login: '&8[&6用戶系統&8] &c你成功登入了。' +vb_nonActiv: '&8[&6用戶系統&8] &f你的帳戶還沒有經過電郵驗證 !' +user_regged: '&8[&6用戶系統&8] &c此用戶名已經註冊過了。' +usage_reg: '&8[&6用戶系統&8] &f用法: 《 /register <密碼> <重覆密碼> 》' +max_reg: '&8[&6用戶系統&8] &f你的IP地址已達到註冊數上限。' +no_perm: '&8[&6用戶系統&8] &b嗯~你想幹甚麼?' +error: '&8[&6用戶系統&8] &f發生錯誤,請與管理員聯絡。' +login_msg: '&8[&6用戶系統&8] &c請使用這個指令來登入: 《 /login <密碼> 》' +reg_msg: '&8[&6用戶系統&8] &c請使用這個指令來註冊: 《 /register <密碼> <重覆密碼> 》' +reg_email_msg: '&8[&6用戶系統&8] &c請使用這個指令來註冊: 《 /register <電郵> <重覆電郵> 》' +usage_unreg: '&8[&6用戶系統&8] &f用法: 《 /unregister <密碼> 》' +pwd_changed: '&8[&6用戶系統&8] &c你成功更換了你的密碼 !' +user_unknown: '&8[&6用戶系統&8] &c此用戶名沒有已登記資料。' +password_error: '&8[&6用戶系統&8] &f密碼不符合。' +password_error_nick: '&8[&6用戶系統&8] &c這個密碼太不安全了!' +password_error_unsafe: '&8[&6用戶系統&8] &c這個密碼太不安全了!' +invalid_session: '&8[&6用戶系統&8] &f登入階段資料已損壞,請等待登入階段結束。' +reg_only: '&8[&6用戶系統&8] &f限已註冊會員,請先到本服網站進行註冊。' +logged_in: '&8[&6用戶系統&8] &c你已經登入過了。' +logout: '&8[&6用戶系統&8] &b你成功登出了。' +same_nick: '&8[&6用戶系統&8] &f同名玩家已在遊玩。' +registered: '&8[&6用戶系統&8] &b你成功註冊了。' +pass_len: '&8[&6用戶系統&8] &f你的密碼並不符合規定長度。' +reload: '&8[&6用戶系統&8] &b登入系統設定及資料庫重新載入完畢。' +timeout: '&8[&6用戶系統&8] &f登入逾時。' +usage_changepassword: '&8[&6用戶系統&8] &f用法: 《 /changepassword <舊密碼> <新密碼> 》' +name_len: '&8[&6用戶系統&8] &c你的用戶名不符合規定長度。' +regex: '&8[&6用戶系統&8] &c用戶名稱錯誤! 登入系統只接受以下字符: REG_EX' +add_email: '&8[&6用戶系統&8] &b請為你的帳戶立即添加電郵地址: 《 /email add <電郵地址> <重覆電郵地址> 》' +recovery_email: '&8[&6用戶系統&8] &b忘記密碼?請使用 /email recovery <電郵地址> 來更新密碼。' +usage_captcha: '&8[&6用戶系統&8] &f用法: 《 /captcha 》' +wrong_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼無效,請使用 《 /captcha 》 再次輸入。' +valid_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼無效 !' +kick_forvip: '&c喔!因為有VIP玩家登入了伺服器。' +kick_fullserver: '&c抱歉! 因為伺服器滿人了,所以你目前未能登入伺服器。' +usage_email_add: '&8[&6用戶系統&8] &f用法: 《 /email add <電郵> <重覆電郵> 》' +usage_email_change: '&8[&6用戶系統&8] &f用法: 《 /email change <舊電郵> <新電郵> 》' +usage_email_recovery: '&8[&6用戶系統&8] &f用法: 《 /email recovery <電郵> 》' +new_email_invalid: '&8[&6用戶系統&8] &c你所填寫的新電郵地址並不正確。' +old_email_invalid: '&8[&6用戶系統&8] &c你所填寫的舊電郵地址並不正確。' +email_invalid: '&8[&6用戶系統&8] &c你所填寫的電郵地址並不正確。' +email_added: '&8[&6用戶系統&8] &a已新增你的電郵地址。' +email_confirm: '&8[&6用戶系統&8] &5請重覆輸入你的電郵地址。' +email_changed: '&8[&6用戶系統&8] &a你的電郵地址已更改。' +email_send: '&8[&6用戶系統&8] &a忘記密碼信件已寄出,請查收。' +country_banned: '&8[&6用戶系統&8] &4本伺服器已停止對你的國家提供遊戲服務。' +antibot_auto_enabled: '&8[&6用戶系統&8] &3防止機械人程序已因應現時大量不尋常連線而啟用。' +antibot_auto_disabled: '&8[&6用戶系統&8] &3不正常連接數已減少,防止機械人程序將於 %m 分鐘後停止。' +email_already_used: '&8[&6用戶系統&8] &4這個電郵地址已被使用。' +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」登入遊戲。' \ 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 d31431f4..94996b16 100644 --- a/src/main/resources/messages/messages_zhtw.yml +++ b/src/main/resources/messages/messages_zhtw.yml @@ -1,6 +1,6 @@ -# Translator: MineWolf50 -# Last Time Edit : 2015 / 7 / 14 , A.M.10:14 -# = = = = = = = = = = = = = = = = = = = = = = = # +# Translator: MineWolf50, lifehome # +# Last modif: 1459528742 UTC # +# -------------------------------------------- # unknown_user: "&b【AuthMe】&6沒有在資料庫內找到該玩家。" unsafe_spawn: '&b【AuthMe】&6你登出的地點不安全,已傳送你到安全的地點。' not_logged_in: '&b【AuthMe】&6你還沒有登入!' From c010a371d46738781b2ee557af1cf532f653cab4 Mon Sep 17 00:00:00 2001 From: Ivan Ip Date: Sat, 2 Apr 2016 01:11:19 +0800 Subject: [PATCH 07/71] Fix placeholder and string sortings. --- src/main/resources/messages/messages_zhcn.yml | 4 ++-- src/main/resources/messages/messages_zhhk.yml | 2 +- src/main/resources/messages/messages_zhtw.yml | 20 +++++++++---------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/resources/messages/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml index be7e1f9c..0334f548 100644 --- a/src/main/resources/messages/messages_zhcn.yml +++ b/src/main/resources/messages/messages_zhcn.yml @@ -41,8 +41,8 @@ name_len: '&8[&6玩家系统&8] &c你的用户名太短或者太长了' regex: '&8[&6玩家系统&8] &c你的用户名包含非法字母,用户名里允许的字母: REG_EX' add_email: '&8[&6玩家系统&8] &c请输入“/email add <你的邮箱> <再输入一次以确认>”以把你的邮箱添加到此帐号' recovery_email: '&8[&6玩家系统&8] &c忘了你的密码?请输入:“/email recovery <你的邮箱>”' -usage_captcha: '&8[&6玩家系统&8] &c正确用法:/captcha <验证码>' -wrong_captcha: '&8[&6玩家系统&8] &c错误的验证码,请输入:“/captcha <验证码>”' +usage_captcha: '&8[&6玩家系统&8] &c正确用法:/captcha ' +wrong_captcha: '&8[&6玩家系统&8] &c错误的验证码,请输入:“/captcha THE_CAPTCHA”' valid_captcha: '&8[&6玩家系统&8] &c你的验证码是有效的!' kick_forvip: '&8[&6玩家系统&8] &cA VIP玩家加入了已满的服务器!' kick_fullserver: '&8[&6玩家系统&8] &c抱歉,服务器已满!' diff --git a/src/main/resources/messages/messages_zhhk.yml b/src/main/resources/messages/messages_zhhk.yml index e5cba6b3..3dc579c7 100644 --- a/src/main/resources/messages/messages_zhhk.yml +++ b/src/main/resources/messages/messages_zhhk.yml @@ -42,7 +42,7 @@ regex: '&8[&6用戶系統&8] &c用戶名稱錯誤! 登入系統只接受以下 add_email: '&8[&6用戶系統&8] &b請為你的帳戶立即添加電郵地址: 《 /email add <電郵地址> <重覆電郵地址> 》' recovery_email: '&8[&6用戶系統&8] &b忘記密碼?請使用 /email recovery <電郵地址> 來更新密碼。' usage_captcha: '&8[&6用戶系統&8] &f用法: 《 /captcha 》' -wrong_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼無效,請使用 《 /captcha 》 再次輸入。' +wrong_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼無效,請使用 《 /captcha THE_CAPTCHA 》 再次輸入。' valid_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼無效 !' kick_forvip: '&c喔!因為有VIP玩家登入了伺服器。' kick_fullserver: '&c抱歉! 因為伺服器滿人了,所以你目前未能登入伺服器。' diff --git a/src/main/resources/messages/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml index 94996b16..52dc0f45 100644 --- a/src/main/resources/messages/messages_zhtw.yml +++ b/src/main/resources/messages/messages_zhtw.yml @@ -1,6 +1,7 @@ # Translator: MineWolf50, lifehome # # Last modif: 1459528742 UTC # # -------------------------------------------- # +kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' unknown_user: "&b【AuthMe】&6沒有在資料庫內找到該玩家。" unsafe_spawn: '&b【AuthMe】&6你登出的地點不安全,已傳送你到安全的地點。' not_logged_in: '&b【AuthMe】&6你還沒有登入!' @@ -9,8 +10,6 @@ usage_log: '&b【AuthMe】&6用法: &c"/login <密碼>"' wrong_pwd: '&b【AuthMe】&6密碼錯誤!' unregistered: '&b【AuthMe】&6你已經成功取消註冊。' reg_disabled: '&b【AuthMe】&6已關閉註冊功能' -password_error_nick: '&b【AuthMe】&6你不可以用你的 ID ( 名稱 ) 來當作密碼 !' -password_error_unsafe: '&b【AuthMe】&6你不可以使用這個不安全的密碼' valid_session: '&b【AuthMe】&6你已經成功登入!' login: '&b【AuthMe】&6密碼正確,你已成功登入!' vb_nonActiv: '&b【AuthMe】&6你的帳號還沒有經過驗證! 檢查看看你的電子信箱 (Email) 吧!' @@ -26,6 +25,8 @@ usage_unreg: '&b【AuthMe】&6用法: &c"/unregister <密碼>"' pwd_changed: '&b【AuthMe】&6密碼變更成功!' user_unknown: '&b【AuthMe】&6這個帳號還沒有註冊過' password_error: '&b【AuthMe】&6兩次輸入的密碼不一致!' +password_error_nick: '&b【AuthMe】&6你不可以用你的 ID ( 名稱 ) 來當作密碼 !' +password_error_unsafe: '&b【AuthMe】&6你不可以使用這個不安全的密碼' invalid_session: '&b【AuthMe】&6憑證日期不相符!' reg_only: '&b【AuthMe】&6請到下列網站 :「 http://example.com 」 進行註冊' logged_in: '&b【AuthMe】&6你已經登入了!' @@ -37,13 +38,11 @@ reload: '&b【AuthMe】&6已重新讀取設定檔及資料庫' timeout: '&b【AuthMe】&6超過登入時間,請稍後再試一次' usage_changepassword: '&b【AuthMe】&6用法: &c"/changepassword <舊密碼> <新密碼>"' name_len: '&b【AuthMe】&6你的暱稱 太長 / 太短 了!' -# TODO regex: Missing tag REG_EX -regex: '&b【AuthMe】&6暱稱裡包含不能使用的字符' +regex: '&b【AuthMe】&6暱稱裡能使用的字符為: REG_EX' add_email: '&b【AuthMe】&6請使用 &c"/email add <你的Email> <再次輸入你的Email>" &6來添加 Email' recovery_email: '&b【AuthMe】&6忘記密碼了嗎? 使用 &c"/email recovery <你的Email>"' usage_captcha: '&b【AuthMe】&6請用 &c"/captcha " &6來輸入你的驗證碼' -# TODO wrong_captcha: Missing tag THE_CAPTCHA -wrong_captcha: '&b【AuthMe】&6錯誤的驗證碼' +wrong_captcha: '&b【AuthMe】&6錯誤的驗證碼,請使用 《 /captcha THE_CAPTCHA 》 再試一次吧。' valid_captcha: '&b【AuthMe】&6驗證碼無效!' kick_forvip: '&b【AuthMe】&6你已經被請出。&c原因 : 有 VIP 玩家登入伺服器' kick_fullserver: '&b【AuthMe】&6伺服器已經滿了,請等等再試一次' @@ -61,8 +60,7 @@ email_exists: '&b【AuthMe】&6這個帳戶已經有設定電子郵件了' country_banned: '&b【AuthMe】&6你所在的地區無法進入此伺服器' antibot_auto_enabled: '&b【AuthMe】&6AntiBotMod已自動啟用!' antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉' -# TODO email_already_used: '&4The email address is already being used' -# 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 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 try another name!' \ No newline at end of file +email_already_used: '&4The email address is already being used' +invalid_name_case: 'You should join using username %valid, not %invalid.' +two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +not_owner_error: 'You are not the owner of this account. Please try another name!' \ No newline at end of file From 0ff8430bf239a58d53bc0f5104e3ac19b571ee76 Mon Sep 17 00:00:00 2001 From: Ivan Ip Date: Sat, 2 Apr 2016 01:23:09 +0800 Subject: [PATCH 08/71] Fixed some typo, also updated zh_TW --- src/main/resources/messages/messages_zhcn.yml | 2 +- src/main/resources/messages/messages_zhtw.yml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/resources/messages/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml index 0334f548..fbf89b5e 100644 --- a/src/main/resources/messages/messages_zhcn.yml +++ b/src/main/resources/messages/messages_zhcn.yml @@ -28,7 +28,7 @@ password_error: '&8[&6玩家系统&8] &f密码不相同' password_error_nick: '&8[&6玩家系统&8] &f你不能使用你的名字作为密码。 ' password_error_unsafe: '&8[&6玩家系统&8] &f你不能使用安全性过低的码。 ' invalid_session: '&8[&6玩家系统&8] &f登陆数据异常,请等待登陆结束' -reg_only: '&8[&6玩家系统&8] &f只允许注册过的玩家进服!请到 https://crafting.hk 注册' +reg_only: '&8[&6玩家系统&8] &f只允许注册过的玩家进服!请到 https://example.cn 注册' logged_in: '&8[&6玩家系统&8] &c你已经登陆过了!' logout: '&8[&6玩家系统&8] &c已成功登出!' same_nick: '&8[&6玩家系统&8] &f同样的用户名现在在线且已经登录了!' diff --git a/src/main/resources/messages/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml index 52dc0f45..9b0d536c 100644 --- a/src/main/resources/messages/messages_zhtw.yml +++ b/src/main/resources/messages/messages_zhtw.yml @@ -1,7 +1,7 @@ # Translator: MineWolf50, lifehome # # Last modif: 1459528742 UTC # # -------------------------------------------- # -kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +kick_antibot: '&b【AuthMe】&cAntiBotMod 正在啟用中,請稍後再嘗試登入吧!' unknown_user: "&b【AuthMe】&6沒有在資料庫內找到該玩家。" unsafe_spawn: '&b【AuthMe】&6你登出的地點不安全,已傳送你到安全的地點。' not_logged_in: '&b【AuthMe】&6你還沒有登入!' @@ -28,7 +28,7 @@ password_error: '&b【AuthMe】&6兩次輸入的密碼不一致!' password_error_nick: '&b【AuthMe】&6你不可以用你的 ID ( 名稱 ) 來當作密碼 !' password_error_unsafe: '&b【AuthMe】&6你不可以使用這個不安全的密碼' invalid_session: '&b【AuthMe】&6憑證日期不相符!' -reg_only: '&b【AuthMe】&6請到下列網站 :「 http://example.com 」 進行註冊' +reg_only: '&b【AuthMe】&6請到下列網站 :「 https://example.tw 」 進行註冊' logged_in: '&b【AuthMe】&6你已經登入了!' logout: '&b【AuthMe】&6你已成功登出' same_nick: '&b【AuthMe】&6有同樣帳號的玩家在線上!' @@ -56,11 +56,11 @@ email_added: '&b【AuthMe】&6已添加Email!' email_confirm: '&b【AuthMe】&6請驗證你的Email!' email_changed: '&b【AuthMe】&6Email已變更!' email_send: '&b【AuthMe】&6已經送出重設密碼要求至你的Email , 請查收。' -email_exists: '&b【AuthMe】&6這個帳戶已經有設定電子郵件了' country_banned: '&b【AuthMe】&6你所在的地區無法進入此伺服器' antibot_auto_enabled: '&b【AuthMe】&6AntiBotMod已自動啟用!' antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉' -email_already_used: '&4The email address is already being used' -invalid_name_case: 'You should join using username %valid, not %invalid.' -two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -not_owner_error: 'You are not the owner of this account. Please try another name!' \ No newline at end of file +email_already_used: '&b【AuthMe】&4這個電郵地址已被使用。' +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」登入遊戲。' \ No newline at end of file From 4f86604699d6a491e329e45036f385b2e6ce761c Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 2 Apr 2016 22:44:20 +0200 Subject: [PATCH 09/71] Check valid password via service - Create validation service; fixes same code being duplicated in four places - Goal is to remove Utils class, by moving methods to validation service or other services - Remove unused properties in legacy settings --- src/main/java/fr/xephi/authme/AuthMe.java | 11 ++- .../xephi/authme/command/CommandService.java | 16 +++- .../authme/ChangePasswordAdminCommand.java | 26 +----- .../authme/RegisterAdminCommand.java | 22 +---- .../changepassword/ChangePasswordCommand.java | 21 +---- .../fr/xephi/authme/process/Management.java | 2 +- .../xephi/authme/process/ProcessService.java | 16 +++- .../process/register/AsyncRegister.java | 41 ++++----- .../fr/xephi/authme/settings/Settings.java | 26 +----- .../xephi/authme/util/ValidationService.java | 42 +++++++++ .../authme/command/CommandServiceTest.java | 20 +++- .../ChangePasswordAdminCommandTest.java | 84 +++-------------- .../ChangePasswordCommandTest.java | 70 ++------------ .../authme/process/ProcessServiceTest.java | 20 +++- .../authme/util/ValidationServiceTest.java | 92 +++++++++++++++++++ 15 files changed, 263 insertions(+), 246 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/util/ValidationService.java create mode 100644 src/test/java/fr/xephi/authme/util/ValidationServiceTest.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 018ebf31..862c6dd7 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -62,6 +62,7 @@ import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.MigrationService; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; +import fr.xephi.authme.util.ValidationService; import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -260,8 +261,9 @@ public class AuthMe extends JavaPlugin { // Set up the permissions manager and command handler permsMan = initializePermissionsManager(); + ValidationService validationService = new ValidationService(newSettings); commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, ipAddressManager, - pluginHooks, spawnLoader, antiBot); + pluginHooks, spawnLoader, antiBot, validationService); // AntiBot delay BukkitService bukkitService = new BukkitService(this); @@ -299,7 +301,7 @@ public class AuthMe extends JavaPlugin { // Set up the management ProcessService processService = new ProcessService(newSettings, messages, this, database, ipAddressManager, - passwordSecurity, pluginHooks, spawnLoader); + passwordSecurity, pluginHooks, spawnLoader, validationService); management = new Management(this, processService, database, PlayerCache.getInstance()); // Set up the BungeeCord hook @@ -432,12 +434,13 @@ public class AuthMe extends JavaPlugin { private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages, PasswordSecurity passwordSecurity, NewSetting settings, IpAddressManager ipAddressManager, PluginHooks pluginHooks, - SpawnLoader spawnLoader, AntiBot antiBot) { + SpawnLoader spawnLoader, AntiBot antiBot, + ValidationService validationService) { HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER)); Set baseCommands = CommandInitializer.buildCommands(); CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager); CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot); + permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot, validationService); return new CommandHandler(commandService); } diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index a4791e68..9d8252a0 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -15,6 +15,7 @@ import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import java.util.List; @@ -36,6 +37,7 @@ public class CommandService { private final PluginHooks pluginHooks; private final SpawnLoader spawnLoader; private final AntiBot antiBot; + private final ValidationService validationService; /** * Constructor. @@ -54,7 +56,7 @@ public class CommandService { public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages, PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings, IpAddressManager ipAddressManager, PluginHooks pluginHooks, SpawnLoader spawnLoader, - AntiBot antiBot) { + AntiBot antiBot, ValidationService validationService) { this.authMe = authMe; this.messages = messages; this.helpProvider = helpProvider; @@ -66,6 +68,7 @@ public class CommandService { this.pluginHooks = pluginHooks; this.spawnLoader = spawnLoader; this.antiBot = antiBot; + this.validationService = validationService; } /** @@ -219,4 +222,15 @@ public class CommandService { return antiBot; } + /** + * Verifies whether a password is valid according to the plugin settings. + * + * @param password the password to verify + * @param username the username the password is associated with + * @return message key with the password error, or {@code null} if password is valid + */ + public MessageKey validatePassword(String password, String username) { + return validationService.validatePassword(password, username); + } + } 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 8ba9d740..867443ed 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 @@ -7,8 +7,6 @@ import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.CommandSender; import java.util.List; @@ -22,30 +20,16 @@ public class ChangePasswordAdminCommand implements ExecutableCommand { public void executeCommand(final CommandSender sender, List arguments, final CommandService commandService) { // Get the player and password - String playerName = arguments.get(0); + final String playerName = arguments.get(0); final String playerPass = arguments.get(1); // Validate the password - String playerPassLowerCase = playerPass.toLowerCase(); - if (!playerPassLowerCase.matches(commandService.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX))) { - commandService.send(sender, MessageKey.PASSWORD_MATCH_ERROR); - return; - } - if (playerPassLowerCase.equalsIgnoreCase(playerName)) { - commandService.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); - return; - } - if (playerPassLowerCase.length() < commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH) - || playerPassLowerCase.length() > commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) { - commandService.send(sender, MessageKey.INVALID_PASSWORD_LENGTH); - return; - } - // TODO #602 20160312: The UNSAFE_PASSWORDS should be all lowercase - // -> introduce a lowercase String list property type - if (commandService.getProperty(SecuritySettings.UNSAFE_PASSWORDS).contains(playerPassLowerCase)) { - commandService.send(sender, MessageKey.PASSWORD_UNSAFE_ERROR); + MessageKey passwordError = commandService.validatePassword(playerPass, playerName); + if (passwordError != null) { + commandService.send(sender, passwordError); return; } + // Set the password final String playerNameLowerCase = playerName.toLowerCase(); commandService.runTaskAsynchronously(new Runnable() { 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 a33f3eb3..e0010a5b 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 @@ -6,8 +6,6 @@ import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -25,26 +23,14 @@ public class RegisterAdminCommand implements ExecutableCommand { final String playerName = arguments.get(0); final String playerPass = arguments.get(1); final String playerNameLowerCase = playerName.toLowerCase(); - final String playerPassLowerCase = playerPass.toLowerCase(); // Command logic - if (!playerPassLowerCase.matches(Settings.getPassRegex)) { - commandService.send(sender, MessageKey.PASSWORD_MATCH_ERROR); - return; - } - if (playerPassLowerCase.equalsIgnoreCase(playerName)) { - commandService.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); - return; - } - if (playerPassLowerCase.length() < commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH) - || playerPassLowerCase.length() > commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) { - commandService.send(sender, MessageKey.INVALID_PASSWORD_LENGTH); - return; - } - if (!Settings.unsafePasswords.isEmpty() && Settings.unsafePasswords.contains(playerPassLowerCase)) { - commandService.send(sender, MessageKey.PASSWORD_UNSAFE_ERROR); + MessageKey passwordError = commandService.validatePassword(playerPass, playerName); + if (passwordError != null) { + commandService.send(sender, passwordError); return; } + commandService.runTaskAsynchronously(new Runnable() { @Override 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 336df152..7d378ca8 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 @@ -5,8 +5,6 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.task.ChangePasswordTask; import org.bukkit.entity.Player; @@ -30,22 +28,9 @@ public class ChangePasswordCommand extends PlayerCommand { } // Make sure the password is allowed - String playerPassLowerCase = newPassword.toLowerCase(); - if (!playerPassLowerCase.matches(commandService.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX))) { - commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR); - return; - } - if (playerPassLowerCase.equalsIgnoreCase(name)) { - commandService.send(player, MessageKey.PASSWORD_IS_USERNAME_ERROR); - return; - } - if (playerPassLowerCase.length() < commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH) - || playerPassLowerCase.length() > commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) { - commandService.send(player, MessageKey.INVALID_PASSWORD_LENGTH); - return; - } - if (commandService.getProperty(SecuritySettings.UNSAFE_PASSWORDS).contains(playerPassLowerCase)) { - commandService.send(player, MessageKey.PASSWORD_UNSAFE_ERROR); + MessageKey passwordError = commandService.validatePassword(newPassword, name); + if (passwordError != null) { + commandService.send(player, passwordError); return; } diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java index 4cea16fc..4b279c9a 100644 --- a/src/main/java/fr/xephi/authme/process/Management.java +++ b/src/main/java/fr/xephi/authme/process/Management.java @@ -41,7 +41,7 @@ public class Management { } public void performRegister(final Player player, final String password, final String email) { - runTask(new AsyncRegister(player, password, email, plugin, dataSource, processService)); + runTask(new AsyncRegister(player, password, email, plugin, dataSource, playerCache, processService)); } public void performUnregister(final Player player, final String password, final boolean force) { diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java index 7f696fe1..0489447a 100644 --- a/src/main/java/fr/xephi/authme/process/ProcessService.java +++ b/src/main/java/fr/xephi/authme/process/ProcessService.java @@ -11,6 +11,7 @@ import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.event.Event; import org.bukkit.scheduler.BukkitTask; @@ -28,10 +29,11 @@ public class ProcessService { private final PasswordSecurity passwordSecurity; private final PluginHooks pluginHooks; private final SpawnLoader spawnLoader; + private final ValidationService validationService; public ProcessService(NewSetting settings, Messages messages, AuthMe authMe, DataSource dataSource, IpAddressManager ipAddressManager, PasswordSecurity passwordSecurity, PluginHooks pluginHooks, - SpawnLoader spawnLoader) { + SpawnLoader spawnLoader, ValidationService validationService) { this.settings = settings; this.messages = messages; this.authMe = authMe; @@ -40,6 +42,7 @@ public class ProcessService { this.passwordSecurity = passwordSecurity; this.pluginHooks = pluginHooks; this.spawnLoader = spawnLoader; + this.validationService = validationService; } /** @@ -199,4 +202,15 @@ public class ProcessService { return dataSource; } + /** + * Verifies whether a password is valid according to the plugin settings. + * + * @param password the password to verify + * @param username the username the password is associated with + * @return message key with the password error, or {@code null} if password is valid + */ + public MessageKey validatePassword(String password, String username) { + return validationService.validatePassword(password, username); + } + } 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 47b715a3..e212fabc 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -12,6 +12,8 @@ import fr.xephi.authme.security.HashAlgorithm; 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.RegistrationSettings; +import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.StringUtils; import org.bukkit.Bukkit; @@ -30,10 +32,11 @@ public class AsyncRegister implements Process { private final String email; private final AuthMe plugin; private final DataSource database; + private final PlayerCache playerCache; private final ProcessService service; public AsyncRegister(Player player, String password, String email, AuthMe plugin, DataSource data, - ProcessService service) { + PlayerCache playerCache, ProcessService service) { this.player = player; this.password = password; this.name = player.getName().toLowerCase(); @@ -41,32 +44,24 @@ public class AsyncRegister implements Process { this.plugin = plugin; this.database = data; this.ip = service.getIpAddressManager().getPlayerIp(player); + this.playerCache = playerCache; this.service = service; } private boolean preRegisterCheck() { - String passLow = password.toLowerCase(); - if (PlayerCache.getInstance().isAuthenticated(name)) { + if (playerCache.isAuthenticated(name)) { service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); return false; - } else if (!Settings.isRegistrationEnabled) { + } else if (!service.getProperty(RegistrationSettings.IS_ENABLED)) { service.send(player, MessageKey.REGISTRATION_DISABLED); return false; } //check the password safety only if it's not a automatically generated password if (service.getProperty(SecuritySettings.PASSWORD_HASH) != HashAlgorithm.TWO_FACTOR) { - if (!passLow.matches(Settings.getPassRegex)) { - service.send(player, MessageKey.PASSWORD_MATCH_ERROR); - return false; - } else if (passLow.equalsIgnoreCase(player.getName())) { - service.send(player, MessageKey.PASSWORD_IS_USERNAME_ERROR); - return false; - } else if (password.length() < Settings.getPasswordMinLen || password.length() > Settings.passwordMaxLength) { - service.send(player, MessageKey.INVALID_PASSWORD_LENGTH); - return false; - } else if (!Settings.unsafePasswords.isEmpty() && Settings.unsafePasswords.contains(password.toLowerCase())) { - service.send(player, MessageKey.PASSWORD_UNSAFE_ERROR); + MessageKey passwordError = service.validatePassword(password, player.getName()); + if (passwordError != null) { + service.send(player, passwordError); return false; } } @@ -75,15 +70,17 @@ public class AsyncRegister implements Process { if (database.isAuthAvailable(name)) { service.send(player, MessageKey.NAME_ALREADY_REGISTERED); return false; - } else if(Settings.getmaxRegPerIp > 0 - && !ip.equalsIgnoreCase("127.0.0.1") - && !ip.equalsIgnoreCase("localhost") + } + + final int maxRegPerIp = service.getProperty(RestrictionSettings.MAX_REGISTRATION_PER_IP); + if (maxRegPerIp > 0 + && !"127.0.0.1".equalsIgnoreCase(ip) + && !"localhost".equalsIgnoreCase(ip) && !plugin.getPermissionsManager().hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)) { - int maxReg = Settings.getmaxRegPerIp; List otherAccounts = database.getAllAuthsByIp(ip); - if (otherAccounts.size() >= maxReg) { - service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxReg), - Integer.toString(otherAccounts.size()), StringUtils.join(", ", otherAccounts.toString())); + if (otherAccounts.size() >= maxRegPerIp) { + service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerIp), + Integer.toString(otherAccounts.size()), StringUtils.join(", ", otherAccounts)); return false; } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index a35c6df8..ef9a4b9d 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -38,11 +38,10 @@ public final class Settings { public static List forceCommandsAsConsole; public static List forceRegisterCommands; public static List forceRegisterCommandsAsConsole; - public static List unsafePasswords; public static HashAlgorithm getPasswordHash; public static Pattern nickPattern; public static boolean useLogging = false; - public static boolean isChatAllowed, isPermissionCheckEnabled, isRegistrationEnabled, + public static boolean isChatAllowed, isPermissionCheckEnabled, isForcedRegistrationEnabled, isTeleportToSpawnEnabled, isSessionsEnabled, isAllowRestrictedIp, isMovementAllowed, isKickNonRegisteredEnabled, @@ -64,10 +63,10 @@ public final class Settings { unRegisteredGroup, backupWindowsPath, getRegisteredGroup, rakamakUsers, rakamakUsersIp, getmailAccount, defaultWorld, - spawnPriority, crazyloginFileName, getPassRegex, sendPlayerTo; + spawnPriority, crazyloginFileName, sendPlayerTo; public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength, getMinNickLength, - getPasswordMinLen, getMovementRadius, getmaxRegPerIp, + getPasswordMinLen, getMovementRadius, getNonActivatedGroup, passwordMaxLength, getRecoveryPassLength, getMailPort, maxLoginTry, captchaLength, saltLength, getmaxRegPerEmail, bCryptLog2Rounds, getMaxLoginPerIp, getMaxJoinPerIp; @@ -86,7 +85,6 @@ public final class Settings { private static void loadVariables() { isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK); isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true); - isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true); isTeleportToSpawnEnabled = load(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN); getWarnMessageInterval = load(RegistrationSettings.MESSAGE_INTERVAL); isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED); @@ -110,7 +108,6 @@ public final class Settings { isForceSpawnLocOnJoinEnabled = configFile.getBoolean("settings.restrictions.ForceSpawnLocOnJoinEnabled", false); isSaveQuitLocationEnabled = configFile.getBoolean("settings.restrictions.SaveQuitLocation", false); isForceSurvivalModeEnabled = configFile.getBoolean("settings.GameMode.ForceSurvivalMode", false); - getmaxRegPerIp = configFile.getInt("settings.restrictions.maxRegPerIp", 1); getPasswordHash = load(SecuritySettings.PASSWORD_HASH); getUnloggedinGroup = load(SecuritySettings.UNLOGGEDIN_GROUP); getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1); @@ -174,7 +171,6 @@ public final class Settings { forceCommandsAsConsole = configFile.getStringList("settings.forceCommandsAsConsole"); recallEmail = configFile.getBoolean("Email.recallPlayers", false); useWelcomeMessage = load(RegistrationSettings.USE_WELCOME_MESSAGE); - unsafePasswords = configFile.getStringList("settings.security.unsafePasswords"); countriesBlacklist = configFile.getStringList("Protection.countriesBlacklist"); broadcastWelcomeMessage = load(RegistrationSettings.BROADCAST_WELCOME_MESSAGE); forceRegKick = configFile.getBoolean("settings.registration.forceKickAfterRegister", false); @@ -188,7 +184,6 @@ public final class Settings { delayJoinMessage = load(RegistrationSettings.DELAY_JOIN_MESSAGE); noTeleport = load(RestrictionSettings.NO_TELEPORT); crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db"); - getPassRegex = configFile.getString("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*"); forceRegisterCommands = configFile.getStringList("settings.forceRegisterCommands"); forceRegisterCommandsAsConsole = configFile.getStringList("settings.forceRegisterCommandsAsConsole"); customAttributes = configFile.getBoolean("Hooks.customAttributes"); @@ -198,21 +193,6 @@ public final class Settings { keepCollisionsDisabled = configFile.getBoolean("settings.keepCollisionsDisabled"); } - /** - * Method switchAntiBotMod. - * - * @param mode boolean - */ - public static void switchAntiBotMod(boolean mode) { - if (mode) { - isKickNonRegisteredEnabled = true; - antiBotInAction = true; - } else { - isKickNonRegisteredEnabled = configFile.getBoolean("settings.restrictions.kickNonRegistered", false); - antiBotInAction = false; - } - } - /** * Load the value via the new Property setup for temporary support within this old settings manager. * diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java new file mode 100644 index 00000000..1adbda71 --- /dev/null +++ b/src/main/java/fr/xephi/authme/util/ValidationService.java @@ -0,0 +1,42 @@ +package fr.xephi.authme.util; + +import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; + +/** + * Validation service. + */ +public class ValidationService { + + private final NewSetting settings; + + public ValidationService(NewSetting settings) { + this.settings = settings; + } + + /** + * Verifies whether a password is valid according to the plugin settings. + * + * @param password the password to verify + * @param username the username the password is associated with + * @return message key with the password error, or {@code null} if password is valid + */ + public MessageKey validatePassword(String password, String username) { + String passLow = password.toLowerCase(); + if (!passLow.matches(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX))) { + return MessageKey.PASSWORD_MATCH_ERROR; + } else if (passLow.equalsIgnoreCase(username)) { + return MessageKey.PASSWORD_IS_USERNAME_ERROR; + } else if (password.length() < settings.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH) + || password.length() > settings.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) { + return MessageKey.INVALID_PASSWORD_LENGTH; + } else if (settings.getProperty(SecuritySettings.UNSAFE_PASSWORDS).contains(passLow)) { + // TODO #602 20160312: The UNSAFE_PASSWORDS should be all lowercase + // -> introduce a lowercase String list property type + return MessageKey.PASSWORD_UNSAFE_ERROR; + } + return null; + } +} diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index d34ee633..dafe6966 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -15,6 +15,7 @@ import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.SecuritySettings; +import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Before; @@ -63,11 +64,13 @@ public class CommandServiceTest { private SpawnLoader spawnLoader; @Mock private AntiBot antiBot; + @Mock + private ValidationService validationService; @Before public void setUpService() { commandService = new CommandService(authMe, commandMapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot); + permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot, validationService); } @Test @@ -228,4 +231,19 @@ public class CommandServiceTest { // then assertThat(ipManager, equalTo(ipAddressManager)); } + + @Test + public void shouldValidatePassword() { + // given + String user = "asdf"; + String password = "mySecret55"; + given(validationService.validatePassword(password, user)).willReturn(MessageKey.INVALID_PASSWORD_LENGTH); + + // when + MessageKey result = commandService.validatePassword(password, user); + + // then + assertThat(result, equalTo(MessageKey.INVALID_PASSWORD_LENGTH)); + verify(validationService).validatePassword(password, user); + } } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java index 28a6a3f8..93c6c6ff 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java @@ -1,6 +1,5 @@ package fr.xephi.authme.command.executable.authme; -import com.google.common.base.Strings; import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; @@ -10,12 +9,12 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; 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 org.mockito.runners.MockitoJUnitRunner; import java.util.Arrays; @@ -29,8 +28,10 @@ import static org.mockito.Mockito.verify; /** * Test for {@link ChangePasswordAdminCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class ChangePasswordAdminCommandTest { + @Mock private CommandService service; @BeforeClass @@ -38,88 +39,22 @@ public class ChangePasswordAdminCommandTest { ConsoleLoggerTestInitializer.setupLogger(); } - @Before - public void setUpServiceMock() { - service = mock(CommandService.class); - given(service.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)).willReturn("[a-zA-Z]+"); - given(service.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)).willReturn(3); - given(service.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)).willReturn(20); - given(service.getProperty(SecuritySettings.UNSAFE_PASSWORDS)) - .willReturn(Arrays.asList("unsafe", "otherUnsafe")); - } - @Test - public void shouldRejectPasswordSameAsUsername() { + public void shouldRejectInvalidPassword() { // given ExecutableCommand command = new ChangePasswordAdminCommand(); CommandSender sender = mock(CommandSender.class); + given(service.validatePassword("Bobby", "bobby")).willReturn(MessageKey.PASSWORD_IS_USERNAME_ERROR); // when command.executeCommand(sender, Arrays.asList("bobby", "Bobby"), service); // then + verify(service).validatePassword("Bobby", "bobby"); verify(service).send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); verify(service, never()).getDataSource(); } - @Test - public void shouldRejectPasswordNotMatchingPattern() { - // given - ExecutableCommand command = new ChangePasswordAdminCommand(); - CommandSender sender = mock(CommandSender.class); - // service mock returns pattern a-zA-Z -> numbers should not be accepted - String invalidPassword = "invalid1234"; - - // when - command.executeCommand(sender, Arrays.asList("myPlayer123", invalidPassword), service); - - // then - verify(service).send(sender, MessageKey.PASSWORD_MATCH_ERROR); - verify(service, never()).getDataSource(); - } - - @Test - public void shouldRejectTooShortPassword() { - // given - ExecutableCommand command = new ChangePasswordAdminCommand(); - CommandSender sender = mock(CommandSender.class); - - // when - command.executeCommand(sender, Arrays.asList("player", "ab"), service); - - // then - verify(service).send(sender, MessageKey.INVALID_PASSWORD_LENGTH); - verify(service, never()).getDataSource(); - } - - @Test - public void shouldRejectTooLongPassword() { - // given - ExecutableCommand command = new ChangePasswordAdminCommand(); - CommandSender sender = mock(CommandSender.class); - - // when - command.executeCommand(sender, Arrays.asList("player", Strings.repeat("a", 30)), service); - - // then - verify(service).send(sender, MessageKey.INVALID_PASSWORD_LENGTH); - verify(service, never()).getDataSource(); - } - - @Test - public void shouldRejectUnsafePassword() { - // given - ExecutableCommand command = new ChangePasswordAdminCommand(); - CommandSender sender = mock(CommandSender.class); - - // when - command.executeCommand(sender, Arrays.asList("player", "unsafe"), service); - - // then - verify(service).send(sender, MessageKey.PASSWORD_UNSAFE_ERROR); - verify(service, never()).getDataSource(); - } - @Test public void shouldRejectCommandForUnknownUser() { // given @@ -173,6 +108,7 @@ public class ChangePasswordAdminCommandTest { runInnerRunnable(service); // then + verify(service).validatePassword(password, player); verify(service).send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS); verify(passwordSecurity).computeHash(password, player); verify(auth).setPassword(hashedPassword); @@ -209,6 +145,7 @@ public class ChangePasswordAdminCommandTest { runInnerRunnable(service); // then + verify(service).validatePassword(password, player); verify(service).send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS); verify(passwordSecurity).computeHash(password, player); verify(auth).setPassword(hashedPassword); @@ -244,6 +181,7 @@ public class ChangePasswordAdminCommandTest { runInnerRunnable(service); // then + verify(service).validatePassword(password, player); verify(service).send(sender, MessageKey.ERROR); verify(passwordSecurity).computeHash(password, player); verify(auth).setPassword(hashedPassword); diff --git a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java index 213dba4c..ef457205 100644 --- a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -57,9 +58,7 @@ public class ChangePasswordCommandTest { command.executeCommand(sender, new ArrayList(), commandService); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender).sendMessage(captor.capture()); - assertThat(captor.getValue(), containsString("only for players")); + verify(sender).sendMessage(argThat(containsString("only for players"))); } @Test @@ -76,75 +75,21 @@ public class ChangePasswordCommandTest { } @Test - public void shouldDenyInvalidPassword() { - // given - CommandSender sender = initPlayerWithName("name", true); - ChangePasswordCommand command = new ChangePasswordCommand(); - - // when - command.executeCommand(sender, Arrays.asList("old123", "!pass"), commandService); - - // then - verify(commandService).send(sender, MessageKey.PASSWORD_MATCH_ERROR); - } - - - @Test - public void shouldRejectPasswordEqualToNick() { - // given - CommandSender sender = initPlayerWithName("tester", true); - ChangePasswordCommand command = new ChangePasswordCommand(); - - // when - command.executeCommand(sender, Arrays.asList("old_", "Tester"), commandService); - - // then - verify(commandService).send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); - } - - @Test - public void shouldRejectTooLongPassword() { + public void shouldRejectInvalidPassword() { // given CommandSender sender = initPlayerWithName("abc12", true); ChangePasswordCommand command = new ChangePasswordCommand(); - given(commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)).willReturn(3); + String password = "newPW"; + given(commandService.validatePassword(password, "abc12")).willReturn(MessageKey.INVALID_PASSWORD_LENGTH); // when - command.executeCommand(sender, Arrays.asList("12", "test"), commandService); + command.executeCommand(sender, Arrays.asList("tester", password), commandService); // then + verify(commandService).validatePassword(password, "abc12"); verify(commandService).send(sender, MessageKey.INVALID_PASSWORD_LENGTH); } - @Test - public void shouldRejectTooShortPassword() { - // given - CommandSender sender = initPlayerWithName("abc12", true); - ChangePasswordCommand command = new ChangePasswordCommand(); - given(commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)).willReturn(7); - - // when - command.executeCommand(sender, Arrays.asList("oldverylongpassword", "tester"), commandService); - - // then - verify(commandService).send(sender, MessageKey.INVALID_PASSWORD_LENGTH); - } - - @Test - public void shouldRejectUnsafeCustomPassword() { - // given - CommandSender sender = initPlayerWithName("player", true); - ChangePasswordCommand command = new ChangePasswordCommand(); - given(commandService.getProperty(SecuritySettings.UNSAFE_PASSWORDS)) - .willReturn(Arrays.asList("test", "abc123")); - - // when - command.executeCommand(sender, Arrays.asList("oldpw", "abc123"), commandService); - - // then - verify(commandService).send(sender, MessageKey.PASSWORD_UNSAFE_ERROR); - } - @Test public void shouldForwardTheDataForValidPassword() { // given @@ -155,6 +100,7 @@ public class ChangePasswordCommandTest { command.executeCommand(sender, Arrays.asList("abc123", "abc123"), commandService); // then + verify(commandService).validatePassword("abc123", "parker"); verify(commandService, never()).send(eq(sender), any(MessageKey.class)); ArgumentCaptor taskCaptor = ArgumentCaptor.forClass(ChangePasswordTask.class); verify(commandService).runTaskAsynchronously(taskCaptor.capture()); diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java index da3c2f8d..23a87bee 100644 --- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java +++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java @@ -11,7 +11,9 @@ import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.properties.SecuritySettings; +import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; +import org.hamcrest.MatcherAssert; import org.junit.Before; import org.junit.Test; @@ -37,7 +39,7 @@ public class ProcessServiceTest { mocks = new HashMap<>(); processService = new ProcessService(newMock(NewSetting.class), newMock(Messages.class), newMock(AuthMe.class), newMock(DataSource.class), newMock(IpAddressManager.class), newMock(PasswordSecurity.class), - newMock(PluginHooks.class), newMock(SpawnLoader.class)); + newMock(PluginHooks.class), newMock(SpawnLoader.class), newMock(ValidationService.class)); } @Test @@ -186,6 +188,22 @@ public class ProcessServiceTest { verify(passwordSecurity).computeHash(password, username); } + @Test + public void shouldValidatePassword() { + // given + String user = "test-user"; + String password = "passw0rd"; + ValidationService validationService = getMock(ValidationService.class); + given(validationService.validatePassword(password, user)).willReturn(MessageKey.PASSWORD_MATCH_ERROR); + + // when + MessageKey result = processService.validatePassword(password, user); + + // then + MatcherAssert.assertThat(result, equalTo(MessageKey.PASSWORD_MATCH_ERROR)); + verify(validationService).validatePassword(password, user); + } + private T newMock(Class clazz) { T mock = mock(clazz); mocks.put(clazz, mock); diff --git a/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java b/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java new file mode 100644 index 00000000..0fd567f2 --- /dev/null +++ b/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java @@ -0,0 +1,92 @@ +package fr.xephi.authme.util; + +import com.google.common.base.Strings; +import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link ValidationService}. + */ +public class ValidationServiceTest { + + private ValidationService validationService; + + @Before + public void createService() { + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)).willReturn("[a-zA-Z]+"); + given(settings.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)).willReturn(3); + given(settings.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)).willReturn(20); + given(settings.getProperty(SecuritySettings.UNSAFE_PASSWORDS)) + .willReturn(Arrays.asList("unsafe", "other-unsafe")); + validationService = new ValidationService(settings); + } + + @Test + public void shouldRejectPasswordSameAsUsername() { + // given/when + MessageKey error = validationService.validatePassword("bobby", "Bobby"); + + // then + assertThat(error, equalTo(MessageKey.PASSWORD_IS_USERNAME_ERROR)); + } + + @Test + public void shouldRejectPasswordNotMatchingPattern() { + // given/when + // service mock returns pattern a-zA-Z -> numbers should not be accepted + MessageKey error = validationService.validatePassword("invalid1234", "myPlayer"); + + // then + assertThat(error, equalTo(MessageKey.PASSWORD_MATCH_ERROR)); + } + + @Test + public void shouldRejectTooShortPassword() { + // given/when + MessageKey error = validationService.validatePassword("ab", "tester"); + + // then + assertThat(error, equalTo(MessageKey.INVALID_PASSWORD_LENGTH)); + } + + @Test + public void shouldRejectTooLongPassword() { + // given/when + MessageKey error = validationService.validatePassword(Strings.repeat("a", 30), "player"); + + // then + assertThat(error, equalTo(MessageKey.INVALID_PASSWORD_LENGTH)); + } + + @Test + public void shouldRejectUnsafePassword() { + // given/when + MessageKey error = validationService.validatePassword("unsafe", "playertest"); + + // then + assertThat(error, equalTo(MessageKey.PASSWORD_UNSAFE_ERROR)); + } + + @Test + public void shouldAcceptValidPassword() { + // given/when + MessageKey error = validationService.validatePassword("safePass", "some_user"); + + // then + assertThat(error, nullValue()); + } + +} From 5a8ba7d46267f19085ca5fa8b6005103faacdc26 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 3 Apr 2016 01:23:38 +0200 Subject: [PATCH 10/71] fix wrong property in config.yml --- src/main/java/fr/xephi/authme/settings/Settings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index ef9a4b9d..1b982352 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -190,7 +190,7 @@ public final class Settings { preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); kickPlayersBeforeStopping = configFile.getBoolean("Security.stop.kickPlayersBeforeStopping", true); sendPlayerTo = configFile.getString("Hooks.sendPlayerTo", ""); - keepCollisionsDisabled = configFile.getBoolean("settings.keepCollisionsDisabled"); + keepCollisionsDisabled = configFile.getBoolean("settings.KeepCollisionsDisabled"); } /** From c46c1251d982464e13f9059cfcdcab30e91251ef Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 3 Apr 2016 01:28:14 +0200 Subject: [PATCH 11/71] fix wrong property in config.yml --- src/main/resources/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5aa33aa7..cd73c34f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -161,7 +161,7 @@ settings: allowedPasswordCharacters: '[\x21-\x7E]*' # Keeps collisions disabled for logged players # Works only with MC 1.9 - keepCollisionsDisabled: false + KeepCollisionsDisabled: false GameMode: # ForceSurvivalMode to player when join ? ForceSurvivalMode: false From ba217a25950b55c5b314b7a5d5867c2474eb5c5a Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 3 Apr 2016 07:25:33 +0200 Subject: [PATCH 12/71] Fix disable collisions setting --- src/main/java/fr/xephi/authme/settings/Settings.java | 2 +- .../fr/xephi/authme/settings/properties/PluginSettings.java | 2 +- src/main/resources/config.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 1b982352..4f449eb6 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -190,7 +190,7 @@ public final class Settings { preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); kickPlayersBeforeStopping = configFile.getBoolean("Security.stop.kickPlayersBeforeStopping", true); sendPlayerTo = configFile.getString("Hooks.sendPlayerTo", ""); - keepCollisionsDisabled = configFile.getBoolean("settings.KeepCollisionsDisabled"); + keepCollisionsDisabled = load(PluginSettings.KEEP_COLLISIONS_DISABLED); } /** 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 de858203..cf0f7932 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java @@ -58,7 +58,7 @@ public class PluginSettings implements SettingsClass { "Works only with MC 1.9" }) public static final Property KEEP_COLLISIONS_DISABLED = - newProperty("settings.KeepCollisionsDisabled", false); + newProperty("settings.restrictions.keepCollisionsDisabled", false); private PluginSettings() { } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index cd73c34f..5aa33aa7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -161,7 +161,7 @@ settings: allowedPasswordCharacters: '[\x21-\x7E]*' # Keeps collisions disabled for logged players # Works only with MC 1.9 - KeepCollisionsDisabled: false + keepCollisionsDisabled: false GameMode: # ForceSurvivalMode to player when join ? ForceSurvivalMode: false From c079692f1d1ee252ef22487881d2b64a543fbc84 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 3 Apr 2016 07:38:13 +0200 Subject: [PATCH 13/71] Minor - code householding (tests) - Remove redundant uses of WrapperMock - Use assertThat() from JUnit, not hamcrest - Use hamcrest Matchers everywhere (not BaseMatchers etc.) - Favor Mockito's argThat() over using ArgumentCaptor (more succinct) - Delete useless test classes --- .../authme/command/CommandHandlerTest.java | 13 +--- .../command/CommandInitializerTest.java | 2 - .../authme/command/CommandMapperTest.java | 32 ++++---- .../authme/command/CommandServiceTest.java | 2 +- .../authme/command/PlayerCommandTest.java | 15 ++-- .../authme/AccountsCommandTest.java | 8 +- .../executable/authme/AuthMeCommandTest.java | 2 +- .../authme/FirstSpawnCommandTest.java | 11 +-- .../authme/GetEmailCommandTest.java | 7 +- .../authme/LastLoginCommandTest.java | 2 +- .../authme/PurgeLastPositionCommandTest.java | 2 +- .../executable/authme/ReloadCommandTest.java | 4 +- .../authme/SetFirstSpawnCommandTest.java | 4 +- .../authme/SetSpawnCommandTest.java | 4 +- .../executable/authme/SpawnCommandTest.java | 4 +- .../captcha/CaptchaCommandTest.java | 75 ------------------- .../ChangePasswordCommandTest.java | 2 +- .../executable/email/AddEmailCommandTest.java | 2 - .../email/RecoverEmailCommandTest.java | 41 ---------- .../executable/login/LoginCommandTest.java | 27 +++---- .../executable/logout/LogoutCommandTest.java | 11 +-- .../register/RegisterCommandTest.java | 7 +- .../authme/command/help/HelpProviderTest.java | 2 - .../datasource/FlatFileIntegrationTest.java | 2 +- .../authme/process/ProcessServiceTest.java | 3 +- .../xephi/authme/security/HashUtilsTest.java | 2 +- .../authme/security/RandomStringTest.java | 2 +- .../xephi/authme/settings/NewSettingTest.java | 2 +- .../authme/settings/domain/PropertyTest.java | 2 +- 29 files changed, 67 insertions(+), 225 deletions(-) delete mode 100644 src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java delete mode 100644 src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java diff --git a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java index 345082bc..e5e6b749 100644 --- a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java @@ -17,13 +17,14 @@ import static fr.xephi.authme.command.FoundResultStatus.NO_PERMISSION; import static fr.xephi.authme.command.FoundResultStatus.SUCCESS; import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL; import static java.util.Arrays.asList; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyListOf; import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; @@ -95,11 +96,8 @@ public class CommandHandlerTest { // then verify(serviceMock).mapPartsToCommand(eq(sender), captor.capture()); assertThat(captor.getValue(), contains("unreg", "testPlayer")); - verify(command, never()).getExecutableCommand(); - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender).sendMessage(captor.capture()); - assertThat(captor.getValue(), containsString("don't have permission")); + verify(sender).sendMessage(argThat(containsString("don't have permission"))); } @Test @@ -170,11 +168,8 @@ public class CommandHandlerTest { // then verify(serviceMock).mapPartsToCommand(eq(sender), captor.capture()); assertThat(captor.getValue(), contains("unreg", "testPlayer")); - verify(command, never()).getExecutableCommand(); - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender).sendMessage(captor.capture()); - assertThat(captor.getValue(), containsString("Failed to parse")); + verify(sender).sendMessage(argThat(containsString("Failed to parse"))); } @Test diff --git a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java index 7e62023f..6e5418d5 100644 --- a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java @@ -3,7 +3,6 @@ package fr.xephi.authme.command; import fr.xephi.authme.permission.AdminPermission; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; import org.junit.Test; @@ -38,7 +37,6 @@ public class CommandInitializerTest { @BeforeClass public static void initializeCommandManager() { - WrapperMock.createInstance(); commands = CommandInitializer.buildCommands(); } diff --git a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java index 8da42043..77840e89 100644 --- a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java @@ -13,12 +13,12 @@ import java.util.Set; import static fr.xephi.authme.command.TestCommandsUtil.getCommandWithLabel; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; @@ -31,7 +31,7 @@ public class CommandMapperTest { private static Set commands; private static CommandMapper mapper; - private static PermissionsManager permissionsManagerMock; + private static PermissionsManager permissionsManager; @BeforeClass public static void setUpCommandHandler() { @@ -40,8 +40,8 @@ public class CommandMapperTest { @Before public void setUpMocks() { - permissionsManagerMock = mock(PermissionsManager.class); - mapper = new CommandMapper(commands, permissionsManagerMock); + permissionsManager = mock(PermissionsManager.class); + mapper = new CommandMapper(commands, permissionsManager); } // ----------- @@ -52,7 +52,7 @@ public class CommandMapperTest { // given List parts = Arrays.asList("authme", "login", "test1"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -71,7 +71,7 @@ public class CommandMapperTest { // given List parts = Arrays.asList("Authme", "REG", "arg1", "arg2"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -89,7 +89,7 @@ public class CommandMapperTest { // given List parts = Arrays.asList("authme", "register", "pass123", "pass123", "pass123"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -107,7 +107,7 @@ public class CommandMapperTest { // given List parts = Arrays.asList("authme", "Reg"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -125,7 +125,7 @@ public class CommandMapperTest { // given List parts = Arrays.asList("authme", "reh", "pass123", "pass123"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -144,7 +144,7 @@ public class CommandMapperTest { // given List parts = Arrays.asList("authme", "asdfawetawty4asdca"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -162,7 +162,7 @@ public class CommandMapperTest { // given List parts = singletonList("unregister"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -180,7 +180,7 @@ public class CommandMapperTest { // given List parts = asList("bogus", "label1", "arg1"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -205,7 +205,7 @@ public class CommandMapperTest { // given List parts = asList("Unreg", "player1"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -223,7 +223,7 @@ public class CommandMapperTest { // given List parts = asList("unregistER", "player1", "wrongArg"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -241,7 +241,7 @@ public class CommandMapperTest { // given List parts = asList("email", "helptest", "arg1"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); @@ -259,7 +259,7 @@ public class CommandMapperTest { // given List parts = Arrays.asList("authme", "login", "test1"); CommandSender sender = mock(CommandSender.class); - given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(false); + given(permissionsManager.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(false); // when FoundCommandResult result = mapper.mapPartsToCommand(sender, parts); diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index dafe6966..645d3a37 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -28,8 +28,8 @@ import org.mockito.runners.MockitoJUnitRunner; import java.util.Arrays; import java.util.List; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; diff --git a/src/test/java/fr/xephi/authme/command/PlayerCommandTest.java b/src/test/java/fr/xephi/authme/command/PlayerCommandTest.java index 4afee564..a4c02b93 100644 --- a/src/test/java/fr/xephi/authme/command/PlayerCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/PlayerCommandTest.java @@ -4,14 +4,13 @@ import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Test; -import org.mockito.ArgumentCaptor; import java.util.Arrays; import java.util.Collections; import java.util.List; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -28,12 +27,10 @@ public class PlayerCommandTest { PlayerCommandImpl command = new PlayerCommandImpl(); // when - command.executeCommand(sender, Collections. emptyList(), mock(CommandService.class)); + command.executeCommand(sender, Collections.emptyList(), mock(CommandService.class)); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender, times(1)).sendMessage(captor.capture()); - assertThat(captor.getValue(), containsString("only for players")); + verify(sender).sendMessage(argThat(containsString("only for players"))); } @Test @@ -58,12 +55,10 @@ public class PlayerCommandTest { PlayerCommandWithAlt command = new PlayerCommandWithAlt(); // when - command.executeCommand(sender, Collections. emptyList(), mock(CommandService.class)); + command.executeCommand(sender, Collections.emptyList(), mock(CommandService.class)); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender, times(1)).sendMessage(captor.capture()); - assertThat(captor.getValue(), containsString("use /authme test instead")); + verify(sender, times(1)).sendMessage(argThat(containsString("use /authme test instead"))); } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java index 82469635..5a837280 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java @@ -14,8 +14,8 @@ import java.util.Collections; import java.util.List; import static fr.xephi.authme.TestHelper.runInnerRunnable; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; @@ -81,7 +81,7 @@ public class AccountsCommandTest { // given List arguments = Collections.singletonList("SomeUser"); given(dataSource.getAuth("someuser")).willReturn(mock(PlayerAuth.class)); - given(dataSource.getAllAuthsByIp(anyString())).willReturn(Collections. emptyList()); + given(dataSource.getAllAuthsByIp(anyString())).willReturn(Collections.emptyList()); // when command.executeCommand(sender, arguments, service); @@ -115,7 +115,7 @@ public class AccountsCommandTest { public void shouldReturnIpUnknown() { // given List arguments = Collections.singletonList("123.45.67.89"); - given(dataSource.getAllAuthsByIp("123.45.67.89")).willReturn(Collections. emptyList()); + given(dataSource.getAllAuthsByIp("123.45.67.89")).willReturn(Collections.emptyList()); // when command.executeCommand(sender, arguments, service); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/AuthMeCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/AuthMeCommandTest.java index 8be1185a..c1c0c6e3 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/AuthMeCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/AuthMeCommandTest.java @@ -8,7 +8,7 @@ import org.mockito.ArgumentCaptor; import java.util.Collections; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/FirstSpawnCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/FirstSpawnCommandTest.java index aa4f7b74..0c70bd01 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/FirstSpawnCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/FirstSpawnCommandTest.java @@ -6,14 +6,13 @@ import fr.xephi.authme.settings.SpawnLoader; import org.bukkit.Location; import org.bukkit.entity.Player; import org.junit.Test; -import org.mockito.ArgumentCaptor; import java.util.Collections; import static org.hamcrest.Matchers.containsString; -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.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -36,7 +35,7 @@ public class FirstSpawnCommandTest { ExecutableCommand command = new FirstSpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then verify(player).teleport(firstSpawn); @@ -54,12 +53,10 @@ public class FirstSpawnCommandTest { ExecutableCommand command = new FirstSpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(player).sendMessage(captor.capture()); - assertThat(captor.getValue(), containsString("spawn has failed")); + verify(player).sendMessage(argThat(containsString("spawn has failed"))); verify(player, never()).teleport(any(Location.class)); } } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java index 247c43ac..6d232037 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/GetEmailCommandTest.java @@ -7,13 +7,12 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import org.bukkit.command.CommandSender; import org.junit.Test; -import org.mockito.ArgumentCaptor; import java.util.Collections; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -61,8 +60,6 @@ public class GetEmailCommandTest { command.executeCommand(sender, Collections.singletonList(user), service); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender).sendMessage(captor.capture()); - assertThat(captor.getValue(), containsString(email)); + verify(sender).sendMessage(argThat(containsString(email))); } } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java index 96cf8844..d1e58e92 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/LastLoginCommandTest.java @@ -103,7 +103,7 @@ public class LastLoginCommandTest { ExecutableCommand command = new LastLoginCommand(); // when - command.executeCommand(sender, Collections. emptyList(), service); + command.executeCommand(sender, Collections.emptyList(), service); // then verify(dataSource).getAuth(name); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java index 9f207866..bcce0342 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommandTest.java @@ -61,7 +61,7 @@ public class PurgeLastPositionCommandTest { ExecutableCommand command = new PurgeLastPositionCommand(); // when - command.executeCommand(sender, Collections. emptyList(), service); + command.executeCommand(sender, Collections.emptyList(), service); // then verify(dataSource).getAuth(player); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java index 873108ee..a0ed7706 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java @@ -37,7 +37,7 @@ public class ReloadCommandTest { ExecutableCommand command = new ReloadCommand(); // when - command.executeCommand(sender, Collections. emptyList(), service); + command.executeCommand(sender, Collections.emptyList(), service); // then verify(authMe).reload(); @@ -55,7 +55,7 @@ public class ReloadCommandTest { ExecutableCommand command = new ReloadCommand(); // when - command.executeCommand(sender, Collections. emptyList(), service); + command.executeCommand(sender, Collections.emptyList(), service); // then verify(authMe).reload(); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/SetFirstSpawnCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/SetFirstSpawnCommandTest.java index 307831ce..74964882 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/SetFirstSpawnCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/SetFirstSpawnCommandTest.java @@ -35,7 +35,7 @@ public class SetFirstSpawnCommandTest { ExecutableCommand command = new SetFirstSpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then verify(spawnLoader).setFirstSpawn(location); @@ -57,7 +57,7 @@ public class SetFirstSpawnCommandTest { ExecutableCommand command = new SetFirstSpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then verify(spawnLoader).setFirstSpawn(location); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/SetSpawnCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/SetSpawnCommandTest.java index 11c28d32..e3e01f99 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/SetSpawnCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/SetSpawnCommandTest.java @@ -35,7 +35,7 @@ public class SetSpawnCommandTest { ExecutableCommand command = new SetSpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then verify(spawnLoader).setSpawn(location); @@ -57,7 +57,7 @@ public class SetSpawnCommandTest { ExecutableCommand command = new SetSpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then verify(spawnLoader).setSpawn(location); diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/SpawnCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/SpawnCommandTest.java index 7b76ad02..799d1ca4 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/SpawnCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/SpawnCommandTest.java @@ -35,7 +35,7 @@ public class SpawnCommandTest { ExecutableCommand command = new SpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then verify(player).teleport(spawn); @@ -53,7 +53,7 @@ public class SpawnCommandTest { ExecutableCommand command = new SpawnCommand(); // when - command.executeCommand(player, Collections. emptyList(), service); + command.executeCommand(player, Collections.emptyList(), service); // then verify(player).sendMessage(argThat(containsString("Spawn has failed"))); diff --git a/src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java deleted file mode 100644 index b3b54a1c..00000000 --- a/src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.xephi.authme.command.executable.captcha; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.command.CommandService; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.output.Messages; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.WrapperMock; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import java.util.ArrayList; -import java.util.Collections; - -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Test for {@link CaptchaCommand}. - */ -public class CaptchaCommandTest { - - private WrapperMock wrapperMock; - private CommandService commandService; - - @Before - public void setUpWrapperMock() { - wrapperMock = WrapperMock.createInstance(); - commandService = mock(CommandService.class); - given(commandService.getProperty(SecuritySettings.USE_CAPTCHA)).willReturn(true); - } - - @Test - public void shouldRejectNonPlayerSender() { - // given - CommandSender sender = Mockito.mock(BlockCommandSender.class); - ExecutableCommand command = new CaptchaCommand(); - - // when - command.executeCommand(sender, new ArrayList(), commandService); - - // then - assertThat(wrapperMock.wasMockCalled(AuthMe.class), equalTo(false)); - assertThat(wrapperMock.wasMockCalled(Messages.class), equalTo(false)); - } - - @Test - public void shouldRejectIfCaptchaIsNotUsed() { - // given - Player player = mockPlayerWithName("testplayer"); - ExecutableCommand command = new CaptchaCommand(); - given(commandService.getProperty(SecuritySettings.USE_CAPTCHA)).willReturn(false); - - // when - command.executeCommand(player, Collections.singletonList("1234"), commandService); - - // then - verify(commandService).send(player, MessageKey.USAGE_LOGIN); - } - - private static Player mockPlayerWithName(String name) { - Player player = Mockito.mock(Player.class); - when(player.getName()).thenReturn(name); - return player; - } -} diff --git a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java index ef457205..bc8e0876 100644 --- a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java @@ -18,9 +18,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import static org.hamcrest.MatcherAssert.assertThat; 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.argThat; import static org.mockito.Mockito.any; diff --git a/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java index f1e55787..17dbddad 100644 --- a/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java @@ -3,7 +3,6 @@ package fr.xephi.authme.command.executable.email; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.process.Management; import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -29,7 +28,6 @@ public class AddEmailCommandTest { @Before public void setUpMocks() { commandService = mock(CommandService.class); - WrapperMock.createInstance(); } @Test diff --git a/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java deleted file mode 100644 index 94c1c8dc..00000000 --- a/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import fr.xephi.authme.command.CommandService; -import fr.xephi.authme.util.WrapperMock; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.Mockito; - -import java.util.ArrayList; - -import static org.mockito.Mockito.mock; - -/** - * Test for {@link RecoverEmailCommand}. - */ -public class RecoverEmailCommandTest { - - @Before - public void setUpMocks() { - WrapperMock wrapper = WrapperMock.createInstance(); - } - - @Test - @Ignore - public void shouldRejectNonPlayerSender() { - // given - CommandSender sender = Mockito.mock(BlockCommandSender.class); - RecoverEmailCommand command = new RecoverEmailCommand(); - - // when - command.executeCommand(sender, new ArrayList(), mock(CommandService.class)); - - // then - } - - // TODO ljacqu 20151121: Expand tests. This command doesn't use a scheduler and has all of its - // logic inside here. -} diff --git a/src/test/java/fr/xephi/authme/command/executable/login/LoginCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/login/LoginCommandTest.java index 5e62866c..9a23bc17 100644 --- a/src/test/java/fr/xephi/authme/command/executable/login/LoginCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/login/LoginCommandTest.java @@ -2,22 +2,20 @@ package fr.xephi.authme.command.executable.login; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.process.Management; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.ArrayList; import java.util.Collections; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; 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.never; @@ -26,17 +24,12 @@ import static org.mockito.Mockito.verify; /** * Test for {@link LoginCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class LoginCommandTest { + @Mock private CommandService commandService; - @Before - public void initializeAuthMeMock() { - WrapperMock.createInstance(); - Settings.captchaLength = 10; - commandService = mock(CommandService.class); - } - @Test public void shouldStopIfSenderIsNotAPlayer() { // given @@ -47,10 +40,8 @@ public class LoginCommandTest { command.executeCommand(sender, new ArrayList(), commandService); // then - Mockito.verify(commandService, never()).getManagement(); - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); - verify(sender).sendMessage(messageCaptor.capture()); - assertThat(messageCaptor.getValue(), containsString("only for players")); + verify(commandService, never()).getManagement(); + verify(sender).sendMessage(argThat(containsString("only for players"))); } @Test @@ -65,7 +56,7 @@ public class LoginCommandTest { command.executeCommand(sender, Collections.singletonList("password"), commandService); // then - Mockito.verify(management).performLogin(eq(sender), eq("password"), eq(false)); + verify(management).performLogin(eq(sender), eq("password"), eq(false)); } } diff --git a/src/test/java/fr/xephi/authme/command/executable/logout/LogoutCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/logout/LogoutCommandTest.java index 6e83e801..7ac3ede6 100644 --- a/src/test/java/fr/xephi/authme/command/executable/logout/LogoutCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/logout/LogoutCommandTest.java @@ -2,21 +2,18 @@ package fr.xephi.authme.command.executable.logout; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.process.Management; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Collections; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -30,8 +27,6 @@ public class LogoutCommandTest { @Before public void initializeAuthMeMock() { - WrapperMock.createInstance(); - Settings.captchaLength = 10; commandService = mock(CommandService.class); } @@ -46,9 +41,7 @@ public class LogoutCommandTest { // then verify(commandService, never()).getManagement(); - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); - verify(sender).sendMessage(messageCaptor.capture()); - assertThat(messageCaptor.getValue(), containsString("only for players")); + verify(sender).sendMessage(argThat(containsString("only for players"))); } @Test 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 e4ff5ac0..84b79726 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 @@ -10,14 +10,13 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Collections; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -47,9 +46,7 @@ public class RegisterCommandTest { // then verify(commandService, never()).getManagement(); - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); - verify(sender).sendMessage(messageCaptor.capture()); - assertThat(messageCaptor.getValue(), containsString("Player only!")); + verify(sender).sendMessage(argThat(containsString("Player only!"))); } @Test diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java index 6568a773..3ec47a4f 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java @@ -6,7 +6,6 @@ import fr.xephi.authme.command.FoundResultStatus; import fr.xephi.authme.command.TestCommandsUtil; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.junit.Before; @@ -47,7 +46,6 @@ public class HelpProviderTest { @BeforeClass public static void setUpCommands() { - WrapperMock.createInstance(); commands = TestCommandsUtil.generateCommands(); } diff --git a/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java index 154511c2..0c0ab8e1 100644 --- a/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/FlatFileIntegrationTest.java @@ -16,8 +16,8 @@ import java.util.List; 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.CoreMatchers.hasItem; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; import static org.junit.Assert.assertThat; diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java index 23a87bee..14d2e3e2 100644 --- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java +++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java @@ -13,7 +13,6 @@ import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; -import org.hamcrest.MatcherAssert; import org.junit.Before; import org.junit.Test; @@ -200,7 +199,7 @@ public class ProcessServiceTest { MessageKey result = processService.validatePassword(password, user); // then - MatcherAssert.assertThat(result, equalTo(MessageKey.PASSWORD_MATCH_ERROR)); + assertThat(result, equalTo(MessageKey.PASSWORD_MATCH_ERROR)); verify(validationService).validatePassword(password, user); } diff --git a/src/test/java/fr/xephi/authme/security/HashUtilsTest.java b/src/test/java/fr/xephi/authme/security/HashUtilsTest.java index 02237cde..e515fdbb 100644 --- a/src/test/java/fr/xephi/authme/security/HashUtilsTest.java +++ b/src/test/java/fr/xephi/authme/security/HashUtilsTest.java @@ -6,9 +6,9 @@ import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; /** * Test for {@link HashUtils}. diff --git a/src/test/java/fr/xephi/authme/security/RandomStringTest.java b/src/test/java/fr/xephi/authme/security/RandomStringTest.java index 71ea587c..3582fb91 100644 --- a/src/test/java/fr/xephi/authme/security/RandomStringTest.java +++ b/src/test/java/fr/xephi/authme/security/RandomStringTest.java @@ -4,8 +4,8 @@ import org.junit.Test; import java.util.regex.Pattern; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; /** * Test for {@link RandomString}. diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java index 0c69919c..fb050862 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java @@ -21,12 +21,12 @@ import java.util.List; import static fr.xephi.authme.settings.properties.PluginSettings.MESSAGES_LANGUAGE; import static fr.xephi.authme.util.StringUtils.makePath; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; 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.Matchers.anyBoolean; import static org.mockito.Matchers.anyDouble; diff --git a/src/test/java/fr/xephi/authme/settings/domain/PropertyTest.java b/src/test/java/fr/xephi/authme/settings/domain/PropertyTest.java index de33c53c..ff84c393 100644 --- a/src/test/java/fr/xephi/authme/settings/domain/PropertyTest.java +++ b/src/test/java/fr/xephi/authme/settings/domain/PropertyTest.java @@ -8,9 +8,9 @@ import org.mockito.internal.stubbing.answers.ReturnsArgumentAt; import java.util.Arrays; import java.util.List; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; From 88e517635cf652b4b639e600f9ab06ccd336c07a Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 3 Apr 2016 13:03:16 +0200 Subject: [PATCH 14/71] wtf was that xD --- .../authme/listener/AuthMePlayerListener.java | 19 ++++++++++--------- .../authme/process/join/AsynchronousJoin.java | 1 - .../process/login/ProcessSyncPlayerLogin.java | 1 - .../fr/xephi/authme/settings/Settings.java | 2 -- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index b5e0a9b3..3c545b1b 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -3,6 +3,7 @@ package fr.xephi.authme.listener; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; import fr.xephi.authme.AntiBot; +import fr.xephi.authme.AntiBot.AntiBotStatus; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; @@ -330,16 +331,16 @@ public class AuthMePlayerListener implements Listener { final String name = player.getName().toLowerCase(); boolean isAuthAvailable = dataSource.isAuthAvailable(name); + if (antiBot.getAntiBotStatus()==AntiBotStatus.ACTIVE && !isAuthAvailable) { + event.setKickMessage(m.retrieveSingle(MessageKey.KICK_ANTIBOT)); + event.setResult(PlayerLoginEvent.Result.KICK_OTHER); + return; + } + if (Settings.isKickNonRegisteredEnabled && !isAuthAvailable) { - if (Settings.antiBotInAction) { - event.setKickMessage(m.retrieveSingle(MessageKey.KICK_ANTIBOT)); - event.setResult(PlayerLoginEvent.Result.KICK_OTHER); - return; - } else { - event.setKickMessage(m.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE)); - event.setResult(PlayerLoginEvent.Result.KICK_OTHER); - return; - } + event.setKickMessage(m.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE)); + event.setResult(PlayerLoginEvent.Result.KICK_OTHER); + return; } if (name.length() > Settings.getMaxNickLength || name.length() < Settings.getMinNickLength) { 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 900abd4c..e1820545 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -27,7 +27,6 @@ import fr.xephi.authme.util.Utils.GroupType; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; -import org.bukkit.inventory.PlayerInventory; import org.bukkit.entity.LivingEntity; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; 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 48b4eda4..1a922ff8 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -4,7 +4,6 @@ import fr.xephi.authme.settings.NewSetting; 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.PluginSettings; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 4f449eb6..6d8e989f 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -25,8 +25,6 @@ public final class Settings { public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder(); public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules"); public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); - // This is not an option! - public static boolean antiBotInAction = false; public static List allowCommands; public static List getJoinPermissions; public static List getUnrestrictedName; From b6ccb3e63234fd36b354e1132d30ce594fb9936a Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 3 Apr 2016 14:24:12 +0200 Subject: [PATCH 15/71] #567 Add/change email should be aware of account threshold --- .../xephi/authme/command/CommandService.java | 13 +----- .../executable/authme/SetEmailCommand.java | 10 +++-- .../executable/email/RecoverEmailCommand.java | 19 +++++---- .../authme/datasource/CacheDataSource.java | 5 --- .../xephi/authme/datasource/DataSource.java | 2 - .../fr/xephi/authme/datasource/FlatFile.java | 5 --- .../fr/xephi/authme/datasource/MySQL.java | 14 ------- .../fr/xephi/authme/datasource/SQLite.java | 16 -------- .../authme/process/email/AsyncAddEmail.java | 3 +- .../process/email/AsyncChangeEmail.java | 4 +- .../process/register/AsyncRegister.java | 9 ++-- .../fr/xephi/authme/settings/Settings.java | 6 +-- .../AbstractDataSourceIntegrationTest.java | 16 -------- .../process/email/AsyncAddEmailTest.java | 41 ++++++++----------- .../process/email/AsyncChangeEmailTest.java | 36 ++++++---------- 15 files changed, 60 insertions(+), 139 deletions(-) diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 9d8252a0..d6861059 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -39,19 +39,8 @@ public class CommandService { private final AntiBot antiBot; private final ValidationService validationService; - /** + /* * Constructor. - * - * @param authMe The plugin instance - * @param commandMapper Command mapper - * @param helpProvider Help provider - * @param messages Messages instance - * @param passwordSecurity The Password Security instance - * @param permissionsManager The permissions manager - * @param settings The settings manager - * @param ipAddressManager The IP address manager - * @param pluginHooks The plugin hooks instance - * @param spawnLoader The spawn loader */ public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages, PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings, diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java index d19a2ce6..9e44fdab 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java @@ -4,7 +4,9 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.util.Utils; import org.bukkit.command.CommandSender; @@ -29,18 +31,20 @@ public class SetEmailCommand implements ExecutableCommand { @Override public void run() { // Validate the user - PlayerAuth auth = commandService.getDataSource().getAuth(playerName); + DataSource dataSource = commandService.getDataSource(); + PlayerAuth auth = dataSource.getAuth(playerName); if (auth == null) { commandService.send(sender, MessageKey.UNKNOWN_USER); return; - } else if (commandService.getDataSource().isEmailStored(playerEmail)) { + } else if (dataSource.countAuthsByEmail(playerEmail) + >= commandService.getProperty(EmailSettings.MAX_REG_PER_EMAIL)) { commandService.send(sender, MessageKey.EMAIL_ALREADY_USED_ERROR); return; } // Set the email address auth.setEmail(playerEmail); - if (!commandService.getDataSource().updateEmail(auth)) { + if (!dataSource.updateEmail(auth)) { commandService.send(sender, MessageKey.ERROR); return; } diff --git a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java index 419ab00d..f4a319a5 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,6 +1,7 @@ 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; @@ -9,7 +10,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.util.StringUtils; import org.bukkit.entity.Player; @@ -19,13 +20,12 @@ public class RecoverEmailCommand extends PlayerCommand { @Override public void runCommand(Player player, List arguments, CommandService commandService) { - String playerMail = arguments.get(0); + final String playerMail = arguments.get(0); final String playerName = player.getName(); - - // Command logic - final AuthMe plugin = AuthMe.getInstance(); + final AuthMe plugin = commandService.getAuthMe(); if (plugin.mail == null) { + ConsoleLogger.showError("Mail API is not set"); commandService.send(player, MessageKey.ERROR); return; } @@ -36,7 +36,7 @@ public class RecoverEmailCommand extends PlayerCommand { return; } - String thePass = RandomString.generate(Settings.getRecoveryPassLength); + String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH)); HashedPassword hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName); PlayerAuth auth; if (PlayerCache.getInstance().isAuthenticated(playerName)) { @@ -47,13 +47,14 @@ public class RecoverEmailCommand extends PlayerCommand { commandService.send(player, MessageKey.UNKNOWN_USER); return; } - if (StringUtils.isEmpty(Settings.getmailAccount)) { + if (StringUtils.isEmpty(commandService.getProperty(EmailSettings.MAIL_ACCOUNT))) { + ConsoleLogger.showError("No mail account set in settings"); commandService.send(player, MessageKey.ERROR); return; } - if (!playerMail.equalsIgnoreCase(auth.getEmail()) || playerMail.equalsIgnoreCase("your@email.com") - || auth.getEmail().equalsIgnoreCase("your@email.com")) { + if (!playerMail.equalsIgnoreCase(auth.getEmail()) || "your@email.com".equalsIgnoreCase(playerMail) + || "your@email.com".equalsIgnoreCase(auth.getEmail())) { commandService.send(player, MessageKey.INVALID_EMAIL); return; } diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 6617f7b5..6aad92b2 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -250,9 +250,4 @@ public class CacheDataSource implements DataSource { public List getLoggedPlayers() { return new ArrayList<>(PlayerCache.getInstance().getCache().values()); } - - @Override - public boolean isEmailStored(String email) { - return source.isEmailStored(email); - } } diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index 5e2cc0c7..9db25555 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -185,8 +185,6 @@ public interface DataSource { */ List getLoggedPlayers(); - boolean isEmailStored(String email); - /** * Reload the data source. */ diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index 288012da..b36fa279 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -521,11 +521,6 @@ public class FlatFile implements DataSource { throw new UnsupportedOperationException("Flat file no longer supported"); } - @Override - public boolean isEmailStored(String email) { - throw new UnsupportedOperationException("Flat file no longer supported"); - } - private static PlayerAuth buildAuthFromArray(String[] args) { // Format allows 2, 3, 4, 7, 8, 9 fields. Anything else is unknown if (args.length >= 2 && args.length <= 9 && args.length != 5 && args.length != 6) { diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index db4ed538..326aef92 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -908,20 +908,6 @@ public class MySQL implements DataSource { return auths; } - @Override - public synchronized boolean isEmailStored(String email) { - String sql = "SELECT 1 FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)"; - try (Connection con = ds.getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, email); - try (ResultSet rs = pst.executeQuery()) { - return rs.next(); - } - } catch (SQLException e) { - logSqlException(e); - } - return false; - } - private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { String salt = col.SALT.isEmpty() ? null : row.getString(col.SALT); int group = col.GROUP.isEmpty() ? -1 : row.getInt(col.GROUP); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index f0462840..a310b7b6 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -580,22 +580,6 @@ public class SQLite implements DataSource { return auths; } - @Override - public synchronized boolean isEmailStored(String email) { - String sql = "SELECT 1 FROM " + tableName + " WHERE " + col.EMAIL + " = ? COLLATE NOCASE;"; - ResultSet rs = null; - try (PreparedStatement ps = con.prepareStatement(sql)) { - ps.setString(1, email); - rs = ps.executeQuery(); - return rs.next(); - } catch (SQLException e) { - logSqlException(e); - } finally { - close(rs); - } - return false; - } - private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { String salt = !col.SALT.isEmpty() ? row.getString(col.SALT) : null; diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java index d1e49b93..9f2451e7 100644 --- a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java +++ b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java @@ -7,6 +7,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Process; import fr.xephi.authme.process.ProcessService; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; @@ -43,7 +44,7 @@ public class AsyncAddEmail implements Process { service.send(player, MessageKey.USAGE_CHANGE_EMAIL); } else if (!Utils.isEmailCorrect(email, service.getSettings())) { service.send(player, MessageKey.INVALID_EMAIL); - } else if (dataSource.isEmailStored(email)) { + } else if (dataSource.countAuthsByEmail(email) >= service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)) { service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR); } else { auth.setEmail(email); diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java index 132decd5..488ddca3 100644 --- a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java +++ b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java @@ -6,6 +6,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Process; import fr.xephi.authme.process.ProcessService; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; @@ -45,7 +46,7 @@ public class AsyncChangeEmail implements Process { service.send(player, MessageKey.INVALID_NEW_EMAIL); } else if (!oldEmail.equals(currentEmail)) { service.send(player, MessageKey.INVALID_OLD_EMAIL); - } else if (dataSource.isEmailStored(newEmail)) { + } else if (dataSource.countAuthsByEmail(newEmail) >= service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)) { service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR); } else { saveNewEmail(auth); @@ -62,7 +63,6 @@ public class AsyncChangeEmail implements Process { service.send(player, MessageKey.EMAIL_CHANGED_SUCCESS); } else { service.send(player, MessageKey.ERROR); - auth.setEmail(newEmail); } } 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 e212fabc..dd41e9cd 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -12,6 +12,7 @@ import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.TwoFactor; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; @@ -99,12 +100,12 @@ public class AsyncRegister implements Process { } private void emailRegister() { - if (Settings.getmaxRegPerEmail > 0 + final int maxRegPerEmail = service.getProperty(EmailSettings.MAX_REG_PER_EMAIL); + if (maxRegPerEmail > 0 && !plugin.getPermissionsManager().hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)) { - int maxReg = Settings.getmaxRegPerEmail; int otherAccounts = database.countAuthsByEmail(email); - if (otherAccounts >= maxReg) { - service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxReg), + if (otherAccounts >= maxRegPerEmail) { + service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerEmail), Integer.toString(otherAccounts), "@"); return; } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 6d8e989f..a8530bce 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -3,6 +3,7 @@ package fr.xephi.authme.settings; import fr.xephi.authme.AuthMe; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.settings.domain.Property; +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.RegistrationSettings; @@ -67,7 +68,7 @@ public final class Settings { getPasswordMinLen, getMovementRadius, getNonActivatedGroup, passwordMaxLength, getRecoveryPassLength, getMailPort, maxLoginTry, captchaLength, saltLength, - getmaxRegPerEmail, bCryptLog2Rounds, getMaxLoginPerIp, getMaxJoinPerIp; + bCryptLog2Rounds, getMaxLoginPerIp, getMaxJoinPerIp; protected static FileConfiguration configFile; /** @@ -143,7 +144,7 @@ public final class Settings { rakamakUseIp = configFile.getBoolean("Converter.Rakamak.useIp", false); noConsoleSpam = load(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE); removePassword = configFile.getBoolean("Security.console.removePassword", true); - getmailAccount = configFile.getString("Email.mailAccount", ""); + getmailAccount = load(EmailSettings.MAIL_ACCOUNT); getMailPort = configFile.getInt("Email.mailPort", 465); getRecoveryPassLength = configFile.getInt("Email.RecoveryPasswordLength", 8); displayOtherAccounts = configFile.getBoolean("settings.restrictions.displayOtherAccounts", true); @@ -151,7 +152,6 @@ public final class Settings { captchaLength = configFile.getInt("Security.captcha.captchaLength", 5); emailRegistration = load(RegistrationSettings.USE_EMAIL_REGISTRATION); saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8); - getmaxRegPerEmail = configFile.getInt("Email.maxRegPerEmail", 1); multiverse = load(HooksSettings.MULTIVERSE); bungee = configFile.getBoolean("Hooks.bungeecord", false); getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds"); diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java index 077209f4..0231a8d6 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java @@ -80,22 +80,6 @@ public abstract class AbstractDataSourceIntegrationTest { assertThat(userAuth.getPassword(), equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32")); } - @Test - public void shouldFindIfEmailExists() { - // given - DataSource dataSource = getDataSource(); - - // when - boolean isUserMailPresent = dataSource.isEmailStored("user@example.org"); - boolean isUserMailPresentCaseInsensitive = dataSource.isEmailStored("user@example.ORG"); - boolean isInvalidMailPresent = dataSource.isEmailStored("not-in-database@example.com"); - - // then - assertThat(isUserMailPresent, equalTo(true)); - assertThat(isUserMailPresentCaseInsensitive, equalTo(true)); - assertThat(isInvalidMailPresent, equalTo(false)); - } - @Test public void shouldCountAuthsByEmail() { // given diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java index 5c165039..9f93a47d 100644 --- a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java +++ b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java @@ -7,12 +7,14 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.entity.Player; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.any; @@ -24,28 +26,23 @@ import static org.mockito.Mockito.when; /** * Test for {@link AsyncAddEmail}. */ +@RunWith(MockitoJUnitRunner.class) public class AsyncAddEmailTest { + @Mock private Player player; + @Mock private DataSource dataSource; + @Mock private PlayerCache playerCache; + @Mock private ProcessService service; @BeforeClass public static void setUp() { - WrapperMock.createInstance(); ConsoleLoggerTestInitializer.setupLogger(); } - // Clean up the fields to ensure that no test uses elements of another test - @After - public void removeFieldValues() { - player = null; - dataSource = null; - playerCache = null; - service = null; - } - @Test public void shouldAddEmail() { // given @@ -55,7 +52,7 @@ public class AsyncAddEmailTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("tester")).willReturn(auth); - given(dataSource.isEmailStored("my.mail@example.org")).willReturn(false); + given(dataSource.countAuthsByEmail("my.mail@example.org")).willReturn(1); given(dataSource.updateEmail(any(PlayerAuth.class))).willReturn(true); // when @@ -77,7 +74,7 @@ public class AsyncAddEmailTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("tester")).willReturn(auth); - given(dataSource.isEmailStored("my.mail@example.org")).willReturn(false); + given(dataSource.countAuthsByEmail("my.mail@example.org")).willReturn(0); given(dataSource.updateEmail(any(PlayerAuth.class))).willReturn(false); // when @@ -97,7 +94,7 @@ public class AsyncAddEmailTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn("another@mail.tld"); given(playerCache.getAuth("my_player")).willReturn(auth); - given(dataSource.isEmailStored("some.mail@example.org")).willReturn(false); + given(dataSource.countAuthsByEmail("some.mail@example.org")).willReturn(0); // when process.run(); @@ -116,7 +113,7 @@ public class AsyncAddEmailTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("my_player")).willReturn(auth); - given(dataSource.isEmailStored("invalid_mail")).willReturn(false); + given(dataSource.countAuthsByEmail("invalid_mail")).willReturn(0); // when process.run(); @@ -135,7 +132,7 @@ public class AsyncAddEmailTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("testname")).willReturn(auth); - given(dataSource.isEmailStored("player@mail.tld")).willReturn(true); + given(dataSource.countAuthsByEmail("player@mail.tld")).willReturn(2); // when process.run(); @@ -196,17 +193,15 @@ public class AsyncAddEmailTest { } /** - * Create an instance of {@link AsyncAddEmail} and save the mcoks to this class' fields. + * Create an instance of {@link AsyncAddEmail} and save the mocks to this class' fields. * * @param email The email to use * @return The created process */ private AsyncAddEmail createProcess(String email) { - player = mock(Player.class); - dataSource = mock(DataSource.class); - playerCache = mock(PlayerCache.class); - service = mock(ProcessService.class); - when(service.getSettings()).thenReturn(mock(NewSetting.class)); + NewSetting settings = mock(NewSetting.class); + when(service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).thenReturn(2); + when(service.getSettings()).thenReturn(settings); return new AsyncAddEmail(player, email, dataSource, playerCache, service); } diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java index bddd0122..1ccb9b67 100644 --- a/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java +++ b/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java @@ -6,12 +6,13 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.entity.Player; -import org.junit.After; -import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.any; @@ -23,29 +24,20 @@ import static org.mockito.Mockito.when; /** * Test for {@link AsyncChangeEmail}. */ +@RunWith(MockitoJUnitRunner.class) public class AsyncChangeEmailTest { + @Mock private Player player; + @Mock private PlayerCache playerCache; + @Mock private DataSource dataSource; + @Mock private ProcessService service; + @Mock private NewSetting settings; - @BeforeClass - public static void setUp() { - WrapperMock.createInstance(); - } - - // Prevent the accidental re-use of a field in another test - @After - public void cleanFields() { - player = null; - playerCache = null; - dataSource = null; - service = null; - settings = null; - } - @Test public void shouldAddEmail() { // given @@ -146,7 +138,7 @@ public class AsyncChangeEmailTest { given(playerCache.isAuthenticated("username")).willReturn(true); PlayerAuth auth = authWithMail("old@example.com"); given(playerCache.getAuth("username")).willReturn(auth); - given(dataSource.isEmailStored("new@example.com")).willReturn(true); + given(dataSource.countAuthsByEmail("new@example.com")).willReturn(5); // when process.run(); @@ -217,11 +209,7 @@ public class AsyncChangeEmailTest { } private AsyncChangeEmail createProcess(String oldEmail, String newEmail) { - player = mock(Player.class); - playerCache = mock(PlayerCache.class); - dataSource = mock(DataSource.class); - service = mock(ProcessService.class); - settings = mock(NewSetting.class); + given(service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).willReturn(5); given(service.getSettings()).willReturn(settings); return new AsyncChangeEmail(player, oldEmail, newEmail, dataSource, playerCache, service); } From 9ea75c502c50ca2a14bb1fde4e42412521ca95a0 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 3 Apr 2016 20:44:13 +0200 Subject: [PATCH 16/71] #567 Move email validation logic to validation service --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- .../xephi/authme/command/CommandService.java | 8 + .../executable/authme/SetEmailCommand.java | 10 +- .../executable/email/AddEmailCommand.java | 9 +- .../executable/register/RegisterCommand.java | 19 ++- .../xephi/authme/process/ProcessService.java | 8 + .../authme/process/email/AsyncAddEmail.java | 6 +- .../process/email/AsyncChangeEmail.java | 6 +- .../fr/xephi/authme/settings/Settings.java | 17 +- src/main/java/fr/xephi/authme/util/Utils.java | 33 +--- .../xephi/authme/util/ValidationService.java | 43 +++++- .../authme/command/CommandServiceTest.java | 31 ++++ .../executable/email/AddEmailCommandTest.java | 44 ++++-- .../register/RegisterCommandTest.java | 6 +- .../authme/process/ProcessServiceTest.java | 99 +++++++----- .../process/email/AsyncAddEmailTest.java | 35 +++-- .../process/email/AsyncChangeEmailTest.java | 30 ++-- .../java/fr/xephi/authme/util/UtilsTest.java | 104 +------------ .../authme/util/ValidationServiceTest.java | 145 +++++++++++++++++- 19 files changed, 402 insertions(+), 253 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 862c6dd7..01cccab1 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -261,7 +261,7 @@ public class AuthMe extends JavaPlugin { // Set up the permissions manager and command handler permsMan = initializePermissionsManager(); - ValidationService validationService = new ValidationService(newSettings); + ValidationService validationService = new ValidationService(newSettings, database, permsMan); commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, ipAddressManager, pluginHooks, spawnLoader, antiBot, validationService); diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index d6861059..2fee46ad 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -222,4 +222,12 @@ public class CommandService { return validationService.validatePassword(password, username); } + public boolean validateEmail(String email) { + return validationService.validateEmail(email); + } + + public boolean isEmailFreeForRegistration(String email, CommandSender sender) { + return validationService.isEmailFreeForRegistration(email, sender); + } + } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java index 9e44fdab..0e7bcf35 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java @@ -6,12 +6,13 @@ import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.util.Utils; import org.bukkit.command.CommandSender; import java.util.List; +/** + * Admin command for setting an email to an account. + */ public class SetEmailCommand implements ExecutableCommand { @Override @@ -22,7 +23,7 @@ public class SetEmailCommand implements ExecutableCommand { final String playerEmail = arguments.get(1); // Validate the email address - if (!Utils.isEmailCorrect(playerEmail, commandService.getSettings())) { + if (!commandService.validateEmail(playerEmail)) { commandService.send(sender, MessageKey.INVALID_EMAIL); return; } @@ -36,8 +37,7 @@ public class SetEmailCommand implements ExecutableCommand { if (auth == null) { commandService.send(sender, MessageKey.UNKNOWN_USER); return; - } else if (dataSource.countAuthsByEmail(playerEmail) - >= commandService.getProperty(EmailSettings.MAX_REG_PER_EMAIL)) { + } else if (!commandService.isEmailFreeForRegistration(playerEmail, sender)) { commandService.send(sender, MessageKey.EMAIL_ALREADY_USED_ERROR); return; } diff --git a/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java index f2b66301..cd92ebf4 100644 --- a/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java @@ -3,11 +3,13 @@ package fr.xephi.authme.command.executable.email; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; import java.util.List; +/** + * Command for setting an email to an account. + */ public class AddEmailCommand extends PlayerCommand { @Override @@ -15,9 +17,8 @@ public class AddEmailCommand extends PlayerCommand { String email = arguments.get(0); String emailConfirmation = arguments.get(1); - if (!Utils.isEmailCorrect(email, commandService.getSettings())) { - commandService.send(player, MessageKey.INVALID_EMAIL); - } else if (email.equals(emailConfirmation)) { + if (email.equals(emailConfirmation)) { + // Closer inspection of the mail address handled by the async task commandService.getManagement().performAddEmail(player, email); } else { commandService.send(player, MessageKey.CONFIRM_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 48a1c3f0..e488eac7 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 @@ -7,13 +7,16 @@ import fr.xephi.authme.process.Management; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.RandomString; 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.SecuritySettings; -import fr.xephi.authme.util.Utils; - import org.bukkit.entity.Player; import java.util.List; +import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH; +import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION; + public class RegisterCommand extends PlayerCommand { @Override @@ -24,25 +27,27 @@ public class RegisterCommand extends PlayerCommand { return; } - if (arguments.isEmpty() || Settings.enablePasswordConfirmation && arguments.size() < 2) { + if (arguments.isEmpty() || commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && arguments.size() < 2) { commandService.send(player, MessageKey.USAGE_REGISTER); return; } final Management management = commandService.getManagement(); - if (Settings.emailRegistration && !Settings.getmailAccount.isEmpty()) { - if (Settings.doubleEmailCheck && arguments.size() < 2 || !arguments.get(0).equals(arguments.get(1))) { + if (commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION) + && !commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { + boolean emailDoubleCheck = commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL); + if (emailDoubleCheck && arguments.size() < 2 || !arguments.get(0).equals(arguments.get(1))) { commandService.send(player, MessageKey.USAGE_REGISTER); return; } final String email = arguments.get(0); - if (!Utils.isEmailCorrect(email, commandService.getSettings())) { + if (!commandService.validateEmail(email)) { commandService.send(player, MessageKey.INVALID_EMAIL); return; } - final String thePass = RandomString.generate(Settings.getRecoveryPassLength); + final String thePass = RandomString.generate(commandService.getProperty(RECOVERY_PASSWORD_LENGTH)); management.performRegister(player, thePass, email); return; } diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java index 0489447a..fd08b7ba 100644 --- a/src/main/java/fr/xephi/authme/process/ProcessService.java +++ b/src/main/java/fr/xephi/authme/process/ProcessService.java @@ -213,4 +213,12 @@ public class ProcessService { return validationService.validatePassword(password, username); } + public boolean validateEmail(String email) { + return validationService.validateEmail(email); + } + + public boolean isEmailFreeForRegistration(String email, CommandSender sender) { + return validationService.isEmailFreeForRegistration(email, sender); + } + } diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java index 9f2451e7..282f8f09 100644 --- a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java +++ b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java @@ -7,9 +7,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Process; import fr.xephi.authme.process.ProcessService; -import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; /** @@ -42,9 +40,9 @@ public class AsyncAddEmail implements Process { if (currentEmail != null && !"your@email.com".equals(currentEmail)) { service.send(player, MessageKey.USAGE_CHANGE_EMAIL); - } else if (!Utils.isEmailCorrect(email, service.getSettings())) { + } else if (!service.validateEmail(email)) { service.send(player, MessageKey.INVALID_EMAIL); - } else if (dataSource.countAuthsByEmail(email) >= service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)) { + } else if (!service.isEmailFreeForRegistration(email, player)) { service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR); } else { auth.setEmail(email); diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java index 488ddca3..7489327b 100644 --- a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java +++ b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java @@ -6,9 +6,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Process; import fr.xephi.authme.process.ProcessService; -import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; /** @@ -42,11 +40,11 @@ public class AsyncChangeEmail implements Process { if (currentEmail == null) { service.send(player, MessageKey.USAGE_ADD_EMAIL); - } else if (newEmail == null || !Utils.isEmailCorrect(newEmail, service.getSettings())) { + } else if (newEmail == null || !service.validateEmail(newEmail)) { service.send(player, MessageKey.INVALID_NEW_EMAIL); } else if (!oldEmail.equals(currentEmail)) { service.send(player, MessageKey.INVALID_OLD_EMAIL); - } else if (dataSource.countAuthsByEmail(newEmail) >= service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)) { + } else if (!service.isEmailFreeForRegistration(newEmail, player)) { service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR); } else { saveNewEmail(auth); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index a8530bce..915c953a 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -39,7 +39,6 @@ public final class Settings { public static List forceRegisterCommandsAsConsole; public static HashAlgorithm getPasswordHash; public static Pattern nickPattern; - public static boolean useLogging = false; public static boolean isChatAllowed, isPermissionCheckEnabled, isForcedRegistrationEnabled, isTeleportToSpawnEnabled, isSessionsEnabled, isAllowRestrictedIp, @@ -50,8 +49,7 @@ public final class Settings { protectInventoryBeforeLogInEnabled, isStopEnabled, reloadSupport, rakamakUseIp, noConsoleSpam, removePassword, displayOtherAccounts, emailRegistration, multiverse, bungee, - banUnsafeIp, doubleEmailCheck, sessionExpireOnIpChange, - disableSocialSpy, useEssentialsMotd, + banUnsafeIp, sessionExpireOnIpChange, useEssentialsMotd, enableProtection, recallEmail, useWelcomeMessage, broadcastWelcomeMessage, forceRegKick, forceRegLogin, checkVeryGames, removeJoinMessage, removeLeaveMessage, delayJoinMessage, @@ -59,15 +57,13 @@ public final class Settings { kickPlayersBeforeStopping, allowAllCommandsIfRegIsOptional, customAttributes, isRemoveSpeedEnabled, preventOtherCase, keepCollisionsDisabled; public static String getNickRegex, getUnloggedinGroup, - unRegisteredGroup, - backupWindowsPath, getRegisteredGroup, + unRegisteredGroup, backupWindowsPath, getRegisteredGroup, rakamakUsers, rakamakUsersIp, getmailAccount, defaultWorld, spawnPriority, crazyloginFileName, sendPlayerTo; public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength, getMinNickLength, - getPasswordMinLen, getMovementRadius, - getNonActivatedGroup, passwordMaxLength, getRecoveryPassLength, - getMailPort, maxLoginTry, captchaLength, saltLength, + getPasswordMinLen, getMovementRadius, getNonActivatedGroup, passwordMaxLength, + maxLoginTry, captchaLength, saltLength, bCryptLog2Rounds, getMaxLoginPerIp, getMaxJoinPerIp; protected static FileConfiguration configFile; @@ -145,8 +141,6 @@ public final class Settings { noConsoleSpam = load(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE); removePassword = configFile.getBoolean("Security.console.removePassword", true); getmailAccount = load(EmailSettings.MAIL_ACCOUNT); - getMailPort = configFile.getInt("Email.mailPort", 465); - getRecoveryPassLength = configFile.getInt("Email.RecoveryPasswordLength", 8); displayOtherAccounts = configFile.getBoolean("settings.restrictions.displayOtherAccounts", true); maxLoginTry = configFile.getInt("Security.captcha.maxLoginTry", 5); captchaLength = configFile.getInt("Security.captcha.captchaLength", 5); @@ -156,10 +150,7 @@ public final class Settings { bungee = configFile.getBoolean("Hooks.bungeecord", false); getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds"); banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false); - doubleEmailCheck = configFile.getBoolean("settings.registration.doubleEmailCheck", false); sessionExpireOnIpChange = configFile.getBoolean("settings.sessions.sessionExpireOnIpChange", true); - useLogging = configFile.getBoolean("Security.console.logConsole", false); - disableSocialSpy = configFile.getBoolean("Hooks.disableSocialSpy", true); bCryptLog2Rounds = configFile.getInt("ExternalBoardOptions.bCryptLog2Round", 10); useEssentialsMotd = configFile.getBoolean("Hooks.useEssentialsMotd", false); defaultWorld = configFile.getString("Purge.defaultWorld", "world"); diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index c9b472c3..1eb4deb8 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -7,9 +7,7 @@ import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.events.AuthMeTeleportEvent; import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.EmailSettings; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; @@ -21,7 +19,6 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.List; /** * Utility class for various operations used in the codebase. @@ -254,38 +251,12 @@ public final class Utils { } } - public static boolean isEmailCorrect(String email, NewSetting settings) { - if (!email.contains("@") || "your@email.com".equalsIgnoreCase(email)) { - return false; - } - final String emailDomain = email.split("@")[1]; - - List whitelist = settings.getProperty(EmailSettings.DOMAIN_WHITELIST); - if (!CollectionUtils.isEmpty(whitelist)) { - return containsIgnoreCase(whitelist, emailDomain); - } - - List blacklist = settings.getProperty(EmailSettings.DOMAIN_BLACKLIST); - return CollectionUtils.isEmpty(blacklist) || !containsIgnoreCase(blacklist, emailDomain); - } - - private static boolean containsIgnoreCase(Collection coll, String needle) { - for (String entry : coll) { - if (entry.equalsIgnoreCase(needle)) { - return true; - } - } - return false; - } - public static String getUUIDorName(OfflinePlayer player) { - String uuidOrName; try { - uuidOrName = player.getUniqueId().toString(); + return player.getUniqueId().toString(); } catch (Exception ignore) { - uuidOrName = player.getName(); + return player.getName(); } - return uuidOrName; } public enum GroupType { diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java index 1adbda71..7f8b78b7 100644 --- a/src/main/java/fr/xephi/authme/util/ValidationService.java +++ b/src/main/java/fr/xephi/authme/util/ValidationService.java @@ -1,9 +1,17 @@ package fr.xephi.authme.util; +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.settings.NewSetting; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; +import org.bukkit.command.CommandSender; + +import java.util.Collection; +import java.util.List; /** * Validation service. @@ -11,9 +19,13 @@ import fr.xephi.authme.settings.properties.SecuritySettings; public class ValidationService { private final NewSetting settings; + private final DataSource dataSource; + private final PermissionsManager permissionsManager; - public ValidationService(NewSetting settings) { + public ValidationService(NewSetting settings, DataSource dataSource, PermissionsManager permissionsManager) { this.settings = settings; + this.dataSource = dataSource; + this.permissionsManager = permissionsManager; } /** @@ -39,4 +51,33 @@ public class ValidationService { } return null; } + + public boolean validateEmail(String email) { + if (!email.contains("@") || "your@email.com".equalsIgnoreCase(email)) { + return false; + } + final String emailDomain = email.split("@")[1]; + + List whitelist = settings.getProperty(EmailSettings.DOMAIN_WHITELIST); + if (!CollectionUtils.isEmpty(whitelist)) { + return containsIgnoreCase(whitelist, emailDomain); + } + + List blacklist = settings.getProperty(EmailSettings.DOMAIN_BLACKLIST); + return CollectionUtils.isEmpty(blacklist) || !containsIgnoreCase(blacklist, emailDomain); + } + + public boolean isEmailFreeForRegistration(String email, CommandSender sender) { + return permissionsManager.hasPermission(sender, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) + || dataSource.countAuthsByEmail(email) < settings.getProperty(EmailSettings.MAX_REG_PER_EMAIL); + } + + private static boolean containsIgnoreCase(Collection coll, String needle) { + for (String entry : coll) { + if (entry.equalsIgnoreCase(needle)) { + return true; + } + } + return false; + } } diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index 645d3a37..6c7ed5e5 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -246,4 +246,35 @@ public class CommandServiceTest { assertThat(result, equalTo(MessageKey.INVALID_PASSWORD_LENGTH)); verify(validationService).validatePassword(password, user); } + + @Test + public void shouldValidateEmail() { + // given + String email = "test@example.tld"; + given(validationService.validateEmail(email)).willReturn(true); + + // when + boolean result = commandService.validateEmail(email); + + // then + assertThat(result, equalTo(true)); + verify(validationService).validateEmail(email); + } + + @Test + public void shouldCheckIfEmailCanBeUsed() { + // given + String email = "mail@example.com"; + CommandSender sender = mock(CommandSender.class); + given(validationService.isEmailFreeForRegistration(email, sender)) + .willReturn(true); + + // when + boolean result = commandService.isEmailFreeForRegistration(email, sender); + + // then + assertThat(result, equalTo(true)); + verify(validationService).isEmailFreeForRegistration(email, sender); + } + } diff --git a/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java index 17dbddad..1ea41355 100644 --- a/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/email/AddEmailCommandTest.java @@ -1,14 +1,15 @@ package fr.xephi.authme.command.executable.email; import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Management; -import fr.xephi.authme.settings.NewSetting; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.ArrayList; import java.util.Arrays; @@ -21,19 +22,16 @@ import static org.mockito.Mockito.verify; /** * Test for {@link AddEmailCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class AddEmailCommandTest { + @Mock private CommandService commandService; - @Before - public void setUpMocks() { - commandService = mock(CommandService.class); - } - @Test public void shouldRejectNonPlayerSender() { // given - CommandSender sender = Mockito.mock(BlockCommandSender.class); + CommandSender sender = mock(BlockCommandSender.class); AddEmailCommand command = new AddEmailCommand(); // when @@ -46,18 +44,34 @@ public class AddEmailCommandTest { @Test public void shouldForwardData() { // given - Player sender = Mockito.mock(Player.class); - AddEmailCommand command = new AddEmailCommand(); + Player sender = mock(Player.class); + String email = "mail@example"; + given(commandService.validateEmail(email)).willReturn(true); Management management = mock(Management.class); given(commandService.getManagement()).willReturn(management); - NewSetting settings = mock(NewSetting.class); - given(commandService.getSettings()).willReturn(settings); + AddEmailCommand command = new AddEmailCommand(); // when - command.executeCommand(sender, Arrays.asList("mail@example", "mail@example"), commandService); + command.executeCommand(sender, Arrays.asList(email, email), commandService); // then - verify(management).performAddEmail(sender, "mail@example"); + verify(management).performAddEmail(sender, email); + } + + @Test + public void shouldFailForConfirmationMismatch() { + // given + Player sender = mock(Player.class); + String email = "asdfasdf@example.com"; + given(commandService.validateEmail(email)).willReturn(true); + AddEmailCommand command = new AddEmailCommand(); + + // when + command.executeCommand(sender, Arrays.asList(email, "wrongConf"), commandService); + + // then + verify(commandService, never()).getManagement(); + verify(commandService).send(sender, MessageKey.CONFIRM_EMAIL_MESSAGE); } } 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 84b79726..72f5e0c0 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 @@ -3,7 +3,7 @@ package fr.xephi.authme.command.executable.register; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Management; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; @@ -14,6 +14,7 @@ import org.junit.Test; import java.util.ArrayList; import java.util.Collections; +import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION; import static org.hamcrest.Matchers.containsString; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.argThat; @@ -31,7 +32,6 @@ public class RegisterCommandTest { @Before public void initializeAuthMeMock() { WrapperMock.createInstance(); - Settings.captchaLength = 10; commandService = mock(CommandService.class); } @@ -70,6 +70,8 @@ public class RegisterCommandTest { RegisterCommand command = new RegisterCommand(); Management management = mock(Management.class); given(commandService.getManagement()).willReturn(management); + given(commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION)).willReturn(false); + given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(false); // when command.executeCommand(sender, Collections.singletonList("password"), commandService); diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java index 14d2e3e2..8e4acddf 100644 --- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java +++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java @@ -15,9 +15,9 @@ import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.junit.Before; import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; @@ -28,23 +28,38 @@ import static org.mockito.Mockito.verify; /** * Test for {@link ProcessService}. */ +@RunWith(MockitoJUnitRunner.class) public class ProcessServiceTest { private ProcessService processService; - private Map, Object> mocks; + @Mock + private ValidationService validationService; + @Mock + private NewSetting settings; + @Mock + private Messages messages; + @Mock + private IpAddressManager ipAddressManager; + @Mock + private PasswordSecurity passwordSecurity; + @Mock + private AuthMe authMe; + @Mock + private DataSource dataSource; + @Mock + private SpawnLoader spawnLoader; + @Mock + private PluginHooks pluginHooks; @Before public void setUpService() { - mocks = new HashMap<>(); - processService = new ProcessService(newMock(NewSetting.class), newMock(Messages.class), newMock(AuthMe.class), - newMock(DataSource.class), newMock(IpAddressManager.class), newMock(PasswordSecurity.class), - newMock(PluginHooks.class), newMock(SpawnLoader.class), newMock(ValidationService.class)); + processService = new ProcessService(settings, messages, authMe, dataSource, ipAddressManager, passwordSecurity, + pluginHooks, spawnLoader, validationService); } @Test public void shouldGetProperty() { // given - NewSetting settings = getMock(NewSetting.class); given(settings.getProperty(SecuritySettings.CAPTCHA_LENGTH)).willReturn(8); // when @@ -58,16 +73,15 @@ public class ProcessServiceTest { @Test public void shouldReturnSettings() { // given/when - NewSetting settings = processService.getSettings(); + NewSetting result = processService.getSettings(); // then - assertThat(settings, equalTo(getMock(NewSetting.class))); + assertThat(result, equalTo(settings)); } @Test public void shouldSendMessageToPlayer() { // given - Messages messages = getMock(Messages.class); CommandSender sender = mock(CommandSender.class); MessageKey key = MessageKey.ACCOUNT_NOT_ACTIVATED; @@ -81,7 +95,6 @@ public class ProcessServiceTest { @Test public void shouldSendMessageWithReplacements() { // given - Messages messages = getMock(Messages.class); CommandSender sender = mock(CommandSender.class); MessageKey key = MessageKey.ACCOUNT_NOT_ACTIVATED; String[] replacements = new String[]{"test", "toast"}; @@ -96,7 +109,6 @@ public class ProcessServiceTest { @Test public void shouldRetrieveMessage() { // given - Messages messages = getMock(Messages.class); MessageKey key = MessageKey.ACCOUNT_NOT_ACTIVATED; String[] lines = new String[]{"First message line", "second line"}; given(messages.retrieve(key)).willReturn(lines); @@ -112,7 +124,6 @@ public class ProcessServiceTest { @Test public void shouldRetrieveSingleMessage() { // given - Messages messages = getMock(Messages.class); MessageKey key = MessageKey.ACCOUNT_NOT_ACTIVATED; String text = "Test text"; given(messages.retrieveSingle(key)).willReturn(text); @@ -128,52 +139,51 @@ public class ProcessServiceTest { @Test public void shouldReturnAuthMeInstance() { // given / when - AuthMe authMe = processService.getAuthMe(); + AuthMe result = processService.getAuthMe(); // then - assertThat(authMe, equalTo(getMock(AuthMe.class))); + assertThat(result, equalTo(authMe)); } @Test public void shouldReturnPluginHooks() { // given / when - PluginHooks pluginHooks = processService.getPluginHooks(); + PluginHooks result = processService.getPluginHooks(); // then - assertThat(pluginHooks, equalTo(getMock(PluginHooks.class))); + assertThat(result, equalTo(pluginHooks)); } @Test public void shouldReturnIpAddressManager() { // given / when - IpAddressManager ipAddressManager = processService.getIpAddressManager(); + IpAddressManager result = processService.getIpAddressManager(); // then - assertThat(ipAddressManager, equalTo(getMock(IpAddressManager.class))); + assertThat(result, equalTo(ipAddressManager)); } @Test public void shouldReturnSpawnLoader() { // given / when - SpawnLoader spawnLoader = processService.getSpawnLoader(); + SpawnLoader result = processService.getSpawnLoader(); // then - assertThat(spawnLoader, equalTo(getMock(SpawnLoader.class))); + assertThat(result, equalTo(spawnLoader)); } @Test public void shouldReturnDatasource() { // given / when - DataSource dataSource = processService.getDataSource(); + DataSource result = processService.getDataSource(); // then - assertThat(dataSource, equalTo(getMock(DataSource.class))); + assertThat(result, equalTo(dataSource)); } @Test public void shouldComputeHash() { // given - PasswordSecurity passwordSecurity = getMock(PasswordSecurity.class); String password = "test123"; String username = "Username"; HashedPassword hashedPassword = new HashedPassword("hashedResult", "salt12342"); @@ -192,7 +202,6 @@ public class ProcessServiceTest { // given String user = "test-user"; String password = "passw0rd"; - ValidationService validationService = getMock(ValidationService.class); given(validationService.validatePassword(password, user)).willReturn(MessageKey.PASSWORD_MATCH_ERROR); // when @@ -203,17 +212,33 @@ public class ProcessServiceTest { verify(validationService).validatePassword(password, user); } - private T newMock(Class clazz) { - T mock = mock(clazz); - mocks.put(clazz, mock); - return mock; + @Test + public void shouldValidateEmail() { + // given + String email = "test@example.tld"; + given(validationService.validateEmail(email)).willReturn(true); + + // when + boolean result = processService.validateEmail(email); + + // then + assertThat(result, equalTo(true)); + verify(validationService).validateEmail(email); } - private T getMock(Class clazz) { - Object mock = mocks.get(clazz); - if (mock == null) { - throw new IllegalArgumentException("No mock of type " + clazz); - } - return clazz.cast(mock); + @Test + public void shouldCheckIfEmailCanBeUsed() { + // given + String email = "mail@example.com"; + CommandSender sender = mock(CommandSender.class); + given(validationService.isEmailFreeForRegistration(email, sender)) + .willReturn(true); + + // when + boolean result = processService.isEmailFreeForRegistration(email, sender); + + // then + assertThat(result, equalTo(true)); + verify(validationService).isEmailFreeForRegistration(email, sender); } } diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java index 9f93a47d..3d6ccee7 100644 --- a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java +++ b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java @@ -6,8 +6,6 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.ProcessService; -import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import org.bukkit.entity.Player; import org.junit.BeforeClass; @@ -21,7 +19,6 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; /** * Test for {@link AsyncAddEmail}. @@ -46,14 +43,16 @@ public class AsyncAddEmailTest { @Test public void shouldAddEmail() { // given - AsyncAddEmail process = createProcess("my.mail@example.org"); + String email = "my.mail@example.org"; + AsyncAddEmail process = createProcess(email); given(player.getName()).willReturn("testEr"); given(playerCache.isAuthenticated("tester")).willReturn(true); PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("tester")).willReturn(auth); - given(dataSource.countAuthsByEmail("my.mail@example.org")).willReturn(1); given(dataSource.updateEmail(any(PlayerAuth.class))).willReturn(true); + given(service.validateEmail(email)).willReturn(true); + given(service.isEmailFreeForRegistration(email, player)).willReturn(true); // when process.run(); @@ -61,21 +60,24 @@ public class AsyncAddEmailTest { // then verify(dataSource).updateEmail(auth); verify(service).send(player, MessageKey.EMAIL_ADDED_SUCCESS); - verify(auth).setEmail("my.mail@example.org"); + verify(auth).setEmail(email); verify(playerCache).updatePlayer(auth); } @Test public void shouldReturnErrorWhenMailCannotBeSaved() { // given - AsyncAddEmail process = createProcess("my.mail@example.org"); + String email = "my.mail@example.org"; + AsyncAddEmail process = createProcess(email); given(player.getName()).willReturn("testEr"); given(playerCache.isAuthenticated("tester")).willReturn(true); PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("tester")).willReturn(auth); - given(dataSource.countAuthsByEmail("my.mail@example.org")).willReturn(0); + given(dataSource.countAuthsByEmail(email)).willReturn(0); given(dataSource.updateEmail(any(PlayerAuth.class))).willReturn(false); + given(service.validateEmail(email)).willReturn(true); + given(service.isEmailFreeForRegistration(email, player)).willReturn(true); // when process.run(); @@ -94,7 +96,6 @@ public class AsyncAddEmailTest { PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn("another@mail.tld"); given(playerCache.getAuth("my_player")).willReturn(auth); - given(dataSource.countAuthsByEmail("some.mail@example.org")).willReturn(0); // when process.run(); @@ -107,13 +108,14 @@ public class AsyncAddEmailTest { @Test public void shouldNotAddMailIfItIsInvalid() { // given - AsyncAddEmail process = createProcess("invalid_mail"); + String email = "invalid_mail"; + AsyncAddEmail process = createProcess(email); given(player.getName()).willReturn("my_Player"); given(playerCache.isAuthenticated("my_player")).willReturn(true); PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("my_player")).willReturn(auth); - given(dataSource.countAuthsByEmail("invalid_mail")).willReturn(0); + given(service.validateEmail(email)).willReturn(false); // when process.run(); @@ -126,13 +128,15 @@ public class AsyncAddEmailTest { @Test public void shouldNotAddMailIfAlreadyUsed() { // given - AsyncAddEmail process = createProcess("player@mail.tld"); + String email = "player@mail.tld"; + AsyncAddEmail process = createProcess(email); given(player.getName()).willReturn("TestName"); given(playerCache.isAuthenticated("testname")).willReturn(true); PlayerAuth auth = mock(PlayerAuth.class); given(auth.getEmail()).willReturn(null); given(playerCache.getAuth("testname")).willReturn(auth); - given(dataSource.countAuthsByEmail("player@mail.tld")).willReturn(2); + given(service.validateEmail(email)).willReturn(true); + given(service.isEmailFreeForRegistration(email, player)).willReturn(false); // when process.run(); @@ -193,15 +197,12 @@ public class AsyncAddEmailTest { } /** - * Create an instance of {@link AsyncAddEmail} and save the mocks to this class' fields. + * Create an instance of {@link AsyncAddEmail} with the class' mocks. * * @param email The email to use * @return The created process */ private AsyncAddEmail createProcess(String email) { - NewSetting settings = mock(NewSetting.class); - when(service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).thenReturn(2); - when(service.getSettings()).thenReturn(settings); return new AsyncAddEmail(player, email, dataSource, playerCache, service); } diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java index 1ccb9b67..a90ff9b2 100644 --- a/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java +++ b/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java @@ -5,7 +5,6 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.ProcessService; -import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import org.bukkit.entity.Player; @@ -35,18 +34,19 @@ public class AsyncChangeEmailTest { private DataSource dataSource; @Mock private ProcessService service; - @Mock - private NewSetting settings; @Test public void shouldAddEmail() { // given - AsyncChangeEmail process = createProcess("old@mail.tld", "new@mail.tld"); + String newEmail = "new@mail.tld"; + AsyncChangeEmail process = createProcess("old@mail.tld", newEmail); given(player.getName()).willReturn("Bobby"); given(playerCache.isAuthenticated("bobby")).willReturn(true); PlayerAuth auth = authWithMail("old@mail.tld"); given(playerCache.getAuth("bobby")).willReturn(auth); given(dataSource.updateEmail(auth)).willReturn(true); + given(service.validateEmail(newEmail)).willReturn(true); + given(service.isEmailFreeForRegistration(newEmail, player)).willReturn(true); // when process.run(); @@ -60,12 +60,15 @@ public class AsyncChangeEmailTest { @Test public void shouldShowErrorIfSaveFails() { // given - AsyncChangeEmail process = createProcess("old@mail.tld", "new@mail.tld"); + String newEmail = "new@mail.tld"; + AsyncChangeEmail process = createProcess("old@mail.tld", newEmail); given(player.getName()).willReturn("Bobby"); given(playerCache.isAuthenticated("bobby")).willReturn(true); PlayerAuth auth = authWithMail("old@mail.tld"); given(playerCache.getAuth("bobby")).willReturn(auth); given(dataSource.updateEmail(auth)).willReturn(false); + given(service.validateEmail(newEmail)).willReturn(true); + given(service.isEmailFreeForRegistration(newEmail, player)).willReturn(true); // when process.run(); @@ -97,11 +100,13 @@ public class AsyncChangeEmailTest { @Test public void shouldRejectInvalidNewMail() { // given - AsyncChangeEmail process = createProcess("old@mail.tld", "bogus"); + String newEmail = "bogus"; + AsyncChangeEmail process = createProcess("old@mail.tld", newEmail); given(player.getName()).willReturn("Bobby"); given(playerCache.isAuthenticated("bobby")).willReturn(true); PlayerAuth auth = authWithMail("old@mail.tld"); given(playerCache.getAuth("bobby")).willReturn(auth); + given(service.validateEmail(newEmail)).willReturn(false); // when process.run(); @@ -115,11 +120,15 @@ public class AsyncChangeEmailTest { @Test public void shouldRejectInvalidOldEmail() { // given - AsyncChangeEmail process = createProcess("old@mail.tld", "new@mail.tld"); + String newEmail = "new@mail.tld"; + AsyncChangeEmail process = createProcess("old@mail.tld", newEmail); given(player.getName()).willReturn("Bobby"); given(playerCache.isAuthenticated("bobby")).willReturn(true); PlayerAuth auth = authWithMail("other@address.email"); given(playerCache.getAuth("bobby")).willReturn(auth); + given(service.validateEmail(newEmail)).willReturn(true); + given(service.isEmailFreeForRegistration(newEmail, player)).willReturn(true); + // when process.run(); @@ -133,12 +142,14 @@ public class AsyncChangeEmailTest { @Test public void shouldRejectAlreadyUsedEmail() { // given - AsyncChangeEmail process = createProcess("old@example.com", "new@example.com"); + String newEmail = "new@example.com"; + AsyncChangeEmail process = createProcess("old@example.com", newEmail); given(player.getName()).willReturn("Username"); given(playerCache.isAuthenticated("username")).willReturn(true); PlayerAuth auth = authWithMail("old@example.com"); given(playerCache.getAuth("username")).willReturn(auth); - given(dataSource.countAuthsByEmail("new@example.com")).willReturn(5); + given(service.validateEmail(newEmail)).willReturn(true); + given(service.isEmailFreeForRegistration(newEmail, player)).willReturn(false); // when process.run(); @@ -210,7 +221,6 @@ public class AsyncChangeEmailTest { private AsyncChangeEmail createProcess(String oldEmail, String newEmail) { given(service.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).willReturn(5); - given(service.getSettings()).willReturn(settings); return new AsyncChangeEmail(player, oldEmail, newEmail, dataSource, playerCache, service); } } diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java index 639946f6..a1e9a6a1 100644 --- a/src/test/java/fr/xephi/authme/util/UtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java @@ -3,26 +3,23 @@ package fr.xephi.authme.util; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.ReflectionTestUtils; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; - -import fr.xephi.authme.settings.properties.EmailSettings; import org.bukkit.entity.Player; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; /** * Test for the {@link Utils} class. @@ -30,7 +27,6 @@ import static org.mockito.Mockito.*; public class UtilsTest { private static AuthMe authMeMock; - private PermissionsManager permissionsManagerMock; /** * The Utils class initializes its fields in a {@code static} block which is only executed once during the JUnit @@ -51,9 +47,6 @@ public class UtilsTest { // before every test -- this is OK because it is retrieved via authMeMock. It is just crucial that authMeMock // remain the same object. reset(authMeMock); - - permissionsManagerMock = mock(PermissionsManager.class); - when(authMeMock.getPermissionsManager()).thenReturn(permissionsManagerMock); } @Test @@ -103,95 +96,6 @@ public class UtilsTest { assertThat(players, hasSize(2)); } - // ---------------- - // Tests for Utils#isEmailCorrect() - // ---------------- - @Test - public void shouldAcceptEmailWithEmptyLists() { - // given - NewSetting settings = mock(NewSetting.class); - given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections. emptyList()); - given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections. emptyList()); - - // when - boolean result = Utils.isEmailCorrect("test@example.org", settings); - - // then - assertThat(result, equalTo(true)); - } - - @Test - public void shouldAcceptEmailWithWhitelist() { - // given - NewSetting settings = mock(NewSetting.class); - given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)) - .willReturn(Arrays.asList("domain.tld", "example.com")); - given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections. emptyList()); - - // when - boolean result = Utils.isEmailCorrect("TesT@Example.com", settings); - - // then - assertThat(result, equalTo(true)); - } - - @Test - public void shouldRejectEmailNotInWhitelist() { - // given - NewSetting settings = mock(NewSetting.class); - given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)) - .willReturn(Arrays.asList("domain.tld", "example.com")); - given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections. emptyList()); - - // when - boolean result = Utils.isEmailCorrect("email@other-domain.abc", settings); - - // then - assertThat(result, equalTo(false)); - } - - @Test - public void shouldAcceptEmailNotInBlacklist() { - // given - NewSetting settings = mock(NewSetting.class); - given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections. emptyList()); - given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)) - .willReturn(Arrays.asList("Example.org", "a-test-name.tld")); - - // when - boolean result = Utils.isEmailCorrect("sample@valid-name.tld", settings); - - // then - assertThat(result, equalTo(true)); - } - - @Test - public void shouldRejectEmailInBlacklist() { - // given - NewSetting settings = mock(NewSetting.class); - given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections. emptyList()); - given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)) - .willReturn(Arrays.asList("Example.org", "a-test-name.tld")); - - // when - boolean result = Utils.isEmailCorrect("sample@a-Test-name.tld", settings); - - // then - assertThat(result, equalTo(false)); - } - - @Test - public void shouldRejectInvalidEmail() { - // given/when/then - assertThat(Utils.isEmailCorrect("invalidinput", mock(NewSetting.class)), equalTo(false)); - } - - @Test - public void shouldRejectDefaultEmail() { - // given/when/then - assertThat(Utils.isEmailCorrect("your@email.com", mock(NewSetting.class)), equalTo(false)); - } - // Note: This method is used through reflections public static Player[] onlinePlayersImpl() { return new Player[]{ diff --git a/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java b/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java index 0fd567f2..ed784510 100644 --- a/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java +++ b/src/test/java/fr/xephi/authme/util/ValidationServiceTest.java @@ -1,14 +1,23 @@ package fr.xephi.authme.util; import com.google.common.base.Strings; +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.settings.NewSetting; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; +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; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.nullValue; @@ -19,19 +28,26 @@ import static org.mockito.Mockito.mock; /** * Test for {@link ValidationService}. */ +@RunWith(MockitoJUnitRunner.class) public class ValidationServiceTest { private ValidationService validationService; + @Mock + private NewSetting settings; + @Mock + private DataSource dataSource; + @Mock + private PermissionsManager permissionsManager; @Before public void createService() { - NewSetting settings = mock(NewSetting.class); given(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)).willReturn("[a-zA-Z]+"); given(settings.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)).willReturn(3); given(settings.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)).willReturn(20); given(settings.getProperty(SecuritySettings.UNSAFE_PASSWORDS)) .willReturn(Arrays.asList("unsafe", "other-unsafe")); - validationService = new ValidationService(settings); + given(settings.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).willReturn(3); + validationService = new ValidationService(settings, dataSource, permissionsManager); } @Test @@ -89,4 +105,129 @@ public class ValidationServiceTest { assertThat(error, nullValue()); } + @Test + public void shouldAcceptEmailWithEmptyLists() { + // given + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.emptyList()); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.emptyList()); + + // when + boolean result = validationService.validateEmail("test@example.org"); + + // then + assertThat(result, equalTo(true)); + } + + @Test + public void shouldAcceptEmailWithWhitelist() { + // given + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)) + .willReturn(Arrays.asList("domain.tld", "example.com")); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.emptyList()); + + // when + boolean result = validationService.validateEmail("TesT@Example.com"); + + // then + assertThat(result, equalTo(true)); + } + + @Test + public void shouldRejectEmailNotInWhitelist() { + // given + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)) + .willReturn(Arrays.asList("domain.tld", "example.com")); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.emptyList()); + + // when + boolean result = validationService.validateEmail("email@other-domain.abc"); + + // then + assertThat(result, equalTo(false)); + } + + @Test + public void shouldAcceptEmailNotInBlacklist() { + // given + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.emptyList()); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)) + .willReturn(Arrays.asList("Example.org", "a-test-name.tld")); + + // when + boolean result = validationService.validateEmail("sample@valid-name.tld"); + + // then + assertThat(result, equalTo(true)); + } + + @Test + public void shouldRejectEmailInBlacklist() { + // given + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.emptyList()); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)) + .willReturn(Arrays.asList("Example.org", "a-test-name.tld")); + + // when + boolean result = validationService.validateEmail("sample@a-Test-name.tld"); + + // then + assertThat(result, equalTo(false)); + } + + @Test + public void shouldRejectInvalidEmail() { + // given/when/then + assertThat(validationService.validateEmail("invalidinput"), equalTo(false)); + } + + @Test + public void shouldRejectDefaultEmail() { + // given/when/then + assertThat(validationService.validateEmail("your@email.com"), equalTo(false)); + } + + public void shouldAllowRegistration() { + // given + CommandSender sender = mock(CommandSender.class); + String email = "my.address@example.org"; + given(permissionsManager.hasPermission(sender, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)) + .willReturn(false); + given(dataSource.countAuthsByEmail(email)).willReturn(2); + + // when + boolean result = validationService.isEmailFreeForRegistration(email, sender); + + // then + assertThat(result, equalTo(true)); + } + + public void shouldRejectEmailWithTooManyAccounts() { + // given + CommandSender sender = mock(CommandSender.class); + String email = "mail@example.org"; + given(permissionsManager.hasPermission(sender, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)) + .willReturn(false); + given(dataSource.countAuthsByEmail(email)).willReturn(5); + + // when + boolean result = validationService.isEmailFreeForRegistration(email, sender); + + // then + assertThat(result, equalTo(false)); + } + + public void shouldAllowBypassForPresentPermission() { + // given + CommandSender sender = mock(CommandSender.class); + String email = "mail-address@example.com"; + given(permissionsManager.hasPermission(sender, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)) + .willReturn(true); + given(dataSource.countAuthsByEmail(email)).willReturn(7); + + // when + boolean result = validationService.isEmailFreeForRegistration(email, sender); + + // then + assertThat(result, equalTo(true)); + } } From 48c5dd03bd21591e87d42c538b76c0ef7cfdb75b Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 5 Apr 2016 21:19:25 +0200 Subject: [PATCH 17/71] Fix restore of tablist hider --- .../AuthMeInventoryPacketAdapter.java | 2 + .../AuthMeTabCompletePacketAdapter.java | 1 + .../listener/AuthMeTablistPacketAdapter.java | 59 +++++++++++++++++-- .../process/login/ProcessSyncPlayerLogin.java | 6 +- .../register/ProcessSyncPasswordRegister.java | 6 +- 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java index 62dcf7e5..9ee17fb1 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java @@ -127,9 +127,11 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter { PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS); inventoryPacket.getIntegers().write(0, PLAYER_INVENTORY); int inventorySize = CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE + HOTBAR_SIZE; + ItemStack[] blankInventory = new ItemStack[inventorySize]; Arrays.fill(blankInventory, new ItemStack(Material.AIR)); inventoryPacket.getItemArrayModifier().write(0, blankInventory); + try { protocolManager.sendServerPacket(player, inventoryPacket, false); } catch (InvocationTargetException invocationExc) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java index ad3402d6..d8266985 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java @@ -6,6 +6,7 @@ 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; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index ef4d0b93..a6df542e 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -1,13 +1,29 @@ package fr.xephi.authme.listener; import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.FieldAccessException; +import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; +import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; +import com.comphenix.protocol.wrappers.PlayerInfoData; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedGameProfile; + import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; +import fr.xephi.authme.util.Utils; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.logging.Level; + +import org.bukkit.entity.Player; public class AuthMeTablistPacketAdapter extends PacketAdapter { @@ -18,6 +34,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { @Override public void onPacketSending(PacketEvent event) { if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) { + //this hides the tablist for the new joining players. Already playing users will see the new player try { if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) { event.setCancelled(true); @@ -28,13 +45,47 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } } - // TODO: fix this in 1.9 + public void sendTablist(Player receiver) { + WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(receiver); + + ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); + NativeGameMode gamemode = NativeGameMode.fromBukkit(receiver.getGameMode()); + + WrappedChatComponent displayName = WrappedChatComponent.fromText(receiver.getDisplayName()); + PlayerInfoData playerInfoData = new PlayerInfoData(gameProfile, 0, gamemode, displayName); + + //add info containing the skin data + PacketContainer addInfo = protocolManager.createPacket(PacketType.Play.Server.PLAYER_INFO); + addInfo.getPlayerInfoAction().write(0, PlayerInfoAction.ADD_PLAYER); + addInfo.getPlayerInfoDataLists().write(0, Arrays.asList(playerInfoData)); + + try { + //adds the skin + protocolManager.sendServerPacket(receiver, addInfo); + } catch (InvocationTargetException ex) { + plugin.getLogger().log(Level.SEVERE, "Exception sending instant skin change packet", ex); + } + + //triggers an update for others player to see them + for (Player onlinePlayer : Utils.getOnlinePlayers()) { + if (onlinePlayer.equals(receiver)) { + continue; + } + + //removes the entity and display them + onlinePlayer.hidePlayer(receiver); + onlinePlayer.showPlayer(receiver); + } + } + + // TODO: fix this public void register() { - ConsoleLogger.showError("The hideTablistBeforeLogin feature is temporarily disabled due to issues with 1.9 clients."); - //ProtocolLibrary.getProtocolManager().addPacketListener(this); + //commented out because it **could (not tested could also work with it)** still conflict with SkinRestorer + ConsoleLogger.showError("The hideTablistBeforeLogin feature is temporarily disabled due to issues"); +// ProtocolLibrary.getProtocolManager().addPacketListener(this); } public void unregister() { - //ProtocolLibrary.getProtocolManager().removePacketListener(this); + ProtocolLibrary.getProtocolManager().removePacketListener(this); } } 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 1a922ff8..a920fa69 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -162,6 +162,10 @@ public class ProcessSyncPlayerLogin implements Runnable { restoreInventory(); } + if (settings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) { + plugin.tablistHider.sendTablist(player); + } + // Cleanup no longer used temporary data LimboCache.getInstance().deleteLimboPlayer(name); if (playerCache.doesCacheExist(player)) { @@ -208,7 +212,7 @@ public class ProcessSyncPlayerLogin implements Runnable { // Login is now finished; we can force all commands forceCommands(); - + sendTo(); } 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 c77a7d03..c3411d92 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -54,7 +54,7 @@ public class ProcessSyncPasswordRegister implements Process { } for (String command : Settings.forceRegisterCommandsAsConsole) { Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), - command.replace("%p", player.getName())); + command.replace("%p", player.getName())); } } @@ -80,6 +80,10 @@ public class ProcessSyncPasswordRegister implements Process { public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); if (limbo != null) { + if (Settings.hideTablistBeforeLogin && plugin.tablistHider != null) { + plugin.tablistHider.sendTablist(player); + } + Utils.teleportToSpawn(player); if (Settings.protectInventoryBeforeLogInEnabled && plugin.inventoryProtector != null) { From 17ae88c94b6c9c4afc5bf7d426830f50b13af43b Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 5 Apr 2016 21:30:32 +0200 Subject: [PATCH 18/71] Fix other players are invisble on hideTablist --- .../fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java | 4 ++-- 1 file changed, 2 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 a6df542e..d62dab64 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -73,8 +73,8 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } //removes the entity and display them - onlinePlayer.hidePlayer(receiver); - onlinePlayer.showPlayer(receiver); + receiver.hidePlayer(receiver); + receiver.showPlayer(receiver); } } From d19d1772ba8d8a37f6f5eb8ac640a98345f6ab4a Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 5 Apr 2016 21:31:55 +0200 Subject: [PATCH 19/71] Fix other players are invisble on hideTablist --- .../fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java | 4 ++-- 1 file changed, 2 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 d62dab64..d38dd87c 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -73,8 +73,8 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } //removes the entity and display them - receiver.hidePlayer(receiver); - receiver.showPlayer(receiver); + receiver.hidePlayer(onlinePlayer); + receiver.showPlayer(onlinePlayer); } } From 46c6eba3eaf66709e6db24f2d75bf64f804fc3cd Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 5 Apr 2016 23:29:42 +0200 Subject: [PATCH 20/71] Bump API --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aacd54fb..b65c4b7d 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ Unknown - 1.9-R0.1-SNAPSHOT + 1.9.2-R0.1-SNAPSHOT From 70fbca3c477d8c37bf8ee58449d9d07758f5d093 Mon Sep 17 00:00:00 2001 From: games647 Date: Wed, 6 Apr 2016 15:20:01 +0200 Subject: [PATCH 21/71] Re-enable hideTablist because it's compatible with SkinRestorer --- .../fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index d38dd87c..03d78a52 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -78,11 +78,8 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } } - // TODO: fix this public void register() { - //commented out because it **could (not tested could also work with it)** still conflict with SkinRestorer - ConsoleLogger.showError("The hideTablistBeforeLogin feature is temporarily disabled due to issues"); -// ProtocolLibrary.getProtocolManager().addPacketListener(this); + ProtocolLibrary.getProtocolManager().addPacketListener(this); } public void unregister() { From d46ad9ab5e79141bd89ed6d3b8900b1e813ab291 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 6 Apr 2016 17:36:34 +0200 Subject: [PATCH 22/71] Update hikari logger --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b65c4b7d..d1fd25e0 100644 --- a/pom.xml +++ b/pom.xml @@ -349,7 +349,7 @@ org.slf4j slf4j-simple - 1.7.20 + 1.7.21 compile true From b3a3843b604625e181b824e1eab4e6ed9f381c8f Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 7 Apr 2016 17:19:52 +0200 Subject: [PATCH 23/71] Tools: doc templates - add support for iterating tags - Support iterating tags - Generate (update) all docs --- docs/commands.md | 66 +++++++++---------- docs/hash_algorithms.md | 6 +- docs/permission_nodes.md | 5 +- src/tools/commands/CommandPageCreater.java | 31 ++++----- src/tools/commands/command_entry.tpl.md | 2 - src/tools/commands/commands.tpl.md | 5 +- .../HashAlgorithmsDescriptionTask.java | 22 +++---- src/tools/hashmethods/hash_algorithms.tpl.md | 5 +- .../hashmethods/hash_algorithms_row.tpl.md | 1 - .../permissions/PermissionsListWriter.java | 24 +++---- .../permissions/permission_node_entry.tpl.md | 1 - src/tools/permissions/permission_nodes.tpl.md | 4 +- src/tools/utils/FileUtils.java | 7 +- src/tools/utils/TagReplacer.java | 51 +++++++++++--- src/tools/utils/TagValue.java | 51 ++++++++++++++ src/tools/utils/TagValueHolder.java | 34 ++++++++++ 16 files changed, 209 insertions(+), 106 deletions(-) delete mode 100644 src/tools/commands/command_entry.tpl.md delete mode 100644 src/tools/hashmethods/hash_algorithms_row.tpl.md delete mode 100644 src/tools/permissions/permission_node_entry.tpl.md create mode 100644 src/tools/utils/TagValue.java create mode 100644 src/tools/utils/TagValueHolder.java diff --git a/docs/commands.md b/docs/commands.md index 70a752d3..ba38674d 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 `< >` @@ -7,74 +7,72 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`). - **/authme**: The main AuthMeReloaded command. The root for all admin commands. - **/authme register** <player> <password>: Register the specified player with the specified password. -
Requires `authme.admin.register` +
Requires `authme.admin.register` - **/authme unregister** <player>: Unregister the specified player. -
Requires `authme.admin.unregister` +
Requires `authme.admin.unregister` - **/authme forcelogin** [player]: Enforce the specified player to login. -
Requires `authme.player.canbeforced` +
Requires `authme.admin.forcelogin` - **/authme password** <player> <pwd>: Change the password of a player. -
Requires `authme.admin.changepassword` +
Requires `authme.admin.changepassword` - **/authme lastlogin** [player]: View the date of the specified players last login. -
Requires `authme.admin.lastlogin` +
Requires `authme.admin.lastlogin` - **/authme accounts** [player]: Display all accounts of a player by his player name or IP. -
Requires `authme.admin.accounts` +
Requires `authme.admin.accounts` - **/authme email** [player]: Display the email address of the specified player if set. -
Requires `authme.admin.getemail` +
Requires `authme.admin.getemail` - **/authme setemail** <player> <email>: Change the email address of the specified player. -
Requires `authme.admin.changemail` +
Requires `authme.admin.changemail` - **/authme getip** <player>: Get the IP address of the specified online player. -
Requires `authme.admin.getip` -- **/authme spawn** <player>: Teleport to the spawn. -
Requires `authme.admin.spawn` +
Requires `authme.admin.getip` +- **/authme spawn**: Teleport to the spawn. +
Requires `authme.admin.spawn` - **/authme setspawn**: Change the player's spawn to your current position. -
Requires `authme.admin.setspawn` +
Requires `authme.admin.setspawn` - **/authme firstspawn**: Teleport to the first spawn. -
Requires `authme.admin.firstspawn` +
Requires `authme.admin.firstspawn` - **/authme setfirstspawn**: Change the first player's spawn to your current position. -
Requires `authme.admin.setfirstspawn` +
Requires `authme.admin.setfirstspawn` - **/authme purge** <days>: Purge old AuthMeReloaded data longer than the specified amount of days ago. -
Requires `authme.admin.purge` +
Requires `authme.admin.purge` - **/authme resetpos** <player/*>: Purge the last know position of the specified player or all of them. -
Requires `authme.admin.purgelastpos` +
Requires `authme.admin.purgelastpos` - **/authme purgebannedplayers**: Purge all AuthMeReloaded data for banned players. -
Requires `authme.admin.purgebannedplayers` +
Requires `authme.admin.purgebannedplayers` - **/authme switchantibot** [mode]: Switch or toggle the AntiBot mode to the specified state. -
Requires `authme.admin.switchantibot` +
Requires `authme.admin.switchantibot` - **/authme reload**: Reload the AuthMeReloaded plugin. -
Requires `authme.admin.reload` +
Requires `authme.admin.reload` - **/authme version**: Show detailed information about the installed AuthMeReloaded version, the developers, contributors, and license. +- **/authme converter** <job>: Converter command for AuthMeReloaded. +
Requires `authme.admin.converter` - **/authme help** [query]: View detailed help for /authme commands. - **/login** <password>: Command to log in using AuthMeReloaded. -
Requires `authme.player.login` +
Requires `authme.player.login` - **/login help** [query]: View detailed help for /login commands. - **/logout**: Command to logout using AuthMeReloaded. -
Requires `authme.player.logout` +
Requires `authme.player.logout` - **/logout help** [query]: View detailed help for /logout commands. - **/register** [password] [verifyPassword]: Command to register using AuthMeReloaded. -
Requires `authme.player.register` +
Requires `authme.player.register` - **/register help** [query]: View detailed help for /register commands. - **/unreg** <password>: Command to unregister using AuthMeReloaded. -
Requires `authme.player.unregister` +
Requires `authme.player.unregister` - **/unreg help** [query]: View detailed help for /unreg commands. - **/changepassword** <oldPassword> <newPassword>: Command to change your password using AuthMeReloaded. -
Requires `authme.player.changepassword` +
Requires `authme.player.changepassword` - **/changepassword help** [query]: View detailed help for /changepassword commands. - **/email**: The AuthMeReloaded Email command base. - **/email add** <email> <verifyEmail>: Add a new email address to your account. -
Requires `authme.player.email.add` +
Requires `authme.player.email.add` - **/email change** <oldEmail> <newEmail>: Change an email address of your account. -
Requires `authme.player.email.change` +
Requires `authme.player.email.change` - **/email recover** <email>: Recover your account using an Email address by sending a mail containing a new password. -
Requires `authme.player.email.recover` +
Requires `authme.player.email.recover` - **/email help** [query]: View detailed help for /email commands. - **/captcha** <captcha>: Captcha command for AuthMeReloaded. -
Requires `authme.player.captcha` +
Requires `authme.player.captcha` - **/captcha help** [query]: View detailed help for /captcha commands. -- **/converter** <job>: Converter command for AuthMeReloaded. -
Requires `authme.admin.converter` -- **/converter help** [query]: View detailed help for /converter commands. - --- -This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Sun Feb 14 19:00:30 CET 2016 +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 diff --git a/docs/hash_algorithms.md b/docs/hash_algorithms.md index a8ba9c6f..6bc2a24f 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. @@ -17,7 +17,7 @@ JOOMLA | Recommended | 65 | | | Text | 32 | MD5 | Do not use | 32 | | | None | | MD5VB | Acceptable | 56 | | | Text | 16 | MYBB | Acceptable | 32 | | | Text | 8 | Y -PBKDF2 | Does not work | 330 | | | Text | 12 | +PBKDF2 | Does not work | 328 | | | Text | 12 | PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 | PHPBB | Acceptable | 34 | | | Text | 16 | PHPFUSION | Do not use | 64 | Y | | | | Y @@ -82,4 +82,4 @@ or bad. --- -This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Sun Feb 14 19:00:32 CET 2016 +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 diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md index 457f1102..0591b97a 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. @@ -42,7 +42,6 @@ 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 Sun Feb 14 19:00:34 CET 2016 +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 diff --git a/src/tools/commands/CommandPageCreater.java b/src/tools/commands/CommandPageCreater.java index 56d41722..8d92dbfb 100644 --- a/src/tools/commands/CommandPageCreater.java +++ b/src/tools/commands/CommandPageCreater.java @@ -1,6 +1,5 @@ package commands; -import com.google.common.collect.ImmutableMap; import fr.xephi.authme.command.CommandArgumentDescription; import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandInitializer; @@ -8,12 +7,12 @@ import fr.xephi.authme.command.CommandPermissions; import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.permission.PermissionNode; import utils.FileUtils; -import utils.TagReplacer; +import utils.TagValue.NestedTagValue; +import utils.TagValueHolder; import utils.ToolTask; import utils.ToolsConstants; import java.util.Collection; -import java.util.Map; import java.util.Scanner; import java.util.Set; @@ -29,31 +28,27 @@ public class CommandPageCreater implements ToolTask { @Override public void execute(Scanner scanner) { final Set baseCommands = CommandInitializer.buildCommands(); - final String template = FileUtils.readFromFile(ToolsConstants.TOOLS_SOURCE_ROOT - + "commands/command_entry.tpl.md"); - - StringBuilder commandsResult = new StringBuilder(); - addCommandsInfo(commandsResult, baseCommands, template); + NestedTagValue commandTags = new NestedTagValue(); + addCommandsInfo(commandTags, baseCommands); FileUtils.generateFileFromTemplate( ToolsConstants.TOOLS_SOURCE_ROOT + "commands/commands.tpl.md", OUTPUT_FILE, - ImmutableMap.of("commands", commandsResult.toString())); + TagValueHolder.create().put("commands", commandTags)); System.out.println("Wrote to '" + OUTPUT_FILE + "' with " + baseCommands.size() + " base commands."); } - private static void addCommandsInfo(StringBuilder sb, Collection commands, - final String template) { + private static void addCommandsInfo(NestedTagValue commandTags, Collection commands) { for (CommandDescription command : commands) { - Map tags = ImmutableMap.of( - "command", CommandUtils.constructCommandPath(command), - "description", command.getDetailedDescription(), - "arguments", formatArguments(command.getArguments()), - "permissions", formatPermissions(command.getCommandPermissions())); - sb.append(TagReplacer.applyReplacements(template, tags)); + TagValueHolder tags = TagValueHolder.create() + .put("command", CommandUtils.constructCommandPath(command)) + .put("description", command.getDetailedDescription()) + .put("arguments", formatArguments(command.getArguments())) + .put("permissions", formatPermissions(command.getCommandPermissions())); + commandTags.add(tags); if (!command.getChildren().isEmpty()) { - addCommandsInfo(sb, command.getChildren(), template); + addCommandsInfo(commandTags, command.getChildren()); } } } diff --git a/src/tools/commands/command_entry.tpl.md b/src/tools/commands/command_entry.tpl.md deleted file mode 100644 index c2978484..00000000 --- a/src/tools/commands/command_entry.tpl.md +++ /dev/null @@ -1,2 +0,0 @@ -- **{command}**{arguments}: {description}[permissions] -
Requires `{permissions}`[/permissions] diff --git a/src/tools/commands/commands.tpl.md b/src/tools/commands/commands.tpl.md index 0815e6ce..c0f4da12 100644 --- a/src/tools/commands/commands.tpl.md +++ b/src/tools/commands/commands.tpl.md @@ -5,6 +5,9 @@ You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >` brackets; optional arguments are enclosed in square brackets (`[ ]`). -{commands} +[#commands] + - **{command}**{arguments}: {description}[permissions] +
Requires `{permissions}`[/permissions] +[/#commands] {gen_footer} diff --git a/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java b/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java index 129242b3..8c8cecbe 100644 --- a/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java +++ b/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java @@ -1,11 +1,11 @@ package hashmethods; -import com.google.common.collect.ImmutableMap; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.WrapperMock; import utils.FileUtils; -import utils.TagReplacer; +import utils.TagValue.NestedTagValue; +import utils.TagValueHolder; import utils.ToolTask; import utils.ToolsConstants; @@ -33,30 +33,28 @@ public class HashAlgorithmsDescriptionTask implements ToolTask { // Gather info and construct a row for each method EncryptionMethodInfoGatherer infoGatherer = new EncryptionMethodInfoGatherer(); Map descriptions = infoGatherer.getDescriptions(); - final String methodRows = constructMethodRows(descriptions); + final NestedTagValue methodRows = constructMethodRows(descriptions); // Write to the docs file - Map tags = ImmutableMap.of("method_rows", methodRows); + TagValueHolder tags = TagValueHolder.create().put("algorithms", methodRows); FileUtils.generateFileFromTemplate(CUR_FOLDER + "hash_algorithms.tpl.md", OUTPUT_FILE, tags); } - private static String constructMethodRows(Map descriptions) { - final String rowTemplate = FileUtils.readFromFile(CUR_FOLDER + "hash_algorithms_row.tpl.md"); - StringBuilder result = new StringBuilder(); + private static NestedTagValue constructMethodRows(Map descriptions) { + NestedTagValue methodTags = new NestedTagValue(); for (Map.Entry entry : descriptions.entrySet()) { MethodDescription description = entry.getValue(); - Map tags = ImmutableMap.builder() + TagValueHolder tags = TagValueHolder.create() .put("name", asString(entry.getKey())) .put("recommendation", asString(description.getUsage())) .put("hash_length", asString(description.getHashLength())) .put("ascii_restricted", asString(description.isAsciiRestricted())) .put("salt_type", asString(description.getSaltType())) .put("salt_length", asString(description.getSaltLength())) - .put("separate_salt", asString(description.hasSeparateSalt())) - .build(); - result.append(TagReplacer.applyReplacements(rowTemplate, tags)); + .put("separate_salt", asString(description.hasSeparateSalt())); + methodTags.add(tags); } - return result.toString(); + return methodTags; } @Override diff --git a/src/tools/hashmethods/hash_algorithms.tpl.md b/src/tools/hashmethods/hash_algorithms.tpl.md index 883ae323..73e85ba0 100644 --- a/src/tools/hashmethods/hash_algorithms.tpl.md +++ b/src/tools/hashmethods/hash_algorithms.tpl.md @@ -7,7 +7,10 @@ AuthMe supports the following hash algorithms for storing your passwords safely. Algorithm | Recommendation | Hash length | ASCII | | Salt type | Length | Separate? --------- | -------------- | ----------- | ----- | --- | --------- | ------ | --------- -{method_rows}CUSTOM | | | | | | | | +[#algorithms] +{name} | {recommendation} | {hash_length} | {ascii_restricted} | | {salt_type} | {salt_length} | {separate_salt} +[/#algorithms] +CUSTOM | | | | | | | | diff --git a/src/tools/hashmethods/hash_algorithms_row.tpl.md b/src/tools/hashmethods/hash_algorithms_row.tpl.md deleted file mode 100644 index 411d1127..00000000 --- a/src/tools/hashmethods/hash_algorithms_row.tpl.md +++ /dev/null @@ -1 +0,0 @@ -{name} | {recommendation} | {hash_length} | {ascii_restricted} | | {salt_type} | {salt_length} | {separate_salt} diff --git a/src/tools/permissions/PermissionsListWriter.java b/src/tools/permissions/PermissionsListWriter.java index 7c599994..dc16cea2 100644 --- a/src/tools/permissions/PermissionsListWriter.java +++ b/src/tools/permissions/PermissionsListWriter.java @@ -1,8 +1,8 @@ package permissions; -import com.google.common.collect.ImmutableMap; import utils.FileUtils; -import utils.TagReplacer; +import utils.TagValue.NestedTagValue; +import utils.TagValueHolder; import utils.ToolTask; import utils.ToolsConstants; @@ -45,29 +45,25 @@ public class PermissionsListWriter implements ToolTask { } private static void generateAndWriteFile() { - final String permissionsTagValue = generatePermissionsList(); + final NestedTagValue permissionsTagValue = generatePermissionsList(); - Map tags = ImmutableMap.of("permissions", permissionsTagValue); + TagValueHolder tags = TagValueHolder.create().put("nodes", permissionsTagValue); FileUtils.generateFileFromTemplate( ToolsConstants.TOOLS_SOURCE_ROOT + "permissions/permission_nodes.tpl.md", PERMISSIONS_OUTPUT_FILE, tags); System.out.println("Wrote to '" + PERMISSIONS_OUTPUT_FILE + "'"); System.out.println("Before committing, please verify the output!"); } - private static String generatePermissionsList() { + private static NestedTagValue generatePermissionsList() { PermissionNodesGatherer gatherer = new PermissionNodesGatherer(); Map permissions = gatherer.gatherNodesWithJavaDoc(); - - final String template = FileUtils.readFromToolsFile("permissions/permission_node_entry.tpl.md"); - StringBuilder sb = new StringBuilder(); - + NestedTagValue permissionTags = new NestedTagValue(); for (Map.Entry entry : permissions.entrySet()) { - Map tags = ImmutableMap.of( - "node", entry.getKey(), - "description", entry.getValue()); - sb.append(TagReplacer.applyReplacements(template, tags)); + permissionTags.add(TagValueHolder.create() + .put("node", entry.getKey()) + .put("description", entry.getValue())); } - return sb.toString(); + return permissionTags; } private static void outputSimpleList() { diff --git a/src/tools/permissions/permission_node_entry.tpl.md b/src/tools/permissions/permission_node_entry.tpl.md deleted file mode 100644 index ab7f0687..00000000 --- a/src/tools/permissions/permission_node_entry.tpl.md +++ /dev/null @@ -1 +0,0 @@ -- **{node}** – {description} diff --git a/src/tools/permissions/permission_nodes.tpl.md b/src/tools/permissions/permission_nodes.tpl.md index 1f420809..8d2a2b4f 100644 --- a/src/tools/permissions/permission_nodes.tpl.md +++ b/src/tools/permissions/permission_nodes.tpl.md @@ -4,6 +4,8 @@ ## AuthMe Permission Nodes The following are the permission nodes that are currently supported by the latest dev builds. -{permissions} +[#nodes] + - **{node}** – {description} +[/#nodes] {gen_footer} diff --git a/src/tools/utils/FileUtils.java b/src/tools/utils/FileUtils.java index 02b9eddd..853965e9 100644 --- a/src/tools/utils/FileUtils.java +++ b/src/tools/utils/FileUtils.java @@ -6,7 +6,6 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.List; -import java.util.Map; /** * Utility class for reading from and writing to files. @@ -18,7 +17,7 @@ public final class FileUtils { private FileUtils() { } - public static void generateFileFromTemplate(String templateFile, String destinationFile, Map tags) { + public static void generateFileFromTemplate(String templateFile, String destinationFile, TagValueHolder tags) { String template = readFromFile(templateFile); String result = TagReplacer.applyReplacements(template, tags); writeToFile(destinationFile, result); @@ -56,8 +55,4 @@ public final class FileUtils { } } - public static String readFromToolsFile(String file) { - return readFromFile(ToolsConstants.TOOLS_SOURCE_ROOT + file); - } - } diff --git a/src/tools/utils/TagReplacer.java b/src/tools/utils/TagReplacer.java index 8e75ecd0..1197e0e7 100644 --- a/src/tools/utils/TagReplacer.java +++ b/src/tools/utils/TagReplacer.java @@ -1,6 +1,7 @@ package utils; -import fr.xephi.authme.util.StringUtils; +import utils.TagValue.NestedTagValue; +import utils.TagValue.TextTagValue; import java.util.Date; import java.util.Map; @@ -26,18 +27,25 @@ public class TagReplacer { * Replace a template with default tags and custom ones supplied by a map. * * @param template The template to process - * @param tags Map with additional tags, e.g. a map entry with key "foo" and value "bar" will replace + * @param tagValues Map with additional tags, e.g. a map entry with key "foo" and value "bar" will replace * any occurrences of "{foo}" to "bar". * @return The filled template */ - public static String applyReplacements(String template, Map tags) { + public static String applyReplacements(String template, TagValueHolder tagValues) { String result = template; - for (Map.Entry tagRule : tags.entrySet()) { + for (Map.Entry> tagRule : tagValues.getValues().entrySet()) { final String name = tagRule.getKey(); - final String value = tagRule.getValue(); - result = replaceOptionalTag(result, name, value) - .replace("{" + name + "}", value); + if (tagRule.getValue() instanceof TextTagValue) { + final TextTagValue value = (TextTagValue) tagRule.getValue(); + result = replaceOptionalTag(result, name, value) + .replace("{" + name + "}", value.getValue()); + } else if (tagRule.getValue() instanceof NestedTagValue) { + final NestedTagValue value = (NestedTagValue) tagRule.getValue(); + result = replaceIterateTag(replaceOptionalTag(result, name, value), name, value); + } else { + throw new IllegalStateException("Unknown tag value type"); + } } return applyReplacements(result); } @@ -58,14 +66,14 @@ public class TagReplacer { + " on " + curDate); } - private static String replaceOptionalTag(String text, String tagName, String tagValue) { + private static String replaceOptionalTag(String text, String tagName, TagValue tagValue) { Pattern regex = Pattern.compile("\\[" + tagName + "](.*?)\\[/" + tagName + "]", Pattern.DOTALL); Matcher matcher = regex.matcher(text); if (!matcher.find()) { // Couldn't find results, so just return text as it is return text; - } else if (StringUtils.isEmpty(tagValue)) { + } else if (tagValue.isEmpty()) { // Tag is empty, replace [tagName]some_text[/tagName] to nothing return matcher.replaceAll(""); } else { @@ -74,5 +82,30 @@ public class TagReplacer { } } + /** + * Replace iterating tags with the value. Tags of the type [#tag]...[/#tag] specify to iterate over the + * entries in {@link NestedTagValue} and to apply any replacements in there. + * + * @param text The file text + * @param tagName The tag name to handle + * @param tagValue The associated value + * @return The text with the applied replacement + */ + private static String replaceIterateTag(String text, String tagName, NestedTagValue tagValue) { + Pattern regex = Pattern.compile("\\[#" + tagName + "](.*?)\\[/#" + tagName + "]\\s?", Pattern.DOTALL); + Matcher matcher = regex.matcher(text); + + if (!matcher.find()) { + return text; + } else if (tagValue.isEmpty()) { + return matcher.replaceAll(""); + } + final String innerTemplate = matcher.group(1).trim() + "\n"; + String result = ""; + for (TagValueHolder entry : tagValue.getValue()) { + result += applyReplacements(innerTemplate, entry); + } + return matcher.replaceAll(result); + } } diff --git a/src/tools/utils/TagValue.java b/src/tools/utils/TagValue.java new file mode 100644 index 00000000..03b34097 --- /dev/null +++ b/src/tools/utils/TagValue.java @@ -0,0 +1,51 @@ +package utils; + +import java.util.ArrayList; +import java.util.List; + + +public abstract class TagValue { + + private final T value; + + public TagValue(T value) { + this.value = value; + } + + public T getValue() { + return value; + } + + public abstract boolean isEmpty(); + + public static final class TextTagValue extends TagValue { + public TextTagValue(String value) { + super(value); + } + + @Override + public boolean isEmpty() { + return getValue().isEmpty(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + } + + public static final class NestedTagValue extends TagValue> { + public NestedTagValue() { + super(new ArrayList()); + } + + @Override + public boolean isEmpty() { + return getValue().isEmpty(); + } + + public void add(TagValueHolder entry) { + getValue().add(entry); + } + } +} diff --git a/src/tools/utils/TagValueHolder.java b/src/tools/utils/TagValueHolder.java new file mode 100644 index 00000000..e2bd09b0 --- /dev/null +++ b/src/tools/utils/TagValueHolder.java @@ -0,0 +1,34 @@ +package utils; + +import utils.TagValue.TextTagValue; + +import java.util.HashMap; +import java.util.Map; + + +public class TagValueHolder { + + private Map> values; + + private TagValueHolder() { + this.values = new HashMap<>(); + } + + public static TagValueHolder create() { + return new TagValueHolder(); + } + + public TagValueHolder put(String key, TagValue value) { + values.put(key, value); + return this; + } + + public TagValueHolder put(String key, String value) { + values.put(key, new TextTagValue(value)); + return this; + } + + public Map> getValues() { + return values; + } +} From 83c02f487f9bd1b82cee3f8dabee65666bc3eb07 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 7 Apr 2016 17:48:33 +0200 Subject: [PATCH 24/71] Minor - improve previous commit --- src/tools/utils/TagReplacer.java | 3 +-- src/tools/utils/TagValue.java | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/tools/utils/TagReplacer.java b/src/tools/utils/TagReplacer.java index 1197e0e7..5efe4c8b 100644 --- a/src/tools/utils/TagReplacer.java +++ b/src/tools/utils/TagReplacer.java @@ -27,8 +27,7 @@ public class TagReplacer { * Replace a template with default tags and custom ones supplied by a map. * * @param template The template to process - * @param tagValues Map with additional tags, e.g. a map entry with key "foo" and value "bar" will replace - * any occurrences of "{foo}" to "bar". + * @param tagValues Container with tags and their associated values * @return The filled template */ public static String applyReplacements(String template, TagValueHolder tagValues) { diff --git a/src/tools/utils/TagValue.java b/src/tools/utils/TagValue.java index 03b34097..7ca66b3d 100644 --- a/src/tools/utils/TagValue.java +++ b/src/tools/utils/TagValue.java @@ -27,11 +27,6 @@ public abstract class TagValue { public boolean isEmpty() { return getValue().isEmpty(); } - - @Override - public int hashCode() { - return super.hashCode(); - } } public static final class NestedTagValue extends TagValue> { From ee3299afd28f9fff9fd458871d91ac5bc8d18f7b Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 7 Apr 2016 19:10:51 +0200 Subject: [PATCH 25/71] Fix startup error #643 --- .../xephi/authme/listener/AuthMeInventoryPacketAdapter.java | 3 ++- .../java/fr/xephi/authme/process/join/AsynchronousJoin.java | 3 ++- .../xephi/authme/process/login/ProcessSyncPlayerLogin.java | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java index 9ee17fb1..c6bb0967 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeInventoryPacketAdapter.java @@ -22,7 +22,6 @@ import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.reflect.MethodUtils; import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; @@ -38,6 +37,8 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.apache.commons.lang.reflect.MethodUtils; + public class AuthMeInventoryPacketAdapter extends PacketAdapter { private static final int PLAYER_INVENTORY = 0; 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 e1820545..75a66f64 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -24,6 +24,7 @@ import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.TimeoutTask; import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils.GroupType; + import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -32,7 +33,7 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitTask; -import com.comphenix.protocol.reflect.MethodUtils; +import org.apache.commons.lang.reflect.MethodUtils; /** */ 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 a920fa69..22938184 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -4,6 +4,7 @@ import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; + import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; @@ -11,10 +12,11 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.PluginManager; import org.bukkit.potion.PotionEffectType; -import com.comphenix.protocol.reflect.MethodUtils; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import org.apache.commons.lang.reflect.MethodUtils; + import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.backup.JsonCache; @@ -33,7 +35,6 @@ import fr.xephi.authme.util.Utils.GroupType; import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; import static fr.xephi.authme.settings.properties.PluginSettings.KEEP_COLLISIONS_DISABLED; - public class ProcessSyncPlayerLogin implements Runnable { private final LimboPlayer limbo; From d56b63c5f0b2ed1eff1534b1b2f1f72d50c1e616 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 7 Apr 2016 22:39:35 +0200 Subject: [PATCH 26/71] Fix #644 --- src/main/java/fr/xephi/authme/DataManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index b518ea99..0e1f20dc 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -63,6 +63,9 @@ public class DataManager { 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; @@ -122,6 +125,9 @@ public class DataManager { } final File userDataFolder = new File(essentialsDataFolder, "userdata"); + if (!userDataFolder.exists() || !userDataFolder.isDirectory()) { + return; + } List offlinePlayers = getOfflinePlayers(cleared); for (OfflinePlayer player : offlinePlayers) { File playerFile = new File(userDataFolder, Utils.getUUIDorName(player) + ".yml"); From 68ef28df08be35ab812b619a3b4d805e13c24b2e Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 7 Apr 2016 22:51:02 +0200 Subject: [PATCH 27/71] Fix minor issues --- .../java/fr/xephi/authme/process/join/AsynchronousJoin.java | 4 ++-- .../fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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 75a66f64..4257cf37 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -184,12 +184,12 @@ public class AsynchronousJoin implements Process { @Override public void run() { player.setOp(false); - if (Settings.isRemoveSpeedEnabled) { + if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { player.setFlySpeed(0.0f); player.setWalkSpeed(0.0f); } player.setNoDamageTicks(registrationTimeout); - if (service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) { + if (plugin.getPluginHooks().isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) { player.performCommand("motd"); } if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 22938184..96429870 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -99,7 +99,7 @@ public class ProcessSyncPlayerLogin implements Runnable { } private void restoreSpeedEffects() { - if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) { + if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) && settings.getProperty(RestrictionSettings.REMOVE_SPEED)) { player.setWalkSpeed(0.2F); player.setFlySpeed(0.1F); } From 4ec98e5b3d0f54e38879d591c20893a38b50c2b3 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 7 Apr 2016 22:57:20 +0200 Subject: [PATCH 28/71] Fix #646 Thanks to @hakumanatatu --- src/main/java/fr/xephi/authme/datasource/MySQL.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 326aef92..75655cd7 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -478,12 +478,12 @@ public class MySQL implements DataSource { pst2.addBatch(); // wp_capabilities pst2.setInt(1, id); - pst2.setString(2, "wp_capabilities"); + pst2.setString(2, wordpressPrefix + "capabilities"); pst2.setString(3, "a:1:{s:10:\"subscriber\";b:1;}"); pst2.addBatch(); // wp_user_level pst2.setInt(1, id); - pst2.setString(2, "wp_user_level"); + pst2.setString(2, wordpressPrefix + "user_level"); pst2.setString(3, "0"); pst2.addBatch(); // default_password_nag From ee177e8a3a8da5ccc05cd0590347af5286ed2690 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 8 Apr 2016 14:34:21 +0200 Subject: [PATCH 29/71] Remove the IPManager We don't need it anymore --- src/main/java/fr/xephi/authme/AuthMe.java | 24 ++-- .../xephi/authme/cache/IpAddressManager.java | 109 ------------------ .../xephi/authme/command/CommandService.java | 10 +- .../executable/authme/GetIpCommand.java | 2 +- .../xephi/authme/hooks/BungeeCordMessage.java | 11 +- .../xephi/authme/process/ProcessService.java | 14 +-- .../authme/process/join/AsynchronousJoin.java | 4 +- .../process/login/AsynchronousLogin.java | 2 +- .../authme/process/quit/AsynchronousQuit.java | 3 +- .../process/register/AsyncRegister.java | 4 +- .../register/ProcessSyncEmailRegister.java | 2 +- .../register/ProcessSyncPasswordRegister.java | 2 +- .../settings/properties/HooksSettings.java | 1 + src/main/java/fr/xephi/authme/util/Utils.java | 7 ++ .../authme/cache/IpAddressManagerTest.java | 29 ----- .../authme/command/CommandServiceTest.java | 14 +-- .../authme/process/ProcessServiceTest.java | 14 +-- 17 files changed, 33 insertions(+), 219 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/cache/IpAddressManager.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 01cccab1..2e7fae7b 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -2,7 +2,6 @@ package fr.xephi.authme; import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; -import fr.xephi.authme.cache.IpAddressManager; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.JsonCache; @@ -135,7 +134,6 @@ public class AuthMe extends JavaPlugin { private JsonCache playerBackup; private PasswordSecurity passwordSecurity; private DataSource database; - private IpAddressManager ipAddressManager; private PluginHooks pluginHooks; private SpawnLoader spawnLoader; private AntiBot antiBot; @@ -253,7 +251,6 @@ public class AuthMe extends JavaPlugin { MigrationService.changePlainTextToSha256(newSettings, database, new SHA256()); passwordSecurity = new PasswordSecurity(getDataSource(), newSettings, Bukkit.getPluginManager()); - ipAddressManager = new IpAddressManager(newSettings); // Initialize spawn loader spawnLoader = new SpawnLoader(getDataFolder(), newSettings, pluginHooks); @@ -262,7 +259,7 @@ public class AuthMe extends JavaPlugin { // Set up the permissions manager and command handler permsMan = initializePermissionsManager(); ValidationService validationService = new ValidationService(newSettings, database, permsMan); - commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, ipAddressManager, + commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, pluginHooks, spawnLoader, antiBot, validationService); // AntiBot delay @@ -300,12 +297,12 @@ public class AuthMe extends JavaPlugin { setupApi(); // Set up the management - ProcessService processService = new ProcessService(newSettings, messages, this, database, ipAddressManager, + ProcessService processService = new ProcessService(newSettings, messages, this, database, passwordSecurity, pluginHooks, spawnLoader, validationService); management = new Management(this, processService, database, PlayerCache.getInstance()); // Set up the BungeeCord hook - setupBungeeCordHook(newSettings, ipAddressManager); + setupBungeeCordHook(newSettings); // Reload support hook reloadSupportHook(); @@ -423,24 +420,23 @@ public class AuthMe extends JavaPlugin { /** * Set up the BungeeCord hook. */ - private void setupBungeeCordHook(NewSetting settings, IpAddressManager ipAddressManager) { + private void setupBungeeCordHook(NewSetting settings) { if (settings.getProperty(HooksSettings.BUNGEECORD)) { Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); Bukkit.getMessenger().registerIncomingPluginChannel( - this, "BungeeCord", new BungeeCordMessage(this, ipAddressManager)); + this, "BungeeCord", new BungeeCordMessage(this)); } } private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages, PasswordSecurity passwordSecurity, NewSetting settings, - IpAddressManager ipAddressManager, PluginHooks pluginHooks, - SpawnLoader spawnLoader, AntiBot antiBot, - ValidationService validationService) { + PluginHooks pluginHooks, SpawnLoader spawnLoader, + AntiBot antiBot, ValidationService validationService) { HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER)); Set baseCommands = CommandInitializer.buildCommands(); CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager); CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot, validationService); + permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService); return new CommandHandler(commandService); } @@ -775,7 +771,7 @@ public class AuthMe extends JavaPlugin { public String replaceAllInfo(String message, Player player) { String playersOnline = Integer.toString(Utils.getOnlinePlayers().size()); - String ipAddress = ipAddressManager.getPlayerIp(player); + String ipAddress = Utils.getPlayerIp(player); return message .replace("&", "\u00a7") .replace("{PLAYER}", player.getName()) @@ -792,7 +788,7 @@ public class AuthMe extends JavaPlugin { public boolean isLoggedIp(String name, String ip) { int count = 0; for (Player player : Utils.getOnlinePlayers()) { - if (ip.equalsIgnoreCase(ipAddressManager.getPlayerIp(player)) + if (ip.equalsIgnoreCase(Utils.getPlayerIp(player)) && database.isLogged(player.getName().toLowerCase()) && !player.getName().equalsIgnoreCase(name)) { ++count; diff --git a/src/main/java/fr/xephi/authme/cache/IpAddressManager.java b/src/main/java/fr/xephi/authme/cache/IpAddressManager.java deleted file mode 100644 index ff3398a5..00000000 --- a/src/main/java/fr/xephi/authme/cache/IpAddressManager.java +++ /dev/null @@ -1,109 +0,0 @@ -package fr.xephi.authme.cache; - -import com.google.common.base.Charsets; -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; -import com.google.common.io.Resources; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.util.StringUtils; -import org.bukkit.entity.Player; - -import java.io.IOException; -import java.net.URL; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Stateful manager for looking up IP address appropriately, including caching. - */ -public class IpAddressManager { - /** - * Whether or not to use the VeryGames API or BungeeCord for IP lookups. - */ - private final boolean useVeryGamesIpCheck; - private final boolean useBungee; - /** - * Cache for lookups. - */ - private final ConcurrentHashMap ipCache; - - /** - * Constructor. - * - * @param settings The settings instance - */ - public IpAddressManager(NewSetting settings) { - this.useVeryGamesIpCheck = settings.getProperty(HooksSettings.ENABLE_VERYGAMES_IP_CHECK); - this.useBungee = settings.getProperty(HooksSettings.BUNGEECORD); - this.ipCache = new ConcurrentHashMap<>(); - } - - /** - * Return the player's IP address. If enabled in the settings, the IP address returned by the - * VeryGames API will be returned. - * - * @param player The player to look up - * - * @return The IP address of the player - */ - public String getPlayerIp(Player player) { - final String playerName = player.getName().toLowerCase(); - final String cachedValue = ipCache.get(playerName); - if (cachedValue != null) { - return cachedValue; - } - - final String plainIp = player.getAddress().getAddress().getHostAddress(); - if (useBungee) { - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF("IP"); - player.sendPluginMessage(AuthMe.getInstance(), "BungeeCord", out.toByteArray()); - } - if (useVeryGamesIpCheck) { - String veryGamesResult = getVeryGamesIp(plainIp, player.getAddress().getPort()); - if (veryGamesResult != null) { - ipCache.put(playerName, veryGamesResult); - return veryGamesResult; - } - } - return plainIp; - } - - /** - * Add a player to the IP address cache. - * - * @param player The player to add or update the cache entry for - * @param ip The IP address to add - */ - public void addCache(String player, String ip) { - ipCache.put(player.toLowerCase(), ip); - } - - /** - * Remove a player's cache entry. - * - * @param player The player to remove - */ - public void removeCache(String player) { - ipCache.remove(player.toLowerCase()); - } - - // returns null if IP could not be looked up - private String getVeryGamesIp(final String plainIp, final int port) { - final String sUrl = String.format("http://monitor-1.verygames.net/api/?action=ipclean-real-ip" - + "&out=raw&ip=%s&port=%d", plainIp, port); - - try { - String result = Resources.toString(new URL(sUrl), Charsets.UTF_8); - if (!StringUtils.isEmpty(result) && !result.contains("error")) { - return result; - } - } catch (IOException e) { - ConsoleLogger.logException("Could not fetch Very Games API with URL '" + sUrl + "':", e); - } - return null; - } - -} diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 2fee46ad..8a6ae24c 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -5,7 +5,6 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.cache.IpAddressManager; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; @@ -33,7 +32,6 @@ public class CommandService { private final PasswordSecurity passwordSecurity; private final PermissionsManager permissionsManager; private final NewSetting settings; - private final IpAddressManager ipAddressManager; private final PluginHooks pluginHooks; private final SpawnLoader spawnLoader; private final AntiBot antiBot; @@ -44,8 +42,7 @@ public class CommandService { */ public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages, PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings, - IpAddressManager ipAddressManager, PluginHooks pluginHooks, SpawnLoader spawnLoader, - AntiBot antiBot, ValidationService validationService) { + PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, ValidationService validationService) { this.authMe = authMe; this.messages = messages; this.helpProvider = helpProvider; @@ -53,7 +50,6 @@ public class CommandService { this.passwordSecurity = passwordSecurity; this.permissionsManager = permissionsManager; this.settings = settings; - this.ipAddressManager = ipAddressManager; this.pluginHooks = pluginHooks; this.spawnLoader = spawnLoader; this.antiBot = antiBot; @@ -191,10 +187,6 @@ public class CommandService { return settings; } - public IpAddressManager getIpAddressManager() { - return ipAddressManager; - } - public PlayerCache getPlayerCache() { return PlayerCache.getInstance(); } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java index d3ba537d..1095b87c 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java @@ -27,7 +27,7 @@ public class GetIpCommand implements ExecutableCommand { if (commandService.getProperty(HooksSettings.ENABLE_VERYGAMES_IP_CHECK)) { sender.sendMessage(player.getName() + "'s real IP is: " - + commandService.getIpAddressManager().getPlayerIp(player)); + + Utils.getPlayerIp(player)); } } } diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 4b6534da..ed089b8a 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -7,7 +7,6 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.cache.IpAddressManager; import fr.xephi.authme.security.crypts.HashedPassword; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; @@ -17,17 +16,14 @@ import org.bukkit.plugin.messaging.PluginMessageListener; public class BungeeCordMessage implements PluginMessageListener { private final AuthMe plugin; - private final IpAddressManager ipAddressManager; /** * Constructor for BungeeCordMessage. * * @param plugin The plugin instance - * @param ipAddressManager The IP address manager */ - public BungeeCordMessage(AuthMe plugin, IpAddressManager ipAddressManager) { + public BungeeCordMessage(AuthMe plugin) { this.plugin = plugin; - this.ipAddressManager = ipAddressManager; } @Override @@ -37,11 +33,6 @@ public class BungeeCordMessage implements PluginMessageListener { } ByteArrayDataInput in = ByteStreams.newDataInput(message); String subChannel = in.readUTF(); - if ("IP".equals(subChannel)) { // We need only the IP channel - String ip = in.readUTF(); - // Put the IP (only the ip not the port) in the hashMap - ipAddressManager.addCache(player.getName(), ip); - } if ("AuthMe".equalsIgnoreCase(subChannel)) { String str = in.readUTF(); final String[] args = str.split(";"); diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java index fd08b7ba..7dcffe1c 100644 --- a/src/main/java/fr/xephi/authme/process/ProcessService.java +++ b/src/main/java/fr/xephi/authme/process/ProcessService.java @@ -1,7 +1,6 @@ package fr.xephi.authme.process; import fr.xephi.authme.AuthMe; -import fr.xephi.authme.cache.IpAddressManager; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.output.MessageKey; @@ -25,20 +24,18 @@ public class ProcessService { private final Messages messages; private final AuthMe authMe; private final DataSource dataSource; - private final IpAddressManager ipAddressManager; private final PasswordSecurity passwordSecurity; private final PluginHooks pluginHooks; private final SpawnLoader spawnLoader; private final ValidationService validationService; public ProcessService(NewSetting settings, Messages messages, AuthMe authMe, DataSource dataSource, - IpAddressManager ipAddressManager, PasswordSecurity passwordSecurity, PluginHooks pluginHooks, + PasswordSecurity passwordSecurity, PluginHooks pluginHooks, SpawnLoader spawnLoader, ValidationService validationService) { this.settings = settings; this.messages = messages; this.authMe = authMe; this.dataSource = dataSource; - this.ipAddressManager = ipAddressManager; this.passwordSecurity = passwordSecurity; this.pluginHooks = pluginHooks; this.spawnLoader = spawnLoader; @@ -155,15 +152,6 @@ public class ProcessService { return authMe; } - /** - * Return the IP address manager. - * - * @return the ip address manager - */ - public IpAddressManager getIpAddressManager() { - return ipAddressManager; - } - /** * Compute the hash for the given password. * 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 4257cf37..60081984 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -69,7 +69,7 @@ public class AsynchronousJoin implements Process { service.getPluginHooks().setEssentialsSocialSpyStatus(player, false); } - final String ip = service.getIpAddressManager().getPlayerIp(player); + final String ip = Utils.getPlayerIp(player); if (isNameRestricted(name, ip, player.getAddress().getHostName(), service.getSettings())) { service.scheduleSyncDelayedTask(new Runnable() { @Override @@ -305,7 +305,7 @@ public class AsynchronousJoin implements Process { private boolean hasJoinedIp(String name, String ip, NewSetting settings) { int count = 0; for (Player player : Utils.getOnlinePlayers()) { - if (ip.equalsIgnoreCase(service.getIpAddressManager().getPlayerIp(player)) + if (ip.equalsIgnoreCase(Utils.getPlayerIp(player)) && !player.getName().equalsIgnoreCase(name)) { count++; } 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 bb039bf1..507a67eb 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -52,7 +52,7 @@ public class AsynchronousLogin implements Process { this.forceLogin = forceLogin; this.plugin = plugin; this.database = data; - this.ip = service.getIpAddressManager().getPlayerIp(player); + this.ip = Utils.getPlayerIp(player); this.service = service; } 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 cb2a79a9..c4e1a7f5 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -43,7 +43,7 @@ public class AsynchronousQuit implements Process { return; } - String ip = service.getIpAddressManager().getPlayerIp(player); + String ip = Utils.getPlayerIp(player); if (PlayerCache.getInstance().isAuthenticated(name)) { if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { @@ -94,7 +94,6 @@ public class AsynchronousQuit implements Process { database.setUnlogged(name); } - service.getIpAddressManager().removeCache(player.getName()); if (plugin.isEnabled()) { service.scheduleSyncDelayedTask(new ProcessSyncronousPlayerQuit(plugin, player, isOp, needToChange)); } 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 dd41e9cd..5cacb105 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -17,6 +17,8 @@ import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.StringUtils; +import fr.xephi.authme.util.Utils; + import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -44,7 +46,7 @@ public class AsyncRegister implements Process { this.email = email; this.plugin = plugin; this.database = data; - this.ip = service.getIpAddressManager().getPlayerIp(player); + this.ip = Utils.getPlayerIp(player); this.playerCache = playerCache; this.service = service; } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java index a58fdded..f1d35039 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java @@ -58,7 +58,7 @@ public class ProcessSyncEmailRegister implements Process { player.saveData(); if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { - ConsoleLogger.info(player.getName() + " registered " + service.getIpAddressManager().getPlayerIp(player)); + ConsoleLogger.info(player.getName() + " registered " + Utils.getPlayerIp(player)); } } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index c3411d92..8e839dda 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -116,7 +116,7 @@ public class ProcessSyncPasswordRegister implements Process { player.saveData(); if (!Settings.noConsoleSpam) { - ConsoleLogger.info(player.getName() + " registered " + service.getIpAddressManager().getPlayerIp(player)); + ConsoleLogger.info(player.getName() + " registered " + Utils.getPlayerIp(player)); } // Kick Player after Registration is enabled, kick the player diff --git a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java index 95d91f85..55e743e4 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java @@ -35,6 +35,7 @@ public class HooksSettings implements SettingsClass { public static final Property CACHE_CUSTOM_ATTRIBUTES = newProperty("Hooks.customAttributes", false); + // TODO REMOVE ME @Comment("These features are only available on VeryGames Server Provider") public static final Property ENABLE_VERYGAMES_IP_CHECK = newProperty("VeryGames.enableIpCheck", false); diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index 1eb4deb8..f2a32987 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -265,4 +265,11 @@ public final class Utils { NOTLOGGEDIN, LOGGEDIN } + + /** + * Returns the IP of the given player. + */ + public static String getPlayerIp(Player p) { + return p.getAddress().getAddress().getHostAddress(); + } } diff --git a/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java b/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java index be172f3d..1ee6cab0 100644 --- a/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java +++ b/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java @@ -3,13 +3,9 @@ package fr.xephi.authme.cache; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.HooksSettings; import org.bukkit.entity.Player; -import org.junit.Test; - import java.net.InetAddress; import java.net.InetSocketAddress; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -35,29 +31,4 @@ public class IpAddressManagerTest { return player; } - @Test - public void shouldRetrieveFromCache() { - // given - IpAddressManager ipAddressManager = new IpAddressManager(mockSettings(true, true)); - ipAddressManager.addCache("Test", "my test IP"); - - // when - String result = ipAddressManager.getPlayerIp(mockPlayer("test", "123.123.123.123")); - - // then - assertThat(result, equalTo("my test IP")); - } - - @Test - public void shouldReturnPlainIp() { - // given - IpAddressManager ipAddressManager = new IpAddressManager(mockSettings(false, false)); - - // when - String result = ipAddressManager.getPlayerIp(mockPlayer("bobby", "8.8.8.8")); - - // then - assertThat(result, equalTo("8.8.8.8")); - } - } diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index 6c7ed5e5..4f641086 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -2,7 +2,6 @@ package fr.xephi.authme.command; import fr.xephi.authme.AntiBot; import fr.xephi.authme.AuthMe; -import fr.xephi.authme.cache.IpAddressManager; import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; @@ -57,8 +56,6 @@ public class CommandServiceTest { @Mock private NewSetting settings; @Mock - private IpAddressManager ipAddressManager; - @Mock private PluginHooks pluginHooks; @Mock private SpawnLoader spawnLoader; @@ -70,7 +67,7 @@ public class CommandServiceTest { @Before public void setUpService() { commandService = new CommandService(authMe, commandMapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot, validationService); + permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService); } @Test @@ -223,15 +220,6 @@ public class CommandServiceTest { assertThat(result, equalTo(authMe)); } - @Test - public void shouldReturnIpAddressManager() { - // given/when - IpAddressManager ipManager = commandService.getIpAddressManager(); - - // then - assertThat(ipManager, equalTo(ipAddressManager)); - } - @Test public void shouldValidatePassword() { // given diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java index 8e4acddf..6117e7f9 100644 --- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java +++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java @@ -1,7 +1,6 @@ package fr.xephi.authme.process; import fr.xephi.authme.AuthMe; -import fr.xephi.authme.cache.IpAddressManager; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.output.MessageKey; @@ -39,8 +38,6 @@ public class ProcessServiceTest { @Mock private Messages messages; @Mock - private IpAddressManager ipAddressManager; - @Mock private PasswordSecurity passwordSecurity; @Mock private AuthMe authMe; @@ -53,7 +50,7 @@ public class ProcessServiceTest { @Before public void setUpService() { - processService = new ProcessService(settings, messages, authMe, dataSource, ipAddressManager, passwordSecurity, + processService = new ProcessService(settings, messages, authMe, dataSource, passwordSecurity, pluginHooks, spawnLoader, validationService); } @@ -154,15 +151,6 @@ public class ProcessServiceTest { assertThat(result, equalTo(pluginHooks)); } - @Test - public void shouldReturnIpAddressManager() { - // given / when - IpAddressManager result = processService.getIpAddressManager(); - - // then - assertThat(result, equalTo(ipAddressManager)); - } - @Test public void shouldReturnSpawnLoader() { // given / when From 30d109b01bd14bd0991ed288c9a92ac5ae347e01 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 8 Apr 2016 14:35:42 +0200 Subject: [PATCH 30/71] Remove IPManager test --- .../authme/cache/IpAddressManagerTest.java | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java diff --git a/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java b/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java deleted file mode 100644 index 1ee6cab0..00000000 --- a/src/test/java/fr/xephi/authme/cache/IpAddressManagerTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.xephi.authme.cache; - -import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.properties.HooksSettings; -import org.bukkit.entity.Player; -import java.net.InetAddress; -import java.net.InetSocketAddress; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * Test for {@link IpAddressManager}. - */ -public class IpAddressManagerTest { - - private static NewSetting mockSettings(boolean useVeryGames, boolean useBungee) { - NewSetting settings = mock(NewSetting.class); - given(settings.getProperty(HooksSettings.ENABLE_VERYGAMES_IP_CHECK)).willReturn(useVeryGames); - given(settings.getProperty(HooksSettings.BUNGEECORD)).willReturn(useBungee); - return settings; - } - - private static Player mockPlayer(String name, String ip) { - Player player = mock(Player.class); - given(player.getName()).willReturn(name); - InetAddress inetAddress = mock(InetAddress.class); - given(inetAddress.getHostAddress()).willReturn(ip); - InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, 8093); - given(player.getAddress()).willReturn(inetSocketAddress); - return player; - } - -} From 0cda9a7698530d5bcb96a02b756805d281af4b75 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 8 Apr 2016 14:44:18 +0200 Subject: [PATCH 31/71] cleanup --- src/main/java/fr/xephi/authme/AuthMe.java | 1 - .../xephi/authme/command/executable/authme/GetIpCommand.java | 4 ---- src/main/java/fr/xephi/authme/settings/Settings.java | 3 +-- .../fr/xephi/authme/settings/SettingsMigrationService.java | 2 +- .../fr/xephi/authme/settings/properties/HooksSettings.java | 5 ----- src/main/resources/config.yml | 3 --- 6 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 2e7fae7b..c6ce5023 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -316,7 +316,6 @@ public class AuthMe extends JavaPlugin { showSettingsWarnings(); // Sponsor messages - ConsoleLogger.info("AuthMe hooks perfectly with the VeryGames server hosting!"); ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt."); ConsoleLogger.info("Do you want a good game server? Look at our sponsor GameHosting.it leader in Italy as Game Server Provider!"); diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java index 1095b87c..f4f1ee30 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java @@ -25,9 +25,5 @@ public class GetIpCommand implements ExecutableCommand { sender.sendMessage(player.getName() + "'s IP is: " + player.getAddress().getAddress().getHostAddress() + ":" + player.getAddress().getPort()); - if (commandService.getProperty(HooksSettings.ENABLE_VERYGAMES_IP_CHECK)) { - sender.sendMessage(player.getName() + "'s real IP is: " - + Utils.getPlayerIp(player)); - } } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 915c953a..2f470c72 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -52,7 +52,7 @@ public final class Settings { banUnsafeIp, sessionExpireOnIpChange, useEssentialsMotd, enableProtection, recallEmail, useWelcomeMessage, broadcastWelcomeMessage, forceRegKick, forceRegLogin, - checkVeryGames, removeJoinMessage, removeLeaveMessage, delayJoinMessage, + removeJoinMessage, removeLeaveMessage, delayJoinMessage, noTeleport, hideTablistBeforeLogin, denyTabcompleteBeforeLogin, kickPlayersBeforeStopping, allowAllCommandsIfRegIsOptional, customAttributes, isRemoveSpeedEnabled, preventOtherCase, keepCollisionsDisabled; @@ -167,7 +167,6 @@ public final class Settings { spawnPriority = load(RestrictionSettings.SPAWN_PRIORITY); getMaxLoginPerIp = load(RestrictionSettings.MAX_LOGIN_PER_IP); getMaxJoinPerIp = load(RestrictionSettings.MAX_JOIN_PER_IP); - checkVeryGames = load(HooksSettings.ENABLE_VERYGAMES_IP_CHECK); removeJoinMessage = load(RegistrationSettings.REMOVE_JOIN_MESSAGE); removeLeaveMessage = load(RegistrationSettings.REMOVE_LEAVE_MESSAGE); delayJoinMessage = load(RegistrationSettings.DELAY_JOIN_MESSAGE); diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java index a3d70dd1..0982713c 100644 --- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java +++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java @@ -59,7 +59,7 @@ public class SettingsMigrationService { private static boolean hasDeprecatedProperties(FileConfiguration configuration) { String[] deprecatedProperties = { "Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications", - "Passpartu", "Performances", "settings.restrictions.enablePasswordVerifier", "Xenoforo.predefinedSalt"}; + "Passpartu", "Performances", "settings.restrictions.enablePasswordVerifier", "Xenoforo.predefinedSalt", "VeryGames"}; for (String deprecatedPath : deprecatedProperties) { if (configuration.contains(deprecatedPath)) { return true; diff --git a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java index 55e743e4..087bb30d 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java @@ -35,11 +35,6 @@ public class HooksSettings implements SettingsClass { public static final Property CACHE_CUSTOM_ATTRIBUTES = newProperty("Hooks.customAttributes", false); - // TODO REMOVE ME - @Comment("These features are only available on VeryGames Server Provider") - public static final Property ENABLE_VERYGAMES_IP_CHECK = - newProperty("VeryGames.enableIpCheck", false); - @Comment({ "-1 means disabled. If you want that only activated players", "can log into your server, you can set here the group number", diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5aa33aa7..fd6a9cb0 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -421,6 +421,3 @@ Protection: antiBotSensibility: 5 # Duration in minutes of the antibot automatic system antiBotDuration: 10 -VeryGames: - # These features are only available on VeryGames Server Provider - enableIpCheck: false From e2b50b72a5420b962d0bca72223751b59c7c05a5 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 8 Apr 2016 19:56:44 +0200 Subject: [PATCH 32/71] Get player via BukkitService; add unit tests for commands --- src/main/java/fr/xephi/authme/AuthMe.java | 20 +- .../java/fr/xephi/authme/DataManager.java | 11 +- .../xephi/authme/command/CommandService.java | 11 +- .../executable/authme/ForceLoginCommand.java | 13 +- .../executable/authme/GetIpCommand.java | 7 +- .../authme/RegisterAdminCommand.java | 13 +- .../authme/UnregisterAdminCommand.java | 2 +- .../authme/listener/AuthMePlayerListener.java | 13 +- .../fr/xephi/authme/util/BukkitService.java | 52 +++++ src/main/java/fr/xephi/authme/util/Utils.java | 4 - .../authme/command/CommandServiceTest.java | 20 +- .../authme/ForceLoginCommandTest.java | 146 ++++++++++++++ .../executable/authme/GetIpCommandTest.java | 75 ++++++++ .../authme/RegisterAdminCommandTest.java | 182 ++++++++++++++++++ 14 files changed, 525 insertions(+), 44 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/command/executable/authme/ForceLoginCommandTest.java create mode 100644 src/test/java/fr/xephi/authme/command/executable/authme/GetIpCommandTest.java create mode 100644 src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index c6ce5023..38d06a0b 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -138,6 +138,7 @@ public class AuthMe extends JavaPlugin { private SpawnLoader spawnLoader; private AntiBot antiBot; private boolean autoPurging; + private BukkitService bukkitService; /** * Get the plugin's instance. @@ -257,13 +258,13 @@ public class AuthMe extends JavaPlugin { // Set up the permissions manager and command handler + bukkitService = new BukkitService(this); permsMan = initializePermissionsManager(); ValidationService validationService = new ValidationService(newSettings, database, permsMan); commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, - pluginHooks, spawnLoader, antiBot, validationService); + pluginHooks, spawnLoader, antiBot, validationService, bukkitService); // AntiBot delay - BukkitService bukkitService = new BukkitService(this); antiBot = new AntiBot(newSettings, messages, permsMan, bukkitService); // Set up Metrics @@ -291,7 +292,7 @@ public class AuthMe extends JavaPlugin { playerBackup = new JsonCache(); // Set the DataManager - dataManager = new DataManager(this, pluginHooks); + dataManager = new DataManager(this, pluginHooks, bukkitService); // Set up the new API setupApi(); @@ -378,7 +379,8 @@ public class AuthMe extends JavaPlugin { PluginManager pluginManager = server.getPluginManager(); // Register event listeners - pluginManager.registerEvents(new AuthMePlayerListener(this, messages, dataSource, antiBot, management), this); + pluginManager.registerEvents(new AuthMePlayerListener( + this, messages, dataSource, antiBot, management, bukkitService), this); pluginManager.registerEvents(new AuthMeBlockListener(), this); pluginManager.registerEvents(new AuthMeEntityListener(), this); pluginManager.registerEvents(new AuthMeServerListener(this, messages, pluginHooks, spawnLoader), this); @@ -429,13 +431,13 @@ public class AuthMe extends JavaPlugin { private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages, PasswordSecurity passwordSecurity, NewSetting settings, - PluginHooks pluginHooks, SpawnLoader spawnLoader, - AntiBot antiBot, ValidationService validationService) { + PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, + ValidationService validationService, BukkitService bukkitService) { HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER)); Set baseCommands = CommandInitializer.buildCommands(); CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager); CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService); + permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService); return new CommandHandler(commandService); } @@ -757,8 +759,8 @@ public class AuthMe extends JavaPlugin { public void run() { for (PlayerAuth auth : database.getLoggedPlayers()) { String email = auth.getEmail(); - if (StringUtils.isEmpty(email) || email.equalsIgnoreCase("your@email.com")) { - Player player = Utils.getPlayer(auth.getRealName()); + if (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email)) { + Player player = bukkitService.getPlayerExact(auth.getRealName()); if (player != null) { messages.send(player, MessageKey.ADD_EMAIL_MESSAGE); } diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 0e1f20dc..a3470ba3 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -3,6 +3,7 @@ package fr.xephi.authme; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.settings.properties.PurgeSettings; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; @@ -17,6 +18,7 @@ public class DataManager { private final AuthMe plugin; private final PluginHooks pluginHooks; + private final BukkitService bukkitService; /** * Constructor for DataManager. @@ -24,9 +26,10 @@ public class DataManager { * @param plugin The plugin instance * @param pluginHooks Plugin hooks instance */ - public DataManager(AuthMe plugin, PluginHooks pluginHooks) { + public DataManager(AuthMe plugin, PluginHooks pluginHooks, BukkitService bukkitService) { this.plugin = plugin; this.pluginHooks = pluginHooks; + this.bukkitService = bukkitService; } private List getOfflinePlayers(List names) { @@ -148,11 +151,9 @@ public class DataManager { ConsoleLogger.showError("Unable to access permissions manager instance!"); return; } - int i = 0; for (String name : cleared) { - permsMan.removeAllGroups(Utils.getPlayer(name)); - i++; + permsMan.removeAllGroups(bukkitService.getPlayerExact(name)); } - ConsoleLogger.info("AutoPurge: Removed permissions from " + i + " player(s)."); + ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); } } diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 8a6ae24c..916ce62f 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -14,8 +14,10 @@ import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.util.List; @@ -36,13 +38,15 @@ public class CommandService { private final SpawnLoader spawnLoader; private final AntiBot antiBot; private final ValidationService validationService; + private final BukkitService bukkitService; /* * Constructor. */ public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages, PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, ValidationService validationService) { + PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, + ValidationService validationService, BukkitService bukkitService) { this.authMe = authMe; this.messages = messages; this.helpProvider = helpProvider; @@ -54,6 +58,7 @@ public class CommandService { this.spawnLoader = spawnLoader; this.antiBot = antiBot; this.validationService = validationService; + this.bukkitService = bukkitService; } /** @@ -222,4 +227,8 @@ public class CommandService { return validationService.isEmailFreeForRegistration(email, sender); } + public Player getPlayer(String name) { + return bukkitService.getPlayerExact(name); + } + } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ForceLoginCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ForceLoginCommand.java index 7bfc0990..c974e7ea 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ForceLoginCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ForceLoginCommand.java @@ -2,13 +2,13 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.util.Utils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.List; +import static fr.xephi.authme.permission.PlayerPermission.CAN_LOGIN_BE_FORCED; + /** * Forces the login of a player, i.e. logs the player in without the need of a (correct) password. */ @@ -19,15 +19,14 @@ public class ForceLoginCommand implements ExecutableCommand { // Get the player query String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - Player player = Utils.getPlayer(playerName); + Player player = commandService.getPlayer(playerName); if (player == null || !player.isOnline()) { sender.sendMessage("Player needs to be online!"); - } else if (!commandService.getPermissionsManager() - .hasPermission(player, PlayerPermission.CAN_LOGIN_BE_FORCED)) { - sender.sendMessage("You cannot force login for the player " + playerName + "!"); + } else if (!commandService.getPermissionsManager().hasPermission(player, CAN_LOGIN_BE_FORCED)) { + sender.sendMessage("You cannot force login the player " + playerName + "!"); } else { commandService.getManagement().performLogin(player, "dontneed", true); - sender.sendMessage("Force Login for " + playerName + " performed!"); + sender.sendMessage("Force login for " + playerName + " performed!"); } } } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java index f4f1ee30..59379aa7 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java @@ -2,8 +2,6 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.util.Utils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -14,9 +12,9 @@ public class GetIpCommand implements ExecutableCommand { @Override public void executeCommand(CommandSender sender, List arguments, CommandService commandService) { // Get the player query - String playerName = (arguments.size() >= 1) ? arguments.get(0) : sender.getName(); + String playerName = arguments.get(0); - Player player = Utils.getPlayer(playerName); + Player player = commandService.getPlayer(playerName); if (player == null) { sender.sendMessage("The player is not online"); return; @@ -24,6 +22,5 @@ public class GetIpCommand implements ExecutableCommand { sender.sendMessage(player.getName() + "'s IP is: " + player.getAddress().getAddress().getHostAddress() + ":" + player.getAddress().getPort()); - } } 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 e0010a5b..2caf7a3c 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 @@ -6,8 +6,8 @@ import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.crypts.HashedPassword; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.util.List; @@ -52,11 +52,12 @@ public class RegisterAdminCommand implements ExecutableCommand { return; } commandService.getDataSource().setUnlogged(playerNameLowerCase); - if (Bukkit.getPlayerExact(playerName) != null) { - Bukkit.getPlayerExact(playerName).kickPlayer("An admin just registered you, please log again"); - } else { - commandService.send(sender, MessageKey.REGISTER_SUCCESS); - ConsoleLogger.info(playerName + " registered"); + + commandService.send(sender, MessageKey.REGISTER_SUCCESS); + ConsoleLogger.info(sender.getName() + " registered " + playerName); + Player player = commandService.getPlayer(playerName); + if (player != null) { + player.kickPlayer("An admin just registered you, please log in again"); } } }); diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java index 03cf400d..0c488f9b 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java @@ -49,7 +49,7 @@ public class UnregisterAdminCommand implements ExecutableCommand { } // Unregister the player - Player target = Utils.getPlayer(playerNameLowerCase); + Player target = commandService.getPlayer(playerNameLowerCase); PlayerCache.getInstance().removePlayer(playerNameLowerCase); Utils.setGroup(target, Utils.GroupType.UNREGISTERED); if (target != null && target.isOnline()) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 3c545b1b..4dee6f41 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -17,6 +17,7 @@ import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.Management; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; @@ -53,7 +54,7 @@ import java.util.concurrent.ConcurrentHashMap; import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent; /** - * Listener class for player's events + * Listener class for player events. */ public class AuthMePlayerListener implements Listener { @@ -64,14 +65,16 @@ public class AuthMePlayerListener implements Listener { private final DataSource dataSource; private final AntiBot antiBot; private final Management management; + private final BukkitService bukkitService; public AuthMePlayerListener(AuthMe plugin, Messages messages, DataSource dataSource, AntiBot antiBot, - Management management) { + Management management, BukkitService bukkitService) { this.plugin = plugin; this.m = messages; this.dataSource = dataSource; this.antiBot = antiBot; this.management = management; + this.bukkitService = bukkitService; } private void handleChat(AsyncPlayerChatEvent event) { @@ -94,7 +97,7 @@ public class AuthMePlayerListener implements Listener { } private void sendLoginOrRegisterMessage(final Player player) { - plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { + bukkitService.runTaskAsynchronously(new Runnable() { @Override public void run() { if (dataSource.isAuthAvailable(player.getName().toLowerCase())) { @@ -236,7 +239,7 @@ public class AuthMePlayerListener implements Listener { // Shedule login task so works after the prelogin // (Fix found by Koolaid5000) - Bukkit.getScheduler().runTask(plugin, new Runnable() { + bukkitService.runTask(new Runnable() { @Override public void run() { management.performJoin(player); @@ -277,7 +280,7 @@ public class AuthMePlayerListener implements Listener { } final String name = event.getName().toLowerCase(); - final Player player = Utils.getPlayer(name); + final Player player = bukkitService.getPlayerExact(name); // Check if forceSingleSession is set to true, so kick player that has // joined with same nick of online player if (player != null && Settings.isForceSingleSessionEnabled) { diff --git a/src/main/java/fr/xephi/authme/util/BukkitService.java b/src/main/java/fr/xephi/authme/util/BukkitService.java index 053fe789..fada6184 100644 --- a/src/main/java/fr/xephi/authme/util/BukkitService.java +++ b/src/main/java/fr/xephi/authme/util/BukkitService.java @@ -2,6 +2,11 @@ package fr.xephi.authme.util; import fr.xephi.authme.AuthMe; import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; + +import java.util.Set; /** * Service for operations requiring server entities, such as for scheduling. @@ -44,6 +49,33 @@ public class BukkitService { return Bukkit.getScheduler().scheduleSyncDelayedTask(authMe, task, delay); } + /** + * Returns a task that will run on the next server tick. + * + * @param task the task to be run + * @return a BukkitTask that contains the id number + * @throws IllegalArgumentException if plugin is null + * @throws IllegalArgumentException if task is null + */ + public BukkitTask runTask(Runnable task) { + return Bukkit.getScheduler().runTask(authMe, task); + } + + /** + * Asynchronous tasks should never access any API in Bukkit. Great care + * should be taken to assure the thread-safety of asynchronous tasks. + *

+ * Returns a task that will run asynchronously. + * + * @param task the task to be run + * @return a BukkitTask that contains the id number + * @throws IllegalArgumentException if plugin is null + * @throws IllegalArgumentException if task is null + */ + public BukkitTask runTaskAsynchronously(Runnable task) { + return Bukkit.getScheduler().runTaskAsynchronously(authMe, task); + } + /** * Broadcast a message to all players. * @@ -54,4 +86,24 @@ public class BukkitService { return Bukkit.broadcastMessage(message); } + /** + * Gets the player with the exact given name, case insensitive. + * + * @param name Exact name of the player to retrieve + * @return a player object if one was found, null otherwise + */ + public Player getPlayerExact(String name) { + return authMe.getServer().getPlayerExact(name); + } + + /** + * Gets a set containing all banned players. + * + * @return a set containing banned players + */ + public Set getBannedPlayers() { + Bukkit.getBannedPlayers(); + return authMe.getServer().getBannedPlayers(); + } + } diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index f2a32987..32913707 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -232,10 +232,6 @@ public final class Utils { } } - public static Player getPlayer(String name) { - return wrapper.getServer().getPlayerExact(name); // bukkit will lowercase the input - } - public static boolean isNPC(Player player) { return player.hasMetadata("NPC") || plugin.getPluginHooks().isNpcInCombatTagPlus(player); } diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index 4f641086..89a35571 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -14,6 +14,7 @@ import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.SecuritySettings; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -63,11 +64,13 @@ public class CommandServiceTest { private AntiBot antiBot; @Mock private ValidationService validationService; + @Mock + private BukkitService bukkitService; @Before public void setUpService() { commandService = new CommandService(authMe, commandMapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService); + permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService); } @Test @@ -265,4 +268,19 @@ public class CommandServiceTest { verify(validationService).isEmailFreeForRegistration(email, sender); } + @Test + public void shouldGetPlayer() { + // given + String playerName = "_tester"; + Player player = mock(Player.class); + given(bukkitService.getPlayerExact(playerName)).willReturn(player); + + // when + Player result = commandService.getPlayer(playerName); + + // then + assertThat(result, equalTo(player)); + verify(bukkitService).getPlayerExact(playerName); + } + } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ForceLoginCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ForceLoginCommandTest.java new file mode 100644 index 00000000..f6a01f2d --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ForceLoginCommandTest.java @@ -0,0 +1,146 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.permission.PlayerPermission; +import fr.xephi.authme.process.Management; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Collections; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyString; +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; + +/** + * Test for {@link ForceLoginCommand}. + */ +@RunWith(MockitoJUnitRunner.class) +public class ForceLoginCommandTest { + + @Mock + private CommandService commandService; + + @Test + public void shouldRejectOfflinePlayer() { + // given + String playerName = "Bobby"; + Player player = mockPlayer(false, playerName); + given(commandService.getPlayer(playerName)).willReturn(player); + CommandSender sender = mock(CommandSender.class); + ExecutableCommand command = new ForceLoginCommand(); + + // when + command.executeCommand(sender, Collections.singletonList(playerName), commandService); + + // then + verify(commandService).getPlayer(playerName); + verify(sender).sendMessage(argThat(equalTo("Player needs to be online!"))); + verify(commandService, never()).getManagement(); + } + + @Test + public void shouldRejectInexistentPlayer() { + // given + String playerName = "us3rname01"; + given(commandService.getPlayer(playerName)).willReturn(null); + CommandSender sender = mock(CommandSender.class); + ExecutableCommand command = new ForceLoginCommand(); + + // when + command.executeCommand(sender, Collections.singletonList(playerName), commandService); + + // then + verify(commandService).getPlayer(playerName); + verify(sender).sendMessage(argThat(equalTo("Player needs to be online!"))); + verify(commandService, never()).getManagement(); + } + + @Test + public void shouldRejectPlayerWithMissingPermission() { + // given + String playerName = "testTest"; + Player player = mockPlayer(true, playerName); + given(commandService.getPlayer(playerName)).willReturn(player); + PermissionsManager permissionsManager = mock(PermissionsManager.class); + given(permissionsManager.hasPermission(player, PlayerPermission.CAN_LOGIN_BE_FORCED)).willReturn(false); + given(commandService.getPermissionsManager()).willReturn(permissionsManager); + + CommandSender sender = mock(CommandSender.class); + ExecutableCommand command = new ForceLoginCommand(); + + // when + command.executeCommand(sender, Collections.singletonList(playerName), commandService); + + // then + verify(commandService).getPlayer(playerName); + verify(sender).sendMessage(argThat(containsString("You cannot force login the player"))); + verify(commandService, never()).getManagement(); + } + + @Test + public void shouldForceLoginPlayer() { + // given + String playerName = "tester23"; + Player player = mockPlayer(true, playerName); + given(commandService.getPlayer(playerName)).willReturn(player); + PermissionsManager permissionsManager = mock(PermissionsManager.class); + given(permissionsManager.hasPermission(player, PlayerPermission.CAN_LOGIN_BE_FORCED)).willReturn(true); + given(commandService.getPermissionsManager()).willReturn(permissionsManager); + Management management = mock(Management.class); + given(commandService.getManagement()).willReturn(management); + + CommandSender sender = mock(CommandSender.class); + ExecutableCommand command = new ForceLoginCommand(); + + // when + command.executeCommand(sender, Collections.singletonList(playerName), commandService); + + // then + verify(commandService).getPlayer(playerName); + verify(management).performLogin(eq(player), anyString(), eq(true)); + } + + @Test + public void shouldForceLoginSenderSelf() { + // given + String senderName = "tester23"; + Player player = mockPlayer(true, senderName); + given(commandService.getPlayer(senderName)).willReturn(player); + PermissionsManager permissionsManager = mock(PermissionsManager.class); + given(permissionsManager.hasPermission(player, PlayerPermission.CAN_LOGIN_BE_FORCED)).willReturn(true); + given(commandService.getPermissionsManager()).willReturn(permissionsManager); + Management management = mock(Management.class); + given(commandService.getManagement()).willReturn(management); + + CommandSender sender = mock(CommandSender.class); + given(sender.getName()).willReturn(senderName); + ExecutableCommand command = new ForceLoginCommand(); + + // when + command.executeCommand(sender, Collections.emptyList(), commandService); + + // then + verify(commandService).getPlayer(senderName); + verify(management).performLogin(eq(player), anyString(), eq(true)); + } + + private static Player mockPlayer(boolean isOnline, String name) { + Player player = mock(Player.class); + given(player.isOnline()).willReturn(isOnline); + given(player.getName()).willReturn(name); + return player; + } +} diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/GetIpCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/GetIpCommandTest.java new file mode 100644 index 00000000..7e070af6 --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/GetIpCommandTest.java @@ -0,0 +1,75 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.command.ExecutableCommand; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collections; + +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * Test for {@link GetIpCommand}. + */ +@RunWith(MockitoJUnitRunner.class) +public class GetIpCommandTest { + + @Mock + private CommandService commandService; + @Mock + private CommandSender sender; + + @Test + public void shouldGetIpOfPlayer() { + // given + given(commandService.getPlayer(anyString())).willReturn(null); + ExecutableCommand command = new GetIpCommand(); + + // when + command.executeCommand(sender, Collections.singletonList("Testt"), commandService); + + // then + verify(commandService).getPlayer("Testt"); + verify(sender).sendMessage(argThat(containsString("not online"))); + } + + @Test + public void shouldReturnIpAddressOfPlayer() { + // given + String playerName = "charlie"; + String ip = "123.34.56.88"; + Player player = mockPlayer(playerName, ip); + given(commandService.getPlayer(playerName)).willReturn(player); + ExecutableCommand command = new GetIpCommand(); + + // when + command.executeCommand(sender, Collections.singletonList(playerName), commandService); + + // then + verify(commandService).getPlayer(playerName); + verify(sender).sendMessage(argThat(allOf(containsString(playerName), containsString(ip)))); + } + + private static Player mockPlayer(String name, String ip) { + Player player = mock(Player.class); + given(player.getName()).willReturn(name); + InetAddress inetAddress = mock(InetAddress.class); + given(inetAddress.getHostAddress()).willReturn(ip); + InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, 8093); + given(player.getAddress()).willReturn(inetSocketAddress); + return player; + } +} 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 new file mode 100644 index 00000000..6ec54852 --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java @@ -0,0 +1,182 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.security.PasswordSecurity; +import fr.xephi.authme.security.crypts.HashedPassword; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +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; + +/** + * Test for {@link RegisterAdminCommand}. + */ +@RunWith(MockitoJUnitRunner.class) +public class RegisterAdminCommandTest { + + @Mock + private CommandSender sender; + @Mock + private CommandService commandService; + + @BeforeClass + public static void setUpLogger() { + ConsoleLoggerTestInitializer.setupLogger(); + } + + @Test + public void shouldRejectInvalidPassword() { + // given + String user = "tester"; + String password = "myPassword"; + given(commandService.validatePassword(password, user)).willReturn(MessageKey.INVALID_PASSWORD_LENGTH); + ExecutableCommand command = new RegisterAdminCommand(); + + // when + command.executeCommand(sender, Arrays.asList(user, password), commandService); + + // then + verify(commandService).validatePassword(password, user); + verify(commandService).send(sender, MessageKey.INVALID_PASSWORD_LENGTH); + verify(commandService, never()).runTaskAsynchronously(any(Runnable.class)); + } + + @Test + public void shouldRejectAlreadyRegisteredAccount() { + // given + String user = "my_name55"; + String password = "@some-pass@"; + given(commandService.validatePassword(password, user)).willReturn(null); + DataSource dataSource = mock(DataSource.class); + given(dataSource.isAuthAvailable(user)).willReturn(true); + given(commandService.getDataSource()).willReturn(dataSource); + ExecutableCommand command = new RegisterAdminCommand(); + + // when + command.executeCommand(sender, Arrays.asList(user, password), commandService); + TestHelper.runInnerRunnable(commandService); + + // then + verify(commandService).validatePassword(password, user); + verify(commandService).send(sender, MessageKey.NAME_ALREADY_REGISTERED); + verify(dataSource, never()).saveAuth(any(PlayerAuth.class)); + } + + @Test + public void shouldHandleSavingError() { + // given + String user = "test-test"; + String password = "afdjhfkt"; + given(commandService.validatePassword(password, user)).willReturn(null); + DataSource dataSource = mock(DataSource.class); + given(dataSource.isAuthAvailable(user)).willReturn(false); + given(dataSource.saveAuth(any(PlayerAuth.class))).willReturn(false); + given(commandService.getDataSource()).willReturn(dataSource); + PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); + HashedPassword hashedPassword = new HashedPassword("235sdf4w5udsgf"); + given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); + given(commandService.getPasswordSecurity()).willReturn(passwordSecurity); + ExecutableCommand command = new RegisterAdminCommand(); + + // when + command.executeCommand(sender, Arrays.asList(user, password), commandService); + TestHelper.runInnerRunnable(commandService); + + // then + verify(commandService).validatePassword(password, user); + verify(commandService).send(sender, MessageKey.ERROR); + ArgumentCaptor captor = ArgumentCaptor.forClass(PlayerAuth.class); + verify(dataSource).saveAuth(captor.capture()); + assertAuthHasInfo(captor.getValue(), user, hashedPassword); + } + + @Test + public void shouldRegisterOfflinePlayer() { + // given + String user = "someone"; + String password = "Al1O3P49S5%"; + given(commandService.validatePassword(password, user)).willReturn(null); + DataSource dataSource = mock(DataSource.class); + given(dataSource.isAuthAvailable(user)).willReturn(false); + given(dataSource.saveAuth(any(PlayerAuth.class))).willReturn(true); + given(commandService.getDataSource()).willReturn(dataSource); + PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); + HashedPassword hashedPassword = new HashedPassword("$aea2345EW235dfsa@#R%987048"); + given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); + given(commandService.getPasswordSecurity()).willReturn(passwordSecurity); + given(commandService.getPlayer(user)).willReturn(null); + ExecutableCommand command = new RegisterAdminCommand(); + + // when + command.executeCommand(sender, Arrays.asList(user, password), commandService); + TestHelper.runInnerRunnable(commandService); + + // then + verify(commandService).validatePassword(password, user); + verify(commandService).send(sender, MessageKey.REGISTER_SUCCESS); + ArgumentCaptor captor = ArgumentCaptor.forClass(PlayerAuth.class); + verify(dataSource).saveAuth(captor.capture()); + assertAuthHasInfo(captor.getValue(), user, hashedPassword); + verify(dataSource).setUnlogged(user); + } + + @Test + public void shouldRegisterOnlinePlayer() { + // given + String user = "someone"; + String password = "Al1O3P49S5%"; + given(commandService.validatePassword(password, user)).willReturn(null); + DataSource dataSource = mock(DataSource.class); + given(dataSource.isAuthAvailable(user)).willReturn(false); + given(dataSource.saveAuth(any(PlayerAuth.class))).willReturn(true); + given(commandService.getDataSource()).willReturn(dataSource); + PasswordSecurity passwordSecurity = mock(PasswordSecurity.class); + HashedPassword hashedPassword = new HashedPassword("$aea2345EW235dfsa@#R%987048"); + given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); + given(commandService.getPasswordSecurity()).willReturn(passwordSecurity); + Player player = mock(Player.class); + given(commandService.getPlayer(user)).willReturn(player); + ExecutableCommand command = new RegisterAdminCommand(); + + // when + command.executeCommand(sender, Arrays.asList(user, password), commandService); + TestHelper.runInnerRunnable(commandService); + + // then + verify(commandService).validatePassword(password, user); + verify(commandService).send(sender, MessageKey.REGISTER_SUCCESS); + ArgumentCaptor captor = ArgumentCaptor.forClass(PlayerAuth.class); + verify(dataSource).saveAuth(captor.capture()); + assertAuthHasInfo(captor.getValue(), user, hashedPassword); + verify(dataSource).setUnlogged(user); + verify(player).kickPlayer(argThat(containsString("please log in again"))); + } + + private void assertAuthHasInfo(PlayerAuth auth, String name, HashedPassword hashedPassword) { + assertThat(auth.getRealName(), equalTo(name)); + assertThat(auth.getNickname(), equalTo(name.toLowerCase())); + assertThat(auth.getPassword(), equalTo(hashedPassword)); + } +} From b7232d4508fb78ca005c6ebbecd4a7dc032f703d Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 9 Apr 2016 14:55:39 +0200 Subject: [PATCH 33/71] Delete module code - Remove code that has been unused for months. If modules come into discussion again it is better to start afresh once requirements are clearer --- .../java/fr/xephi/authme/modules/Module.java | 38 ---- .../xephi/authme/modules/ModuleManager.java | 184 ------------------ 2 files changed, 222 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/modules/Module.java delete mode 100644 src/main/java/fr/xephi/authme/modules/ModuleManager.java diff --git a/src/main/java/fr/xephi/authme/modules/Module.java b/src/main/java/fr/xephi/authme/modules/Module.java deleted file mode 100644 index f64349cf..00000000 --- a/src/main/java/fr/xephi/authme/modules/Module.java +++ /dev/null @@ -1,38 +0,0 @@ -package fr.xephi.authme.modules; - -/** - */ -public abstract class Module { - - /** - * Method getName. - * - * @return String - */ - public abstract String getName(); - - /** - * Method getType. - * - * @return ModuleType - */ - public abstract ModuleType getType(); - - public void load() { - } - - public void unload() { - } - - /** - */ - enum ModuleType { - MANAGER, - MYSQL, - REDIS, - ACTIONS, - CONVERTERS, - EMAILS, - CUSTOM - } -} diff --git a/src/main/java/fr/xephi/authme/modules/ModuleManager.java b/src/main/java/fr/xephi/authme/modules/ModuleManager.java deleted file mode 100644 index 6228091c..00000000 --- a/src/main/java/fr/xephi/authme/modules/ModuleManager.java +++ /dev/null @@ -1,184 +0,0 @@ -package fr.xephi.authme.modules; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.settings.Settings; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -/** - */ -public class ModuleManager { - - private final List modules = new ArrayList<>(); - - /** - * Constructor for ModuleManager. - * - * @param plugin AuthMe - */ - public ModuleManager(AuthMe plugin) { - } - - /** - * Method isModuleEnabled. - * - * @param name String - * - * @return boolean - */ - public boolean isModuleEnabled(String name) { - for (Module m : modules) { - if (m.getName().equalsIgnoreCase(name)) - return true; - } - return false; - } - - /** - * Method isModuleEnabled. - * - * @param type Module.ModuleType - * - * @return boolean - */ - public boolean isModuleEnabled(Module.ModuleType type) { - for (Module m : modules) { - if (m.getType() == type) - return true; - } - return false; - } - - /** - * Method getModule. - * - * @param name String - * - * @return Module - */ - public Module getModule(String name) { - for (Module m : modules) { - if (m.getName().equalsIgnoreCase(name)) - return m; - } - return null; - } - - /** - * Method getModule. - * - * @param type Module.ModuleType - * - * @return Module - */ - public Module getModule(Module.ModuleType type) { - for (Module m : modules) { - if (m.getType() == type) - return m; - } - return null; - } - - /** - * Method loadModules. - * - * @return int - */ - public int loadModules() { - File dir = Settings.MODULE_FOLDER; - int count = 0; - if (!dir.isDirectory()) { - dir.mkdirs(); - return count; - } - - File[] files = dir.listFiles(); - if (files == null) { - return count; - } - for (File pathToJar : files) { - JarFile jarFile = null; - URLClassLoader cl = null; - try { - jarFile = new JarFile(pathToJar); - URL[] urls = {new URL("jar:file:" + pathToJar.getAbsolutePath() + "!/")}; - cl = URLClassLoader.newInstance(urls); - - Enumeration e = jarFile.entries(); - while (e.hasMoreElements()) { - JarEntry je = (JarEntry) e.nextElement(); - if (je.isDirectory() || !je.getName().endsWith("Main.class")) { - continue; - } - String className = je.getName().substring(0, je.getName().length() - 6); - className = className.replace('/', '.'); - Class c = cl.loadClass(className); - if (!Module.class.isAssignableFrom(c)) { - continue; - } - - Module mod = (Module) c.newInstance(); - mod.load(); - modules.add(mod); - count++; - break; - } - - } catch (Exception ex) { - ConsoleLogger.logException("Cannot load " + pathToJar.getName() + " jar file!", ex); - } finally { - try { - if (jarFile != null) { - jarFile.close(); - } - if (cl != null) { - cl.close(); - } - } catch (IOException ignored) { - } - } - } - return count; - } - - public void reloadModules() { - unloadModules(); - loadModules(); - } - - /** - * Method unloadModule. - * - * @param name String - */ - public void unloadModule(String name) { - Iterator it = modules.iterator(); - while (it.hasNext()) { - Module m = it.next(); - if (m.getName().equalsIgnoreCase(name)) { - m.unload(); - it.remove(); - return; - } - } - } - - public void unloadModules() { - Iterator it = modules.iterator(); - while (it.hasNext()) { - it.next().unload(); - it.remove(); - } - } - -} From 590532e557fd6f5e8eaa3010477731347d19aa89 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 13 Apr 2016 18:47:02 +0200 Subject: [PATCH 34/71] the useless commit --- pom.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d1fd25e0..ec273c53 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ jar AuthMeReloaded - Authentication plugin for CraftBukkit/Spigot! + The first authentication plugin for the Bukkit API! 2013 http://dev.bukkit.org/bukkit-plugins/authme-reloaded/ @@ -23,7 +23,7 @@ scm:git:https://github.com/Xephi/AuthMeReloaded.git scm:git:git@github.com:Xephi/AuthMeReloaded.git - http://github.com/Xephi/AuthMeReloaded + https://github.com/Xephi/AuthMeReloaded @@ -40,6 +40,7 @@ The GNU General Public Licence version 3 (GPLv3) http://www.gnu.org/licenses/gpl-3.0.html + repo From 3c59bb1efba109d3af738163ff612c609e904c7d Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 13 Apr 2016 21:30:57 +0200 Subject: [PATCH 35/71] Simpler travis config --- .travis.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1645036e..81706d34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,13 +3,7 @@ sudo: false language: java jdk: oraclejdk7 -cache: - directories: - - '$HOME/.m2/repository' - -script: - - mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false - - mvn clean install -B -U +script: mvn verify -B notifications: webhooks: From 3bb7ff2b8549459f7f8ea68cef8f459d945d0f4d Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 14 Apr 2016 11:48:24 +0200 Subject: [PATCH 36/71] #653 Empty salt column causes error when retrieving password - Handle potentially empty salt column in MySQL and SQLite - Create unit tests reflecting these cases --- .../fr/xephi/authme/datasource/MySQL.java | 18 ++++----- .../fr/xephi/authme/datasource/SQLite.java | 22 +++++------ .../AbstractDataSourceIntegrationTest.java | 37 ++++++++++++++++++- .../datasource/MySqlIntegrationTest.java | 4 +- .../datasource/SQLiteIntegrationTest.java | 3 +- 5 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 75655cd7..236d22e1 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -274,20 +274,20 @@ public class MySQL implements DataSource { @Override public HashedPassword getPassword(String user) { - String sql = "SELECT " + col.PASSWORD + "," + col.SALT + " FROM " + tableName - + " WHERE " + col.NAME + "=?;"; - ResultSet rs = null; + boolean useSalt = !col.SALT.isEmpty(); + String sql = "SELECT " + col.PASSWORD + + (useSalt ? ", " + col.SALT : "") + + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { pst.setString(1, user.toLowerCase()); - rs = pst.executeQuery(); - if (rs.next()) { - return new HashedPassword(rs.getString(col.PASSWORD), - !col.SALT.isEmpty() ? rs.getString(col.SALT) : null); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + return new HashedPassword(rs.getString(col.PASSWORD), + useSalt ? rs.getString(col.SALT) : null); + } } } catch (SQLException ex) { logSqlException(ex); - } finally { - close(rs); } return null; } diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index a310b7b6..dfc74740 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -154,22 +154,20 @@ public class SQLite implements DataSource { @Override public HashedPassword getPassword(String user) { - PreparedStatement pst = null; - ResultSet rs = null; - try { - pst = con.prepareStatement("SELECT " + col.PASSWORD + "," + col.SALT - + " FROM " + tableName + " WHERE " + col.NAME + "=?"); + boolean useSalt = !col.SALT.isEmpty(); + String sql = "SELECT " + col.PASSWORD + + (useSalt ? ", " + col.SALT : "") + + " FROM " + tableName + " WHERE " + col.NAME + "=?"; + try (PreparedStatement pst = con.prepareStatement(sql)) { pst.setString(1, user); - rs = pst.executeQuery(); - if (rs.next()) { - return new HashedPassword(rs.getString(col.PASSWORD), - !col.SALT.isEmpty() ? rs.getString(col.SALT) : null); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + return new HashedPassword(rs.getString(col.PASSWORD), + useSalt ? rs.getString(col.SALT) : null); + } } } catch (SQLException ex) { logSqlException(ex); - } finally { - close(rs); - close(pst); } return null; } diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java index 0231a8d6..30f3484e 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java @@ -22,7 +22,11 @@ import static org.junit.Assume.assumeThat; */ public abstract class AbstractDataSourceIntegrationTest { - protected abstract DataSource getDataSource(); + protected DataSource getDataSource() { + return getDataSource("salt"); + } + + protected abstract DataSource getDataSource(String saltColumn); @Test public void shouldReturnIfAuthIsAvailableOrNot() { @@ -56,6 +60,22 @@ public abstract class AbstractDataSourceIntegrationTest { assertThat(userPassword, equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32")); } + @Test + public void shouldReturnPasswordWithEmptySaltColumn() { + // given + DataSource dataSource = getDataSource(""); + + // when + HashedPassword bobbyPassword = dataSource.getPassword("bobby"); + HashedPassword invalidPassword = dataSource.getPassword("doesNotExist"); + HashedPassword userPassword = dataSource.getPassword("user"); + + // then + assertThat(bobbyPassword, equalToHash("$SHA$11aa0706173d7272$dbba966")); + assertThat(invalidPassword, nullValue()); + assertThat(userPassword, equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b")); + } + @Test public void shouldGetAuth() { // given @@ -133,6 +153,21 @@ public abstract class AbstractDataSourceIntegrationTest { assertThat(dataSource.getPassword("user"), equalToHash(newHash)); } + @Test + public void shouldUpdatePasswordWithNoSalt() { + // given + DataSource dataSource = getDataSource(""); + HashedPassword newHash = new HashedPassword("new_hash", "1241"); + + // when + boolean response1 = dataSource.updatePassword("user", newHash); + boolean response2 = dataSource.updatePassword("non-existent-name", new HashedPassword("asdfasdf", "a1f34ec")); + + // then + assertThat(response1 && response2, equalTo(true)); + assertThat(dataSource.getPassword("user"), equalToHash("new_hash")); + } + @Test public void shouldRemovePlayerAuth() { // given diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java index 81e2e122..88c6601c 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -53,7 +53,6 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { }); set(DatabaseSettings.MYSQL_DATABASE, "h2_test"); set(DatabaseSettings.MYSQL_TABLE, "authme"); - set(DatabaseSettings.MYSQL_COL_SALT, "salt"); ConsoleLoggerTestInitializer.setupLogger(); Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-initialize.sql"); @@ -80,7 +79,8 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { } @Override - protected DataSource getDataSource() { + protected DataSource getDataSource(String saltColumn) { + when(settings.getProperty(DatabaseSettings.MYSQL_COL_SALT)).thenReturn(saltColumn); return new MySQL(settings, hikariSource); } diff --git a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java index 2ef4e15a..1ec9d990 100644 --- a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java @@ -75,7 +75,8 @@ public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest { } @Override - protected DataSource getDataSource() { + protected DataSource getDataSource(String saltColumn) { + when(settings.getProperty(DatabaseSettings.MYSQL_COL_SALT)).thenReturn(saltColumn); return new SQLite(settings, con); } From ca0cbe6caf49aa87483b92a3fc368b755608c062 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 14 Apr 2016 12:28:19 +0200 Subject: [PATCH 37/71] Code householding - Move console initialization for tests into TestHelper - Remove unused properties in legacy Settings - Add issue number to TODO comments where applicable --- src/main/java/fr/xephi/authme/AuthMe.java | 10 +-- .../xephi/authme/datasource/DataSource.java | 62 ++++++++++++------- .../authme/listener/AuthMeEntityListener.java | 2 +- .../fr/xephi/authme/settings/Settings.java | 5 +- .../authme/ConsoleLoggerTestInitializer.java | 20 ------ src/test/java/fr/xephi/authme/TestHelper.java | 21 +++---- .../ChangePasswordAdminCommandTest.java | 4 +- .../authme/RegisterAdminCommandTest.java | 3 +- .../executable/authme/ReloadCommandTest.java | 4 +- .../converter/ForceFlatToSqliteTest.java | 3 +- .../AbstractResourceClosingTest.java | 4 +- .../datasource/MySqlIntegrationTest.java | 3 +- .../datasource/SQLiteIntegrationTest.java | 4 +- .../xephi/authme/hooks/PluginHooksTest.java | 4 +- .../output/MessagesIntegrationTest.java | 3 +- .../process/email/AsyncAddEmailTest.java | 4 +- .../authme/security/crypts/BcryptTest.java | 4 +- .../crypts/CryptPBKDF2DjangoTest.java | 4 +- .../authme/security/crypts/IPB4Test.java | 4 +- .../authme/security/crypts/XFBCRYPTTest.java | 4 +- .../settings/NewSettingIntegrationTest.java | 3 +- .../xephi/authme/settings/NewSettingTest.java | 4 +- .../java/fr/xephi/authme/util/UtilsTest.java | 4 +- 23 files changed, 82 insertions(+), 101 deletions(-) delete mode 100644 src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 38d06a0b..d001cd4b 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -106,23 +106,25 @@ public class AuthMe extends JavaPlugin { private static Server server; /* * Maps and stuff - * TODO: Clean up and Move into a manager */ + // TODO #601: Integrate CaptchaManager public final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); public final ConcurrentHashMap captcha = new ConcurrentHashMap<>(); public final ConcurrentHashMap cap = new ConcurrentHashMap<>(); /* * Public Instances - * TODO #432: Encapsulation */ public NewAPI api; + // TODO #655: Encapsulate mail public SendMailSSL mail; + // TODO #656: Encapsulate data manager public DataManager dataManager; /* - * Plugin Hooks - * TODO: Move into modules + * Private instances + * TODO #432: Move instantiation and management of these services */ + // TODO #604: Encapsulate ProtocolLib members public AuthMeInventoryPacketAdapter inventoryProtector; public AuthMeTabCompletePacketAdapter tabComplete; public AuthMeTablistPacketAdapter tablistHider; diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index 9db25555..4c844a83 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -122,69 +122,85 @@ public interface DataSource { void close(); /** - * Method purgeBanned. + * Purge all given players, i.e. delete all players whose name is in the list. * - * @param banned List of String + * @param banned the list of players to delete */ void purgeBanned(List banned); /** - * Method getType. + * Return the data source type. * - * @return DataSourceType + * @return the data source type */ DataSourceType getType(); /** - * Method isLogged. + * Query the datasource whether the player is logged in or not. * - * @param user String - * - * @return boolean + * @param user The name of the player to verify + * @return True if logged in, false otherwise */ boolean isLogged(String user); /** - * Method setLogged. + * Set a player as logged in. * - * @param user String + * @param user The name of the player to change */ void setLogged(String user); /** - * Method setUnlogged. + * Set a player as unlogged (not logged in). * - * @param user String + * @param user The name of the player to change */ void setUnlogged(String user); + /** + * Set all players who are marked as logged in as NOT logged in. + */ void purgeLogged(); /** - * Method getAccountsRegistered. + * Return all players which are logged in. * - * @return int + * @return All logged in players + */ + List getLoggedPlayers(); + + /** + * Return the number of registered accounts. + * + * @return Total number of accounts */ int getAccountsRegistered(); + /** + * Update a player's real name (capitalization). + * + * @param user The name of the user (lowercase) + * @param realName The real name of the user (proper casing) + * @return True upon success, false upon failure + */ boolean updateRealName(String user, String realName); + /** + * Update a player's IP address. + * + * @param user The name of the user (lowercase) + * @param ip The IP address to save + * @return True upon success, false upon failure + */ boolean updateIp(String user, String ip); /** - * Method getAllAuths. + * Return all players of the database. * - * @return List of PlayerAuth + * @return List of all players */ List getAllAuths(); - /** - * Method getLoggedPlayers. - * - * @return List of PlayerAuth - */ - List getLoggedPlayers(); - /** * Reload the data source. */ diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 50b0e61c..897607ee 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -33,7 +33,7 @@ public class AuthMeEntityListener implements Listener { } } - // TODO #360: npc status can be used to bypass security!!! + // Note #360: npc status can be used to bypass security!!! @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onEntityDamage(EntityDamageEvent event) { if (shouldCancelEvent(event)) { diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 2f470c72..ca5ddc3b 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -24,7 +24,6 @@ import java.util.regex.Pattern; public final class Settings { public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder(); - public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules"); public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); public static List allowCommands; public static List getJoinPermissions; @@ -62,7 +61,7 @@ public final class Settings { spawnPriority, crazyloginFileName, sendPlayerTo; public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength, getMinNickLength, - getPasswordMinLen, getMovementRadius, getNonActivatedGroup, passwordMaxLength, + getMovementRadius, getNonActivatedGroup, maxLoginTry, captchaLength, saltLength, bCryptLog2Rounds, getMaxLoginPerIp, getMaxJoinPerIp; protected static FileConfiguration configFile; @@ -88,7 +87,6 @@ public final class Settings { isChatAllowed = load(RestrictionSettings.ALLOW_CHAT); getMaxNickLength = configFile.getInt("settings.restrictions.maxNicknameLength", 20); getMinNickLength = configFile.getInt("settings.restrictions.minNicknameLength", 3); - getPasswordMinLen = configFile.getInt("settings.security.minPasswordLength", 4); getNickRegex = configFile.getString("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_?]*"); nickPattern = Pattern.compile(getNickRegex); isAllowRestrictedIp = load(RestrictionSettings.ENABLE_RESTRICTED_USERS); @@ -120,7 +118,6 @@ public final class Settings { denyTabcompleteBeforeLogin = load(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN); hideTablistBeforeLogin = load(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN); - passwordMaxLength = load(SecuritySettings.MAX_PASSWORD_LENGTH); backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\"); isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true); reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); diff --git a/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java b/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java deleted file mode 100644 index cfa871e3..00000000 --- a/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.xephi.authme; - -import org.mockito.Mockito; - -import java.util.logging.Logger; - -/** - * Test initializer for {@link ConsoleLogger}. - */ -public class ConsoleLoggerTestInitializer { - - private ConsoleLoggerTestInitializer() { - } - - public static Logger setupLogger() { - Logger logger = Mockito.mock(Logger.class); - ConsoleLogger.setLogger(logger); - return logger; - } -} diff --git a/src/test/java/fr/xephi/authme/TestHelper.java b/src/test/java/fr/xephi/authme/TestHelper.java index 5f1db10d..fe55de5f 100644 --- a/src/test/java/fr/xephi/authme/TestHelper.java +++ b/src/test/java/fr/xephi/authme/TestHelper.java @@ -3,11 +3,13 @@ package fr.xephi.authme; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.util.BukkitService; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import java.io.File; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.logging.Logger; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.verify; @@ -68,20 +70,6 @@ public final class TestHelper { runnable.run(); } - /** - * Execute a {@link Runnable} passed to a mock's {@link BukkitService#scheduleSyncDelayedTask(Runnable)} method. - * Note that calling this method expects that there be a runnable sent to the method and will fail - * otherwise. - * - * @param service The mock service - */ - public static void runSyncDelayedTask(BukkitService service) { - ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); - verify(service).scheduleSyncDelayedTask(captor.capture()); - Runnable runnable = captor.getValue(); - runnable.run(); - } - /** * Execute a {@link Runnable} passed to a mock's {@link BukkitService#scheduleSyncDelayedTask(Runnable, long)} * method. Note that calling this method expects that there be a runnable sent to the method and will fail @@ -96,4 +84,9 @@ public final class TestHelper { runnable.run(); } + public static Logger setupLogger() { + Logger logger = Mockito.mock(Logger.class); + ConsoleLogger.setLogger(logger); + return logger; + } } diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java index 93c6c6ff..b4f42886 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommandTest.java @@ -1,6 +1,6 @@ package fr.xephi.authme.command.executable.authme; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.CommandService; @@ -36,7 +36,7 @@ public class ChangePasswordAdminCommandTest { @BeforeClass public static void setUpLogger() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Test 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 6ec54852..66b7d6c4 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java @@ -1,6 +1,5 @@ package fr.xephi.authme.command.executable.authme; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.TestHelper; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.command.CommandService; @@ -43,7 +42,7 @@ public class RegisterAdminCommandTest { @BeforeClass public static void setUpLogger() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Test diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java index a0ed7706..99600c89 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java @@ -1,7 +1,7 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; @@ -24,7 +24,7 @@ public class ReloadCommandTest { @BeforeClass public static void setUpLogger() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Test diff --git a/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java b/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java index 17d4fb06..6f6082ce 100644 --- a/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java +++ b/src/test/java/fr/xephi/authme/converter/ForceFlatToSqliteTest.java @@ -1,7 +1,6 @@ package fr.xephi.authme.converter; import com.google.common.io.Files; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.TestHelper; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.datasource.DataSource; @@ -37,7 +36,7 @@ public class ForceFlatToSqliteTest { @BeforeClass public static void setup() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Before diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java index 69bb0512..75908e3e 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java @@ -4,7 +4,7 @@ import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.crypts.HashedPassword; @@ -107,7 +107,7 @@ public abstract class AbstractResourceClosingTest { return ((Property) invocation.getArguments()[0]).getDefaultValue(); } }); - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } /** Initialize the dataSource implementation to test based on a mock connection. */ diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java index 88c6601c..ec90dab0 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -2,7 +2,6 @@ package fr.xephi.authme.datasource; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; @@ -53,7 +52,7 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { }); set(DatabaseSettings.MYSQL_DATABASE, "h2_test"); set(DatabaseSettings.MYSQL_TABLE, "authme"); - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/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 1ec9d990..3cfe9eb2 100644 --- a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java @@ -1,6 +1,5 @@ package fr.xephi.authme.datasource; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; @@ -52,8 +51,7 @@ public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest { }); set(DatabaseSettings.MYSQL_DATABASE, "sqlite-test"); set(DatabaseSettings.MYSQL_TABLE, "authme"); - set(DatabaseSettings.MYSQL_COL_SALT, "salt"); - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-initialize.sql"); // Note ljacqu 20160221: It appears that we can only run one statement per Statement.execute() so we split diff --git a/src/test/java/fr/xephi/authme/hooks/PluginHooksTest.java b/src/test/java/fr/xephi/authme/hooks/PluginHooksTest.java index be12afce..e8475d9c 100644 --- a/src/test/java/fr/xephi/authme/hooks/PluginHooksTest.java +++ b/src/test/java/fr/xephi/authme/hooks/PluginHooksTest.java @@ -2,8 +2,8 @@ package fr.xephi.authme.hooks; import com.earth2me.essentials.Essentials; import com.earth2me.essentials.User; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.TestHelper; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; @@ -29,7 +29,7 @@ public class PluginHooksTest { @BeforeClass public static void setLogger() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Test diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index 39955365..2037280b 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -1,7 +1,6 @@ package fr.xephi.authme.output; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.TestHelper; import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.CommandSender; @@ -36,7 +35,7 @@ public class MessagesIntegrationTest { @BeforeClass public static void setup() { WrapperMock.createInstance(); - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } /** diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java index 3d6ccee7..9f92a5c8 100644 --- a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java +++ b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java @@ -1,6 +1,6 @@ package fr.xephi.authme.process.email; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; @@ -37,7 +37,7 @@ public class AsyncAddEmailTest { @BeforeClass public static void setUp() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Test diff --git a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java index 6ee29114..2c27e00a 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java @@ -1,6 +1,6 @@ package fr.xephi.authme.security.crypts; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; @@ -14,7 +14,7 @@ public class BcryptTest extends AbstractEncryptionMethodTest { public static void setUpSettings() { WrapperMock.createInstance(); Settings.bCryptLog2Rounds = 8; - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } public BcryptTest() { diff --git a/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2DjangoTest.java b/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2DjangoTest.java index 7175d210..1da3c5b9 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2DjangoTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/CryptPBKDF2DjangoTest.java @@ -1,6 +1,6 @@ package fr.xephi.authme.security.crypts; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import org.junit.BeforeClass; /** @@ -10,7 +10,7 @@ public class CryptPBKDF2DjangoTest extends AbstractEncryptionMethodTest { @BeforeClass public static void setupLogger() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } public CryptPBKDF2DjangoTest() { diff --git a/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java b/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java index 58c6f570..1b7ac3f1 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java @@ -1,6 +1,6 @@ package fr.xephi.authme.security.crypts; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; @@ -12,7 +12,7 @@ public class IPB4Test extends AbstractEncryptionMethodTest { @BeforeClass public static void setUpSettings() { WrapperMock.createInstance(); - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } public IPB4Test() { diff --git a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java index ed49ccd7..96c30d1c 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java @@ -1,6 +1,6 @@ package fr.xephi.authme.security.crypts; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; @@ -12,7 +12,7 @@ public class XFBCRYPTTest extends AbstractEncryptionMethodTest { @BeforeClass public static void setup() { WrapperMock.createInstance(); - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } public XFBCRYPTTest() { diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java index 81ad2980..1ee5a50c 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java @@ -2,7 +2,6 @@ package fr.xephi.authme.settings; import com.google.common.collect.ImmutableMap; import com.google.common.io.Files; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.TestConfiguration; @@ -48,7 +47,7 @@ public class NewSettingIntegrationTest { @BeforeClass public static void setUpLogger() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Before diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java index fb050862..e53a66d2 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java @@ -1,6 +1,6 @@ package fr.xephi.authme.settings; -import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.TestConfiguration; @@ -48,7 +48,7 @@ public class NewSettingTest { @BeforeClass public static void setUpLogger() { - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Before diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java index a1e9a6a1..38b536f0 100644 --- a/src/test/java/fr/xephi/authme/util/UtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java @@ -1,8 +1,8 @@ package fr.xephi.authme.util; import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.Settings; import org.bukkit.entity.Player; import org.junit.Before; @@ -37,7 +37,7 @@ public class UtilsTest { public static void setUpMocks() { WrapperMock wrapperMock = WrapperMock.createInstance(); authMeMock = wrapperMock.getAuthMe(); - ConsoleLoggerTestInitializer.setupLogger(); + TestHelper.setupLogger(); } @Before From b825f52a16cda116086acaed2e4aa07c78ef7861 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Thu, 14 Apr 2016 18:09:38 +0200 Subject: [PATCH 38/71] Ignore message if string is empty --- src/main/java/fr/xephi/authme/output/Messages.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/fr/xephi/authme/output/Messages.java b/src/main/java/fr/xephi/authme/output/Messages.java index cf029275..8ac42a7b 100644 --- a/src/main/java/fr/xephi/authme/output/Messages.java +++ b/src/main/java/fr/xephi/authme/output/Messages.java @@ -76,6 +76,9 @@ public class Messages { + "Please verify your config file at '" + fileName + "'"); return formatMessage(getDefault(code)); } + if(message.isEmpty()) { + return new String[0]; + } return formatMessage(message); } From 6074ba59d5087c2dd256d184d0756dc62c8411bf Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 15 Apr 2016 12:27:34 +0200 Subject: [PATCH 39/71] #654 Add test verifying nothing is sent for empty message - Including various test simplifications --- .../output/MessagesIntegrationTest.java | 50 ++++++++----------- src/test/resources/messages_test.yml | 4 +- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index 2037280b..696d53d6 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -2,7 +2,6 @@ package fr.xephi.authme.output; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.TestHelper; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Before; @@ -15,11 +14,15 @@ import java.io.File; import java.util.logging.Logger; import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -34,7 +37,6 @@ public class MessagesIntegrationTest { @BeforeClass public static void setup() { - WrapperMock.createInstance(); TestHelper.setupLogger(); } @@ -61,7 +63,7 @@ public class MessagesIntegrationTest { String[] message = messages.retrieve(key); // then - String[] lines = new String[]{"This test message", "includes", "some new lines"}; + String[] lines = new String[]{"We've got", "new lines", "and ' apostrophes"}; assertThat(message, equalTo(lines)); } @@ -74,7 +76,7 @@ public class MessagesIntegrationTest { String message = messages.retrieveSingle(key); // then - assertThat(message, equalTo("This test message\nincludes\nsome new lines")); + assertThat(message, equalTo("We've got\nnew lines\nand ' apostrophes")); } @Test @@ -91,16 +93,16 @@ public class MessagesIntegrationTest { } @Test - public void shouldRetainApostrophes() { + public void shouldNotSendEmptyMessage() { // given - MessageKey key = MessageKey.NOT_LOGGED_IN; + MessageKey key = MessageKey.EMAIL_ALREADY_USED_ERROR; + CommandSender sender = mock(CommandSender.class); // when - String[] message = messages.retrieve(key); + messages.send(sender, key); // then - assertThat(message, arrayWithSize(1)); - assertThat(message[0], equalTo("Apostrophes ' should be loaded correctly, don't you think?")); + verify(sender, never()).sendMessage(anyString()); } @Test @@ -126,10 +128,10 @@ public class MessagesIntegrationTest { messages.send(player, key); // then - String[] lines = new String[]{"This test message", "includes", "some new lines"}; - for (String line : lines) { - verify(player).sendMessage(line); - } + String[] lines = new String[]{"We've got", "new lines", "and ' apostrophes"}; + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(player, times(3)).sendMessage(captor.capture()); + assertThat(captor.getAllValues(), contains(lines)); } @Test @@ -142,14 +144,11 @@ public class MessagesIntegrationTest { messages.send(sender, key, "1234"); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender, times(1)).sendMessage(captor.capture()); - String message = captor.getValue(); - assertThat(message, equalTo("Use /captcha 1234 to solve the captcha")); + verify(sender, times(1)).sendMessage(argThat(equalTo("Use /captcha 1234 to solve the captcha"))); } @Test - public void shouldNotThrowForKeyWithNoTagReplacements() { + public void shouldNotLogErrorForKeyWithNoTagReplacements() { // given MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR; CommandSender sender = mock(CommandSender.class); @@ -158,10 +157,7 @@ public class MessagesIntegrationTest { messages.send(sender, key); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(sender, times(1)).sendMessage(captor.capture()); - String message = captor.getValue(); - assertThat(message, equalTo("Use /captcha THE_CAPTCHA to solve the captcha")); + verify(sender).sendMessage(argThat(equalTo("Use /captcha THE_CAPTCHA to solve the captcha"))); } @Test @@ -175,13 +171,11 @@ public class MessagesIntegrationTest { messages.send(mock(CommandSender.class), key, "rep", "rep2"); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(logger).warning(captor.capture()); - assertThat(captor.getValue(), containsString("Invalid number of replacements")); + verify(logger).warning(argThat(containsString("Invalid number of replacements"))); } @Test - public void shouldThrowForReplacementsOnKeyWithNoTags() { + public void shouldSendErrorForReplacementsOnKeyWithNoTags() { // given Logger logger = mock(Logger.class); ConsoleLogger.setLogger(logger); @@ -191,9 +185,7 @@ public class MessagesIntegrationTest { messages.send(mock(CommandSender.class), key, "Replacement"); // then - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(logger).warning(captor.capture()); - assertThat(captor.getValue(), containsString("Invalid number of replacements")); + verify(logger).warning(argThat(containsString("Invalid number of replacements"))); } @Test diff --git a/src/test/resources/messages_test.yml b/src/test/resources/messages_test.yml index 156a24de..d637484c 100644 --- a/src/test/resources/messages_test.yml +++ b/src/test/resources/messages_test.yml @@ -1,9 +1,9 @@ # Sample messages file -unknown_user: 'This test message&nincludes&nsome new lines' +unknown_user: 'We''ve got&nnew lines&nand '' apostrophes' unsafe_spawn: '&cHere we have&bdefined some colors &dand some other <hings' -not_logged_in: 'Apostrophes '' should be loaded correctly, don''t you think?' reg_voluntarily: 'You can register yourself to the server with the command "/register "' usage_log: '&cUsage: /login ' wrong_pwd: '&cWrong password!' wrong_captcha: 'Use /captcha THE_CAPTCHA to solve the captcha' +email_already_used: '' From 71515f188ae3111ce7bd02cb541a5d9b2e1c59e9 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 15 Apr 2016 14:37:47 +0200 Subject: [PATCH 40/71] #551 Email registration should fail if no server email is configured - Stop registration and issue an error if the email address setting is empty for email registration - Refactor register command into smaller portions - Create tests --- .../executable/register/RegisterCommand.java | 81 ++++--- .../register/RegisterCommandTest.java | 209 ++++++++++++++++-- .../output/MessagesIntegrationTest.java | 2 +- 3 files changed, 240 insertions(+), 52 deletions(-) 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 e488eac7..efc688b0 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 @@ -1,20 +1,20 @@ 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.output.MessageKey; -import fr.xephi.authme.process.Management; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.RandomString; -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.SecuritySettings; import org.bukkit.entity.Player; import java.util.List; 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; import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION; public class RegisterCommand extends PlayerCommand { @@ -27,41 +27,62 @@ public class RegisterCommand extends PlayerCommand { return; } - if (arguments.isEmpty() || commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && arguments.size() < 2) { + // Ensure that there is 1 argument, or 2 if confirmation is required + final boolean useConfirmation = isConfirmationRequired(commandService); + if (arguments.isEmpty() || useConfirmation && arguments.size() < 2) { commandService.send(player, MessageKey.USAGE_REGISTER); return; } - final Management management = commandService.getManagement(); - if (commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION) - && !commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { - boolean emailDoubleCheck = commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL); - if (emailDoubleCheck && arguments.size() < 2 || !arguments.get(0).equals(arguments.get(1))) { - commandService.send(player, MessageKey.USAGE_REGISTER); - return; - } - - final String email = arguments.get(0); - if (!commandService.validateEmail(email)) { - commandService.send(player, MessageKey.INVALID_EMAIL); - return; - } - - final String thePass = RandomString.generate(commandService.getProperty(RECOVERY_PASSWORD_LENGTH)); - management.performRegister(player, thePass, email); - return; + if (commandService.getProperty(USE_EMAIL_REGISTRATION)) { + handleEmailRegistration(player, arguments, commandService); + } else { + handlePasswordRegistration(player, arguments, commandService); } - - if (arguments.size() > 1 && Settings.enablePasswordConfirmation && !arguments.get(0).equals(arguments.get(1))) { - commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR); - return; - } - - management.performRegister(player, arguments.get(0), ""); } @Override - public String getAlternativeCommand() { + protected String getAlternativeCommand() { return "/authme register "; } + + private void handlePasswordRegistration(Player player, List arguments, CommandService commandService) { + if (commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) { + commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR); + } else { + commandService.getManagement().performRegister(player, arguments.get(0), ""); + } + } + + private void handleEmailRegistration(Player player, List arguments, CommandService commandService) { + if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { + player.sendMessage("Cannot register: no email address is set for the server. " + + "Please contact an administrator"); + ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email is set" + + "to send emails from. Please add one in your config at " + EmailSettings.MAIL_ACCOUNT.getPath()); + return; + } + + final String email = arguments.get(0); + if (!commandService.validateEmail(email)) { + commandService.send(player, MessageKey.INVALID_EMAIL); + } else if (commandService.getProperty(ENABLE_CONFIRM_EMAIL) && !email.equals(arguments.get(1))) { + commandService.send(player, MessageKey.USAGE_REGISTER); + } else { + String thePass = RandomString.generate(commandService.getProperty(RECOVERY_PASSWORD_LENGTH)); + commandService.getManagement().performRegister(player, thePass, email); + } + } + + /** + * Return whether the password or email has to be confirmed. + * + * @param commandService The command service + * @return True if the confirmation is needed, false otherwise + */ + private boolean isConfirmationRequired(CommandService commandService) { + return commandService.getProperty(USE_EMAIL_REGISTRATION) + ? commandService.getProperty(ENABLE_CONFIRM_EMAIL) + : commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION); + } } 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 72f5e0c0..6f86a5f6 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 @@ -1,38 +1,63 @@ package fr.xephi.authme.command.executable.register; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Management; +import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.util.WrapperMock; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; -import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION; import static org.hamcrest.Matchers.containsString; 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.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link RegisterCommand}. */ +@RunWith(MockitoJUnitRunner.class) public class RegisterCommandTest { + @Mock private CommandService commandService; + @Mock + private Management management; + @Mock + private Player sender; + + @BeforeClass + public static void setup() { + TestHelper.setupLogger(); + } @Before - public void initializeAuthMeMock() { - WrapperMock.createInstance(); - commandService = mock(CommandService.class); + public void linkMocksAndProvideSettingDefaults() { + given(commandService.getManagement()).willReturn(management); + given(commandService.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.BCRYPT); + given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(false); + given(commandService.getProperty(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION)).willReturn(false); } @Test @@ -45,39 +70,181 @@ public class RegisterCommandTest { command.executeCommand(sender, new ArrayList(), commandService); // then - verify(commandService, never()).getManagement(); verify(sender).sendMessage(argThat(containsString("Player only!"))); + verifyZeroInteractions(management); } @Test - public void shouldFailForEmptyArguments() { + public void shouldForwardToManagementForTwoFactor() { // given - CommandSender sender = mock(Player.class); - RegisterCommand command = new RegisterCommand(); + given(commandService.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.TWO_FACTOR); + ExecutableCommand command = new RegisterCommand(); // when - command.executeCommand(sender, new ArrayList(), commandService); + command.executeCommand(sender, Collections.emptyList(), commandService); + + // then + verify(management).performRegister(sender, "", ""); + } + + @Test + public void shouldReturnErrorForEmptyArguments() { + // given + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Collections.emptyList(), commandService); // then verify(commandService).send(sender, MessageKey.USAGE_REGISTER); - verify(commandService, never()).getManagement(); + verifyZeroInteractions(management); } @Test - public void shouldForwardRegister() { + public void shouldReturnErrorForMissingConfirmation() { // given - Player sender = mock(Player.class); - RegisterCommand command = new RegisterCommand(); - Management management = mock(Management.class); - given(commandService.getManagement()).willReturn(management); - given(commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION)).willReturn(false); - given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(false); + given(commandService.getProperty(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION)).willReturn(true); + ExecutableCommand command = new RegisterCommand(); // when - command.executeCommand(sender, Collections.singletonList("password"), commandService); + command.executeCommand(sender, Collections.singletonList("arrrr"), commandService); // then - verify(management).performRegister(sender, "password", ""); + verify(commandService).send(sender, MessageKey.USAGE_REGISTER); + verifyZeroInteractions(management); } + @Test + public void shouldReturnErrorForMissingEmailConfirmation() { + // given + given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true); + given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true); + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Collections.singletonList("test@example.org"), commandService); + + // then + verify(commandService).send(sender, MessageKey.USAGE_REGISTER); + verifyZeroInteractions(management); + } + + @Test + public void shouldThrowErrorForMissingEmailConfiguration() { + // 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(""); + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Collections.singletonList("myMail@example.tld"), commandService); + + // then + verify(sender).sendMessage(argThat(containsString("no email address"))); + verifyZeroInteractions(management); + } + + @Test + public void shouldRejectInvalidEmail() { + // given + String playerMail = "player@example.org"; + given(commandService.validateEmail(playerMail)).willReturn(false); + + 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"); + + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Arrays.asList(playerMail, playerMail), commandService); + + // then + verify(commandService).validateEmail(playerMail); + verify(commandService).send(sender, MessageKey.INVALID_EMAIL); + verifyZeroInteractions(management); + } + + @Test + public void shouldRejectInvalidEmailConfirmation() { + // given + String playerMail = "bobber@bobby.org"; + given(commandService.validateEmail(playerMail)).willReturn(true); + + 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"); + + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Arrays.asList(playerMail, "invalid"), commandService); + + // then + verify(commandService).send(sender, MessageKey.USAGE_REGISTER); + verifyZeroInteractions(management); + } + + @Test + public void shouldPerformEmailRegistration() { + // given + String playerMail = "asfd@lakjgre.lds"; + given(commandService.validateEmail(playerMail)).willReturn(true); + int passLength = 7; + given(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH)).willReturn(passLength); + + 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"); + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Arrays.asList(playerMail, playerMail), commandService); + + // then + verify(commandService).validateEmail(playerMail); + verify(management).performRegister(eq(sender), argThat(stringWithLength(passLength)), eq(playerMail)); + } + + @Test + public void shouldRejectInvalidPasswordConfirmation() { + // given + given(commandService.getProperty(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION)).willReturn(true); + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Arrays.asList("myPass", "mypass"), commandService); + + // then + verify(commandService).send(sender, MessageKey.PASSWORD_MATCH_ERROR); + verifyZeroInteractions(management); + } + + @Test + public void shouldPerformPasswordValidation() { + // given + ExecutableCommand command = new RegisterCommand(); + + // when + command.executeCommand(sender, Collections.singletonList("myPass"), commandService); + + // then + verify(management).performRegister(sender, "myPass", ""); + } + + + private static TypeSafeMatcher stringWithLength(final int length) { + return new TypeSafeMatcher() { + @Override + protected boolean matchesSafely(String item) { + return item != null && item.length() == length; + } + + @Override + public void describeTo(Description description) { + description.appendText("String with length " + length); + } + }; + } } diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index 696d53d6..cd858ad8 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -144,7 +144,7 @@ public class MessagesIntegrationTest { messages.send(sender, key, "1234"); // then - verify(sender, times(1)).sendMessage(argThat(equalTo("Use /captcha 1234 to solve the captcha"))); + verify(sender, times(1)).sendMessage("Use /captcha 1234 to solve the captcha"); } @Test From 3674ac087ce487ae8880f64fcdeef3ac164cc78b Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 15 Apr 2016 15:17:58 +0200 Subject: [PATCH 41/71] Code householding + settings migration - Migrate and remove unused properties in legacy Settings - Add forgotten space in Register command - Fix javadoc errors shown on Jenkins --- .../java/fr/xephi/authme/DataManager.java | 7 +- .../executable/register/RegisterCommand.java | 2 +- .../process/login/AsynchronousLogin.java | 3 +- .../process/login/ProcessSyncPlayerLogin.java | 68 +++++++++---------- .../register/ProcessSyncPasswordRegister.java | 27 +++++--- .../fr/xephi/authme/settings/Settings.java | 30 ++------ src/main/java/fr/xephi/authme/util/Utils.java | 4 ++ 7 files changed, 60 insertions(+), 81 deletions(-) diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index a3470ba3..061683fa 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -20,11 +20,8 @@ public class DataManager { private final PluginHooks pluginHooks; private final BukkitService bukkitService; - /** - * Constructor for DataManager. - * - * @param plugin The plugin instance - * @param pluginHooks Plugin hooks instance + /* + * Constructor. */ public DataManager(AuthMe plugin, PluginHooks pluginHooks, BukkitService bukkitService) { this.plugin = plugin; 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 efc688b0..d060c56b 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 @@ -58,7 +58,7 @@ public class RegisterCommand extends PlayerCommand { if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { player.sendMessage("Cannot register: no email address is set for the server. " + "Please contact an administrator"); - ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email is set" + 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()); return; } 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 507a67eb..4368fd83 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -182,8 +182,7 @@ public class AsynchronousLogin implements Process { // task, we schedule it in the end // so that we can be sure, and have not to care if it might be // processed in other order. - ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin( - player, plugin, database, service.getSettings()); + ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin(player, plugin, database, service); if (syncPlayerLogin.getLimbo() != null) { if (syncPlayerLogin.getLimbo().getTimeoutTask() != null) { syncPlayerLogin.getLimbo().getTimeoutTask().cancel(); 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 96429870..7f037d26 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -1,22 +1,7 @@ package fr.xephi.authme.process.login; -import fr.xephi.authme.settings.NewSetting; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.plugin.PluginManager; -import org.bukkit.potion.PotionEffectType; - import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; - -import org.apache.commons.lang.reflect.MethodUtils; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.backup.JsonCache; @@ -28,14 +13,26 @@ import fr.xephi.authme.events.LoginEvent; import fr.xephi.authme.events.RestoreInventoryEvent; import fr.xephi.authme.events.SpawnTeleportEvent; import fr.xephi.authme.listener.AuthMePlayerListener; +import fr.xephi.authme.process.Process; +import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.settings.Settings; +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.Utils; import fr.xephi.authme.util.Utils.GroupType; +import org.apache.commons.lang.reflect.MethodUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginManager; +import org.bukkit.potion.PotionEffectType; -import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; import static fr.xephi.authme.settings.properties.PluginSettings.KEEP_COLLISIONS_DISABLED; +import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; -public class ProcessSyncPlayerLogin implements Runnable { +public class ProcessSyncPlayerLogin implements Process { private final LimboPlayer limbo; private final Player player; @@ -44,7 +41,7 @@ public class ProcessSyncPlayerLogin implements Runnable { private final AuthMe plugin; private final PluginManager pm; private final JsonCache playerCache; - private final NewSetting settings; + private final ProcessService service; private final boolean restoreCollisions = MethodUtils .getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null; @@ -55,10 +52,9 @@ public class ProcessSyncPlayerLogin implements Runnable { * @param player Player * @param plugin AuthMe * @param database DataSource - * @param settings The plugin settings + * @param service The process service */ - public ProcessSyncPlayerLogin(Player player, AuthMe plugin, - DataSource database, NewSetting settings) { + public ProcessSyncPlayerLogin(Player player, AuthMe plugin, DataSource database, ProcessService service) { this.plugin = plugin; this.pm = plugin.getServer().getPluginManager(); this.player = player; @@ -66,7 +62,7 @@ public class ProcessSyncPlayerLogin implements Runnable { this.limbo = LimboCache.getInstance().getLimboPlayer(name); this.auth = database.getAuth(name); this.playerCache = new JsonCache(); - this.settings = settings; + this.service = service; } public LimboPlayer getLimbo() { @@ -99,7 +95,7 @@ public class ProcessSyncPlayerLogin implements Runnable { } private void restoreSpeedEffects() { - if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) && settings.getProperty(RestrictionSettings.REMOVE_SPEED)) { + if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { player.setWalkSpeed(0.2F); player.setFlySpeed(0.1F); } @@ -114,10 +110,10 @@ public class ProcessSyncPlayerLogin implements Runnable { } private void forceCommands() { - for (String command : Settings.forceCommands) { + for (String command : service.getProperty(RegistrationSettings.FORCE_COMMANDS)) { player.performCommand(command.replace("%p", player.getName())); } - for (String command : Settings.forceCommandsAsConsole) { + for (String command : service.getProperty(RegistrationSettings.FORCE_COMMANDS_AS_CONSOLE)) { Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), command.replace("%p", player.getName())); } } @@ -155,15 +151,15 @@ public class ProcessSyncPlayerLogin implements Runnable { } } - if (restoreCollisions && !settings.getProperty(KEEP_COLLISIONS_DISABLED)) { + if (restoreCollisions && !service.getProperty(KEEP_COLLISIONS_DISABLED)) { player.setCollidable(true); } - if (settings.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { + if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { restoreInventory(); } - if (settings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) { + if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) { plugin.tablistHider.sendTablist(player); } @@ -188,24 +184,24 @@ public class ProcessSyncPlayerLogin implements Runnable { } restoreSpeedEffects(); - if (settings.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { + if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { player.removePotionEffect(PotionEffectType.BLINDNESS); } // The Login event now fires (as intended) after everything is processed Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player)); player.saveData(); - if (settings.getProperty(HooksSettings.BUNGEECORD)) { + if (service.getProperty(HooksSettings.BUNGEECORD)) { sendBungeeMessage(); } // Login is done, display welcome message - if (settings.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { - if (settings.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) { - for (String s : settings.getWelcomeMessage()) { + if (service.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { + if (service.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) { + for (String s : service.getSettings().getWelcomeMessage()) { Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player)); } } else { - for (String s : settings.getWelcomeMessage()) { + for (String s : service.getSettings().getWelcomeMessage()) { player.sendMessage(plugin.replaceAllInfo(s, player)); } } @@ -218,10 +214,10 @@ public class ProcessSyncPlayerLogin implements Runnable { } private void sendTo() { - if (!settings.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) { + if (!service.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) { ByteArrayDataOutput out = ByteStreams.newDataOutput(); out.writeUTF("Connect"); - out.writeUTF(settings.getProperty(HooksSettings.BUNGEECORD_SERVER)); + out.writeUTF(service.getProperty(HooksSettings.BUNGEECORD_SERVER)); player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); } } 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 8e839dda..cf018d18 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -12,9 +12,11 @@ import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Process; import fr.xephi.authme.process.ProcessService; 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.MessageTask; import fr.xephi.authme.task.TimeoutTask; import fr.xephi.authme.util.Utils; @@ -23,6 +25,9 @@ import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitTask; +import static fr.xephi.authme.settings.properties.RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN; +import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND; + /** */ public class ProcessSyncPasswordRegister implements Process { @@ -49,10 +54,10 @@ public class ProcessSyncPasswordRegister implements Process { } private void forceCommands() { - for (String command : Settings.forceRegisterCommands) { + for (String command : service.getProperty(RegistrationSettings.FORCE_REGISTER_COMMANDS)) { player.performCommand(command.replace("%p", player.getName())); } - for (String command : Settings.forceRegisterCommandsAsConsole) { + for (String command : service.getProperty(RegistrationSettings.FORCE_REGISTER_COMMANDS_AS_CONSOLE)) { Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), command.replace("%p", player.getName())); } @@ -62,7 +67,7 @@ public class ProcessSyncPasswordRegister implements Process { Utils.teleportToSpawn(player); LimboCache cache = LimboCache.getInstance(); cache.updateLimboPlayer(player); - int delay = service.getProperty(RestrictionSettings.TIMEOUT) * 20; + int delay = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; int interval = service.getProperty(RegistrationSettings.MESSAGE_INTERVAL); BukkitTask task; if (delay != 0) { @@ -80,15 +85,15 @@ public class ProcessSyncPasswordRegister implements Process { public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); if (limbo != null) { - if (Settings.hideTablistBeforeLogin && plugin.tablistHider != null) { + if (service.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && plugin.tablistHider != null) { plugin.tablistHider.sendTablist(player); } Utils.teleportToSpawn(player); - if (Settings.protectInventoryBeforeLogInEnabled && plugin.inventoryProtector != null) { + if (service.getProperty(HIDE_TABLIST_BEFORE_LOGIN) && plugin.inventoryProtector != null) { RestoreInventoryEvent event = new RestoreInventoryEvent(player); - Bukkit.getPluginManager().callEvent(event); + service.callEvent(event); if (!event.isCancelled()) { plugin.inventoryProtector.sendInventoryPacket(player); } @@ -103,7 +108,7 @@ public class ProcessSyncPasswordRegister implements Process { service.send(player, MessageKey.REGISTER_SUCCESS); - if (!Settings.getmailAccount.isEmpty()) { + if (!service.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { service.send(player, MessageKey.ADD_EMAIL_MESSAGE); } @@ -115,12 +120,12 @@ public class ProcessSyncPasswordRegister implements Process { plugin.getServer().getPluginManager().callEvent(new LoginEvent(player)); player.saveData(); - if (!Settings.noConsoleSpam) { + if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info(player.getName() + " registered " + Utils.getPlayerIp(player)); } // Kick Player after Registration is enabled, kick the player - if (Settings.forceRegKick) { + if (service.getProperty(RegistrationSettings.FORCE_KICK_AFTER_REGISTER)) { player.kickPlayer(service.retrieveSingleMessage(MessageKey.REGISTER_SUCCESS)); return; } @@ -139,12 +144,12 @@ public class ProcessSyncPasswordRegister implements Process { } // Request Login after Registration - if (Settings.forceRegLogin) { + if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) { forceLogin(player); return; } - if (Settings.bungee) { + if (service.getProperty(HooksSettings.BUNGEECORD)) { sendBungeeMessage(); } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index ca5ddc3b..2a24628f 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.security.HashAlgorithm; import fr.xephi.authme.settings.domain.Property; -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.RegistrationSettings; @@ -26,14 +25,10 @@ public final class Settings { public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder(); public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); public static List allowCommands; - public static List getJoinPermissions; public static List getUnrestrictedName; - public static List getRestrictedIp; public static List getForcedWorlds; public static List countries; public static List countriesBlacklist; - public static List forceCommands; - public static List forceCommandsAsConsole; public static List forceRegisterCommands; public static List forceRegisterCommandsAsConsole; public static HashAlgorithm getPasswordHash; @@ -44,7 +39,6 @@ public final class Settings { isMovementAllowed, isKickNonRegisteredEnabled, isForceSingleSessionEnabled, isForceSpawnLocOnJoinEnabled, isSaveQuitLocationEnabled, isForceSurvivalModeEnabled, - isKickOnWrongPasswordEnabled, enablePasswordConfirmation, protectInventoryBeforeLogInEnabled, isStopEnabled, reloadSupport, rakamakUseIp, noConsoleSpam, removePassword, displayOtherAccounts, emailRegistration, multiverse, bungee, @@ -52,13 +46,12 @@ public final class Settings { enableProtection, recallEmail, useWelcomeMessage, broadcastWelcomeMessage, forceRegKick, forceRegLogin, removeJoinMessage, removeLeaveMessage, delayJoinMessage, - noTeleport, hideTablistBeforeLogin, denyTabcompleteBeforeLogin, - kickPlayersBeforeStopping, allowAllCommandsIfRegIsOptional, - customAttributes, isRemoveSpeedEnabled, preventOtherCase, keepCollisionsDisabled; + noTeleport, allowAllCommandsIfRegIsOptional, + isRemoveSpeedEnabled, preventOtherCase; public static String getNickRegex, getUnloggedinGroup, unRegisteredGroup, backupWindowsPath, getRegisteredGroup, - rakamakUsers, rakamakUsersIp, getmailAccount, defaultWorld, - spawnPriority, crazyloginFileName, sendPlayerTo; + rakamakUsers, rakamakUsersIp, defaultWorld, + spawnPriority, crazyloginFileName; public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength, getMinNickLength, getMovementRadius, getNonActivatedGroup, @@ -90,12 +83,9 @@ public final class Settings { getNickRegex = configFile.getString("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_?]*"); nickPattern = Pattern.compile(getNickRegex); isAllowRestrictedIp = load(RestrictionSettings.ENABLE_RESTRICTED_USERS); - getRestrictedIp = load(RestrictionSettings.ALLOWED_RESTRICTED_USERS); isMovementAllowed = configFile.getBoolean("settings.restrictions.allowMovement", false); isRemoveSpeedEnabled = configFile.getBoolean("settings.restrictions.removeSpeed", true); getMovementRadius = configFile.getInt("settings.restrictions.allowedMovementRadius", 100); - getJoinPermissions = configFile.getStringList("GroupOptions.Permissions.PermissionsOnJoin"); - isKickOnWrongPasswordEnabled = configFile.getBoolean("settings.restrictions.kickOnWrongPassword", false); isKickNonRegisteredEnabled = configFile.getBoolean("settings.restrictions.kickNonRegistered", false); isForceSingleSessionEnabled = configFile.getBoolean("settings.restrictions.ForceSingleSession", true); isForceSpawnLocOnJoinEnabled = configFile.getBoolean("settings.restrictions.ForceSpawnLocOnJoinEnabled", false); @@ -112,12 +102,7 @@ public final class Settings { } getRegisteredGroup = configFile.getString("GroupOptions.RegisteredPlayerGroup", ""); - enablePasswordConfirmation = load(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION); - protectInventoryBeforeLogInEnabled = load(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN); - denyTabcompleteBeforeLogin = load(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN); - hideTablistBeforeLogin = load(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN); - backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\"); isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true); reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); @@ -137,7 +122,6 @@ public final class Settings { rakamakUseIp = configFile.getBoolean("Converter.Rakamak.useIp", false); noConsoleSpam = load(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE); removePassword = configFile.getBoolean("Security.console.removePassword", true); - getmailAccount = load(EmailSettings.MAIL_ACCOUNT); displayOtherAccounts = configFile.getBoolean("settings.restrictions.displayOtherAccounts", true); maxLoginTry = configFile.getInt("Security.captcha.maxLoginTry", 5); captchaLength = configFile.getInt("Security.captcha.captchaLength", 5); @@ -153,8 +137,6 @@ public final class Settings { defaultWorld = configFile.getString("Purge.defaultWorld", "world"); enableProtection = configFile.getBoolean("Protection.enableProtection", false); countries = configFile.getStringList("Protection.countries"); - forceCommands = configFile.getStringList("settings.forceCommands"); - forceCommandsAsConsole = configFile.getStringList("settings.forceCommandsAsConsole"); recallEmail = configFile.getBoolean("Email.recallPlayers", false); useWelcomeMessage = load(RegistrationSettings.USE_WELCOME_MESSAGE); countriesBlacklist = configFile.getStringList("Protection.countriesBlacklist"); @@ -171,11 +153,7 @@ public final class Settings { crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db"); forceRegisterCommands = configFile.getStringList("settings.forceRegisterCommands"); forceRegisterCommandsAsConsole = configFile.getStringList("settings.forceRegisterCommandsAsConsole"); - customAttributes = configFile.getBoolean("Hooks.customAttributes"); preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); - kickPlayersBeforeStopping = configFile.getBoolean("Security.stop.kickPlayersBeforeStopping", true); - sendPlayerTo = configFile.getString("Hooks.sendPlayerTo", ""); - keepCollisionsDisabled = load(PluginSettings.KEEP_COLLISIONS_DISABLED); } /** diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index 32913707..905dd7ec 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -264,6 +264,10 @@ public final class Utils { /** * Returns the IP of the given player. + * + * @param p The player to return the IP address for + * + * @return The player's IP address */ public static String getPlayerIp(Player p) { return p.getAddress().getAddress().getHostAddress(); From 6c9297a667dc450157aa95cf2591282fcc3c3b2c Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 15 Apr 2016 15:21:29 +0200 Subject: [PATCH 42/71] #647 Update Hungarian messages - By rErEaT --- src/main/resources/messages/messages_hu.yml | 62 ++++++++++----------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml index b3f22882..7aa03b39 100644 --- a/src/main/resources/messages/messages_hu.yml +++ b/src/main/resources/messages/messages_hu.yml @@ -1,50 +1,50 @@ -reg_only: Csak regisztrált játékosoknak! Jelentkezni a mail@email.com e-mail címen lehet -usage_unreg: '&cHasználat: /unregister jelszó' -registered: '&aSikeres regisztráció. Üdvözöllek!' -user_regged: '&cJátékosnév már regisztrálva' -login_msg: '&cKérlek jelentkezz be: "/login jelszó"' +reg_only: '&4Csak regisztrált játékosok tudnak csatlakozni a szerverhez! Kérlek kattints a http://example.com weboldalra és regisztráld magad!' +usage_unreg: '&cHasználat: "/unregister "' +registered: '&aSikeres regisztráció.' +user_regged: '&cEz a játékosnév már regisztrálva van!' +login_msg: '&cKérlek jelentkezz be: "/login "' not_logged_in: '&cNem vagy bejelentkezve!' logout: '&cSikeresen kijelentkeztél!' -usage_log: '&cBejelentkezés: /login ' -unknown_user: '&cA kért felhasználó nem telálható az adatbázisban!' -reg_voluntarily: Regisztrálhatod magad a szerveren a következö parancsal "/register " +usage_log: '&cBejelentkezés: "/login "' +unknown_user: '&cA kért felhasználó nem található az adatbázisban!' +reg_voluntarily: Regisztrálhatod magad a szerveren a következö parancsal "/register " reg_disabled: '&cRegisztráció letiltva!' no_perm: '&cNincs jogod ehhez!' -usage_reg: '&cHasználat: /register ' +usage_reg: '&cHasználat: "/register "' password_error_nick: '&cNem használhatod a felhasználóneved jelszónak, kérlek válassz másikat...' password_error_unsafe: '&cA választott jelszó nem biztonságos, kérlek válassz másikat...' unregistered: '&cRegisztráció sikeresen törölve!' same_nick: 'Ezzel a játékosnévvel már játszanak a szerveren.' -valid_session: '&2A hálózati kapcsolat újraépítése megtörtént.' +valid_session: '&2A megadott időkereten belül csatlakoztál vissza így a rendszer automatikusan beléptetett.' pwd_changed: '&cJelszó cserélve!' reload: 'Beálítások és adatbázis újratöltve!' timeout: 'Bejelentkezési időtúllépés!' -error: 'Hiba lépett fel; Lépj kapcsolatba a tulajjal' +error: 'Hiba lépett fel! Lépj kapcsolatba a tulajjal!' logged_in: '&cMár be vagy jelentkezve!' login: '&aSikeresen beléptél!' wrong_pwd: '&4Hibás jelszó!' user_unknown: '&cEz a felhasználó nincs regisztrálva!' -reg_msg: '&cKérlek Regisztrálj: "/register jelszó jelszóújra"' +reg_msg: '&cKérlek Regisztrálj: "/register "' reg_email_msg: '&cKérlek regisztrálj: "/register "' -unsafe_spawn: 'A kilépési helyzeted nem biztonságos, teleportálás a Spawnra.' -max_reg: 'Csak egy karakterrel registrálhatsz!' +unsafe_spawn: 'A kilépési helyzeted nem biztonságos, teleportálás a kezdő pozícióra.' +max_reg: '&cElérted a maximálisan beregisztrálható karakterek számát. (%reg_count/%max_acc %reg_names)!' password_error: 'A két jelszó nem egyezik!' -invalid_session: '&cAz IP címed megváltozott és a hálózati kapcsolatod lejárt. Kapcsolódj újra.' +invalid_session: '&cAz IP címed megváltozott, ezért a visszacsatlakozási időkereted lejárt.' pass_len: 'A jelszavad nem éri el a minimális hosszúságot!' -vb_nonActiv: '&cA felhasználód aktiválása még nem történt meg, ellenőrizd a leveleid!' -usage_changepassword: 'Használat: /changepassword <új Jelszó>' +vb_nonActiv: '&cA felhasználód aktiválása még nem történt meg, ellenőrizd a megadott emailed!' +usage_changepassword: 'Használat: "/changepassword <új Jelszó>"' name_len: '&4A felhasználó neved túl hosszú, vagy túl rövid! Válassz másikat!' regex: '&4A felhasználóneved nem használható karaktereket tartalmaz. Elfogadott karakterek: REG_EX' add_email: '&3Kérlek add hozzá a felhasználódhoz az email címedet "/email add "' recovery_email: '&3Ha elfelejtetted a jelszavad, használd az: "/email recovery "' -usage_captcha: '&3A bejelentkezéshez CAPTCHA szükséges, kérem használd a következő parancsot "/captcha "' -wrong_captcha: '&cHibás captcha, kérlek írd be a következő parancsot "/captcha THE_CAPTCHA" a chat-be!' -valid_captcha: '&2Captcha sikeresen feloldva!' +usage_captcha: '&3A bejelentkezéshez CAPTCHA szükséges, kérlek használd a következő parancsot "/captcha "' +wrong_captcha: '&cHibás CAPTCHA, kérlek írd be a következő parancsot "/captcha THE_CAPTCHA"!' +valid_captcha: '&2CAPTCHA sikeresen feloldva!' kick_forvip: '&3VIP játékos csatlakozott a szerverhez!' kick_fullserver: '&4A szerver megtelt, próbálj csatlakozni később!' -usage_email_add: '&cHasználat: /email add ' -usage_email_change: '&cHasználat: /email change <új Email>' -usage_email_recovery: '&cHasználat: /email recovery ' +usage_email_add: '&cHasználat: "/email add "' +usage_email_change: '&cHasználat: "/email change <új Email>"' +usage_email_recovery: '&cHasználat: "/email recovery "' new_email_invalid: '&cHibás az új email cím, próbáld újra!' old_email_invalid: '&cHibás a régi email cím, próbáld újra!' email_invalid: '&cHibás az email cím, próbáld újra!' @@ -52,12 +52,12 @@ email_added: '&2Az email címed rögzítése sikeresen megtörtént!' email_confirm: '&cKérlek ellenőrízd az email címedet!' email_changed: '&2Az email cím cseréje sikeresen megtörtént!' email_send: '&2A jelszó visszaállításhoz szükséges emailt elküldtük! Ellenőrízd a leveleidet!' -email_exists: '&cA visszaállító emailt elküldtük! Hiba esetén újkérheted az alábbi parancs segítségével:' +email_exists: '&cA visszaállító emailt elküldtük! Hiba esetén újra kérheted az alábbi parancs segítségével:' +email_already_used: '&4Ez az email cím már használatban van!' country_banned: '&4Az országod tiltólistán van ezen a szerveren!' -antibot_auto_enabled: '&4[AntiBot] Az AntiBot védelem bekapcsolt a nagy számú hálózati kapcsolat miatt!' -antibot_auto_disabled: '&2[AntiBot] Az AntiBot kikapcsol %m múlva!' -kick_antibot: 'Az AntiBot védelem bekapcsolva! Kérünk várj pár másodpercet a csatlakozáshoz.' -# TODO email_already_used: '&4The email address is already being used' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' -# 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 try another name!' \ No newline at end of file +antibot_auto_enabled: '&4[AntiBot] Az AntiBot védelem bekapcsolt, mert a megszabott időn belül több felhasználó csatlakozott!' +antibot_auto_disabled: '&2[AntiBot] Az AntiBot kikapcsol %m perc múlva!' +kick_antibot: 'Az AntiBot védelem bekapcsolva! Kérlek várj pár percet mielőtt csatlakozol.' +not_owner_error: 'Ez nem a te felhasználód. Kérlek válassz másik nevet!' +invalid_name_case: '%valid a felhasználó neved nem? Akkor ne %invalid névvel próbálj feljönni.' +two_factor_create: '&2A te titkos kódod a következő: %code. Vagy skenneld be a következő oldalról: %url' From 4040cd9ba69c4a768f092010535d0d8b71a7dea7 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 15 Apr 2016 21:50:32 +0200 Subject: [PATCH 43/71] #658 Add hide_chat setting --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- .../authme/listener/AuthMePlayerListener.java | 19 ++++++++++++++----- .../fr/xephi/authme/settings/Settings.java | 3 ++- .../properties/RestrictionSettings.java | 11 ++++++++--- src/main/resources/config.yml | 2 ++ 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index d001cd4b..bcb45b09 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -382,7 +382,7 @@ public class AuthMe extends JavaPlugin { // Register event listeners pluginManager.registerEvents(new AuthMePlayerListener( - this, messages, dataSource, antiBot, management, bukkitService), this); + this, newSettings, messages, dataSource, antiBot, management, bukkitService), this); pluginManager.registerEvents(new AuthMeBlockListener(), this); pluginManager.registerEvents(new AuthMeEntityListener(), this); pluginManager.registerEvents(new AuthMeServerListener(this, messages, pluginHooks, spawnLoader), this); diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 4dee6f41..6ea4bd81 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -16,7 +16,11 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.Management; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; +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.GeoLiteAPI; import fr.xephi.authme.util.Utils; @@ -61,15 +65,17 @@ public class AuthMePlayerListener implements Listener { public static final ConcurrentHashMap joinMessage = new ConcurrentHashMap<>(); public static final ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap<>(); private final AuthMe plugin; + private final NewSetting settings; private final Messages m; private final DataSource dataSource; private final AntiBot antiBot; private final Management management; private final BukkitService bukkitService; - public AuthMePlayerListener(AuthMe plugin, Messages messages, DataSource dataSource, AntiBot antiBot, + public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource, AntiBot antiBot, Management management, BukkitService bukkitService) { this.plugin = plugin; + this.settings = settings; this.m = messages; this.dataSource = dataSource; this.antiBot = antiBot; @@ -78,15 +84,18 @@ public class AuthMePlayerListener implements Listener { } private void handleChat(AsyncPlayerChatEvent event) { - if (Settings.isChatAllowed) { + if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) { return; } final Player player = event.getPlayer(); if (Utils.checkAuth(player)) { for (Player p : Utils.getOnlinePlayers()) { + if(!settings.getProperty(RestrictionSettings.HIDE_CHAT)) { + break; + } if (!PlayerCache.getInstance().isAuthenticated(p.getName())) { - event.getRecipients().remove(p); // TODO: it should be configurable + event.getRecipients().remove(p); } } return; @@ -103,7 +112,7 @@ public class AuthMePlayerListener implements Listener { if (dataSource.isAuthAvailable(player.getName().toLowerCase())) { m.send(player, MessageKey.LOGIN_MESSAGE); } else { - if (Settings.emailRegistration) { + if (settings.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)) { m.send(player, MessageKey.REGISTER_EMAIL_MESSAGE); } else { m.send(player, MessageKey.REGISTER_MESSAGE); @@ -116,7 +125,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { String cmd = event.getMessage().split(" ")[0].toLowerCase(); - if (Settings.useEssentialsMotd && cmd.equals("/motd")) { + if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && cmd.equals("/motd")) { return; } if (!Settings.isForcedRegistrationEnabled && Settings.allowAllCommandsIfRegIsOptional) { diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 2a24628f..f448adee 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -47,7 +47,7 @@ public final class Settings { broadcastWelcomeMessage, forceRegKick, forceRegLogin, removeJoinMessage, removeLeaveMessage, delayJoinMessage, noTeleport, allowAllCommandsIfRegIsOptional, - isRemoveSpeedEnabled, preventOtherCase; + isRemoveSpeedEnabled, preventOtherCase, hideChat; public static String getNickRegex, getUnloggedinGroup, unRegisteredGroup, backupWindowsPath, getRegisteredGroup, rakamakUsers, rakamakUsersIp, defaultWorld, @@ -154,6 +154,7 @@ public final class Settings { forceRegisterCommands = configFile.getStringList("settings.forceRegisterCommands"); forceRegisterCommandsAsConsole = configFile.getStringList("settings.forceRegisterCommandsAsConsole"); preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); + hideChat = load(RestrictionSettings.HIDE_CHAT); } /** 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 c2b2cb68..72cb8a9b 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java @@ -12,12 +12,16 @@ import static fr.xephi.authme.settings.domain.Property.newProperty; public class RestrictionSettings implements SettingsClass { @Comment({ - "Can not authenticated players chat and see the chat log?", + "Can not authenticated players chat?", "Keep in mind that this feature also blocks all commands not", "listed in the list below."}) public static final Property ALLOW_CHAT = newProperty("settings.restrictions.allowChat", false); + @Comment("Can not authenticated players see the chat log?") + public static final Property HIDE_CHAT = + newProperty("settings.restrictions.hideChat", false); + @Comment({ "Allow unlogged users to use all the commands if registration is not forced!", "WARNING: use this only if you need it!)"}) @@ -29,8 +33,9 @@ public class RestrictionSettings implements SettingsClass { newListProperty("settings.restrictions.allowCommands", "login", "register", "l", "reg", "email", "captcha"); - @Comment("Max number of allowed registrations per IP") - // TODO ljacqu 20160109: If 0 == unlimited, add this fact to the comment + @Comment({ + "Max number of allowed registrations per IP", + "The value 0 means an unlimited number of registrations!"}) public static final Property MAX_REGISTRATION_PER_IP = newProperty("settings.restrictions.maxRegPerIp", 1); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index fd6a9cb0..86aecfaa 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -67,6 +67,8 @@ settings: # 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 # WARNING: use this only if you need it! # Allow unlogged users to use all the commands if registration is not forced! allowAllCommandsIfRegistrationIsOptional: false From 4911499333bb73cb99a4dacebf9151cd84c92867 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Fri, 15 Apr 2016 22:16:13 +0200 Subject: [PATCH 44/71] Allow player falling, avoid useless lag and deny jumps! #618 --- .../fr/xephi/authme/listener/AuthMePlayerListener.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 6ea4bd81..2548669e 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -172,9 +172,13 @@ public class AuthMePlayerListener implements Listener { return; } + /* + * Limit player X and Z movements to 1 block + * Deny player Y+ movements (allows falling) + */ if (event.getFrom().getBlockX() == event.getTo().getBlockX() - && event.getFrom().getBlockY() == event.getTo().getBlockY() - && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { + && event.getFrom().getBlockZ() == event.getTo().getBlockZ() + && event.getFrom().getY() - event.getTo().getY() >= 0) { return; } @@ -185,6 +189,7 @@ public class AuthMePlayerListener implements Listener { if (!Settings.isMovementAllowed) { event.setTo(event.getFrom()); + // sgdc3 TODO: remove this, maybe we should set the effect every x ticks, idk! if (Settings.isRemoveSpeedEnabled) { player.setFlySpeed(0.0f); player.setWalkSpeed(0.0f); From f4bc4322f050afc362fa1e0090dbee425609e423 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 15 Apr 2016 23:03:01 +0200 Subject: [PATCH 45/71] Create export/import messages task - Allows communication with a web interface (PHP) to translate messages - Saving via import still needs to be improved --- .../translation/ExportMessagesTask.java | 60 +++++++++++++++ .../translation/ImportMessagesTask.java | 75 +++++++++++++++++++ .../messages/translation/LanguageExport.java | 19 +++++ .../messages/translation/MessageExport.java | 22 ++++++ .../translation/export/export-is-written-here | 0 5 files changed, 176 insertions(+) create mode 100644 src/tools/messages/translation/ExportMessagesTask.java create mode 100644 src/tools/messages/translation/ImportMessagesTask.java create mode 100644 src/tools/messages/translation/LanguageExport.java create mode 100644 src/tools/messages/translation/MessageExport.java create mode 100644 src/tools/messages/translation/export/export-is-written-here diff --git a/src/tools/messages/translation/ExportMessagesTask.java b/src/tools/messages/translation/ExportMessagesTask.java new file mode 100644 index 00000000..e6bd5c2c --- /dev/null +++ b/src/tools/messages/translation/ExportMessagesTask.java @@ -0,0 +1,60 @@ +package messages.translation; + +import com.google.gson.Gson; +import fr.xephi.authme.output.MessageKey; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import utils.FileUtils; +import utils.ToolTask; +import utils.ToolsConstants; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +/** + * Task to export all messages for translation purposes. + */ +public class ExportMessagesTask implements ToolTask { + + private final Gson gson = new Gson(); + + @Override + public String getTaskName() { + return "exportMessages"; + } + + @Override + public void execute(Scanner scanner) { + FileConfiguration defaultMessages = YamlConfiguration.loadConfiguration( + new File(ToolsConstants.MAIN_RESOURCES_ROOT + "messages/messages_en.yml")); + + File[] messageFiles = new File(ToolsConstants.MAIN_RESOURCES_ROOT + "messages").listFiles(); + if (messageFiles == null || messageFiles.length == 0) { + throw new IllegalStateException("Could not read messages folder"); + } + + for (File file : messageFiles) { + String code = file.getName().substring("messages_".length(), file.getName().length() - ".yml".length()); + exportLanguage(code, defaultMessages, YamlConfiguration.loadConfiguration(file)); + } + } + + private void exportLanguage(String code, FileConfiguration defaultMessages, FileConfiguration messageFile) { + List list = new ArrayList<>(); + for (MessageKey key : MessageKey.values()) { + list.add(new MessageExport(key.getKey(), key.getTags(), getString(key, defaultMessages), + getString(key, messageFile))); + } + + FileUtils.writeToFile( + ToolsConstants.TOOLS_SOURCE_ROOT + "messages/translation/export/messages_" + code + ".json", + gson.toJson(new LanguageExport(code, list))); + } + + private static String getString(MessageKey key, FileConfiguration configuration) { + return configuration.getString(key.getKey(), ""); + } + +} diff --git a/src/tools/messages/translation/ImportMessagesTask.java b/src/tools/messages/translation/ImportMessagesTask.java new file mode 100644 index 00000000..4b75c9f2 --- /dev/null +++ b/src/tools/messages/translation/ImportMessagesTask.java @@ -0,0 +1,75 @@ +package messages.translation; + +import com.google.common.io.Resources; +import com.google.gson.Gson; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.yaml.snakeyaml.DumperOptions; +import utils.ToolTask; +import utils.ToolsConstants; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Scanner; + +/** + * Imports a message file from a JSON export. + */ +public class ImportMessagesTask implements ToolTask { + + private static final String MESSAGES_FOLDER = ToolsConstants.MAIN_RESOURCES_ROOT + "messages/"; + private Gson gson = new Gson(); + + @Override + public String getTaskName() { + return "importMessages"; + } + + @Override + public void execute(Scanner scanner) { + System.out.println("Enter URL to export from"); + String url = scanner.nextLine(); + LanguageExport languageExport = getLanguageExportFromUrl(url); + if (languageExport == null) { + throw new IllegalStateException("An error occurred: constructed language export is null"); + } + + mergeExportIntoFile(languageExport); + System.out.println("Saved to messages file for code '" + languageExport.code + "'"); + } + + private LanguageExport getLanguageExportFromUrl(String url) { + try { + URL uri = new URL(url); + String json = Resources.toString(uri, Charset.forName("UTF-8")); + return gson.fromJson(json, LanguageExport.class); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private void mergeExportIntoFile(LanguageExport export) { + String languageCode = export.code; + File file = new File(MESSAGES_FOLDER + "messages_" + languageCode + ".yml"); + if (!file.exists()) { + throw new IllegalStateException("Messages file for language code " + languageCode + " does not exist"); + } + FileConfiguration fileConfiguration = YamlConfiguration.loadConfiguration(file); + + for (MessageExport messageExport : export.messages) { + fileConfiguration.set(messageExport.key, messageExport.translatedMessage); + } + try { + Field dumperOptionsField = YamlConfiguration.class.getDeclaredField("yamlOptions"); + dumperOptionsField.setAccessible(true); + DumperOptions options = (DumperOptions) dumperOptionsField.get(fileConfiguration); + options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); + fileConfiguration.save(file); + } catch (IOException | NoSuchFieldException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/src/tools/messages/translation/LanguageExport.java b/src/tools/messages/translation/LanguageExport.java new file mode 100644 index 00000000..3be0fa44 --- /dev/null +++ b/src/tools/messages/translation/LanguageExport.java @@ -0,0 +1,19 @@ +package messages.translation; + +import java.util.Collections; +import java.util.List; + +/** + * Export of a language's messages. + */ +public class LanguageExport { + + public final String code; + public final List messages; + + public LanguageExport(String code, List messages) { + this.code = code; + this.messages = Collections.unmodifiableList(messages); + } + +} diff --git a/src/tools/messages/translation/MessageExport.java b/src/tools/messages/translation/MessageExport.java new file mode 100644 index 00000000..da2c0874 --- /dev/null +++ b/src/tools/messages/translation/MessageExport.java @@ -0,0 +1,22 @@ +package messages.translation; + +import fr.xephi.authme.util.StringUtils; + +/** + * Container class for one translatable message. + */ +public class MessageExport { + + public final String key; + public final String tags; + public final String defaultMessage; + public final String translatedMessage; + + public MessageExport(String key, String[] tags, String defaultMessage, String translatedMessage) { + this.key = key; + this.tags = StringUtils.join(",", tags); + this.defaultMessage = defaultMessage; + this.translatedMessage = translatedMessage; + } + +} diff --git a/src/tools/messages/translation/export/export-is-written-here b/src/tools/messages/translation/export/export-is-written-here new file mode 100644 index 00000000..e69de29b From 6c49f5844f1a42100a5969fd5b4b65d91181ba87 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 16 Apr 2016 11:47:18 +0200 Subject: [PATCH 46/71] Improve saving in messages import - Keep same style (messages wrapped in single quotes) - Remove verification comments and run verification after merge again --- src/tools/messages/VerifyMessagesTask.java | 2 +- .../translation/AuthMeYamlConfiguration.java | 58 +++++++++++++++++++ .../translation/ImportMessagesTask.java | 54 ++++++++++++----- 3 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 src/tools/messages/translation/AuthMeYamlConfiguration.java diff --git a/src/tools/messages/VerifyMessagesTask.java b/src/tools/messages/VerifyMessagesTask.java index e540554a..28b42b71 100644 --- a/src/tools/messages/VerifyMessagesTask.java +++ b/src/tools/messages/VerifyMessagesTask.java @@ -93,7 +93,7 @@ public final class VerifyMessagesTask implements ToolTask { } } - private static void verifyFileAndAddKeys(MessageFileVerifier verifier, FileConfiguration defaultMessages) { + public static void verifyFileAndAddKeys(MessageFileVerifier verifier, FileConfiguration defaultMessages) { Map missingKeys = verifier.getMissingKeys(); if (!missingKeys.isEmpty() || !verifier.getMissingTags().isEmpty()) { verifier.addMissingKeys(defaultMessages); diff --git a/src/tools/messages/translation/AuthMeYamlConfiguration.java b/src/tools/messages/translation/AuthMeYamlConfiguration.java new file mode 100644 index 00000000..f8724dff --- /dev/null +++ b/src/tools/messages/translation/AuthMeYamlConfiguration.java @@ -0,0 +1,58 @@ +package messages.translation; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.IOException; +import java.util.regex.Pattern; + +/** + * Extension of {@link YamlConfiguration} to customize the writing style. + */ +public class AuthMeYamlConfiguration extends YamlConfiguration { + + // Differences to YamlConfiguration: Texts are always in single quotes + // and line breaks are only applied after 200 chars + @Override + public String saveToString() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); + options.setPrettyFlow(true); + options.setWidth(200); + Yaml yaml = new Yaml(options); + + String header = buildHeader(); + String dump = yaml.dump(getValues(false)); + + if (dump.equals(BLANK_CONFIG)) { + dump = ""; + } + // By setting the scalar style to SINGLE_QUOTED both keys and values will be enclosed in single quotes. + // We want all texts wrapped in single quotes, but not the keys. Seems like this is not possible in SnakeYAML + dump = Pattern.compile("^'([a-zA-Z0-9-_]+)': ", Pattern.MULTILINE) + .matcher(dump).replaceAll("$1: "); + + return header + dump; + } + + /** + * Behaves similarly to {@link YamlConfiguration#loadConfiguration(File)} but returns an object + * of this class instead. + * + * @param file the file to load + * @return the constructed AuthMeYamlConfiguration instance + */ + public static AuthMeYamlConfiguration loadConfiguration(File file) { + AuthMeYamlConfiguration config = new AuthMeYamlConfiguration(); + try { + config.load(file); + } catch (IOException | InvalidConfigurationException ex) { + throw new IllegalStateException(ex); + } + return config; + } +} diff --git a/src/tools/messages/translation/ImportMessagesTask.java b/src/tools/messages/translation/ImportMessagesTask.java index 4b75c9f2..36e8c29d 100644 --- a/src/tools/messages/translation/ImportMessagesTask.java +++ b/src/tools/messages/translation/ImportMessagesTask.java @@ -2,21 +2,27 @@ package messages.translation; import com.google.common.io.Resources; import com.google.gson.Gson; +import messages.MessageFileVerifier; +import messages.VerifyMessagesTask; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import org.yaml.snakeyaml.DumperOptions; +import utils.FileUtils; import utils.ToolTask; import utils.ToolsConstants; import java.io.File; import java.io.IOException; -import java.lang.reflect.Field; import java.net.URL; import java.nio.charset.Charset; import java.util.Scanner; +import java.util.regex.Pattern; /** - * Imports a message file from a JSON export. + * Imports a message file from a remote JSON export and validates the resulting file. + *

+ * Comments at the top of an existing file should remain after the import, but it is important + * to verify that no unwanted changes have been applied to the file. Note that YAML comments + * tend to disappear if there is no space between the # and the first character. */ public class ImportMessagesTask implements ToolTask { @@ -30,8 +36,9 @@ public class ImportMessagesTask implements ToolTask { @Override public void execute(Scanner scanner) { - System.out.println("Enter URL to export from"); + System.out.println("Enter URL to import from"); String url = scanner.nextLine(); + LanguageExport languageExport = getLanguageExportFromUrl(url); if (languageExport == null) { throw new IllegalStateException("An error occurred: constructed language export is null"); @@ -41,10 +48,10 @@ public class ImportMessagesTask implements ToolTask { System.out.println("Saved to messages file for code '" + languageExport.code + "'"); } - private LanguageExport getLanguageExportFromUrl(String url) { + private LanguageExport getLanguageExportFromUrl(String location) { try { - URL uri = new URL(url); - String json = Resources.toString(uri, Charset.forName("UTF-8")); + URL url = new URL(location); + String json = Resources.toString(url, Charset.forName("UTF-8")); return gson.fromJson(json, LanguageExport.class); } catch (IOException e) { throw new IllegalStateException(e); @@ -53,23 +60,40 @@ public class ImportMessagesTask implements ToolTask { private void mergeExportIntoFile(LanguageExport export) { String languageCode = export.code; - File file = new File(MESSAGES_FOLDER + "messages_" + languageCode + ".yml"); + String fileName = MESSAGES_FOLDER + "messages_" + languageCode + ".yml"; + File file = new File(fileName); if (!file.exists()) { throw new IllegalStateException("Messages file for language code " + languageCode + " does not exist"); } - FileConfiguration fileConfiguration = YamlConfiguration.loadConfiguration(file); + removeAllTodoComments(fileName); + FileConfiguration fileConfiguration = AuthMeYamlConfiguration.loadConfiguration(file); for (MessageExport messageExport : export.messages) { - fileConfiguration.set(messageExport.key, messageExport.translatedMessage); + if (!messageExport.translatedMessage.isEmpty()) { + fileConfiguration.set(messageExport.key, messageExport.translatedMessage); + } } try { - Field dumperOptionsField = YamlConfiguration.class.getDeclaredField("yamlOptions"); - dumperOptionsField.setAccessible(true); - DumperOptions options = (DumperOptions) dumperOptionsField.get(fileConfiguration); - options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); fileConfiguration.save(file); - } catch (IOException | NoSuchFieldException | IllegalAccessException e) { + } catch (IOException e) { throw new IllegalStateException(e); } + + MessageFileVerifier verifier = new MessageFileVerifier(fileName); + VerifyMessagesTask.verifyFileAndAddKeys(verifier, YamlConfiguration.loadConfiguration( + new File(MESSAGES_FOLDER + "messages_en.yml"))); + } + + /** + * Removes all to-do comments written by {@link VerifyMessagesTask}. This is helpful as the YamlConfiguration + * moves those comments otherwise upon saving. + * + * @param file The file whose to-do comments should be removed + */ + private static void removeAllTodoComments(String file) { + String contents = FileUtils.readFromFile(file); + String regex = "^# TODO .*$"; + contents = Pattern.compile(regex, Pattern.MULTILINE).matcher(contents).replaceAll(""); + FileUtils.writeToFile(file, contents); } } From 354581160a3efcb9f648aaa239a2f4c4f0996dc3 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 17 Apr 2016 12:17:22 +0200 Subject: [PATCH 47/71] Change export messages task to send updated file to remote server --- .../translation/ExportMessagesTask.java | 80 +++++++++++++++---- .../translation/WriteAllExportsTask.java | 37 +++++++++ 2 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 src/tools/messages/translation/WriteAllExportsTask.java diff --git a/src/tools/messages/translation/ExportMessagesTask.java b/src/tools/messages/translation/ExportMessagesTask.java index e6bd5c2c..41a96c61 100644 --- a/src/tools/messages/translation/ExportMessagesTask.java +++ b/src/tools/messages/translation/ExportMessagesTask.java @@ -1,23 +1,36 @@ package messages.translation; +import com.google.common.io.CharStreams; import com.google.gson.Gson; import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.util.StringUtils; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import utils.FileUtils; import utils.ToolTask; import utils.ToolsConstants; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** - * Task to export all messages for translation purposes. + * Task to export a language's messages to the remote translation service. */ public class ExportMessagesTask implements ToolTask { + /** The folder containing the messages files. */ + protected static final String MESSAGES_FOLDER = ToolsConstants.MAIN_RESOURCES_ROOT + "messages/"; + /** The remote URL to send an updated file to. */ + //private static final String UPDATE_URL = "http://jalu.ch/ext/authme/update.php"; + private static final String UPDATE_URL = "http://localhost/AuthMe-translate/update.php"; private final Gson gson = new Gson(); @Override @@ -27,34 +40,71 @@ public class ExportMessagesTask implements ToolTask { @Override public void execute(Scanner scanner) { - FileConfiguration defaultMessages = YamlConfiguration.loadConfiguration( - new File(ToolsConstants.MAIN_RESOURCES_ROOT + "messages/messages_en.yml")); + System.out.println("Enter language code of messages to export:"); + String languageCode = scanner.nextLine().trim(); - File[] messageFiles = new File(ToolsConstants.MAIN_RESOURCES_ROOT + "messages").listFiles(); - if (messageFiles == null || messageFiles.length == 0) { - throw new IllegalStateException("Could not read messages folder"); + File file = new File(MESSAGES_FOLDER + "messages_" + languageCode + ".yml"); + if (!file.exists()) { + throw new IllegalStateException("File '" + file.getAbsolutePath() + "' does not exist"); } - for (File file : messageFiles) { - String code = file.getName().substring("messages_".length(), file.getName().length() - ".yml".length()); - exportLanguage(code, defaultMessages, YamlConfiguration.loadConfiguration(file)); - } + FileConfiguration configuration = YamlConfiguration.loadConfiguration(file); + String json = convertToJson(languageCode, loadDefaultMessages(), configuration); + + System.out.println("Enter update code (generated on remote side)"); + String updateCode = scanner.nextLine().trim(); + String result = sendJsonToRemote(json, updateCode, languageCode); + System.out.println("Answer: " + result); } - private void exportLanguage(String code, FileConfiguration defaultMessages, FileConfiguration messageFile) { + protected String convertToJson(String code, FileConfiguration defaultMessages, FileConfiguration messageFile) { List list = new ArrayList<>(); for (MessageKey key : MessageKey.values()) { list.add(new MessageExport(key.getKey(), key.getTags(), getString(key, defaultMessages), getString(key, messageFile))); } - FileUtils.writeToFile( - ToolsConstants.TOOLS_SOURCE_ROOT + "messages/translation/export/messages_" + code + ".json", - gson.toJson(new LanguageExport(code, list))); + return gson.toJson(new LanguageExport(code, list)); + } + + protected FileConfiguration loadDefaultMessages() { + return YamlConfiguration.loadConfiguration(new File(MESSAGES_FOLDER + "messages_en.yml")); } private static String getString(MessageKey key, FileConfiguration configuration) { return configuration.getString(key.getKey(), ""); } + private static String sendJsonToRemote(String file, String code, String language) { + try { + String encodedData = "file=" + URLEncoder.encode(file, "UTF-8") + + "&code=" + URLEncoder.encode(code, "UTF-8") + + "&language=" + URLEncoder.encode(language, "UTF-8"); + + URL url = new URL(UPDATE_URL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("Content-Length", String.valueOf(encodedData.length())); + OutputStream os = conn.getOutputStream(); + os.write(encodedData.getBytes()); + os.flush(); + os.close(); + + return "Response code: " + conn.getResponseCode() + + "\n" + inputStreamToString(conn.getInputStream()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static String inputStreamToString(InputStream is) { + try (InputStreamReader isr = new InputStreamReader(is)) { + return CharStreams.toString(isr); + } catch (IOException e) { + return "Failed to read output - " + StringUtils.formatException(e); + } + } + } diff --git a/src/tools/messages/translation/WriteAllExportsTask.java b/src/tools/messages/translation/WriteAllExportsTask.java new file mode 100644 index 00000000..413943d4 --- /dev/null +++ b/src/tools/messages/translation/WriteAllExportsTask.java @@ -0,0 +1,37 @@ +package messages.translation; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import utils.FileUtils; +import utils.ToolsConstants; + +import java.io.File; +import java.util.Scanner; + +/** + * Task which exports all messages to a local folder. + */ +public class WriteAllExportsTask extends ExportMessagesTask { + + private static final String OUTPUT_FOLDER = ToolsConstants.TOOLS_SOURCE_ROOT + "messages/translation/export/"; + + @Override + public String getTaskName() { + return "writeAllExports"; + } + + @Override + public void execute(Scanner scanner) { + File[] messageFiles = new File(MESSAGES_FOLDER).listFiles(); + if (messageFiles == null || messageFiles.length == 0) { + throw new IllegalStateException("Could not read messages folder"); + } + + final FileConfiguration defaultMessages = loadDefaultMessages(); + for (File file : messageFiles) { + String code = file.getName().substring("messages_".length(), file.getName().length() - ".yml".length()); + String json = convertToJson(code, defaultMessages, YamlConfiguration.loadConfiguration(file)); + FileUtils.writeToFile(OUTPUT_FOLDER + "messages_" + code + ".json", json); + } + } +} From 92c476785b83a367f1a3bd911f95e2979c30ac1f Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 17 Apr 2016 23:17:38 +0200 Subject: [PATCH 48/71] Remove generated code / allow import of new languages - Exporting back messages to the remote server is now handled by IP whitelisting, not with temporary codes --- .../translation/ExportMessagesTask.java | 12 +++----- .../translation/ImportMessagesTask.java | 29 +++++++++++++++---- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/tools/messages/translation/ExportMessagesTask.java b/src/tools/messages/translation/ExportMessagesTask.java index 41a96c61..c281696b 100644 --- a/src/tools/messages/translation/ExportMessagesTask.java +++ b/src/tools/messages/translation/ExportMessagesTask.java @@ -29,8 +29,7 @@ public class ExportMessagesTask implements ToolTask { /** The folder containing the messages files. */ protected static final String MESSAGES_FOLDER = ToolsConstants.MAIN_RESOURCES_ROOT + "messages/"; /** The remote URL to send an updated file to. */ - //private static final String UPDATE_URL = "http://jalu.ch/ext/authme/update.php"; - private static final String UPDATE_URL = "http://localhost/AuthMe-translate/update.php"; + private static final String UPDATE_URL = "http://jalu.ch/ext/authme/update.php"; private final Gson gson = new Gson(); @Override @@ -51,9 +50,7 @@ public class ExportMessagesTask implements ToolTask { FileConfiguration configuration = YamlConfiguration.loadConfiguration(file); String json = convertToJson(languageCode, loadDefaultMessages(), configuration); - System.out.println("Enter update code (generated on remote side)"); - String updateCode = scanner.nextLine().trim(); - String result = sendJsonToRemote(json, updateCode, languageCode); + String result = sendJsonToRemote(languageCode, json); System.out.println("Answer: " + result); } @@ -75,10 +72,9 @@ public class ExportMessagesTask implements ToolTask { return configuration.getString(key.getKey(), ""); } - private static String sendJsonToRemote(String file, String code, String language) { + private static String sendJsonToRemote(String language, String json) { try { - String encodedData = "file=" + URLEncoder.encode(file, "UTF-8") - + "&code=" + URLEncoder.encode(code, "UTF-8") + String encodedData = "file=" + URLEncoder.encode(json, "UTF-8") + "&language=" + URLEncoder.encode(language, "UTF-8"); URL url = new URL(UPDATE_URL); diff --git a/src/tools/messages/translation/ImportMessagesTask.java b/src/tools/messages/translation/ImportMessagesTask.java index 36e8c29d..1edcdf04 100644 --- a/src/tools/messages/translation/ImportMessagesTask.java +++ b/src/tools/messages/translation/ImportMessagesTask.java @@ -2,6 +2,7 @@ package messages.translation; import com.google.common.io.Resources; import com.google.gson.Gson; +import fr.xephi.authme.output.MessageKey; import messages.MessageFileVerifier; import messages.VerifyMessagesTask; import org.bukkit.configuration.file.FileConfiguration; @@ -14,7 +15,9 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; +import java.util.HashSet; import java.util.Scanner; +import java.util.Set; import java.util.regex.Pattern; /** @@ -28,6 +31,7 @@ public class ImportMessagesTask implements ToolTask { private static final String MESSAGES_FOLDER = ToolsConstants.MAIN_RESOURCES_ROOT + "messages/"; private Gson gson = new Gson(); + private Set messageCodes; @Override public String getTaskName() { @@ -37,7 +41,8 @@ public class ImportMessagesTask implements ToolTask { @Override public void execute(Scanner scanner) { System.out.println("Enter URL to import from"); - String url = scanner.nextLine(); + // Dirty trick: replace https:// with http:// so we don't have to worry about installing certificates... + String url = scanner.nextLine().replace("https://", "http://"); LanguageExport languageExport = getLanguageExportFromUrl(url); if (languageExport == null) { @@ -62,14 +67,19 @@ public class ImportMessagesTask implements ToolTask { String languageCode = export.code; String fileName = MESSAGES_FOLDER + "messages_" + languageCode + ".yml"; File file = new File(fileName); - if (!file.exists()) { - throw new IllegalStateException("Messages file for language code " + languageCode + " does not exist"); + FileConfiguration fileConfiguration; + if (file.exists()) { + removeAllTodoComments(fileName); + fileConfiguration = AuthMeYamlConfiguration.loadConfiguration(file); + } else { + fileConfiguration = new AuthMeYamlConfiguration(); } - removeAllTodoComments(fileName); - FileConfiguration fileConfiguration = AuthMeYamlConfiguration.loadConfiguration(file); + buildMessageCodeList(); for (MessageExport messageExport : export.messages) { - if (!messageExport.translatedMessage.isEmpty()) { + if (!messageCodes.contains(messageExport.key)) { + throw new IllegalStateException("Message key '" + messageExport.key + "' does not exist"); + } else if (!messageExport.translatedMessage.isEmpty()) { fileConfiguration.set(messageExport.key, messageExport.translatedMessage); } } @@ -84,6 +94,13 @@ public class ImportMessagesTask implements ToolTask { new File(MESSAGES_FOLDER + "messages_en.yml"))); } + private void buildMessageCodeList() { + messageCodes = new HashSet<>(MessageKey.values().length); + for (MessageKey messageKey : MessageKey.values()) { + messageCodes.add(messageKey.getKey()); + } + } + /** * Removes all to-do comments written by {@link VerifyMessagesTask}. This is helpful as the YamlConfiguration * moves those comments otherwise upon saving. From af2d493796c5f86f9c460c2e1958bde79573bdd4 Mon Sep 17 00:00:00 2001 From: Maxetto Date: Tue, 19 Apr 2016 16:57:15 +0200 Subject: [PATCH 49/71] Update messages_it.yml Added new translations, Added Color Codes, Reflect more the English one, Consistency Update between Italian terms, Reordered the lines to reflect the English ones. (cherry picked from commit f747475) --- src/main/resources/messages/messages_it.yml | 108 ++++++++++---------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml index e7c77c89..6361a4c9 100644 --- a/src/main/resources/messages/messages_it.yml +++ b/src/main/resources/messages/messages_it.yml @@ -1,64 +1,64 @@ -#Lingua Italiana creata da Maxetto e sgdc3. -unknown_user: 'L''utente non è presente nel database.' -unsafe_spawn: 'Il tuo punto di disconnessione risulta ostruito o insicuro, sei stato teletrasportato al punto di rigenerazione!' +# Lingua Italiana creata da Maxetto e sgdc3. +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!' not_logged_in: '&cNon hai ancora eseguito l''autenticazione!' reg_voluntarily: 'Puoi eseguire la registrazione al server con il comando: "/register "' usage_log: '&cUtilizzo: /login ' wrong_pwd: '&cPassword non corretta!' -unregistered: '&cSei stato rimosso dal database con successo!' +unregistered: '&2Sei stato correttamente rimosso dal database!' reg_disabled: '&cLa registrazione tramite i comandi di gioco è disabilitata.' -valid_session: '&cAutenticato automaticamente attraverso la precedente sessione!' -login: '&cAutenticazone effettuata correttamente!' -vb_nonActiv: 'Il tuo account non è stato ancora verificato, controlla fra le tue email per scoprire come attivarlo!' +valid_session: '&2Autenticato automaticamente attraverso la precedente sessione!' +login: '&2Autenticazone effettuata correttamente!' +vb_nonActiv: '&cIl tuo account non è stato ancora verificato, controlla fra le tue email per scoprire come attivarlo!' user_regged: '&cHai già effettuato la registrazione, non puoi eseguirla nuovamente.' usage_reg: '&cUtilizzo: /register ' -error: 'Qualcosa è andato storto, riporta questo errore ad un Admin!' -max_reg: 'Hai raggiunto il numero massimo di registrazioni per questo indirizzo IP!' -no_perm: '&cNon hai il permesso di eseguire questa operazione.' -login_msg: '&cPerfavore, esegui l''autenticazione con il comando: "/login "' -reg_msg: '&cPerfavore, esegui la registrazione con il comando: "/register "' -reg_email_msg: '&cPerfavore, esegui la registrazione con il comando: "/register "' +max_reg: '&cHai raggiunto il numero massimo di registrazioni (%reg_count/%max_acc %reg_names) per questo indirizzo IP!' +no_perm: '&4Non hai il permesso di eseguire questa operazione.' +error: '&4Qualcosa è andato storto, riporta questo errore ad un Admin!' +login_msg: '&cPer favore, esegui l''autenticazione con il comando: "/login "' +reg_msg: '&3Per favore, esegui la registrazione con il comando: "/register "' +reg_email_msg: '&3Per favore, esegui la registrazione con il comando: "/register "' usage_unreg: '&cUtilizzo: /unregister ' -pwd_changed: '&cPassword cambiata con successo!' +pwd_changed: '&2Password cambiata correttamente!' user_unknown: '&cL''utente non ha ancora eseguito la registrazione.' -password_error: 'Le Password non corrispondono!' -password_error_nick: 'Non puoi usare il tuo nome utente come password, scegline un''altra!' -password_error_unsafe: 'La password che hai inserito non è sicura, scegline un''altra!' -invalid_session: 'I tuoi dati di connessione attuali non sono quelli utilizzati in precedenza. Attendi la fine della sessione attuale.' -reg_only: 'Puoi giocare in questo server solo dopo aver effettuato la registrazione attraverso il sito web! Perfavore, vai su http://esempio.it per procedere!' -logged_in: '&cHai già eseguito l''autenticazione, non devi eseguirla nuovamente!' -logout: '&cDisconnessione avvenuta correttamente!' -same_nick: 'Questo stesso nome utente è già online sul server!' -registered: '&cRegistrato correttamente!' -pass_len: 'La password che hai inserito è troppo corta o troppo lunga, scegline un''altra!' -reload: 'La configurazione e il database sono stati ricaricati con successo!' -timeout: 'Tempo scaduto per effettuare l''autenticazione' -usage_changepassword: 'Utilizzo: /changepassword ' -name_len: '&cIl tuo nome utente è troppo corto o troppo lungo!' -regex: '&cIl tuo nome utente contiene caratteri non consentiti. I caratteri consentiti sono: REG_EX' -add_email: '&cPer poter recuperare la password in futuro, aggiungi un indirizzo email al tuo account con il comando: "/email add "' -recovery_email: '&cHai dimenticato la tua password? Puoi recuperarla eseguendo il comando: "/email recovery "' -usage_captcha: '&cAbbiamo bisogno che tu inserisca un captcha, perfavore scrivi: "/captcha "' -wrong_captcha: '&cCaptcha sbagliato, perfavore riprova con il comando: "/captcha THE_CAPTCHA"' -valid_captcha: '&cIl captcha inserito è valido!' -kick_forvip: '&cUn utente VIP è entrato mentre il server era pieno e ha preso il tuo posto!' -kick_fullserver: '&cIl server è attualmente pieno, riprova più tardi!' -usage_email_add: '&fUtilizzo: /email add ' -usage_email_change: '&fUtilizzo: /email change ' -usage_email_recovery: '&fUtilizzo: /email recovery ' -new_email_invalid: 'Il nuovo indirizzo email inserito non è valido!' -old_email_invalid: 'Il vecchio indirizzo email inserito non è valido!' -email_invalid: 'L''indirizzo email inserito non è valido' -email_added: 'Indirizzo email aggiunto correttamente!' -email_confirm: 'Conferma il tuo indirizzo email!' -email_changed: 'Indirizzo email cambiato correttamente!' -email_send: 'Una email di recupero è stata appena inviata al tuo indirizzo email!' -email_exists: 'Il tuo account ha già un''indirizzo email configurato. Se vuoi, puoi cambiarlo con il seguente comando:' -country_banned: 'Il tuo paese è bandito da questo server!' -antibot_auto_enabled: 'Il servizio di AntiBot è stato automaticamente abilitato a seguito delle numerose connessioni!' -antibot_auto_disabled: "Il servizio di AntiBot è stato automaticamente disabilitato dopo %m Minuti, sperando che l'attacco sia finito!" -kick_antibot: 'Il servizio di AntiBot è attualmente attivo! Devi aspettare qualche minuto prima di poter entrare nel server.' +password_error: '&cLe password non corrispondono!' +password_error_nick: '&cNon puoi usare il tuo nome utente come password, per favore scegline un''altra...' +password_error_unsafe: '&cLa password che hai inserito non è sicura, per favore scegline un''altra...' +invalid_session: '&cIl tuo indirizzo IP è cambiato e la tua sessione è stata terminata!' +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!' +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!' +timeout: '&4Tempo scaduto per effettuare l''autenticazione, sei stato espulso dal server, per favore riprova!' +usage_changepassword: '&cUtilizzo: /changepassword ' +name_len: '&4Il tuo nome utente è troppo corto o troppo lungo!' +regex: '&4Il tuo nome utente contiene caratteri non consentiti. I caratteri consentiti sono: REG_EX' +add_email: '&3Per poter recuperare la password in futuro, aggiungi un indirizzo email al tuo account con il comando: "/email add "' +recovery_email: '&3Hai dimenticato la tua password? Puoi recuperarla eseguendo il comando: "/email recovery "' +usage_captcha: '&3Per poterti autenticare devi risolvere un captcha, per favore scrivi: "/captcha "' +wrong_captcha: '&cCaptcha sbagliato, per favore riprova scrivendo: "/captcha THE_CAPTCHA" in chat!' +valid_captcha: '&2Il captcha inserito è valido!' +kick_forvip: '&3Un utente VIP è entrato mentre il server era pieno e ha preso il tuo posto!' +kick_fullserver: '&4Il server è attualmente pieno, riprova più tardi!' +usage_email_add: '&cUtilizzo: /email add ' +usage_email_change: '&cUtilizzo: /email change ' +usage_email_recovery: '&cUtilizzo: /email recovery ' +new_email_invalid: '&cIl nuovo indirizzo email inserito non è valido, riprova!' +old_email_invalid: '&cIl vecchio indirizzo email inserito non è valido, riprova!' +email_invalid: '&cL''indirizzo email inserito non è valido, riprova!' +email_added: '&2Indirizzo email aggiunto correttamente al tuo account!' +email_confirm: '&cPer favore, conferma il tuo indirizzo email!' +email_changed: '&2Indirizzo email cambiato correttamente!' +email_send: '&2Una email di recupero è stata appena inviata al tuo indirizzo email!' +email_exists: '&cUna email di recupero è già stata inviata! Se vuoi, puoi annullarla e mandarne un''altra con il seguente comando:' +country_banned: '&4Il tuo paese è bandito da questo server!' +antibot_auto_enabled: '&4Il servizio di AntiBot è stato automaticamente abilitato a seguito delle numerose connessioni!' +antibot_auto_disabled: "&2Il servizio di AntiBot è stato automaticamente disabilitato dopo %m Minuti, sperando che l'attacco sia finito!" +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' -# TODO email_already_used: '&4The email address is already being used' -# 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 try another name!' \ No newline at end of file +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".' From 37fb29f8b9bb6d280970df781394c10e22678501 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 20 Apr 2016 21:22:57 +0200 Subject: [PATCH 50/71] #638 Register with Wordpress fails with SQL exception - Remove semicolon in query, looks like executeBatch() does not like it --- src/main/java/fr/xephi/authme/datasource/MySQL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 236d22e1..5182b859 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -429,7 +429,7 @@ public class MySQL implements DataSource { rs = pst.executeQuery(); if (rs.next()) { int id = rs.getInt(col.ID); - sql = "INSERT INTO " + wordpressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?);"; + sql = "INSERT INTO " + wordpressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?)"; pst2 = con.prepareStatement(sql); // First Name pst2.setInt(1, id); From e81839557568b8a868c3e195c618d4c6f58d945e Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 20 Apr 2016 21:39:13 +0200 Subject: [PATCH 51/71] #667 /authme switchantibot throws NullPointerException - Antibot was not provided to CommandService (from where it's retrieved in the SwitchAntiBot command) because it was initialized afterwards --- src/main/java/fr/xephi/authme/AuthMe.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index bcb45b09..77dd4f2d 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -258,17 +258,13 @@ public class AuthMe extends JavaPlugin { // Initialize spawn loader spawnLoader = new SpawnLoader(getDataFolder(), newSettings, pluginHooks); - - // Set up the permissions manager and command handler bukkitService = new BukkitService(this); permsMan = initializePermissionsManager(); + antiBot = new AntiBot(newSettings, messages, permsMan, bukkitService); ValidationService validationService = new ValidationService(newSettings, database, permsMan); commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService); - // AntiBot delay - antiBot = new AntiBot(newSettings, messages, permsMan, bukkitService); - // Set up Metrics MetricsStarter.setupMetrics(plugin, newSettings); From 00cb01b3bda80a882548197d6d56d4cb28c7e0f4 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 21 Apr 2016 18:05:47 +0200 Subject: [PATCH 52/71] #663 Don't print stacktrace when encountering invalid hash formats --- .../fr/xephi/authme/security/crypts/CryptPBKDF2Django.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java index 14b3e35b..27ca14f8 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java @@ -4,6 +4,7 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.security.crypts.description.AsciiRestricted; import fr.xephi.authme.security.pbkdf2.PBKDF2Engine; import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters; +import fr.xephi.authme.util.StringUtils; import javax.xml.bind.DatatypeConverter; @@ -31,8 +32,8 @@ public class CryptPBKDF2Django extends HexSaltedMethod { try { iterations = Integer.parseInt(line[1]); } catch (NumberFormatException e) { - ConsoleLogger.logException("Could not read number of rounds in '" + hashedPassword.getHash() - + " for CryptPBKDF2Django", e); + ConsoleLogger.showError("Could not read number of rounds for CryptPBKDF2Django:" + + StringUtils.formatException(e)); return false; } String salt = line[2]; From c67527aac03b914bad10a62bcb68ebda36ed0e7e Mon Sep 17 00:00:00 2001 From: games647 Date: Fri, 22 Apr 2016 17:04:46 +0200 Subject: [PATCH 53/71] Fix vanished players are visible after join (Fixes #670) --- .../fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index 03d78a52..138439cd 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -68,7 +68,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { //triggers an update for others player to see them for (Player onlinePlayer : Utils.getOnlinePlayers()) { - if (onlinePlayer.equals(receiver)) { + if (onlinePlayer.equals(receiver) || !receiver.canSee(onlinePlayer)) { continue; } From 2cd43d599d955d3e4eed9687aa749891bc881dc7 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 22 Apr 2016 21:24:17 +0200 Subject: [PATCH 54/71] Minor - MyBB has alphanumerical salts, not restricted to hexadecimal --- src/main/java/fr/xephi/authme/security/crypts/MYBB.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/security/crypts/MYBB.java b/src/main/java/fr/xephi/authme/security/crypts/MYBB.java index 555f3213..32ad154a 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/MYBB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/MYBB.java @@ -19,7 +19,7 @@ public class MYBB extends SeparateSaltMethod { @Override public String generateSalt() { - return RandomString.generateHex(8); + return RandomString.generateLowerUpper(8); } } From 1182b58b990773f0c2c62a0dc01aaf9a1dbf96a9 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 22 Apr 2016 21:55:25 +0200 Subject: [PATCH 55/71] Player listener - migrate legacy setting use to new settings --- .../authme/listener/AuthMePlayerListener.java | 65 ++++++++++--------- .../fr/xephi/authme/settings/Settings.java | 59 +++++------------ 2 files changed, 50 insertions(+), 74 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 2548669e..ecfb6dc0 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -56,6 +56,9 @@ import org.bukkit.event.player.PlayerShearEntityEvent; import java.util.concurrent.ConcurrentHashMap; import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent; +import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_MOVEMENT_RADIUS; +import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_ALL_COMMANDS_IF_REGISTRATION_IS_OPTIONAL; +import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT; /** * Listener class for player events. @@ -90,19 +93,17 @@ public class AuthMePlayerListener implements Listener { final Player player = event.getPlayer(); if (Utils.checkAuth(player)) { - for (Player p : Utils.getOnlinePlayers()) { - if(!settings.getProperty(RestrictionSettings.HIDE_CHAT)) { - break; - } - if (!PlayerCache.getInstance().isAuthenticated(p.getName())) { - event.getRecipients().remove(p); + if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) { + for (Player p : Utils.getOnlinePlayers()) { + if (!PlayerCache.getInstance().isAuthenticated(p.getName())) { + event.getRecipients().remove(p); + } } } - return; + } else { + event.setCancelled(true); + sendLoginOrRegisterMessage(player); } - - event.setCancelled(true); - sendLoginOrRegisterMessage(player); } private void sendLoginOrRegisterMessage(final Player player) { @@ -125,13 +126,14 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { String cmd = event.getMessage().split(" ")[0].toLowerCase(); - if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && cmd.equals("/motd")) { + if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && "/motd".equals(cmd)) { return; } - if (!Settings.isForcedRegistrationEnabled && Settings.allowAllCommandsIfRegIsOptional) { + if (!settings.getProperty(RegistrationSettings.FORCE) + && settings.getProperty(ALLOW_ALL_COMMANDS_IF_REGISTRATION_IS_OPTIONAL)) { return; } - if (Settings.allowCommands.contains(cmd)) { + if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) { return; } if (Utils.checkAuth(event.getPlayer())) { @@ -168,7 +170,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPlayerMove(PlayerMoveEvent event) { - if (Settings.isMovementAllowed && Settings.getMovementRadius <= 0) { + if (settings.getProperty(ALLOW_UNAUTHED_MOVEMENT) && settings.getProperty(ALLOWED_MOVEMENT_RADIUS) <= 0) { return; } @@ -187,17 +189,17 @@ public class AuthMePlayerListener implements Listener { return; } - if (!Settings.isMovementAllowed) { + if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) { event.setTo(event.getFrom()); // sgdc3 TODO: remove this, maybe we should set the effect every x ticks, idk! - if (Settings.isRemoveSpeedEnabled) { + if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) { player.setFlySpeed(0.0f); player.setWalkSpeed(0.0f); } return; } - if (Settings.noTeleport) { + if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { return; } @@ -207,7 +209,7 @@ public class AuthMePlayerListener implements Listener { player.teleport(spawn); return; } - if (spawn.distance(player.getLocation()) > Settings.getMovementRadius) { + if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) { player.teleport(spawn); } } @@ -220,11 +222,11 @@ public class AuthMePlayerListener implements Listener { return; } - if (Settings.removeJoinMessage) { + if (settings.getProperty(RegistrationSettings.REMOVE_JOIN_MESSAGE)) { event.setJoinMessage(null); return; } - if (!Settings.delayJoinMessage) { + if (!settings.getProperty(RegistrationSettings.DELAY_JOIN_MESSAGE)) { return; } @@ -232,11 +234,10 @@ public class AuthMePlayerListener implements Listener { String joinMsg = event.getJoinMessage(); // Remove the join message while the player isn't logging in - if (joinMsg == null) { - return; + if (joinMsg != null) { + event.setJoinMessage(null); + joinMessage.put(name, joinMsg); } - event.setJoinMessage(null); - joinMessage.put(name, joinMsg); } @EventHandler(priority = EventPriority.LOW) @@ -246,7 +247,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (Settings.isForceSurvivalModeEnabled + if (settings.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE) && !player.hasPermission(PlayerStatePermission.BYPASS_FORCE_SURVIVAL.getNode())) { player.setGameMode(GameMode.SURVIVAL); } @@ -264,7 +265,7 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onPreLogin(AsyncPlayerPreLoginEvent event) { PlayerAuth auth = dataSource.getAuth(event.getName()); - if (Settings.preventOtherCase && auth != null && auth.getRealName() != null) { + if (settings.getProperty(RegistrationSettings.PREVENT_OTHER_CASE) && auth != null && auth.getRealName() != null) { String realName = auth.getRealName(); if (!realName.isEmpty() && !realName.equals("Player") && !realName.equals(event.getName())) { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); @@ -297,7 +298,7 @@ public class AuthMePlayerListener implements Listener { final Player player = bukkitService.getPlayerExact(name); // Check if forceSingleSession is set to true, so kick player that has // joined with same nick of online player - if (player != null && Settings.isForceSingleSessionEnabled) { + if (player != null && settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); event.setKickMessage(m.retrieveSingle(MessageKey.USERNAME_ALREADY_ONLINE_ERROR)); LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); @@ -354,7 +355,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (Settings.isKickNonRegisteredEnabled && !isAuthAvailable) { + if (settings.getProperty(RestrictionSettings.KICK_NON_REGISTERED) && !isAuthAvailable) { event.setKickMessage(m.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE)); event.setResult(PlayerLoginEvent.Result.KICK_OTHER); return; @@ -374,7 +375,7 @@ public class AuthMePlayerListener implements Listener { antiBot.checkAntiBot(player); - if (Settings.bungee) { + if (settings.getProperty(HooksSettings.BUNGEECORD)) { ByteArrayDataOutput out = ByteStreams.newDataOutput(); out.writeUTF("IP"); player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); @@ -389,7 +390,7 @@ public class AuthMePlayerListener implements Listener { return; } - if (Settings.removeLeaveMessage) { + if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) { event.setQuitMessage(null); } @@ -404,8 +405,8 @@ public class AuthMePlayerListener implements Listener { return; } - if ((!Settings.isForceSingleSessionEnabled) - && (event.getReason().equals(m.retrieveSingle(MessageKey.USERNAME_ALREADY_ONLINE_ERROR)))) { + if (!settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION) + && event.getReason().equals(m.retrieveSingle(MessageKey.USERNAME_ALREADY_ONLINE_ERROR))) { event.setCancelled(true); return; } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index f448adee..2f865b49 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -29,34 +29,25 @@ public final class Settings { public static List getForcedWorlds; public static List countries; public static List countriesBlacklist; - public static List forceRegisterCommands; - public static List forceRegisterCommandsAsConsole; public static HashAlgorithm getPasswordHash; public static Pattern nickPattern; public static boolean isChatAllowed, isPermissionCheckEnabled, isForcedRegistrationEnabled, isTeleportToSpawnEnabled, - isSessionsEnabled, isAllowRestrictedIp, - isMovementAllowed, isKickNonRegisteredEnabled, + isSessionsEnabled, isAllowRestrictedIp, isMovementAllowed, isForceSingleSessionEnabled, isForceSpawnLocOnJoinEnabled, - isSaveQuitLocationEnabled, isForceSurvivalModeEnabled, - protectInventoryBeforeLogInEnabled, isStopEnabled, reloadSupport, - rakamakUseIp, noConsoleSpam, removePassword, displayOtherAccounts, - emailRegistration, multiverse, bungee, - banUnsafeIp, sessionExpireOnIpChange, useEssentialsMotd, - enableProtection, recallEmail, useWelcomeMessage, - broadcastWelcomeMessage, forceRegKick, forceRegLogin, - removeJoinMessage, removeLeaveMessage, delayJoinMessage, - noTeleport, allowAllCommandsIfRegIsOptional, - isRemoveSpeedEnabled, preventOtherCase, hideChat; + isSaveQuitLocationEnabled, protectInventoryBeforeLogInEnabled, + isStopEnabled, reloadSupport, rakamakUseIp, noConsoleSpam, + removePassword, displayOtherAccounts, emailRegistration, + multiverse, bungee, banUnsafeIp, sessionExpireOnIpChange, + enableProtection, recallEmail, forceRegLogin, noTeleport, + allowAllCommandsIfRegIsOptional, isRemoveSpeedEnabled; public static String getNickRegex, getUnloggedinGroup, unRegisteredGroup, backupWindowsPath, getRegisteredGroup, - rakamakUsers, rakamakUsersIp, defaultWorld, - spawnPriority, crazyloginFileName; + rakamakUsers, rakamakUsersIp, defaultWorld, crazyloginFileName; public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength, getMinNickLength, - getMovementRadius, getNonActivatedGroup, - maxLoginTry, captchaLength, saltLength, - bCryptLog2Rounds, getMaxLoginPerIp, getMaxJoinPerIp; + getNonActivatedGroup, maxLoginTry, captchaLength, saltLength, + bCryptLog2Rounds, getMaxLoginPerIp; protected static FileConfiguration configFile; /** @@ -71,7 +62,7 @@ public final class Settings { private static void loadVariables() { isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK); - isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true); + isForcedRegistrationEnabled = load(RegistrationSettings.FORCE); isTeleportToSpawnEnabled = load(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN); getWarnMessageInterval = load(RegistrationSettings.MESSAGE_INTERVAL); isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED); @@ -83,14 +74,11 @@ public final class Settings { getNickRegex = configFile.getString("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_?]*"); nickPattern = Pattern.compile(getNickRegex); isAllowRestrictedIp = load(RestrictionSettings.ENABLE_RESTRICTED_USERS); - isMovementAllowed = configFile.getBoolean("settings.restrictions.allowMovement", false); - isRemoveSpeedEnabled = configFile.getBoolean("settings.restrictions.removeSpeed", true); - getMovementRadius = configFile.getInt("settings.restrictions.allowedMovementRadius", 100); - isKickNonRegisteredEnabled = configFile.getBoolean("settings.restrictions.kickNonRegistered", false); - isForceSingleSessionEnabled = configFile.getBoolean("settings.restrictions.ForceSingleSession", true); - isForceSpawnLocOnJoinEnabled = configFile.getBoolean("settings.restrictions.ForceSpawnLocOnJoinEnabled", false); + isMovementAllowed = load(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT); + isRemoveSpeedEnabled = load(RestrictionSettings.REMOVE_SPEED); + isForceSingleSessionEnabled = load(RestrictionSettings.FORCE_SINGLE_SESSION); + isForceSpawnLocOnJoinEnabled = load(RestrictionSettings.FORCE_SPAWN_LOCATION_AFTER_LOGIN); isSaveQuitLocationEnabled = configFile.getBoolean("settings.restrictions.SaveQuitLocation", false); - isForceSurvivalModeEnabled = configFile.getBoolean("settings.GameMode.ForceSurvivalMode", false); getPasswordHash = load(SecuritySettings.PASSWORD_HASH); getUnloggedinGroup = load(SecuritySettings.UNLOGGEDIN_GROUP); getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1); @@ -107,7 +95,7 @@ public final class Settings { isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true); reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); - allowAllCommandsIfRegIsOptional = configFile.getBoolean("settings.restrictions.allowAllCommandsIfRegistrationIsOptional", false); + allowAllCommandsIfRegIsOptional = load(RestrictionSettings.ALLOW_ALL_COMMANDS_IF_REGISTRATION_IS_OPTIONAL); allowCommands = new ArrayList<>(); allowCommands.addAll(Arrays.asList("/login", "/l", "/register", "/reg", "/email", "/captcha")); for (String cmd : configFile.getStringList("settings.restrictions.allowCommands")) { @@ -128,33 +116,20 @@ public final class Settings { emailRegistration = load(RegistrationSettings.USE_EMAIL_REGISTRATION); saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8); multiverse = load(HooksSettings.MULTIVERSE); - bungee = configFile.getBoolean("Hooks.bungeecord", false); + bungee = load(HooksSettings.BUNGEECORD); getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds"); banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false); sessionExpireOnIpChange = configFile.getBoolean("settings.sessions.sessionExpireOnIpChange", true); bCryptLog2Rounds = configFile.getInt("ExternalBoardOptions.bCryptLog2Round", 10); - useEssentialsMotd = configFile.getBoolean("Hooks.useEssentialsMotd", false); defaultWorld = configFile.getString("Purge.defaultWorld", "world"); enableProtection = configFile.getBoolean("Protection.enableProtection", false); countries = configFile.getStringList("Protection.countries"); recallEmail = configFile.getBoolean("Email.recallPlayers", false); - useWelcomeMessage = load(RegistrationSettings.USE_WELCOME_MESSAGE); countriesBlacklist = configFile.getStringList("Protection.countriesBlacklist"); - broadcastWelcomeMessage = load(RegistrationSettings.BROADCAST_WELCOME_MESSAGE); - forceRegKick = configFile.getBoolean("settings.registration.forceKickAfterRegister", false); forceRegLogin = load(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER); - spawnPriority = load(RestrictionSettings.SPAWN_PRIORITY); getMaxLoginPerIp = load(RestrictionSettings.MAX_LOGIN_PER_IP); - getMaxJoinPerIp = load(RestrictionSettings.MAX_JOIN_PER_IP); - removeJoinMessage = load(RegistrationSettings.REMOVE_JOIN_MESSAGE); - removeLeaveMessage = load(RegistrationSettings.REMOVE_LEAVE_MESSAGE); - delayJoinMessage = load(RegistrationSettings.DELAY_JOIN_MESSAGE); noTeleport = load(RestrictionSettings.NO_TELEPORT); crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db"); - forceRegisterCommands = configFile.getStringList("settings.forceRegisterCommands"); - forceRegisterCommandsAsConsole = configFile.getStringList("settings.forceRegisterCommandsAsConsole"); - preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); - hideChat = load(RestrictionSettings.HIDE_CHAT); } /** From 0dab8878483ab321a09945a6fa2008da1f0c5b0c Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 23 Apr 2016 00:18:03 +0200 Subject: [PATCH 56/71] Code householding - Various migrations from legacy settings to new settings - PlayerListener: use shouldCancelEvent() to see if chat should be canceled - Merge permission manager listener with general server listener --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- .../authme/command/CommandInitializer.java | 2 +- .../authme/listener/AuthMePlayerListener.java | 22 +++-- .../authme/listener/AuthMeServerListener.java | 6 ++ .../authme/permission/PermissionsManager.java | 59 +++---------- .../PermissionsManagerBukkitListener.java | 85 ------------------- .../authme/process/join/AsynchronousJoin.java | 43 +++++----- .../process/login/AsynchronousLogin.java | 8 +- .../fr/xephi/authme/settings/Settings.java | 19 ++--- .../properties/RestrictionSettings.java | 4 +- 10 files changed, 63 insertions(+), 187 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/permission/PermissionsManagerBukkitListener.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 77dd4f2d..3b037bfb 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -614,7 +614,7 @@ public class AuthMe extends JavaPlugin { * Set up the permissions manager. */ private PermissionsManager initializePermissionsManager() { - PermissionsManager manager = new PermissionsManager(Bukkit.getServer(), this, getLogger()); + PermissionsManager manager = new PermissionsManager(Bukkit.getServer(), getLogger()); manager.setup(); return manager; } diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index b4150ade..6635545f 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -271,7 +271,7 @@ public final class CommandInitializer { CommandDescription.builder() .parent(AUTHME_BASE) .labels("converter", "convert", "conv") - .description("Converter Command") + .description("Converter command") .detailedDescription("Converter command for AuthMeReloaded.") .withArgument("job", "Conversion job: xauth / crazylogin / rakamak / " + "royalauth / vauth / sqlitetosql", false) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index ecfb6dc0..87399a7a 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -75,8 +75,8 @@ public class AuthMePlayerListener implements Listener { private final Management management; private final BukkitService bukkitService; - public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource, AntiBot antiBot, - Management management, BukkitService bukkitService) { + public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource, + AntiBot antiBot, Management management, BukkitService bukkitService) { this.plugin = plugin; this.settings = settings; this.m = messages; @@ -92,17 +92,15 @@ public class AuthMePlayerListener implements Listener { } final Player player = event.getPlayer(); - if (Utils.checkAuth(player)) { - if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) { - for (Player p : Utils.getOnlinePlayers()) { - if (!PlayerCache.getInstance().isAuthenticated(p.getName())) { - event.getRecipients().remove(p); - } - } - } - } else { + if (shouldCancelEvent(player)) { event.setCancelled(true); sendLoginOrRegisterMessage(player); + } else if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) { + for (Player p : Utils.getOnlinePlayers()) { + if (!PlayerCache.getInstance().isAuthenticated(p.getName())) { + event.getRecipients().remove(p); + } + } } } @@ -349,7 +347,7 @@ public class AuthMePlayerListener implements Listener { final String name = player.getName().toLowerCase(); boolean isAuthAvailable = dataSource.isAuthAvailable(name); - if (antiBot.getAntiBotStatus()==AntiBotStatus.ACTIVE && !isAuthAvailable) { + if (antiBot.getAntiBotStatus() == AntiBotStatus.ACTIVE && !isAuthAvailable) { event.setKickMessage(m.retrieveSingle(MessageKey.KICK_ANTIBOT)); event.setResult(PlayerLoginEvent.Result.KICK_OTHER); return; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index d0f16357..ec8326b5 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -52,6 +52,9 @@ public class AuthMeServerListener implements Listener { return; } + // Call the onPluginDisable method in the permissions manager + plugin.getPermissionsManager().onPluginDisable(event); + final String pluginName = event.getPlugin().getName(); if ("Essentials".equalsIgnoreCase(pluginName)) { pluginHooks.unhookEssentials(); @@ -82,6 +85,9 @@ public class AuthMeServerListener implements Listener { return; } + // Call the onPluginEnable method in the permissions manager + plugin.getPermissionsManager().onPluginEnable(event); + final String pluginName = event.getPlugin().getName(); if ("Essentials".equalsIgnoreCase(pluginName)) { pluginHooks.tryHookToEssentials(); diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index 5805b8d6..ee27f82c 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -1,11 +1,10 @@ package fr.xephi.authme.permission; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - +import de.bananaco.bpermissions.api.ApiLayer; +import de.bananaco.bpermissions.api.CalculableType; +import fr.xephi.authme.command.CommandDescription; +import fr.xephi.authme.util.CollectionUtils; +import net.milkbowl.vault.permission.Permission; import org.anjocaido.groupmanager.GroupManager; import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; import org.bukkit.Bukkit; @@ -18,15 +17,15 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.RegisteredServiceProvider; import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; - -import de.bananaco.bpermissions.api.ApiLayer; -import de.bananaco.bpermissions.api.CalculableType; -import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.util.CollectionUtils; -import net.milkbowl.vault.permission.Permission; import ru.tehkode.permissions.PermissionUser; import ru.tehkode.permissions.bukkit.PermissionsEx; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + /** *

* PermissionsManager. @@ -49,18 +48,10 @@ public class PermissionsManager implements PermissionsService { * Server instance. */ private final Server server; - /** - * Plugin instance. - */ - private final Plugin plugin; /** * Logger instance. */ private Logger log; - /** - * The permissions manager Bukkit listener instance. - */ - private PermissionsManagerBukkitListener bukkitListener; /** * Type of permissions system that is currently used. * Null if no permissions system is hooked and/or used. @@ -79,28 +70,11 @@ public class PermissionsManager implements PermissionsService { * Constructor. * * @param server Server instance - * @param plugin Plugin instance * @param log Logger */ - public PermissionsManager(Server server, Plugin plugin, Logger log) { + public PermissionsManager(Server server, Logger log) { this.server = server; - this.plugin = plugin; this.log = log; - - // Create and register the Bukkit listener on the server if it's valid - if(this.server != null) { - // Create the Bukkit listener - this.bukkitListener = new PermissionsManagerBukkitListener(this); - - // Get the plugin manager instance - PluginManager pluginManager = this.server.getPluginManager(); - - // Register the Bukkit listener - pluginManager.registerEvents(this.bukkitListener, this.plugin); - - // Show a status message. - //this.log.info("Started permission plugins state listener!"); - } } /** @@ -282,15 +256,6 @@ public class PermissionsManager implements PermissionsService { } } - /** - * Get the permissions manager Bukkit listener instance. - * - * @return Listener instance. - */ - public PermissionsManagerBukkitListener getListener() { - return this.bukkitListener; - } - /** * 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. diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManagerBukkitListener.java b/src/main/java/fr/xephi/authme/permission/PermissionsManagerBukkitListener.java deleted file mode 100644 index d87f1b3c..00000000 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManagerBukkitListener.java +++ /dev/null @@ -1,85 +0,0 @@ -package fr.xephi.authme.permission; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.event.server.PluginEnableEvent; - -public class PermissionsManagerBukkitListener implements Listener { - - /** - * The permissions manager instance. - */ - private PermissionsManager permissionsManager; - - /** - * Whether the listener is enabled or not. - */ - private boolean enabled = true; - - /** - * Constructor.\ - * - * @param permissionsManager Permissions manager instance. - */ - public PermissionsManagerBukkitListener(PermissionsManager permissionsManager) { - this.permissionsManager = permissionsManager; - } - - /** - * Check whether the listener is enabled. - * - * @return True if the listener is enabled. - */ - public boolean isEnabled() { - return this.enabled; - } - - /** - * Set whether the listener is enabled. - * Disabling the listener will stop the event handling until it's enabled again. - * - * @param enabled True if enabled, false if disabled. - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - /** - * Called when a plugin is enabled. - * - * @param event Event reference. - */ - @EventHandler - public void onPluginEnable(PluginEnableEvent event) { - // Make sure the listener is enabled - if(!isEnabled()) - return; - - // Make sure the permissions manager is set - if(this.permissionsManager == null) - return; - - // Call the onPluginEnable method in the permissions manager - permissionsManager.onPluginEnable(event); - } - - /** - * Called when a plugin is disabled. - * - * @param event Event reference. - */ - @EventHandler - public void onPluginDisable(PluginDisableEvent event) { - // Make sure the listener is enabled - if(!isEnabled()) - return; - - // Make sure the permissions manager is set - if(this.permissionsManager == null) - return; - - // Call the onPluginDisable method in the permissions manager - permissionsManager.onPluginDisable(event); - } -} 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 60081984..4e276867 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -14,26 +14,26 @@ import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.Process; import fr.xephi.authme.process.ProcessService; -import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.TimeoutTask; import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils.GroupType; - +import org.apache.commons.lang.reflect.MethodUtils; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.entity.Player; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitTask; -import org.apache.commons.lang.reflect.MethodUtils; +import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; /** */ @@ -70,13 +70,13 @@ public class AsynchronousJoin implements Process { } final String ip = Utils.getPlayerIp(player); - if (isNameRestricted(name, ip, player.getAddress().getHostName(), service.getSettings())) { + if (isNameRestricted(name, ip, player.getAddress().getHostName())) { service.scheduleSyncDelayedTask(new Runnable() { @Override public void run() { AuthMePlayerListener.causeByAuthMe.putIfAbsent(name, true); player.kickPlayer(service.retrieveSingleMessage(MessageKey.NOT_OWNER_ERROR)); - if (Settings.banUnsafeIp) { + if (service.getProperty(RestrictionSettings.BAN_UNKNOWN_IP)) { plugin.getServer().banIP(ip); } } @@ -87,7 +87,7 @@ public class AsynchronousJoin implements Process { && !plugin.getPermissionsManager().hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) && !"127.0.0.1".equalsIgnoreCase(ip) && !"localhost".equalsIgnoreCase(ip) - && hasJoinedIp(player.getName(), ip, service.getSettings())) { + && hasJoinedIp(player.getName(), ip)) { service.scheduleSyncDelayedTask(new Runnable() { @Override public void run() { @@ -103,7 +103,7 @@ public class AsynchronousJoin implements Process { final Location spawnLoc = service.getSpawnLoader().getSpawnLocation(player); final boolean isAuthAvailable = database.isAuthAvailable(name); if (isAuthAvailable) { - if (!Settings.noTeleport) { + if (!service.getProperty(RestrictionSettings.NO_TELEPORT)) { if (Settings.isTeleportToSpawnEnabled || (Settings.isForceSpawnLocOnJoinEnabled && Settings.getForcedWorlds.contains(player.getWorld().getName()))) { service.scheduleSyncDelayedTask(new Runnable() { @Override @@ -122,12 +122,12 @@ public class AsynchronousJoin implements Process { LimboCache.getInstance().updateLimboPlayer(player); // protect inventory - if (Settings.protectInventoryBeforeLogInEnabled && plugin.inventoryProtector != null) { + if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN) && plugin.inventoryProtector != null) { ProtectInventoryEvent ev = new ProtectInventoryEvent(player); plugin.getServer().getPluginManager().callEvent(ev); if (ev.isCancelled()) { plugin.inventoryProtector.sendInventoryPacket(player); - if (!Settings.noConsoleSpam) { + if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + "..."); } } @@ -145,7 +145,7 @@ public class AsynchronousJoin implements Process { service.send(player, MessageKey.SESSION_RECONNECTION); plugin.getManagement().performLogin(player, "dontneed", true); return; - } else if (Settings.sessionExpireOnIpChange) { + } else if (service.getProperty(PluginSettings.SESSIONS_EXPIRE_ON_IP_CHANGE)) { service.send(player, MessageKey.SESSION_EXPIRED); } } @@ -153,7 +153,7 @@ public class AsynchronousJoin implements Process { if (!Settings.unRegisteredGroup.isEmpty()) { Utils.setGroup(player, Utils.GroupType.UNREGISTERED); } - if (!Settings.isForcedRegistrationEnabled) { + if (!service.getProperty(RegistrationSettings.FORCE)) { return; } @@ -184,7 +184,8 @@ public class AsynchronousJoin implements Process { @Override public void run() { player.setOp(false); - if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { + if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) + && service.getProperty(RestrictionSettings.REMOVE_SPEED)) { player.setFlySpeed(0.0f); player.setWalkSpeed(0.0f); } @@ -211,7 +212,7 @@ public class AsynchronousJoin implements Process { if (isAuthAvailable) { msg = MessageKey.LOGIN_MESSAGE; } else { - msg = Settings.emailRegistration + msg = service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION) ? MessageKey.REGISTER_EMAIL_MESSAGE : MessageKey.REGISTER_MESSAGE; } @@ -277,24 +278,22 @@ public class AsynchronousJoin implements Process { * @param name The name to check * @param ip The IP address of the player * @param domain The hostname of the IP address - * @param settings The settings instance * @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 */ - private static boolean isNameRestricted(String name, String ip, String domain, NewSetting settings) { - if (!settings.getProperty(RestrictionSettings.ENABLE_RESTRICTED_USERS)) { + private boolean isNameRestricted(String name, String ip, String domain) { + if (!service.getProperty(RestrictionSettings.ENABLE_RESTRICTED_USERS)) { return false; } boolean nameFound = false; - for (String entry : settings.getProperty(RestrictionSettings.ALLOWED_RESTRICTED_USERS)) { + for (String entry : service.getProperty(RestrictionSettings.ALLOWED_RESTRICTED_USERS)) { String[] args = entry.split(";"); String testName = args[0]; String testIp = args[1]; if (testName.equalsIgnoreCase(name)) { nameFound = true; - if ((ip != null && testIp.equals(ip)) - || (domain != null && testIp.equalsIgnoreCase(domain))) { + if ((ip != null && testIp.equals(ip)) || (domain != null && testIp.equalsIgnoreCase(domain))) { return false; } } @@ -302,7 +301,7 @@ public class AsynchronousJoin implements Process { return nameFound; } - private boolean hasJoinedIp(String name, String ip, NewSetting settings) { + private boolean hasJoinedIp(String name, String ip) { int count = 0; for (Player player : Utils.getOnlinePlayers()) { if (ip.equalsIgnoreCase(Utils.getPlayerIp(player)) @@ -310,6 +309,6 @@ public class AsynchronousJoin implements Process { count++; } } - return count >= settings.getProperty(RestrictionSettings.MAX_JOIN_PER_IP); + return count >= service.getProperty(RestrictionSettings.MAX_JOIN_PER_IP); } } diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java index 4368fd83..98a49be7 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -17,6 +17,7 @@ import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.security.RandomString; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; @@ -166,11 +167,12 @@ public class AsynchronousLogin implements Process { displayOtherAccounts(auth); - if (Settings.recallEmail && (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email))) { + if (service.getProperty(EmailSettings.RECALL_PLAYERS) + && (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email))) { service.send(player, MessageKey.ADD_EMAIL_MESSAGE); } - if (!Settings.noConsoleSpam) { + if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info(realName + " logged in!"); } @@ -212,7 +214,7 @@ public class AsynchronousLogin implements Process { } private void displayOtherAccounts(PlayerAuth auth) { - if (!Settings.displayOtherAccounts || auth == null) { + if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS) || auth == null) { return; } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 2f865b49..7b6ce411 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -31,15 +31,14 @@ public final class Settings { public static List countriesBlacklist; public static HashAlgorithm getPasswordHash; public static Pattern nickPattern; - public static boolean isChatAllowed, isPermissionCheckEnabled, + public static boolean isPermissionCheckEnabled, isForcedRegistrationEnabled, isTeleportToSpawnEnabled, - isSessionsEnabled, isAllowRestrictedIp, isMovementAllowed, + isSessionsEnabled, isAllowRestrictedIp, isForceSingleSessionEnabled, isForceSpawnLocOnJoinEnabled, isSaveQuitLocationEnabled, protectInventoryBeforeLogInEnabled, - isStopEnabled, reloadSupport, rakamakUseIp, noConsoleSpam, - removePassword, displayOtherAccounts, emailRegistration, - multiverse, bungee, banUnsafeIp, sessionExpireOnIpChange, - enableProtection, recallEmail, forceRegLogin, noTeleport, + isStopEnabled, reloadSupport, rakamakUseIp, + removePassword, multiverse, bungee, + enableProtection, forceRegLogin, noTeleport, allowAllCommandsIfRegIsOptional, isRemoveSpeedEnabled; public static String getNickRegex, getUnloggedinGroup, unRegisteredGroup, backupWindowsPath, getRegisteredGroup, @@ -68,13 +67,11 @@ public final class Settings { isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED); getSessionTimeout = configFile.getInt("settings.sessions.timeout", 10); getRegistrationTimeout = load(RestrictionSettings.TIMEOUT); - isChatAllowed = load(RestrictionSettings.ALLOW_CHAT); getMaxNickLength = configFile.getInt("settings.restrictions.maxNicknameLength", 20); getMinNickLength = configFile.getInt("settings.restrictions.minNicknameLength", 3); getNickRegex = configFile.getString("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_?]*"); nickPattern = Pattern.compile(getNickRegex); isAllowRestrictedIp = load(RestrictionSettings.ENABLE_RESTRICTED_USERS); - isMovementAllowed = load(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT); isRemoveSpeedEnabled = load(RestrictionSettings.REMOVE_SPEED); isForceSingleSessionEnabled = load(RestrictionSettings.FORCE_SINGLE_SESSION); isForceSpawnLocOnJoinEnabled = load(RestrictionSettings.FORCE_SPAWN_LOCATION_AFTER_LOGIN); @@ -108,23 +105,17 @@ public final class Settings { rakamakUsers = configFile.getString("Converter.Rakamak.fileName", "users.rak"); rakamakUsersIp = configFile.getString("Converter.Rakamak.ipFileName", "UsersIp.rak"); rakamakUseIp = configFile.getBoolean("Converter.Rakamak.useIp", false); - noConsoleSpam = load(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE); removePassword = configFile.getBoolean("Security.console.removePassword", true); - displayOtherAccounts = configFile.getBoolean("settings.restrictions.displayOtherAccounts", true); maxLoginTry = configFile.getInt("Security.captcha.maxLoginTry", 5); captchaLength = configFile.getInt("Security.captcha.captchaLength", 5); - emailRegistration = load(RegistrationSettings.USE_EMAIL_REGISTRATION); saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8); multiverse = load(HooksSettings.MULTIVERSE); bungee = load(HooksSettings.BUNGEECORD); getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds"); - banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false); - sessionExpireOnIpChange = configFile.getBoolean("settings.sessions.sessionExpireOnIpChange", true); bCryptLog2Rounds = configFile.getInt("ExternalBoardOptions.bCryptLog2Round", 10); defaultWorld = configFile.getString("Purge.defaultWorld", "world"); enableProtection = configFile.getBoolean("Protection.enableProtection", false); countries = configFile.getStringList("Protection.countries"); - recallEmail = configFile.getBoolean("Email.recallPlayers", false); countriesBlacklist = configFile.getStringList("Protection.countriesBlacklist"); forceRegLogin = load(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER); getMaxLoginPerIp = load(RestrictionSettings.MAX_LOGIN_PER_IP); 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 72cb8a9b..134f9e17 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java @@ -18,13 +18,13 @@ public class RestrictionSettings implements SettingsClass { public static final Property ALLOW_CHAT = newProperty("settings.restrictions.allowChat", false); - @Comment("Can not authenticated players see the chat log?") + @Comment("Hide the chat log from players who are not authenticated?") public static final Property HIDE_CHAT = newProperty("settings.restrictions.hideChat", false); @Comment({ "Allow unlogged users to use all the commands if registration is not forced!", - "WARNING: use this only if you need it!)"}) + "WARNING: use this only if you need it!"}) public static final Property ALLOW_ALL_COMMANDS_IF_REGISTRATION_IS_OPTIONAL = newProperty("settings.restrictions.allowAllCommandsIfRegistrationIsOptional", false); From 229c8429cbeb9c2cfb5d08e48c5d1712f837cf27 Mon Sep 17 00:00:00 2001 From: Very Evil Olaf Date: Sat, 23 Apr 2016 08:37:46 +0200 Subject: [PATCH 57/71] Minor fixes Some grammar stuff and eye candy --- src/main/resources/messages/messages_de.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/resources/messages/messages_de.yml b/src/main/resources/messages/messages_de.yml index 04345292..df6d96a4 100644 --- a/src/main/resources/messages/messages_de.yml +++ b/src/main/resources/messages/messages_de.yml @@ -1,5 +1,5 @@ unknown_user: '&cBenutzer ist nicht in der Datenbank' -unsafe_spawn: '&cDeine Logoutposition war unsicher, Du wurdest zum Spawn teleportiert' +unsafe_spawn: '&cDeine Logoutposition war unsicher, du wurdest zum Spawn teleportiert' not_logged_in: '&cNicht eingeloggt!' reg_voluntarily: 'Du kannst dich mit folgendem Befehl registrieren "/register "' usage_log: '&cBenutze: /login ' @@ -21,10 +21,10 @@ usage_unreg: '&cBenutze: /unregister ' pwd_changed: '&2Passwort geändert!' user_unknown: '&cBenutzername nicht registriert!' password_error: '&cPasswörter stimmen nicht überein!' -password_error_nick: '&cDu kannst nicht Deinen Namen als Passwort nutzen!' -password_error_unsafe: '&cDu kannst nicht unsichere Passwörter nutzen!' -invalid_session: '&cUngültige Session. Bitte starte das Spiel neu oder warte, bis die Session abgelaufen ist' -reg_only: '&4Nur für registrierte Spieler! Bitte besuche http://example.com zum Registrieren' +password_error_nick: '&cDu kannst deinen Namen nicht als Passwort verwenden!' +password_error_unsafe: '&cPasswort unsicher! Bitte wähle ein anderes.' +invalid_session: '&cUngültige Session. Bitte starte das Spiel neu oder warte, bis die Session abgelaufen ist.' +reg_only: '&4Nur für registrierte Spieler! Bitte besuche http://example.com um dich zu registrieren.' logged_in: '&cBereits eingeloggt!' logout: '&2Erfolgreich ausgeloggt' same_nick: '&4Jemand mit diesem Namen spielt bereits auf dem Server!' @@ -34,8 +34,8 @@ reload: '&2Konfiguration und Datenbank wurden erfolgreich neu geladen.' timeout: '&4Zeitüberschreitung beim Login' usage_changepassword: '&cBenutze: /changepassword ' name_len: '&4Dein Nickname ist zu kurz oder zu lang.' -regex: '&4Dein Nickname enthält nicht erlaubte Zeichen. Zulässige Zeichen: REG_EX' -add_email: '&3Bitte hinterlege Deine E-Mail-Adresse: /email add ' +regex: '&4Dein Nickname enthält unerlaubte Zeichen. Zulässige Zeichen: REG_EX' +add_email: '&3Bitte hinterlege deine E-Mail-Adresse: /email add ' recovery_email: '&3Passwort vergessen? Nutze "/email recovery " für ein neues Passwort' usage_captcha: '&3Um dich einzuloggen, tippe dieses Captcha so ein: /captcha ' wrong_captcha: '&cFalsches Captcha, bitte nutze: /captcha THE_CAPTCHA' From ee745f153d11544955996246312b48bf8068f4e4 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 23 Apr 2016 11:06:33 +0200 Subject: [PATCH 58/71] messages_de consistency: Lowercase all occurrences of "du" --- src/main/resources/messages/messages_de.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/resources/messages/messages_de.yml b/src/main/resources/messages/messages_de.yml index df6d96a4..4cc59867 100644 --- a/src/main/resources/messages/messages_de.yml +++ b/src/main/resources/messages/messages_de.yml @@ -1,22 +1,22 @@ unknown_user: '&cBenutzer ist nicht in der Datenbank' unsafe_spawn: '&cDeine Logoutposition war unsicher, du wurdest zum Spawn teleportiert' not_logged_in: '&cNicht eingeloggt!' -reg_voluntarily: 'Du kannst dich mit folgendem Befehl registrieren "/register "' +reg_voluntarily: 'Du kannst dich mit folgendem Befehl registrieren: "/register "' usage_log: '&cBenutze: /login ' wrong_pwd: '&cFalsches Passwort' unregistered: '&cBenutzerkonto erfolgreich gelöscht!' reg_disabled: '&cRegistrierungen sind deaktiviert' valid_session: '&2Erfolgreich eingeloggt!' login: '&2Erfolgreich eingeloggt!' -vb_nonActiv: '&cDein Account wurde noch nicht aktiviert. Bitte prüfe Deine E-Mails!' +vb_nonActiv: '&cDein Account wurde noch nicht aktiviert. Bitte prüfe deine E-Mails!' user_regged: '&cDieser Benutzername ist schon vergeben' usage_reg: '&cBenutze: /register ' -max_reg: '&cDu hast die maximale Anzahl an Accounts erreicht.' +max_reg: '&cDu hast die maximale Anzahl an Accounts erreicht (%max_acc/%reg_count).' no_perm: '&4Du hast keine Rechte, um diese Aktion auszuführen!' error: '&4Ein Fehler ist aufgetreten. Bitte kontaktiere einen Administrator.' -login_msg: '&cBitte logge Dich ein mit "/login "' -reg_msg: '&3Bitte registriere Dich mit "/register "' -reg_email_msg: '&3Bitte registriere Dich mit "/register "' +login_msg: '&cBitte logge dich ein mit "/login "' +reg_msg: '&3Bitte registriere dich mit "/register "' +reg_email_msg: '&3Bitte registriere dich mit "/register "' usage_unreg: '&cBenutze: /unregister ' pwd_changed: '&2Passwort geändert!' user_unknown: '&cBenutzername nicht registriert!' @@ -49,14 +49,14 @@ new_email_invalid: '&cDie neue E-Mail ist ungültig!' old_email_invalid: '&cDie alte E-Mail ist ungültig!' email_invalid: '&cUngültige E-Mail!' email_added: '&2E-Mail hinzugefügt!' -email_confirm: '&cBitte bestätige Deine E-Mail!' +email_confirm: '&cBitte bestätige deine E-Mail!' email_changed: '&2E-Mail aktualisiert!' email_send: '&2Wiederherstellungs-E-Mail wurde gesendet!' email_exists: '&cEine Wiederherstellungs-E-Mail wurde bereits versandt! Nutze folgenden Befehl um eine neue E-Mail zu versenden:' country_banned: '&4Dein Land ist gesperrt!' antibot_auto_enabled: '&4[AntiBotService] AntiBotMod wurde aufgrund hoher Netzauslastung automatisch aktiviert!' antibot_auto_disabled: '&2[AntiBotService] AntiBotMod wurde nach %m Minuten deaktiviert, hoffentlich ist die Invasion vorbei.' -kick_antibot: 'AntiBotMod ist aktiviert! Bitte warte einige Minuten, bevor Du Dich mit dem Server verbindest.' +kick_antibot: 'AntiBotMod ist aktiviert! Bitte warte einige Minuten, bevor du dich mit dem Server verbindest.' two_factor_create: '&2Dein geheimer Code ist %code. Du kannst ihn hier abfragen: %url' email_already_used: '&4Diese E-Mail-Adresse wird bereits genutzt.' invalid_name_case: 'Dein registrierter Benutzername ist &2%valid&f - nicht &4%invalid&f.' From a78e0408c623cca2156ff8e4a51a9af546712122 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 23 Apr 2016 12:46:30 +0200 Subject: [PATCH 59/71] #449 Remove use of legacy settings in encryption methods --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- .../authme/converter/RakamakConverter.java | 4 +- .../authme/security/PasswordSecurity.java | 81 ++++++++++++++----- .../xephi/authme/security/crypts/BCRYPT.java | 11 ++- .../security/crypts/EncryptionMethod.java | 8 +- .../authme/security/crypts/SALTED2MD5.java | 11 ++- .../fr/xephi/authme/settings/Settings.java | 5 +- .../HashAlgorithmIntegrationTest.java | 25 ++++-- .../authme/security/PasswordSecurityTest.java | 77 ++++++++++-------- .../authme/security/crypts/BcryptTest.java | 19 +++-- .../authme/security/crypts/IPB4Test.java | 2 - .../security/crypts/SALTED2MD5Test.java | 22 ++--- .../authme/security/crypts/XFBCRYPTTest.java | 2 - .../EncryptionMethodInfoGatherer.java | 44 +++++++--- .../HashAlgorithmsDescriptionTask.java | 8 -- 15 files changed, 203 insertions(+), 118 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 3b037bfb..77f419b0 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -338,7 +338,7 @@ public class AuthMe extends JavaPlugin { } database.reload(); messages.reload(newSettings.getMessagesFile()); - passwordSecurity.reload(newSettings); + passwordSecurity.reload(); spawnLoader.initialize(newSettings); } diff --git a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java index 289e11be..79de45ad 100644 --- a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java +++ b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java @@ -4,7 +4,6 @@ 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.security.HashAlgorithm; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; @@ -35,7 +34,6 @@ public class RakamakConverter implements Converter { @Override // TODO ljacqu 20151229: Restructure this into smaller portions public void run() { - HashAlgorithm hash = Settings.getPasswordHash; boolean useIP = Settings.rakamakUseIp; String fileName = Settings.rakamakUsers; String ipFileName = Settings.rakamakUsersIp; @@ -64,7 +62,7 @@ public class RakamakConverter implements Converter { while ((line = users.readLine()) != null) { if (line.contains("=")) { String[] arguments = line.split("="); - HashedPassword hashedPassword = passwordSecurity.computeHash(hash, arguments[1], arguments[0]); + HashedPassword hashedPassword = passwordSecurity.computeHash(arguments[1], arguments[0]); playerPSW.put(arguments[0], hashedPassword); } diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index da506b6b..94a8abeb 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -8,46 +8,75 @@ import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.plugin.PluginManager; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + /** * Manager class for password-related operations. */ public class PasswordSecurity { + private final NewSetting settings; private HashAlgorithm algorithm; private boolean supportOldAlgorithm; private final DataSource dataSource; private final PluginManager pluginManager; public PasswordSecurity(DataSource dataSource, NewSetting settings, PluginManager pluginManager) { + this.settings = settings; this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); this.supportOldAlgorithm = settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH); this.dataSource = dataSource; this.pluginManager = pluginManager; } + /** + * Compute the hash of the configured algorithm for the given password and username. + * + * @param password The password to hash + * @param playerName The player's name + * + * @return The password hash + */ public HashedPassword computeHash(String password, String playerName) { - return computeHash(algorithm, password, playerName); - } - - public HashedPassword computeHash(HashAlgorithm algorithm, String password, String playerName) { String playerLowerCase = playerName.toLowerCase(); - EncryptionMethod method = initializeEncryptionMethod(algorithm, playerLowerCase); + EncryptionMethod method = initializeEncryptionMethodWithEvent(algorithm, playerLowerCase); return method.computeHash(password, playerLowerCase); } + /** + * Check if the given password matches the player's stored password. + * + * @param password The password to check + * @param playerName The player to check for + * + * @return True if the password is correct, false otherwise + */ public boolean comparePassword(String password, String playerName) { HashedPassword auth = dataSource.getPassword(playerName); return auth != null && comparePassword(password, auth, playerName); } + /** + * Check if the given password matches the given hashed password. + * + * @param password The password to check + * @param hashedPassword The hashed password to check against + * @param playerName The player to check for + * + * @return True if the password matches, false otherwise + */ public boolean comparePassword(String password, HashedPassword hashedPassword, String playerName) { - EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName); + EncryptionMethod method = initializeEncryptionMethodWithEvent(algorithm, playerName); String playerLowerCase = playerName.toLowerCase(); return methodMatches(method, password, hashedPassword, playerLowerCase) || supportOldAlgorithm && compareWithAllEncryptionMethods(password, hashedPassword, playerLowerCase); } - public void reload(NewSetting settings) { + /** + * Reload the configuration. + */ + public void reload() { this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); this.supportOldAlgorithm = settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH); } @@ -63,11 +92,10 @@ public class PasswordSecurity { * * @return True if there was a password match with another encryption method, false otherwise */ - private boolean compareWithAllEncryptionMethods(String password, HashedPassword hashedPassword, - String playerName) { + private boolean compareWithAllEncryptionMethods(String password, HashedPassword hashedPassword, String playerName) { for (HashAlgorithm algorithm : HashAlgorithm.values()) { if (!HashAlgorithm.CUSTOM.equals(algorithm)) { - EncryptionMethod method = initializeEncryptionMethodWithoutEvent(algorithm); + EncryptionMethod method = initializeEncryptionMethod(algorithm, settings); if (methodMatches(method, password, hashedPassword, playerName)) { hashPasswordForNewAlgorithm(password, playerName); return true; @@ -85,6 +113,7 @@ public class PasswordSecurity { * @param password The password to check * @param hashedPassword The hash to check against * @param playerName The name of the player + * * @return True if the password matched, false otherwise */ private static boolean methodMatches(EncryptionMethod method, String password, @@ -103,33 +132,45 @@ public class PasswordSecurity { * * @return The encryption method */ - private EncryptionMethod initializeEncryptionMethod(HashAlgorithm algorithm, String playerName) { - EncryptionMethod method = initializeEncryptionMethodWithoutEvent(algorithm); + private EncryptionMethod initializeEncryptionMethodWithEvent(HashAlgorithm algorithm, String playerName) { + EncryptionMethod method = initializeEncryptionMethod(algorithm, settings); PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName); pluginManager.callEvent(event); return event.getMethod(); } /** - * Initialize the encryption method corresponding to the given hash algorithm. + * Initialize the encryption method associated with the given hash algorithm. * * @param algorithm The algorithm to retrieve the encryption method for + * @param settings The settings instance to pass to the constructor if required * - * @return The associated encryption method + * @return The associated encryption method, or null if CUSTOM / deprecated */ - private static EncryptionMethod initializeEncryptionMethodWithoutEvent(HashAlgorithm algorithm) { + public static EncryptionMethod initializeEncryptionMethod(HashAlgorithm algorithm, + NewSetting settings) { try { - return HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm) - ? null - : algorithm.getClazz().newInstance(); - } catch (InstantiationException | IllegalAccessException e) { + if (HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)) { + return null; + } + Constructor constructor = algorithm.getClazz().getConstructors()[0]; + Class[] parameters = constructor.getParameterTypes(); + if (parameters.length == 0) { + return (EncryptionMethod) constructor.newInstance(); + } else if (parameters.length == 1 && parameters[0] == NewSetting.class) { + return (EncryptionMethod) constructor.newInstance(settings); + } else { + throw new UnsupportedOperationException("Did not find default constructor or constructor with settings " + + "parameter in class " + algorithm.getClazz().getSimpleName()); + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new UnsupportedOperationException("Constructor for '" + algorithm.getClazz().getSimpleName() + "' could not be invoked. (Is there no default constructor?)", e); } } private void hashPasswordForNewAlgorithm(String password, String playerName) { - HashedPassword hashedPassword = initializeEncryptionMethod(algorithm, playerName) + HashedPassword hashedPassword = initializeEncryptionMethodWithEvent(algorithm, playerName) .computeHash(password, playerName); dataSource.updatePassword(playerName, hashedPassword); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java index 181571b3..a114adc0 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java +++ b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java @@ -5,7 +5,8 @@ import fr.xephi.authme.security.crypts.description.HasSalt; import fr.xephi.authme.security.crypts.description.Recommendation; import fr.xephi.authme.security.crypts.description.SaltType; import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.util.StringUtils; @@ -13,6 +14,12 @@ import fr.xephi.authme.util.StringUtils; @HasSalt(value = SaltType.TEXT) // length depends on Settings.bCryptLog2Rounds public class BCRYPT implements EncryptionMethod { + private final int bCryptLog2Rounds; + + public BCRYPT(NewSetting settings) { + this.bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND); + } + @Override public String computeHash(String password, String salt, String name) { return BCryptService.hashpw(password, salt); @@ -36,7 +43,7 @@ public class BCRYPT implements EncryptionMethod { @Override public String generateSalt() { - return BCryptService.gensalt(Settings.bCryptLog2Rounds); + return BCryptService.gensalt(bCryptLog2Rounds); } @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java b/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java index 26efc156..b1c0b003 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java +++ b/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java @@ -2,6 +2,10 @@ package fr.xephi.authme.security.crypts; /** * Public interface for custom password encryption methods. + *

+ * Note that {@link fr.xephi.authme.security.PasswordSecurity} requires classes implementing this interface + * to either have the default constructor or an accessible constructor with one parameter of type + * {@link fr.xephi.authme.settings.NewSetting}. */ public interface EncryptionMethod { @@ -31,9 +35,9 @@ public interface EncryptionMethod { /** * Check whether the given hash matches the clear-text password. * - * @param password The clear-text password to verify + * @param password The clear-text password to verify * @param hashedPassword The hash to check the password against - * @param name The player name to do the check for (sometimes required for generating the salt) + * @param name The player name to do the check for (sometimes required for generating the salt) * * @return True if the password matches, false otherwise */ diff --git a/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java b/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java index 613bcd3f..27066f7a 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java +++ b/src/main/java/fr/xephi/authme/security/crypts/SALTED2MD5.java @@ -5,7 +5,8 @@ import fr.xephi.authme.security.crypts.description.HasSalt; import fr.xephi.authme.security.crypts.description.Recommendation; import fr.xephi.authme.security.crypts.description.SaltType; import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.SecuritySettings; import static fr.xephi.authme.security.HashUtils.md5; @@ -13,6 +14,12 @@ import static fr.xephi.authme.security.HashUtils.md5; @HasSalt(value = SaltType.TEXT) // length defined by Settings.saltLength public class SALTED2MD5 extends SeparateSaltMethod { + private final int saltLength; + + public SALTED2MD5(NewSetting settings) { + saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH); + } + @Override public String computeHash(String password, String salt, String name) { return md5(md5(password) + salt); @@ -20,7 +27,7 @@ public class SALTED2MD5 extends SeparateSaltMethod { @Override public String generateSalt() { - return RandomString.generateHex(Settings.saltLength); + return RandomString.generateHex(saltLength); } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 7b6ce411..b5d5c387 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -45,8 +45,7 @@ public final class Settings { rakamakUsers, rakamakUsersIp, defaultWorld, crazyloginFileName; public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength, getMinNickLength, - getNonActivatedGroup, maxLoginTry, captchaLength, saltLength, - bCryptLog2Rounds, getMaxLoginPerIp; + getNonActivatedGroup, maxLoginTry, captchaLength, getMaxLoginPerIp; protected static FileConfiguration configFile; /** @@ -108,11 +107,9 @@ public final class Settings { removePassword = configFile.getBoolean("Security.console.removePassword", true); maxLoginTry = configFile.getInt("Security.captcha.maxLoginTry", 5); captchaLength = configFile.getInt("Security.captcha.captchaLength", 5); - saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8); multiverse = load(HooksSettings.MULTIVERSE); bungee = load(HooksSettings.BUNGEECORD); getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds"); - bCryptLog2Rounds = configFile.getInt("ExternalBoardOptions.bCryptLog2Round", 10); defaultWorld = configFile.getString("Purge.defaultWorld", "world"); enableProtection = configFile.getBoolean("Protection.enableProtection", false); countries = configFile.getStringList("Protection.countries"); diff --git a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java index 2472c659..976a7a44 100644 --- a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java @@ -1,10 +1,11 @@ package fr.xephi.authme.security; -import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.EncryptionMethod; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.HooksSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; import org.junit.Test; @@ -12,19 +13,25 @@ import java.util.HashSet; import java.util.Set; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; /** * Integration test for {@link HashAlgorithm}. */ public class HashAlgorithmIntegrationTest { + private static NewSetting settings; + @BeforeClass public static void setUpWrapper() { - WrapperMock.createInstance(); - Settings.bCryptLog2Rounds = 8; - Settings.saltLength = 16; + settings = mock(NewSetting.class); + given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8); + given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(16); } @Test @@ -47,8 +54,10 @@ public class HashAlgorithmIntegrationTest { public void shouldBeAbleToInstantiateEncryptionAlgorithms() throws InstantiationException, IllegalAccessException { // given / when / then for (HashAlgorithm algorithm : HashAlgorithm.values()) { - if (!HashAlgorithm.CUSTOM.equals(algorithm)) { - EncryptionMethod method = algorithm.getClazz().newInstance(); + if (!HashAlgorithm.CUSTOM.equals(algorithm) && !HashAlgorithm.PLAINTEXT.equals(algorithm)) { + EncryptionMethod method = PasswordSecurity.initializeEncryptionMethod(algorithm, settings); + assertThat("Encryption method for algorithm '" + algorithm + "' is not null", + method, not(nullValue())); HashedPassword hashedPassword = method.computeHash("pwd", "name"); assertThat("Salt should not be null if method.hasSeparateSalt(), and vice versa. Method: '" + method + "'", StringUtils.isEmpty(hashedPassword.getSalt()), equalTo(!method.hasSeparateSalt())); diff --git a/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java b/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java index de223e6f..470b8a2d 100644 --- a/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java +++ b/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java @@ -1,22 +1,25 @@ package fr.xephi.authme.security; import fr.xephi.authme.ReflectionTestUtils; -import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.PasswordEncryptionEvent; -import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.EncryptionMethod; +import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.JOOMLA; -import fr.xephi.authme.security.crypts.PHPBB; import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.WrapperMock; import org.bukkit.event.Event; import org.bukkit.plugin.PluginManager; 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.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import static org.hamcrest.Matchers.equalTo; @@ -35,19 +38,24 @@ import static org.mockito.Mockito.verify; /** * Test for {@link PasswordSecurity}. */ +@RunWith(MockitoJUnitRunner.class) public class PasswordSecurityTest { + @Mock private PluginManager pluginManager; + @Mock private DataSource dataSource; + @Mock private EncryptionMethod method; private Class caughtClassInEvent; + @BeforeClass + public static void setUpTest() { + TestHelper.setupLogger(); + } + @Before public void setUpMocks() { - WrapperMock.createInstance(); - pluginManager = mock(PluginManager.class); - dataSource = mock(DataSource.class); - method = mock(EncryptionMethod.class); caughtClassInEvent = null; // When the password encryption event is emitted, replace the encryption method with our mock. @@ -97,7 +105,6 @@ public class PasswordSecurityTest { String playerLowerCase = playerName.toLowerCase(); String clearTextPass = "passw0Rd1"; - PlayerAuth auth = mock(PlayerAuth.class); given(dataSource.getPassword(playerName)).willReturn(password); given(method.comparePassword(clearTextPass, password, playerLowerCase)).willReturn(false); PasswordSecurity security = @@ -165,6 +172,25 @@ public class PasswordSecurityTest { verify(dataSource).updatePassword(playerLowerCase, newPassword); } + @Test + public void shouldTryAllMethodsAndFail() { + // given + HashedPassword password = new HashedPassword("hashNotMatchingAnyMethod", "someBogusSalt"); + String playerName = "asfd"; + String clearTextPass = "someInvalidPassword"; + given(dataSource.getPassword(playerName)).willReturn(password); + given(method.comparePassword(clearTextPass, password, playerName)).willReturn(false); + PasswordSecurity security = + new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.MD5, true), pluginManager); + + // when + boolean result = security.comparePassword(clearTextPass, playerName); + + // then + assertThat(result, equalTo(false)); + verify(dataSource, never()).updatePassword(anyString(), any(HashedPassword.class)); + } + @Test public void shouldHashPassword() { // given @@ -188,28 +214,6 @@ public class PasswordSecurityTest { assertThat(event.getPlayerName(), equalTo(usernameLowerCase)); } - @Test - public void shouldHashPasswordWithGivenAlgorithm() { - // given - String password = "TopSecretPass#112525"; - String username = "someone12"; - HashedPassword hashedPassword = new HashedPassword("~T!est#Hash", "__someSalt__"); - given(method.computeHash(password, username)).willReturn(hashedPassword); - PasswordSecurity security = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.JOOMLA, true), pluginManager); - - // when - HashedPassword result = security.computeHash(HashAlgorithm.PHPBB, password, username); - - // then - assertThat(result, equalTo(hashedPassword)); - ArgumentCaptor captor = ArgumentCaptor.forClass(PasswordEncryptionEvent.class); - verify(pluginManager).callEvent(captor.capture()); - PasswordEncryptionEvent event = captor.getValue(); - assertThat(PHPBB.class.equals(caughtClassInEvent), equalTo(true)); - assertThat(event.getPlayerName(), equalTo(username)); - } - @Test public void shouldSkipCheckIfMandatorySaltIsUnavailable() { // given @@ -234,12 +238,13 @@ public class PasswordSecurityTest { @Test public void shouldReloadSettings() { // given - PasswordSecurity passwordSecurity = - new PasswordSecurity(dataSource, mockSettings(HashAlgorithm.BCRYPT, false), pluginManager); - NewSetting updatedSettings = mockSettings(HashAlgorithm.MD5, true); + NewSetting settings = mockSettings(HashAlgorithm.BCRYPT, false); + PasswordSecurity passwordSecurity = new PasswordSecurity(dataSource, settings, pluginManager); + given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.MD5); + given(settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH)).willReturn(true); // when - passwordSecurity.reload(updatedSettings); + passwordSecurity.reload(); // then assertThat(ReflectionTestUtils.getFieldValue(PasswordSecurity.class, passwordSecurity, "algorithm"), @@ -252,6 +257,8 @@ public class PasswordSecurityTest { NewSetting settings = mock(NewSetting.class); given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(algorithm); given(settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH)).willReturn(supportOldPassword); + given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8); + given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(16); return settings; } diff --git a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java index 2c27e00a..d8b6aa02 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java @@ -1,24 +1,25 @@ package fr.xephi.authme.security.crypts; import fr.xephi.authme.TestHelper; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.WrapperMock; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.HooksSettings; import org.junit.BeforeClass; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + /** * Test for {@link BCRYPT}. */ public class BcryptTest extends AbstractEncryptionMethodTest { @BeforeClass - public static void setUpSettings() { - WrapperMock.createInstance(); - Settings.bCryptLog2Rounds = 8; + public static void initializeLogger() { TestHelper.setupLogger(); } public BcryptTest() { - super(new BCRYPT(), + super(new BCRYPT(mockSettings()), "$2a$10$6iATmYgwJVc3YONhVcZFve3Cfb5GnwvKhJ20r.hMjmcNkIT9.Uh9K", // password "$2a$10$LOhUxhEcS0vgDPv/jkXvCurNb7LjP9xUlEolJGk.Uhgikqc6FtIOi", // PassWord1 "$2a$10$j9da7SGiaakWhzIms9BtwemLUeIhSEphGUQ3XSlvYgpYsGnGCKRBa", // &^%te$t?Pw@_ @@ -26,4 +27,10 @@ public class BcryptTest extends AbstractEncryptionMethodTest { ); } + private static NewSetting mockSettings() { + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8); + return settings; + } + } diff --git a/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java b/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java index 1b7ac3f1..325d37d5 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/IPB4Test.java @@ -1,7 +1,6 @@ package fr.xephi.authme.security.crypts; import fr.xephi.authme.TestHelper; -import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; /** @@ -11,7 +10,6 @@ public class IPB4Test extends AbstractEncryptionMethodTest { @BeforeClass public static void setUpSettings() { - WrapperMock.createInstance(); TestHelper.setupLogger(); } diff --git a/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java b/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java index b483421c..fb51fabf 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java @@ -1,26 +1,28 @@ package fr.xephi.authme.security.crypts; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.WrapperMock; -import org.junit.Before; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.SecuritySettings; + +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; /** * Test for {@link SALTED2MD5}. */ public class SALTED2MD5Test extends AbstractEncryptionMethodTest { - @Before - public void setUpAlgorithm() { - WrapperMock.createInstance(); - Settings.saltLength = 8; - } - public SALTED2MD5Test() { - super(new SALTED2MD5(), + super(new SALTED2MD5(mockSettings()), new HashedPassword("9f3d13dc01a6fe61fd669954174399f3", "9b5f5749"), // password new HashedPassword("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"), // PassWord1 new HashedPassword("38dcb83cc68424afe3cda012700c2bb1", "eb2c3394"), // &^%te$t?Pw@_ new HashedPassword("ad25606eae5b760c8a2469d65578ac39", "04eee598")); // âË_3(íù*) } + private static NewSetting mockSettings() { + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(8); + return settings; + } + } diff --git a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java index 96c30d1c..bda1c0f8 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java @@ -1,7 +1,6 @@ package fr.xephi.authme.security.crypts; import fr.xephi.authme.TestHelper; -import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; /** @@ -11,7 +10,6 @@ public class XFBCRYPTTest extends AbstractEncryptionMethodTest { @BeforeClass public static void setup() { - WrapperMock.createInstance(); TestHelper.setupLogger(); } diff --git a/src/tools/hashmethods/EncryptionMethodInfoGatherer.java b/src/tools/hashmethods/EncryptionMethodInfoGatherer.java index 237215af..4ade88ce 100644 --- a/src/tools/hashmethods/EncryptionMethodInfoGatherer.java +++ b/src/tools/hashmethods/EncryptionMethodInfoGatherer.java @@ -1,11 +1,16 @@ package hashmethods; import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.HexSaltedMethod; import fr.xephi.authme.security.crypts.description.AsciiRestricted; import fr.xephi.authme.security.crypts.description.HasSalt; import fr.xephi.authme.security.crypts.description.Recommendation; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.HooksSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; +import org.mockito.BDDMockito; import java.lang.annotation.Annotation; import java.util.HashMap; @@ -14,6 +19,7 @@ import java.util.Map; import java.util.Set; import static com.google.common.collect.Sets.newHashSet; +import static org.mockito.Mockito.mock; /** * Gathers information on {@link EncryptionMethod} implementations based on @@ -25,6 +31,8 @@ public class EncryptionMethodInfoGatherer { private final static Set> RELEVANT_ANNOTATIONS = newHashSet(HasSalt.class, Recommendation.class, AsciiRestricted.class); + private static NewSetting settings = createSettings(); + private Map descriptions; public EncryptionMethodInfoGatherer() { @@ -38,16 +46,19 @@ public class EncryptionMethodInfoGatherer { private void constructDescriptions() { for (HashAlgorithm algorithm : HashAlgorithm.values()) { - Class methodClazz = algorithm.getClazz(); - if (!HashAlgorithm.CUSTOM.equals(algorithm) && !methodClazz.isAnnotationPresent(Deprecated.class)) { - MethodDescription description = createDescription(methodClazz); + if (!HashAlgorithm.CUSTOM.equals(algorithm) && !algorithm.getClazz().isAnnotationPresent(Deprecated.class)) { + MethodDescription description = createDescription(algorithm); descriptions.put(algorithm, description); } } } - private static MethodDescription createDescription(Class clazz) { - EncryptionMethod method = instantiateMethod(clazz); + private static MethodDescription createDescription(HashAlgorithm algorithm) { + Class clazz = algorithm.getClazz(); + EncryptionMethod method = PasswordSecurity.initializeEncryptionMethod(algorithm, settings); + if (method == null) { + throw new NullPointerException("Method for '" + algorithm + "' is null"); + } MethodDescription description = new MethodDescription(clazz); description.setHashLength(method.computeHash("test", "user").getHash().length()); description.setHasSeparateSalt(method.hasSeparateSalt()); @@ -118,18 +129,25 @@ public class EncryptionMethodInfoGatherer { } } - private static EncryptionMethod instantiateMethod(Class clazz) { - try { - return clazz.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new RuntimeException("Could not instantiate " + clazz, e); - } - } - // Convenience method for retrieving an annotation in a typed fashion. // We know implicitly that the key of the map always corresponds to the type of the value private static T returnTyped(Map, Annotation> map, Class key) { return key.cast(map.get(key)); } + private static NewSetting createSettings() { + // TODO #672 Don't mock settings but instantiate a NewSetting object without any validation / migration + NewSetting settings = mock(NewSetting.class); + BDDMockito.given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8); + BDDMockito.given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(8); + return settings; + + /*try (InputStreamReader isr = new InputStreamReader(getClass().getResourceAsStream("config.yml"))) { + FileConfiguration configuration = YamlConfiguration.loadConfiguration(isr); + return new NewSetting(configuration, null, null, null); + } catch (IOException e) { + throw new UnsupportedOperationException(e); + }*/ + } + } diff --git a/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java b/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java index 8c8cecbe..6d1a57ed 100644 --- a/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java +++ b/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java @@ -1,8 +1,6 @@ package hashmethods; import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.WrapperMock; import utils.FileUtils; import utils.TagValue.NestedTagValue; import utils.TagValueHolder; @@ -24,12 +22,6 @@ public class HashAlgorithmsDescriptionTask implements ToolTask { @Override public void execute(Scanner scanner) { - // Unfortunately, we need the Wrapper to be around to work with Settings, and certain encryption methods - // directly read from the Settings file - WrapperMock.createInstance(); - Settings.bCryptLog2Rounds = 8; - Settings.saltLength = 8; - // Gather info and construct a row for each method EncryptionMethodInfoGatherer infoGatherer = new EncryptionMethodInfoGatherer(); Map descriptions = infoGatherer.getDescriptions(); From 59d3bc95c0a174dd4196bc7daed3b90eea63469b Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 23 Apr 2016 15:24:41 +0200 Subject: [PATCH 60/71] Move getOnlinePlayers() from Utils to BukkitService; delete Wrapper --- src/main/java/fr/xephi/authme/AuthMe.java | 21 ++-- .../xephi/authme/cache/backup/JsonCache.java | 4 +- .../xephi/authme/command/CommandService.java | 9 ++ .../authme/UnregisterAdminCommand.java | 7 +- .../executable/authme/VersionCommand.java | 36 +++--- .../authme/converter/RakamakConverter.java | 6 +- .../authme/listener/AuthMePlayerListener.java | 6 +- .../listener/AuthMeTablistPacketAdapter.java | 15 +-- .../xephi/authme/process/ProcessService.java | 18 ++- .../authme/process/join/AsynchronousJoin.java | 5 +- .../process/login/AsynchronousLogin.java | 6 +- .../process/login/ProcessSyncPlayerLogin.java | 2 +- .../ProcessSynchronousPlayerLogout.java | 3 +- .../register/ProcessSyncEmailRegister.java | 2 +- .../register/ProcessSyncPasswordRegister.java | 7 +- .../unregister/AsynchronousUnregister.java | 8 +- .../fr/xephi/authme/settings/Settings.java | 4 - .../fr/xephi/authme/task/MessageTask.java | 31 +++-- .../fr/xephi/authme/util/BukkitService.java | 79 ++++++++++++- .../java/fr/xephi/authme/util/GeoLiteAPI.java | 5 +- src/main/java/fr/xephi/authme/util/Utils.java | 75 +------------ .../java/fr/xephi/authme/util/Wrapper.java | 74 ------------ .../authme/process/ProcessServiceTest.java | 5 +- .../xephi/authme/util/BukkitServiceTest.java | 66 +++++++++++ .../java/fr/xephi/authme/util/UtilsTest.java | 106 ------------------ .../fr/xephi/authme/util/WrapperMock.java | 90 --------------- 26 files changed, 262 insertions(+), 428 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/util/Wrapper.java create mode 100644 src/test/java/fr/xephi/authme/util/BukkitServiceTest.java delete mode 100644 src/test/java/fr/xephi/authme/util/UtilsTest.java delete mode 100644 src/test/java/fr/xephi/authme/util/WrapperMock.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 77f419b0..08a1945c 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -250,6 +250,7 @@ public class AuthMe extends JavaPlugin { return; } + bukkitService = new BukkitService(this); pluginHooks = new PluginHooks(server.getPluginManager()); MigrationService.changePlainTextToSha256(newSettings, database, new SHA256()); @@ -257,8 +258,6 @@ public class AuthMe extends JavaPlugin { // Initialize spawn loader spawnLoader = new SpawnLoader(getDataFolder(), newSettings, pluginHooks); - - bukkitService = new BukkitService(this); permsMan = initializePermissionsManager(); antiBot = new AntiBot(newSettings, messages, permsMan, bukkitService); ValidationService validationService = new ValidationService(newSettings, database, permsMan); @@ -297,7 +296,7 @@ public class AuthMe extends JavaPlugin { // Set up the management ProcessService processService = new ProcessService(newSettings, messages, this, database, - passwordSecurity, pluginHooks, spawnLoader, validationService); + passwordSecurity, pluginHooks, spawnLoader, validationService, bukkitService); management = new Management(this, processService, database, PlayerCache.getInstance()); // Set up the BungeeCord hook @@ -400,7 +399,7 @@ public class AuthMe extends JavaPlugin { private void reloadSupportHook() { if (database != null) { - int playersOnline = Utils.getOnlinePlayers().size(); + int playersOnline = bukkitService.getOnlinePlayers().size(); if (playersOnline < 1) { database.purgeLogged(); } else if (Settings.reloadSupport) { @@ -499,9 +498,11 @@ public class AuthMe extends JavaPlugin { @Override public void onDisable() { // Save player data - Collection players = Utils.getOnlinePlayers(); - for (Player player : players) { - savePlayer(player); + if (bukkitService != null) { + Collection players = bukkitService.getOnlinePlayers(); + for (Player player : players) { + savePlayer(player); + } } // Do backup on stop if enabled @@ -660,7 +661,7 @@ public class AuthMe extends JavaPlugin { tabComplete = null; } if (newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && tablistHider == null) { - tablistHider = new AuthMeTablistPacketAdapter(this); + tablistHider = new AuthMeTablistPacketAdapter(this, bukkitService); tablistHider.register(); } else if (tablistHider != null) { tablistHider.unregister(); @@ -769,7 +770,7 @@ public class AuthMe extends JavaPlugin { } public String replaceAllInfo(String message, Player player) { - String playersOnline = Integer.toString(Utils.getOnlinePlayers().size()); + String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size()); String ipAddress = Utils.getPlayerIp(player); return message .replace("&", "\u00a7") @@ -786,7 +787,7 @@ public class AuthMe extends JavaPlugin { public boolean isLoggedIp(String name, String ip) { int count = 0; - for (Player player : Utils.getOnlinePlayers()) { + for (Player player : bukkitService.getOnlinePlayers()) { if (ip.equalsIgnoreCase(Utils.getPlayerIp(player)) && database.isLogged(player.getName().toLowerCase()) && !player.getName().equalsIgnoreCase(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 81e30543..d9735491 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -10,8 +10,8 @@ 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.settings.Settings; import org.bukkit.entity.Player; import java.io.File; @@ -24,7 +24,7 @@ public class JsonCache { private final File cacheDir; public JsonCache() { - cacheDir = Settings.CACHE_FOLDER; + cacheDir = new File(AuthMe.getInstance().getDataFolder(), "cache"); if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { ConsoleLogger.showError("Failed to create cache directory."); } diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 916ce62f..5c5abfcc 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -19,6 +19,7 @@ import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.Collection; import java.util.List; /** @@ -231,4 +232,12 @@ public class CommandService { return bukkitService.getPlayerExact(name); } + public Collection getOnlinePlayers() { + return bukkitService.getOnlinePlayers(); + } + + public BukkitService getBukkitService() { + return bukkitService; + } + } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java index 0c488f9b..58ccdf0f 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java @@ -63,10 +63,9 @@ public class UnregisterAdminCommand implements ExecutableCommand { LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setTimeoutTask(id); } LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setMessageTask( - scheduler.runTask( - plugin, new MessageTask(plugin, playerNameLowerCase, MessageKey.REGISTER_MESSAGE, interval) - ) - ); + scheduler.runTask(plugin, new MessageTask(commandService.getBukkitService(), plugin.getMessages(), + playerNameLowerCase, MessageKey.REGISTER_MESSAGE, interval))); + if (commandService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2)); } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java index 7b99521d..1a15dc04 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java @@ -3,11 +3,11 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.util.Utils; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.Collection; import java.util.List; import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; @@ -22,11 +22,12 @@ public class VersionCommand implements ExecutableCommand { sender.sendMessage(ChatColor.GOLD + "Version: " + ChatColor.WHITE + AuthMe.getPluginName() + " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")"); sender.sendMessage(ChatColor.GOLD + "Developers:"); - printDeveloper(sender, "Xephi", "xephi59", "Lead Developer"); - printDeveloper(sender, "DNx5", "DNx5", "Developer"); - printDeveloper(sender, "games647", "games647", "Developer"); - printDeveloper(sender, "Tim Visee", "timvisee", "Developer"); - printDeveloper(sender, "Sgdc3", "sgdc3", "Project manager, Contributor"); + Collection onlinePlayers = commandService.getOnlinePlayers(); + printDeveloper(sender, "Xephi", "xephi59", "Lead Developer", onlinePlayers); + printDeveloper(sender, "DNx5", "DNx5", "Developer", onlinePlayers); + printDeveloper(sender, "games647", "games647", "Developer", onlinePlayers); + printDeveloper(sender, "Tim Visee", "timvisee", "Developer", onlinePlayers); + printDeveloper(sender, "Sgdc3", "sgdc3", "Project manager, Contributor", onlinePlayers); sender.sendMessage(ChatColor.GOLD + "Website: " + ChatColor.WHITE + "http://dev.bukkit.org/bukkit-plugins/authme-reloaded/"); sender.sendMessage(ChatColor.GOLD + "License: " + ChatColor.WHITE + "GNU GPL v3.0" @@ -38,12 +39,14 @@ public class VersionCommand implements ExecutableCommand { /** * Print a developer with proper styling. * - * @param sender The command sender. - * @param name The display name of the developer. - * @param minecraftName The Minecraft username of the developer, if available. - * @param function The function of the developer. + * @param sender The command sender + * @param name The display name of the developer + * @param minecraftName The Minecraft username of the developer, if available + * @param function The function of the developer + * @param onlinePlayers The list of online players */ - private static void printDeveloper(CommandSender sender, String name, String minecraftName, String function) { + private static void printDeveloper(CommandSender sender, String name, String minecraftName, String function, + Collection onlinePlayers) { // Print the name StringBuilder msg = new StringBuilder(); msg.append(" ") @@ -55,7 +58,7 @@ public class VersionCommand implements ExecutableCommand { msg.append(ChatColor.GRAY).append(ChatColor.ITALIC).append(" (").append(function).append(")"); // Show the online status - if (isPlayerOnline(minecraftName)) { + if (isPlayerOnline(minecraftName, onlinePlayers)) { msg.append(ChatColor.GREEN).append(ChatColor.ITALIC).append(" (In-Game)"); } @@ -66,12 +69,13 @@ public class VersionCommand implements ExecutableCommand { /** * Check whether a player is online. * - * @param minecraftName The Minecraft player name. + * @param minecraftName The Minecraft player name + * @param onlinePlayers List of online players * - * @return True if the player is online, false otherwise. + * @return True if the player is online, false otherwise */ - private static boolean isPlayerOnline(String minecraftName) { - for (Player player : Utils.getOnlinePlayers()) { + private static boolean isPlayerOnline(String minecraftName, Collection onlinePlayers) { + for (Player player : onlinePlayers) { if (player.getName().equalsIgnoreCase(minecraftName)) { return true; } diff --git a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java index 79de45ad..f1acf300 100644 --- a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java +++ b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java @@ -24,11 +24,13 @@ public class RakamakConverter implements Converter { private final AuthMe instance; private final DataSource database; private final CommandSender sender; + private final File pluginFolder; public RakamakConverter(AuthMe instance, CommandSender sender) { this.instance = instance; this.database = instance.getDataSource(); this.sender = sender; + pluginFolder = instance.getDataFolder(); } @Override @@ -37,8 +39,8 @@ public class RakamakConverter implements Converter { boolean useIP = Settings.rakamakUseIp; String fileName = Settings.rakamakUsers; String ipFileName = Settings.rakamakUsersIp; - File source = new File(Settings.PLUGIN_FOLDER, fileName); - File ipfiles = new File(Settings.PLUGIN_FOLDER, ipFileName); + File source = new File(pluginFolder, fileName); + File ipfiles = new File(pluginFolder, ipFileName); HashMap playerIP = new HashMap<>(); HashMap playerPSW = new HashMap<>(); try { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 87399a7a..a17eacd5 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -96,7 +96,7 @@ public class AuthMePlayerListener implements Listener { event.setCancelled(true); sendLoginOrRegisterMessage(player); } else if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) { - for (Player p : Utils.getOnlinePlayers()) { + for (Player p : bukkitService.getOnlinePlayers()) { if (!PlayerCache.getInstance().isAuthenticated(p.getName())) { event.getRecipients().remove(p); } @@ -319,11 +319,11 @@ public class AuthMePlayerListener implements Listener { if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL) { if (permsMan.hasPermission(player, PlayerStatePermission.IS_VIP)) { - int playersOnline = Utils.getOnlinePlayers().size(); + int playersOnline = bukkitService.getOnlinePlayers().size(); if (playersOnline > plugin.getServer().getMaxPlayers()) { event.allow(); } else { - Player pl = plugin.generateKickPlayer(Utils.getOnlinePlayers()); + Player pl = plugin.generateKickPlayer(bukkitService.getOnlinePlayers()); if (pl != null) { pl.kickPlayer(m.retrieveSingle(MessageKey.KICK_FOR_VIP)); event.allow(); diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index 138439cd..a23ce5c1 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -13,22 +13,23 @@ 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.Utils; +import fr.xephi.authme.util.BukkitService; +import org.bukkit.entity.Player; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.logging.Level; -import org.bukkit.entity.Player; - public class AuthMeTablistPacketAdapter extends PacketAdapter { - public AuthMeTablistPacketAdapter(AuthMe plugin) { + private final BukkitService bukkitService; + + public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) { super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO); + this.bukkitService = bukkitService; } @Override @@ -40,7 +41,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { event.setCancelled(true); } } catch (FieldAccessException e) { - ConsoleLogger.showError("Couldn't access field."); + ConsoleLogger.logException("Couldn't access field", e); } } } @@ -67,7 +68,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } //triggers an update for others player to see them - for (Player onlinePlayer : Utils.getOnlinePlayers()) { + for (Player onlinePlayer : bukkitService.getOnlinePlayers()) { if (onlinePlayer.equals(receiver) || !receiver.canSee(onlinePlayer)) { continue; } diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java index 7dcffe1c..653be156 100644 --- a/src/main/java/fr/xephi/authme/process/ProcessService.java +++ b/src/main/java/fr/xephi/authme/process/ProcessService.java @@ -10,11 +10,15 @@ import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.scheduler.BukkitTask; +import java.util.Collection; + /** * Service for asynchronous and synchronous processes. */ @@ -28,10 +32,11 @@ public class ProcessService { private final PluginHooks pluginHooks; private final SpawnLoader spawnLoader; private final ValidationService validationService; + private final BukkitService bukkitService; public ProcessService(NewSetting settings, Messages messages, AuthMe authMe, DataSource dataSource, - PasswordSecurity passwordSecurity, PluginHooks pluginHooks, - SpawnLoader spawnLoader, ValidationService validationService) { + PasswordSecurity passwordSecurity, PluginHooks pluginHooks, SpawnLoader spawnLoader, + ValidationService validationService, BukkitService bukkitService) { this.settings = settings; this.messages = messages; this.authMe = authMe; @@ -40,6 +45,7 @@ public class ProcessService { this.pluginHooks = pluginHooks; this.spawnLoader = spawnLoader; this.validationService = validationService; + this.bukkitService = bukkitService; } /** @@ -209,4 +215,12 @@ public class ProcessService { return validationService.isEmailFreeForRegistration(email, sender); } + public Collection getOnlinePlayers() { + return bukkitService.getOnlinePlayers(); + } + + public BukkitService getBukkitService() { + return bukkitService; + } + } 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 4e276867..37b0dfbd 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -217,7 +217,8 @@ public class AsynchronousJoin implements Process { : MessageKey.REGISTER_MESSAGE; } if (msgInterval > 0 && LimboCache.getInstance().getLimboPlayer(name) != null) { - BukkitTask msgTask = service.runTask(new MessageTask(plugin, name, msg, msgInterval)); + BukkitTask msgTask = service.runTask(new MessageTask(service.getBukkitService(), plugin.getMessages(), + name, msg, msgInterval)); LimboCache.getInstance().getLimboPlayer(name).setMessageTask(msgTask); } } @@ -303,7 +304,7 @@ public class AsynchronousJoin implements Process { private boolean hasJoinedIp(String name, String ip) { int count = 0; - for (Player player : Utils.getOnlinePlayers()) { + for (Player player : service.getOnlinePlayers()) { if (ip.equalsIgnoreCase(Utils.getPlayerIp(player)) && !player.getName().equalsIgnoreCase(name)) { count++; 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 98a49be7..b7bb3f2b 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -97,8 +97,8 @@ public class AsynchronousLogin implements Process { String[] msg = service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION) ? service.retrieveMessage(MessageKey.REGISTER_EMAIL_MESSAGE) : service.retrieveMessage(MessageKey.REGISTER_MESSAGE); - BukkitTask messageTask = service.runTask( - new MessageTask(plugin, name, msg, service.getProperty(RegistrationSettings.MESSAGE_INTERVAL))); + BukkitTask messageTask = service.runTask(new MessageTask(service.getBukkitService(), + name, msg, service.getProperty(RegistrationSettings.MESSAGE_INTERVAL))); limboPlayer.setMessageTask(messageTask); } return null; @@ -223,7 +223,7 @@ public class AsynchronousLogin implements Process { return; } String message = "[AuthMe] " + StringUtils.join(", ", auths) + "."; - for (Player player : Utils.getOnlinePlayers()) { + for (Player player : service.getOnlinePlayers()) { if (plugin.getPermissionsManager().hasPermission(player, AdminPermission.SEE_OTHER_ACCOUNTS) || (player.getName().equals(this.player.getName()) && plugin.getPermissionsManager().hasPermission(player, PlayerPermission.SEE_OWN_ACCOUNTS))) { 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 7f037d26..9f5de6bd 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -174,7 +174,7 @@ public class ProcessSyncPlayerLogin implements Process { String jm = AuthMePlayerListener.joinMessage.get(name); if (jm != null) { if (!jm.isEmpty()) { - for (Player p : Utils.getOnlinePlayers()) { + for (Player p : service.getOnlinePlayers()) { if (p.isOnline()) { p.sendMessage(jm); } 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 bc2ea16d..d6d66b90 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java @@ -74,7 +74,8 @@ public class ProcessSynchronousPlayerLogout implements Process { BukkitTask id = service.runTaskLater(new TimeoutTask(plugin, name, player), timeOut); LimboCache.getInstance().getLimboPlayer(name).setTimeoutTask(id); } - BukkitTask msgT = service.runTask(new MessageTask(plugin, name, MessageKey.LOGIN_MESSAGE, interval)); + BukkitTask msgT = service.runTask(new MessageTask(service.getBukkitService(), plugin.getMessages(), + name, MessageKey.LOGIN_MESSAGE, interval)); LimboCache.getInstance().getLimboPlayer(name).setMessageTask(msgT); if (player.isInsideVehicle() && player.getVehicle() != null) { player.getVehicle().eject(); diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java index f1d35039..461857aa 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java @@ -52,7 +52,7 @@ public class ProcessSyncEmailRegister implements Process { limbo.setTimeoutTask(id); } BukkitTask messageTask = service.runTask(new MessageTask( - service.getAuthMe(), name, service.retrieveMessage(MessageKey.LOGIN_MESSAGE), msgInterval)); + service.getBukkitService(), name, service.retrieveMessage(MessageKey.LOGIN_MESSAGE), msgInterval)); limbo.setMessageTask(messageTask); } 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 cf018d18..84288822 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -32,8 +32,8 @@ import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND; */ public class ProcessSyncPasswordRegister implements Process { - protected final Player player; - protected final String name; + private final Player player; + private final String name; private final AuthMe plugin; private final ProcessService service; @@ -74,7 +74,8 @@ public class ProcessSyncPasswordRegister implements Process { task = service.runTaskLater(new TimeoutTask(service.getAuthMe(), name, player), delay); cache.getLimboPlayer(name).setTimeoutTask(task); } - task = service.runTask(new MessageTask(plugin, name, MessageKey.LOGIN_MESSAGE, interval)); + task = service.runTask(new MessageTask(service.getBukkitService(), plugin.getMessages(), + name, MessageKey.LOGIN_MESSAGE, interval)); cache.getLimboPlayer(name).setMessageTask(task); if (player.isInsideVehicle() && player.getVehicle() != null) { player.getVehicle().eject(); diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java index 29c2b8c3..7b2c2a7f 100644 --- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java +++ b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java @@ -20,7 +20,6 @@ import fr.xephi.authme.util.Utils.GroupType; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; public class AsynchronousUnregister implements Process { @@ -73,13 +72,12 @@ public class AsynchronousUnregister implements Process { LimboCache.getInstance().addLimboPlayer(player); LimboPlayer limboPlayer = LimboCache.getInstance().getLimboPlayer(name); int interval = service.getProperty(RegistrationSettings.MESSAGE_INTERVAL); - BukkitScheduler scheduler = plugin.getServer().getScheduler(); if (timeOut != 0) { - BukkitTask id = scheduler.runTaskLater(plugin, new TimeoutTask(plugin, name, player), timeOut); + BukkitTask id = service.runTaskLater(new TimeoutTask(plugin, name, player), timeOut); limboPlayer.setTimeoutTask(id); } - limboPlayer.setMessageTask(scheduler.runTask(plugin, - new MessageTask(plugin, name, MessageKey.REGISTER_MESSAGE, interval))); + limboPlayer.setMessageTask(service.runTask(new MessageTask(service.getBukkitService(), + plugin.getMessages(), name, MessageKey.REGISTER_MESSAGE, interval))); service.send(player, MessageKey.UNREGISTERED_SUCCESS); ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); return; diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index b5d5c387..129f35b3 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -8,10 +8,8 @@ import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.Wrapper; import org.bukkit.configuration.file.FileConfiguration; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -22,8 +20,6 @@ import java.util.regex.Pattern; */ public final class Settings { - public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder(); - public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); public static List allowCommands; public static List getUnrestrictedName; public static List getForcedWorlds; diff --git a/src/main/java/fr/xephi/authme/task/MessageTask.java b/src/main/java/fr/xephi/authme/task/MessageTask.java index 56d1493d..e09d5039 100644 --- a/src/main/java/fr/xephi/authme/task/MessageTask.java +++ b/src/main/java/fr/xephi/authme/task/MessageTask.java @@ -1,10 +1,10 @@ package fr.xephi.authme.task; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.util.Utils; +import fr.xephi.authme.output.Messages; +import fr.xephi.authme.util.BukkitService; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; @@ -12,28 +12,27 @@ import org.bukkit.scheduler.BukkitTask; */ public class MessageTask implements Runnable { - private final AuthMe plugin; + private final BukkitService bukkitService; private final String name; private final String[] msg; private final int interval; - /** - * Constructor for MessageTask. - * - * @param plugin AuthMe - * @param name String - * @param lines String[] - * @param interval int + /* + * Constructor. */ - public MessageTask(AuthMe plugin, String name, String[] lines, int interval) { - this.plugin = plugin; + public MessageTask(BukkitService bukkitService, String name, String[] lines, int interval) { + this.bukkitService = bukkitService; this.name = name; this.msg = lines; this.interval = interval; } - public MessageTask(AuthMe plugin, String name, MessageKey messageKey, int interval) { - this(plugin, name, plugin.getMessages().retrieve(messageKey), interval); + /* + * Constructor. + */ + public MessageTask(BukkitService bukkitService, Messages messages, String name, MessageKey messageKey, + int interval) { + this(bukkitService, name, messages.retrieve(messageKey), interval); } @Override @@ -42,12 +41,12 @@ public class MessageTask implements Runnable { return; } - for (Player player : Utils.getOnlinePlayers()) { + for (Player player : bukkitService.getOnlinePlayers()) { if (player.getName().equalsIgnoreCase(name)) { for (String ms : msg) { player.sendMessage(ms); } - BukkitTask nextTask = plugin.getServer().getScheduler().runTaskLater(plugin, this, interval * 20); + BukkitTask nextTask = bukkitService.runTaskLater(this, interval * 20); if (LimboCache.getInstance().hasLimboPlayer(name)) { LimboCache.getInstance().getLimboPlayer(name).setMessageTask(nextTask); } diff --git a/src/main/java/fr/xephi/authme/util/BukkitService.java b/src/main/java/fr/xephi/authme/util/BukkitService.java index fada6184..ea405d80 100644 --- a/src/main/java/fr/xephi/authme/util/BukkitService.java +++ b/src/main/java/fr/xephi/authme/util/BukkitService.java @@ -1,11 +1,17 @@ package fr.xephi.authme.util; import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Set; /** @@ -19,9 +25,12 @@ public class BukkitService { public static final int TICKS_PER_MINUTE = 60 * TICKS_PER_SECOND; private final AuthMe authMe; + private final boolean getOnlinePlayersIsCollection; + private Method getOnlinePlayers; public BukkitService(AuthMe authMe) { this.authMe = authMe; + getOnlinePlayersIsCollection = initializeOnlinePlayersIsCollectionField(); } /** @@ -61,6 +70,20 @@ public class BukkitService { return Bukkit.getScheduler().runTask(authMe, task); } + /** + * Returns a task that will run after the specified number of server + * ticks. + * + * @param task the task to be run + * @param delay the ticks to wait before running the task + * @return a BukkitTask that contains the id number + * @throws IllegalArgumentException if plugin is null + * @throws IllegalArgumentException if task is null + */ + public BukkitTask runTaskLater(Runnable task, long delay) { + return Bukkit.getScheduler().runTaskLater(authMe, task, delay); + } + /** * Asynchronous tasks should never access any API in Bukkit. Great care * should be taken to assure the thread-safety of asynchronous tasks. @@ -102,8 +125,60 @@ public class BukkitService { * @return a set containing banned players */ public Set getBannedPlayers() { - Bukkit.getBannedPlayers(); - return authMe.getServer().getBannedPlayers(); + return Bukkit.getBannedPlayers(); + } + + /** + * 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, + * or a Collection. Always use this wrapper to retrieve online players instead of {@link + * Bukkit#getOnlinePlayers()} directly. + * + * @return collection of online players + * + * @see SpigotMC + * forum + * @see StackOverflow + */ + @SuppressWarnings("unchecked") + public Collection getOnlinePlayers() { + if (getOnlinePlayersIsCollection) { + return Bukkit.getOnlinePlayers(); + } + try { + // The lookup of a method via Reflections is rather expensive, so we keep a reference to it + if (getOnlinePlayers == null) { + getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); + } + Object obj = getOnlinePlayers.invoke(null); + if (obj instanceof Collection) { + return (Collection) obj; + } else if (obj instanceof Player[]) { + return Arrays.asList((Player[]) obj); + } else { + String type = (obj != null) ? obj.getClass().getName() : "null"; + ConsoleLogger.showError("Unknown list of online players of type " + type); + } + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + ConsoleLogger.logException("Could not retrieve list of online players:", e); + } + return Collections.emptyList(); + } + + /** + * Method run upon initialization to verify whether or not the Bukkit implementation + * returns the online players as a Collection. + * + * @see #getOnlinePlayers() + */ + private static boolean initializeOnlinePlayersIsCollectionField() { + try { + Method method = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); + return method.getReturnType() == Collection.class; + } catch (NoSuchMethodException e) { + ConsoleLogger.showError("Error verifying if getOnlinePlayers is a collection! Method doesn't exist"); + } + return false; } } diff --git a/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java b/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java index d5cba2d7..83594086 100644 --- a/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java +++ b/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java @@ -1,8 +1,8 @@ package fr.xephi.authme.util; import com.maxmind.geoip.LookupService; +import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.settings.Settings; import java.io.File; import java.io.FileOutputStream; @@ -37,7 +37,8 @@ public class GeoLiteAPI { if (lookupService != null) { return true; } - final File data = new File(Settings.PLUGIN_FOLDER, "GeoIP.dat"); + final File pluginFolder = AuthMe.getInstance().getDataFolder(); + final File data = new File(pluginFolder, "GeoIP.dat"); boolean dataIsOld = (System.currentTimeMillis() - data.lastModified()) > TimeUnit.DAYS.toMillis(30); if (dataIsOld && !data.delete()) { ConsoleLogger.showError("Failed to delete GeoLiteAPI database"); diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index 905dd7ec..5850645b 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -14,31 +14,16 @@ import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.entity.Player; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; /** * Utility class for various operations used in the codebase. */ public final class Utils { - private static AuthMe plugin; - private static Wrapper wrapper; - - private static boolean getOnlinePlayersIsCollection = false; - private static Method getOnlinePlayers; - - static { - wrapper = Wrapper.getInstance(); - plugin = wrapper.getAuthMe(); - initializeOnlinePlayersIsCollectionField(); - } + private static AuthMe plugin = AuthMe.getInstance(); private Utils() { - // Utility class } /** @@ -167,12 +152,12 @@ public final class Utils { final World world = theWorld; final Location loc = new Location(world, x, y, z); - Bukkit.getScheduler().scheduleSyncDelayedTask(wrapper.getAuthMe(), new Runnable() { + Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { @Override public void run() { AuthMeTeleportEvent tpEvent = new AuthMeTeleportEvent(pl, loc); - wrapper.getServer().getPluginManager().callEvent(tpEvent); + plugin.getServer().getPluginManager().callEvent(tpEvent); if (!tpEvent.isCancelled()) { pl.teleport(tpEvent.getTo()); } @@ -180,58 +165,6 @@ public final class Utils { }); } - /** - * 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, - * or a Collection. Always use this wrapper to retrieve online players instead of {@link - * Bukkit#getOnlinePlayers()} directly. - * - * @return collection of online players - * - * @see SpigotMC - * forum - * @see StackOverflow - */ - @SuppressWarnings("unchecked") - public static Collection getOnlinePlayers() { - if (getOnlinePlayersIsCollection) { - return Bukkit.getOnlinePlayers(); - } - try { - // The lookup of a method via Reflections is rather expensive, so we keep a reference to it - if (getOnlinePlayers == null) { - getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); - } - Object obj = getOnlinePlayers.invoke(null); - if (obj instanceof Collection) { - return (Collection) obj; - } else if (obj instanceof Player[]) { - return Arrays.asList((Player[]) obj); - } else { - String type = (obj != null) ? obj.getClass().getName() : "null"; - ConsoleLogger.showError("Unknown list of online players of type " + type); - } - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - ConsoleLogger.logException("Could not retrieve list of online players:", e); - } - return Collections.emptyList(); - } - - /** - * Method run when the Utils class is loaded to verify whether or not the Bukkit implementation - * returns the online players as a Collection. - * - * @see Utils#getOnlinePlayers() - */ - private static void initializeOnlinePlayersIsCollectionField() { - try { - Method method = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); - getOnlinePlayersIsCollection = method.getReturnType() == Collection.class; - } catch (NoSuchMethodException e) { - ConsoleLogger.showError("Error verifying if getOnlinePlayers is a collection! Method doesn't exist"); - } - } - public static boolean isNPC(Player player) { return player.hasMetadata("NPC") || plugin.getPluginHooks().isNpcInCombatTagPlus(player); } @@ -240,7 +173,7 @@ public final class Utils { if (Settings.isTeleportToSpawnEnabled && !Settings.noTeleport) { Location spawn = plugin.getSpawnLocation(player); AuthMeTeleportEvent tpEvent = new AuthMeTeleportEvent(player, spawn); - wrapper.getServer().getPluginManager().callEvent(tpEvent); + plugin.getServer().getPluginManager().callEvent(tpEvent); if (!tpEvent.isCancelled()) { player.teleport(tpEvent.getTo()); } diff --git a/src/main/java/fr/xephi/authme/util/Wrapper.java b/src/main/java/fr/xephi/authme/util/Wrapper.java deleted file mode 100644 index bdd1d5a2..00000000 --- a/src/main/java/fr/xephi/authme/util/Wrapper.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.xephi.authme.util; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.output.Messages; -import org.bukkit.Bukkit; -import org.bukkit.Server; -import org.bukkit.scheduler.BukkitScheduler; - -import java.io.File; - -/** - * Wrapper for the retrieval of common singletons used throughout the application. - * This class simply delegates the calls. - */ -public class Wrapper { - - private static Wrapper singleton; - - /** - * Package-private constructor for testing purposes to inject a mock instance. - */ - Wrapper() { - } - - /** - * Package-private setter of the singleton field used for tests to inject a mock instance. - * - * @param wrapper The wrapper to use as singleton - */ - static void setSingleton(Wrapper wrapper) { - Wrapper.singleton = wrapper; - } - - public static Wrapper getInstance() { - if (singleton == null) { - singleton = new Wrapper(); - } - return singleton; - } - - public AuthMe getAuthMe() { - return AuthMe.getInstance(); - } - - public Server getServer() { - return getAuthMe().getServer(); - } - - public Messages getMessages() { - return getAuthMe().getMessages(); - } - - public PlayerCache getPlayerCache() { - return PlayerCache.getInstance(); - } - - /** - * Return the folder containing plugin data via the AuthMe instance. - * - * @return The plugin data folder - * @see AuthMe#getDataFolder() - */ - public File getDataFolder() { - return getAuthMe().getDataFolder(); - } - - public BukkitScheduler getScheduler() { - return Bukkit.getScheduler(); - } - - - -} diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java index 6117e7f9..ab935d02 100644 --- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java +++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java @@ -10,6 +10,7 @@ import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.properties.SecuritySettings; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.junit.Before; @@ -47,11 +48,13 @@ public class ProcessServiceTest { private SpawnLoader spawnLoader; @Mock private PluginHooks pluginHooks; + @Mock + private BukkitService bukkitService; @Before public void setUpService() { processService = new ProcessService(settings, messages, authMe, dataSource, passwordSecurity, - pluginHooks, spawnLoader, validationService); + pluginHooks, spawnLoader, validationService, bukkitService); } @Test diff --git a/src/test/java/fr/xephi/authme/util/BukkitServiceTest.java b/src/test/java/fr/xephi/authme/util/BukkitServiceTest.java new file mode 100644 index 00000000..7c848504 --- /dev/null +++ b/src/test/java/fr/xephi/authme/util/BukkitServiceTest.java @@ -0,0 +1,66 @@ +package fr.xephi.authme.util; + +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ReflectionTestUtils; +import org.bukkit.entity.Player; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Collection; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link BukkitService}. + */ +@RunWith(MockitoJUnitRunner.class) +public class BukkitServiceTest { + + @Mock + private AuthMe authMe; + + /** + * Checks that {@link BukkitService#getOnlinePlayersIsCollection} is initialized to {@code true} on startup; + * the test scope is configured with a Bukkit implementation that returns a Collection and not an array. + */ + @Test + public void shouldHavePlayerListAsCollectionMethod() { + // given + BukkitService bukkitService = new BukkitService(authMe); + + // when + boolean doesMethodReturnCollection = (Boolean) ReflectionTestUtils + .getFieldValue(BukkitService.class, bukkitService, "getOnlinePlayersIsCollection"); + + // then + assertThat(doesMethodReturnCollection, equalTo(true)); + } + + @Test + public void shouldRetrieveListOfOnlinePlayersFromReflectedMethod() { + // given + BukkitService bukkitService = new BukkitService(authMe); + ReflectionTestUtils.setField(BukkitService.class, bukkitService, "getOnlinePlayersIsCollection", false); + ReflectionTestUtils.setField(BukkitService.class, bukkitService, "getOnlinePlayers", + ReflectionTestUtils.getMethod(BukkitServiceTest.class, "onlinePlayersImpl")); + + // when + Collection players = bukkitService.getOnlinePlayers(); + + // then + assertThat(players, hasSize(2)); + } + + // Note: This method is used through reflections + public static Player[] onlinePlayersImpl() { + return new Player[]{ + mock(Player.class), mock(Player.class) + }; + } + +} diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java deleted file mode 100644 index 38b536f0..00000000 --- a/src/test/java/fr/xephi/authme/util/UtilsTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package fr.xephi.authme.util; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ReflectionTestUtils; -import fr.xephi.authme.TestHelper; -import fr.xephi.authme.settings.Settings; -import org.bukkit.entity.Player; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -import java.util.Collection; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; - -/** - * Test for the {@link Utils} class. - */ -public class UtilsTest { - - private static AuthMe authMeMock; - - /** - * The Utils class initializes its fields in a {@code static} block which is only executed once during the JUnit - * tests, too. It is therefore important to initialize the mocks once with {@code @BeforeClass}. Initializing with - * {@code @Before} as we usually do will create mocks that won't have any use in the Utils class. - */ - @BeforeClass - public static void setUpMocks() { - WrapperMock wrapperMock = WrapperMock.createInstance(); - authMeMock = wrapperMock.getAuthMe(); - TestHelper.setupLogger(); - } - - @Before - public void setIndirectMocks() { - // Since the mocks aren't set up for each test case it is important to reset them when verifying whether or not - // they have been called. We want to return null for permissions manager once so we initialize a mock for it - // before every test -- this is OK because it is retrieved via authMeMock. It is just crucial that authMeMock - // remain the same object. - reset(authMeMock); - } - - @Test - public void shouldNotAddToNormalGroupIfPermissionsAreDisabled() { - // given - Settings.isPermissionCheckEnabled = false; - Player player = mock(Player.class); - - // when - boolean result = Utils.addNormal(player, "test_group"); - - // then - assertThat(result, equalTo(false)); - verify(authMeMock, never()).getPermissionsManager(); - } - - @Test - @Ignore - // TODO ljacqu 20160206: Running this test with all others results in an error - // because Utils is used elsewhere. The AuthMe field is set in a static block - // so creating the WrapperMock here will have no effect - public void shouldNotAddToNormalGroupIfPermManagerIsNull() { - // given - Settings.isPermissionCheckEnabled = true; - given(authMeMock.getPermissionsManager()).willReturn(null); - Player player = mock(Player.class); - - // when - boolean result = Utils.addNormal(player, "test_group"); - - // then - assertThat(result, equalTo(false)); - verify(authMeMock).getPermissionsManager(); - } - - @Test - public void shouldRetrieveListOfOnlinePlayersFromReflectedMethod() { - // given - ReflectionTestUtils.setField(Utils.class, null, "getOnlinePlayersIsCollection", false); - ReflectionTestUtils.setField(Utils.class, null, "getOnlinePlayers", - ReflectionTestUtils.getMethod(UtilsTest.class, "onlinePlayersImpl")); - - // when - Collection players = Utils.getOnlinePlayers(); - - // then - assertThat(players, hasSize(2)); - } - - // Note: This method is used through reflections - public static Player[] onlinePlayersImpl() { - return new Player[]{ - mock(Player.class), mock(Player.class) - }; - } - -} diff --git a/src/test/java/fr/xephi/authme/util/WrapperMock.java b/src/test/java/fr/xephi/authme/util/WrapperMock.java deleted file mode 100644 index fbf880ba..00000000 --- a/src/test/java/fr/xephi/authme/util/WrapperMock.java +++ /dev/null @@ -1,90 +0,0 @@ -package fr.xephi.authme.util; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.output.Messages; -import org.bukkit.Server; -import org.bukkit.scheduler.BukkitScheduler; -import org.mockito.Mockito; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -/** - * Class returning mocks for all calls in {@link Wrapper}. - * This class keeps track of its mocks and will always return - * the same one for each type. - */ -public class WrapperMock extends Wrapper { - - private Map, Object> mocks = new HashMap<>(); - - private WrapperMock() { - super(); - } - - /** - * Create a new instance of the WrapperMock and inject it as singleton into the Wrapper class. - * - * @return The created singleton - */ - public static WrapperMock createInstance() { - WrapperMock instance = new WrapperMock(); - Wrapper.setSingleton(instance); - return instance; - } - - @Override - public Server getServer() { - return getMock(Server.class); - } - - @Override - public AuthMe getAuthMe() { - return getMock(AuthMe.class); - } - - @Override - public BukkitScheduler getScheduler() { - return getMock(BukkitScheduler.class); - } - - @Override - public Messages getMessages() { - return getMock(Messages.class); - } - - @Override - public PlayerCache getPlayerCache() { - return getMock(PlayerCache.class); - } - - @Override - public File getDataFolder() { - return new File("/"); - } - - /** - * Return whether a mock of the given class type was created, i.e. verify whether a certain method was executed on - * the Wrapper to retrieve an entity. - * - * @param mockClass The class of the mock to verify - * - * @return True if the mock has been created, false otherwise - */ - public boolean wasMockCalled(Class mockClass) { - return mocks.get(mockClass) != null; - } - - private T getMock(Class clazz) { - Object o = mocks.get(clazz); - if (o == null) { - o = Mockito.mock(clazz); - mocks.put(clazz, o); - } - return clazz.cast(o); - } - - -} From 077cb242f0df36bbaa28386abc473bc89671c869 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 29 Apr 2016 21:16:42 +0200 Subject: [PATCH 61/71] #550 Show welcome message only after login - Never send welcome message just after registration (with no subsequent login) - Always run force command options upon registration --- .../register/ProcessSyncPasswordRegister.java | 28 +++++++------------ .../properties/RegistrationSettings.java | 2 +- src/main/resources/config.yml | 10 +++---- 3 files changed, 16 insertions(+), 24 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 84288822..b9505143 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -63,7 +63,12 @@ public class ProcessSyncPasswordRegister implements Process { } } - private void forceLogin(Player player) { + /** + * Request that the player log in. + * + * @param player the player + */ + private void requestLogin(Player player) { Utils.teleportToSpawn(player); LimboCache cache = LimboCache.getInstance(); cache.updateLimboPlayer(player); @@ -131,22 +136,12 @@ public class ProcessSyncPasswordRegister implements Process { return; } - // Register is finish and player is logged, display welcome message - if (service.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { - if (service.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) { - for (String s : service.getSettings().getWelcomeMessage()) { - plugin.getServer().broadcastMessage(plugin.replaceAllInfo(s, player)); - } - } else { - for (String s : service.getSettings().getWelcomeMessage()) { - player.sendMessage(plugin.replaceAllInfo(s, player)); - } - } - } + // Register is now finished; we can force all commands + forceCommands(); - // Request Login after Registration + // Request login after registration if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) { - forceLogin(player); + requestLogin(player); return; } @@ -154,9 +149,6 @@ public class ProcessSyncPasswordRegister implements Process { sendBungeeMessage(); } - // Register is now finished; we can force all commands - forceCommands(); - sendTo(); } diff --git a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java index c2c2bbe3..db1cb1ee 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java @@ -67,7 +67,7 @@ public class RegistrationSettings implements SettingsClass { newListProperty("settings.forceRegisterCommandsAsConsole"); @Comment({ - "Enable to display the welcome message (welcome.txt) after a registration or a login", + "Enable 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", diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 86aecfaa..17b62b37 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -253,11 +253,11 @@ settings: 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 register or 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 + # 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 From 8d489efffdd6017951bb73ce99056c71195bda44 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 29 Apr 2016 21:58:32 +0200 Subject: [PATCH 62/71] #683 Plaintext to SHA256: Add warning message + skip SHA hashes - Add message not to stop the server before conversion finishes - Skip hashes starting with $SHA$ during conversion - Create unit tests --- .../xephi/authme/util/MigrationService.java | 14 +- .../authme/util/MigrationServiceTest.java | 129 ++++++++++++++++++ 2 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/util/MigrationServiceTest.java diff --git a/src/main/java/fr/xephi/authme/util/MigrationService.java b/src/main/java/fr/xephi/authme/util/MigrationService.java index 86f98e4c..6d86adbe 100644 --- a/src/main/java/fr/xephi/authme/util/MigrationService.java +++ b/src/main/java/fr/xephi/authme/util/MigrationService.java @@ -37,12 +37,18 @@ public final class MigrationService { if (HashAlgorithm.PLAINTEXT == settings.getProperty(SecuritySettings.PASSWORD_HASH)) { ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated;" + " it will be changed and hashed now to the AuthMe default hashing method"); + ConsoleLogger.showError("Don't stop your server; wait for the conversion to have been completed!"); List allAuths = dataSource.getAllAuths(); for (PlayerAuth auth : allAuths) { - HashedPassword hashedPassword = authmeSha256.computeHash( - auth.getPassword().getHash(), auth.getNickname()); - auth.setPassword(hashedPassword); - dataSource.updatePassword(auth); + String hash = auth.getPassword().getHash(); + if (hash.startsWith("$SHA$")) { + ConsoleLogger.showError("Skipping conversion for " + auth.getNickname() + "; detected SHA hash"); + } else { + HashedPassword hashedPassword = authmeSha256.computeHash( + auth.getPassword().getHash(), auth.getNickname()); + auth.setPassword(hashedPassword); + dataSource.updatePassword(auth); + } } settings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); settings.save(); diff --git a/src/test/java/fr/xephi/authme/util/MigrationServiceTest.java b/src/test/java/fr/xephi/authme/util/MigrationServiceTest.java new file mode 100644 index 00000000..d27f642e --- /dev/null +++ b/src/test/java/fr/xephi/authme/util/MigrationServiceTest.java @@ -0,0 +1,129 @@ +package fr.xephi.authme.util; + +import fr.xephi.authme.TestHelper; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.security.crypts.SHA256; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.SecuritySettings; +import org.junit.BeforeClass; +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.util.Arrays; + +import static fr.xephi.authme.AuthMeMatchers.equalToHash; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +/** + * Test for {@link MigrationService}. + */ +@RunWith(MockitoJUnitRunner.class) +public class MigrationServiceTest { + + @Mock + private NewSetting settings; + + @Mock + private DataSource dataSource; + + @Mock + private SHA256 sha256; + + @BeforeClass + public static void setUpLogger() { + TestHelper.setupLogger(); + } + + @Test + public void shouldMigratePlaintextHashes() { + // given + PlayerAuth auth1 = authWithNickAndHash("bobby", "test"); + PlayerAuth auth2 = authWithNickAndHash("user", "myPassword"); + PlayerAuth auth3 = authWithNickAndHash("Tester12", "$tester12_pw"); + given(dataSource.getAllAuths()).willReturn(Arrays.asList(auth1, auth2, auth3)); + setSha256MockToUppercase(sha256); + given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.PLAINTEXT); + + // when + MigrationService.changePlainTextToSha256(settings, dataSource, sha256); + + // then + verify(sha256, times(3)).computeHash(anyString(), anyString()); + verify(dataSource).getAllAuths(); // need to verify this because we use verifyNoMoreInteractions() after + verify(dataSource).updatePassword(auth1); + assertThat(auth1.getPassword(), equalToHash("TEST")); + verify(dataSource).updatePassword(auth2); + assertThat(auth2.getPassword(), equalToHash("MYPASSWORD")); + verify(dataSource).updatePassword(auth3); + assertThat(auth3.getPassword(), equalToHash("$TESTER12_PW")); + verifyNoMoreInteractions(dataSource); + verify(settings).setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); + } + + @Test + public void shouldNotMigrateShaHashes() { + // given + PlayerAuth auth1 = authWithNickAndHash("testUser", "abc1234"); + PlayerAuth auth2 = authWithNickAndHash("minecraft", "$SHA$f28930ae09823eba4cd98a3"); + given(dataSource.getAllAuths()).willReturn(Arrays.asList(auth1, auth2)); + setSha256MockToUppercase(sha256); + given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.PLAINTEXT); + + // when + MigrationService.changePlainTextToSha256(settings, dataSource, sha256); + + // then + verify(sha256).computeHash(eq("abc1234"), argThat(equalToIgnoringCase("testUser"))); + verifyNoMoreInteractions(sha256); + verify(dataSource).getAllAuths(); // need to verify this because we use verifyNoMoreInteractions() after + verify(dataSource).updatePassword(auth1); + assertThat(auth1.getPassword(), equalToHash("ABC1234")); + verifyNoMoreInteractions(dataSource); + verify(settings).setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); + } + + @Test + public void shouldNotMigrateForHashOtherThanPlaintext() { + // given + given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.BCRYPT); + + // when + MigrationService.changePlainTextToSha256(settings, dataSource, sha256); + + // then + verify(settings).getProperty(SecuritySettings.PASSWORD_HASH); + verifyNoMoreInteractions(settings, dataSource, sha256); + } + + private static PlayerAuth authWithNickAndHash(String nick, String hash) { + return PlayerAuth.builder() + .name(nick) + .password(hash, null) + .build(); + } + + private static void setSha256MockToUppercase(SHA256 sha256) { + given(sha256.computeHash(anyString(), anyString())).willAnswer(new Answer() { + @Override + public HashedPassword answer(InvocationOnMock invocation) { + String plainPassword = (String) invocation.getArguments()[0]; + return new HashedPassword(plainPassword.toUpperCase(), null); + } + }); + } +} From 7f44ecdb40826235cd0cf61be130bcdfdf7af7fb Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 29 Apr 2016 22:39:46 +0200 Subject: [PATCH 63/71] Create event consistency test + test code cleanup --- .../xephi/authme/util/MigrationService.java | 3 +- src/test/java/fr/xephi/authme/TestHelper.java | 36 +++++++ .../authme/events/EventsConsistencyTest.java | 94 +++++++++++++++++++ .../SettingsClassConsistencyTest.java | 23 +---- .../authme/util/MigrationServiceTest.java | 5 + 5 files changed, 139 insertions(+), 22 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/events/EventsConsistencyTest.java diff --git a/src/main/java/fr/xephi/authme/util/MigrationService.java b/src/main/java/fr/xephi/authme/util/MigrationService.java index 6d86adbe..7bf028f6 100644 --- a/src/main/java/fr/xephi/authme/util/MigrationService.java +++ b/src/main/java/fr/xephi/authme/util/MigrationService.java @@ -44,8 +44,7 @@ public final class MigrationService { if (hash.startsWith("$SHA$")) { ConsoleLogger.showError("Skipping conversion for " + auth.getNickname() + "; detected SHA hash"); } else { - HashedPassword hashedPassword = authmeSha256.computeHash( - auth.getPassword().getHash(), auth.getNickname()); + HashedPassword hashedPassword = authmeSha256.computeHash(hash, auth.getNickname()); auth.setPassword(hashedPassword); dataSource.updatePassword(auth); } diff --git a/src/test/java/fr/xephi/authme/TestHelper.java b/src/test/java/fr/xephi/authme/TestHelper.java index fe55de5f..463b3870 100644 --- a/src/test/java/fr/xephi/authme/TestHelper.java +++ b/src/test/java/fr/xephi/authme/TestHelper.java @@ -6,6 +6,9 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; @@ -84,9 +87,42 @@ public final class TestHelper { runnable.run(); } + /** + * Assign the necessary fields on ConsoleLogger with mocks. + * + * @return The logger mock used + */ public static Logger setupLogger() { Logger logger = Mockito.mock(Logger.class); ConsoleLogger.setLogger(logger); return logger; } + + /** + * Check that a class only has a hidden, zero-argument constructor, preventing the + * instantiation of such classes (utility classes). Invokes the hidden constructor + * as to register the code coverage. + * + * @param clazz The class to validate + */ + public static void validateHasOnlyPrivateEmptyConstructor(Class clazz) { + Constructor[] constructors = clazz.getDeclaredConstructors(); + if (constructors.length > 1) { + throw new IllegalStateException("Class " + clazz.getSimpleName() + " has more than one constructor"); + } else if (constructors[0].getParameterTypes().length != 0) { + throw new IllegalStateException("Constructor of " + clazz + " does not have empty parameter list"); + } else if (!Modifier.isPrivate(constructors[0].getModifiers())) { + throw new IllegalStateException("Constructor of " + clazz + " is not private"); + } + + // Ugly hack to get coverage on the private constructors + // http://stackoverflow.com/questions/14077842/how-to-test-a-private-constructor-in-java-application + try { + constructors[0].setAccessible(true); + constructors[0].newInstance(); + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new UnsupportedOperationException(e); + } + } + } diff --git a/src/test/java/fr/xephi/authme/events/EventsConsistencyTest.java b/src/test/java/fr/xephi/authme/events/EventsConsistencyTest.java new file mode 100644 index 00000000..d7ba5f74 --- /dev/null +++ b/src/test/java/fr/xephi/authme/events/EventsConsistencyTest.java @@ -0,0 +1,94 @@ +package fr.xephi.authme.events; + +import org.apache.commons.lang.reflect.MethodUtils; +import org.bukkit.event.Event; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +/** + * Checks the consistency of the AuthMe event classes. + */ +public class EventsConsistencyTest { + + private static final String SRC_FOLDER = "src/main/java/"; + private static final String EVENTS_FOLDER = SRC_FOLDER + "/fr/xephi/authme/events/"; + private static List> classes; + + @BeforeClass + public static void scanEventClasses() { + File eventsFolder = new File(EVENTS_FOLDER); + File[] filesInFolder = eventsFolder.listFiles(); + if (filesInFolder == null || filesInFolder.length == 0) { + throw new IllegalStateException("Could not read folder '" + EVENTS_FOLDER + "'. Is it correct?"); + } + + classes = new ArrayList<>(); + for (File file : filesInFolder) { + Class clazz = getEventClassFromFile(file); + if (clazz != null) { + classes.add(clazz); + } + } + if (classes.isEmpty()) { + throw new IllegalStateException("Did not find any AuthMe event classes. Is the folder correct?"); + } + } + + @Test + public void shouldExtendFromCustomEvent() { + for (Class clazz : classes) { + assertThat("Class " + clazz.getSimpleName() + " is subtype of CustomEvent", + CustomEvent.class.isAssignableFrom(clazz), equalTo(true)); + } + } + + /** + * Bukkit requires a static getHandlerList() method on all event classes, see {@link Event}. + * This test checks that such a method is present, and that it is absent if the class + * is not instantiable (abstract class). + */ + @Test + public void shouldHaveStaticEventHandlerMethod() { + for (Class clazz : classes) { + Method handlerListMethod = MethodUtils.getAccessibleMethod(clazz, "getHandlerList", new Class[]{}); + if (canBeInstantiated(clazz)) { + assertThat("Class " + clazz.getSimpleName() + " has static method getHandlerList()", + handlerListMethod != null && Modifier.isStatic(handlerListMethod.getModifiers()), equalTo(true)); + } else { + assertThat("Non-instantiable class " + clazz.getSimpleName() + " does not have static getHandlerList()", + handlerListMethod, nullValue()); + } + } + } + + private static boolean canBeInstantiated(Class clazz) { + return !clazz.isInterface() && !clazz.isEnum() && !Modifier.isAbstract(clazz.getModifiers()); + } + + private static Class getEventClassFromFile(File file) { + String fileName = file.getPath(); + String className = fileName + .substring(SRC_FOLDER.length(), fileName.length() - ".java".length()) + .replace(File.separator, "."); + try { + Class clazz = EventsConsistencyTest.class.getClassLoader().loadClass(className); + if (Event.class.isAssignableFrom(clazz)) { + return (Class) clazz; + } + return null; + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Could not load class '" + className + "'", e); + } + } + +} 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 c6b00383..75c1a56a 100644 --- a/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java @@ -1,22 +1,20 @@ package fr.xephi.authme.settings.properties; import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.TestHelper; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.domain.SettingsClass; import org.junit.BeforeClass; import org.junit.Test; import java.io.File; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @@ -86,24 +84,9 @@ public class SettingsClassConsistencyTest { } @Test - public void shouldHaveHiddenDefaultConstructorOnly() { + public void shouldHaveHiddenEmptyConstructorOnly() { for (Class clazz : classes) { - Constructor[] constructors = clazz.getDeclaredConstructors(); - assertThat(clazz + " should only have one constructor", - constructors, arrayWithSize(1)); - assertThat("Constructor of " + clazz + " is private", - Modifier.isPrivate(constructors[0].getModifiers()), equalTo(true)); - - // Ugly hack to get coverage on the private constructors - // http://stackoverflow.com/questions/14077842/how-to-test-a-private-constructor-in-java-application - try { - Constructor constructor = clazz.getDeclaredConstructor(); - constructor.setAccessible(true); - constructor.newInstance(); - } catch (NoSuchMethodException | InstantiationException - | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } + TestHelper.validateHasOnlyPrivateEmptyConstructor(clazz); } } diff --git a/src/test/java/fr/xephi/authme/util/MigrationServiceTest.java b/src/test/java/fr/xephi/authme/util/MigrationServiceTest.java index d27f642e..34fda2bb 100644 --- a/src/test/java/fr/xephi/authme/util/MigrationServiceTest.java +++ b/src/test/java/fr/xephi/authme/util/MigrationServiceTest.java @@ -110,6 +110,11 @@ public class MigrationServiceTest { verifyNoMoreInteractions(settings, dataSource, sha256); } + @Test + public void shouldHaveHiddenEmptyConstructorOnly() { + TestHelper.validateHasOnlyPrivateEmptyConstructor(MigrationService.class); + } + private static PlayerAuth authWithNickAndHash(String nick, String hash) { return PlayerAuth.builder() .name(nick) From b32e5da4c597a7e1e42fa33fe3eff40555164e8e Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 30 Apr 2016 09:30:52 +0200 Subject: [PATCH 64/71] #611 Admin unregister forces player to register even for optional registration - Make /authme unregister behave the same way as /unregister for optional registration: user is informed but can continue playing; no teleportation to spawn --- .../authme/UnregisterAdminCommand.java | 59 ++++++++++++------- .../unregister/AsynchronousUnregister.java | 1 - .../fr/xephi/authme/settings/Settings.java | 5 +- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java index 58ccdf0f..5c8196dd 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java @@ -7,31 +7,29 @@ import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.RegistrationSettings; +import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.TimeoutTask; +import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.Utils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; import java.util.List; +import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND; + /** * Admin command to unregister a player. */ public class UnregisterAdminCommand implements ExecutableCommand { - @Override public void executeCommand(final CommandSender sender, List arguments, CommandService commandService) { - // AuthMe plugin instance - final AuthMe plugin = AuthMe.getInstance(); - // Get the player name String playerName = arguments.get(0); String playerNameLowerCase = playerName.toLowerCase(); @@ -53,27 +51,44 @@ public class UnregisterAdminCommand implements ExecutableCommand { PlayerCache.getInstance().removePlayer(playerNameLowerCase); Utils.setGroup(target, Utils.GroupType.UNREGISTERED); if (target != null && target.isOnline()) { - Utils.teleportToSpawn(target); - LimboCache.getInstance().addLimboPlayer(target); - int timeOut = Settings.getRegistrationTimeout * 20; - int interval = Settings.getWarnMessageInterval; - BukkitScheduler scheduler = sender.getServer().getScheduler(); - if (timeOut != 0) { - BukkitTask id = scheduler.runTaskLater(plugin, new TimeoutTask(plugin, playerNameLowerCase, target), timeOut); - LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setTimeoutTask(id); - } - LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setMessageTask( - scheduler.runTask(plugin, new MessageTask(commandService.getBukkitService(), plugin.getMessages(), - playerNameLowerCase, MessageKey.REGISTER_MESSAGE, interval))); - - if (commandService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { - target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2)); + if (commandService.getProperty(RegistrationSettings.FORCE)) { + applyUnregisteredEffectsAndTasks(target, commandService); } commandService.send(target, MessageKey.UNREGISTERED_SUCCESS); } // Show a status message commandService.send(sender, MessageKey.UNREGISTERED_SUCCESS); - ConsoleLogger.info(playerName + " unregistered"); + ConsoleLogger.info(sender.getName() + " unregistered " + playerName); + } + + /** + * When registration is forced, applies the configured "unregistered effects" to the player as he + * would encounter when joining the server before logging on - reminder task to log in, + * timeout kick, blindness. + * + * @param target the player that was unregistered + * @param service the command service + */ + private void applyUnregisteredEffectsAndTasks(Player target, CommandService service) { + final AuthMe plugin = service.getAuthMe(); + final BukkitService bukkitService = service.getBukkitService(); + final String playerNameLowerCase = target.getName().toLowerCase(); + + Utils.teleportToSpawn(target); + LimboCache.getInstance().addLimboPlayer(target); + int timeOut = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; + int interval = service.getProperty(RegistrationSettings.MESSAGE_INTERVAL); + if (timeOut != 0) { + BukkitTask id = bukkitService.runTaskLater(new TimeoutTask(plugin, playerNameLowerCase, target), timeOut); + LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setTimeoutTask(id); + } + LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setMessageTask( + bukkitService.runTask(new MessageTask(service.getBukkitService(), plugin.getMessages(), + playerNameLowerCase, MessageKey.REGISTER_MESSAGE, interval))); + + if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { + target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2)); + } } } diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java index 7b2c2a7f..cd3f41a2 100644 --- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java +++ b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java @@ -97,7 +97,6 @@ public class AsynchronousUnregister implements Process { } service.send(player, MessageKey.UNREGISTERED_SUCCESS); ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); - Utils.teleportToSpawn(player); } else { service.send(player, MessageKey.WRONG_PASSWORD); } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 129f35b3..944f675d 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -39,8 +39,7 @@ public final class Settings { public static String getNickRegex, getUnloggedinGroup, unRegisteredGroup, backupWindowsPath, getRegisteredGroup, rakamakUsers, rakamakUsersIp, defaultWorld, crazyloginFileName; - public static int getWarnMessageInterval, getSessionTimeout, - getRegistrationTimeout, getMaxNickLength, getMinNickLength, + public static int getSessionTimeout, getMaxNickLength, getMinNickLength, getNonActivatedGroup, maxLoginTry, captchaLength, getMaxLoginPerIp; protected static FileConfiguration configFile; @@ -58,10 +57,8 @@ public final class Settings { isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK); isForcedRegistrationEnabled = load(RegistrationSettings.FORCE); isTeleportToSpawnEnabled = load(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN); - getWarnMessageInterval = load(RegistrationSettings.MESSAGE_INTERVAL); isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED); getSessionTimeout = configFile.getInt("settings.sessions.timeout", 10); - getRegistrationTimeout = load(RestrictionSettings.TIMEOUT); getMaxNickLength = configFile.getInt("settings.restrictions.maxNicknameLength", 20); getMinNickLength = configFile.getInt("settings.restrictions.minNicknameLength", 3); getNickRegex = configFile.getString("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_?]*"); From c8b191fda0b123549bcf4fe9752d74cdbc5802b6 Mon Sep 17 00:00:00 2001 From: games647 Date: Sat, 30 Apr 2016 13:05:31 +0200 Subject: [PATCH 65/71] Add warning if hideTablist is not compatible with the mc version (Fixes #680) --- .../authme/listener/AuthMeTablistPacketAdapter.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index a23ce5c1..6d4ea8ba 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -8,15 +8,18 @@ import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.FieldAccessException; +import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; import com.comphenix.protocol.wrappers.PlayerInfoData; import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedGameProfile; + import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.util.BukkitService; + import org.bukkit.entity.Player; import java.lang.reflect.InvocationTargetException; @@ -80,7 +83,12 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { } public void register() { - ProtocolLibrary.getProtocolManager().addPacketListener(this); + if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) { + ProtocolLibrary.getProtocolManager().addPacketListener(this); + } else { + ConsoleLogger.info("The hideTablist feature is not compatible with your minecraft version"); + ConsoleLogger.info("It requires 1.8+. Disabling the hideTablist feature..."); + } } public void unregister() { From 1f0f3f1bea02042d45b39b21565cebd3aec9e524 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 30 Apr 2016 14:11:19 +0200 Subject: [PATCH 66/71] #675 Clean up country protection code - Move validation to validation service --- src/main/java/fr/xephi/authme/AuthMe.java | 11 ++-- .../authme/listener/AuthMePlayerListener.java | 32 ++++----- .../authme/listener/AuthMeServerListener.java | 22 ++++--- .../xephi/authme/util/ValidationService.java | 66 ++++++++++++++++--- 4 files changed, 91 insertions(+), 40 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 08a1945c..6aebc2f2 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -306,7 +306,8 @@ public class AuthMe extends JavaPlugin { reloadSupportHook(); // Register event listeners - registerEventListeners(messages, database, management, pluginHooks, spawnLoader, antiBot); + registerEventListeners( + messages, database, management, pluginHooks, spawnLoader, antiBot, bukkitService, validationService); // Start Email recall task if needed scheduleRecallEmailTask(); @@ -371,16 +372,18 @@ public class AuthMe extends JavaPlugin { * Register all event listeners. */ private void registerEventListeners(Messages messages, DataSource dataSource, Management management, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot) { + PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, + BukkitService bukkitService, ValidationService validationService) { // Get the plugin manager instance PluginManager pluginManager = server.getPluginManager(); // Register event listeners pluginManager.registerEvents(new AuthMePlayerListener( - this, newSettings, messages, dataSource, antiBot, management, bukkitService), this); + this, newSettings, messages, dataSource, antiBot, management, bukkitService, validationService), this); pluginManager.registerEvents(new AuthMeBlockListener(), this); pluginManager.registerEvents(new AuthMeEntityListener(), this); - pluginManager.registerEvents(new AuthMeServerListener(this, messages, pluginHooks, spawnLoader), this); + pluginManager.registerEvents(new AuthMeServerListener( + this, messages, newSettings, pluginHooks, spawnLoader, validationService), this); // Try to register 1.6 player listeners try { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index a17eacd5..e3753793 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -19,11 +19,12 @@ import fr.xephi.authme.process.Management; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.HooksSettings; +import fr.xephi.authme.settings.properties.ProtectionSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.BukkitService; -import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.Utils; +import fr.xephi.authme.util.ValidationService; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -74,9 +75,11 @@ public class AuthMePlayerListener implements Listener { private final AntiBot antiBot; private final Management management; private final BukkitService bukkitService; + private final ValidationService validationService; public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource, - AntiBot antiBot, Management management, BukkitService bukkitService) { + AntiBot antiBot, Management management, BukkitService bukkitService, + ValidationService validationService) { this.plugin = plugin; this.settings = settings; this.m = messages; @@ -84,6 +87,7 @@ public class AuthMePlayerListener implements Listener { this.antiBot = antiBot; this.management = management; this.bukkitService = bukkitService; + this.validationService = validationService; } private void handleChat(AsyncPlayerChatEvent event) { @@ -265,30 +269,22 @@ public class AuthMePlayerListener implements Listener { PlayerAuth auth = dataSource.getAuth(event.getName()); if (settings.getProperty(RegistrationSettings.PREVENT_OTHER_CASE) && auth != null && auth.getRealName() != null) { String realName = auth.getRealName(); - if (!realName.isEmpty() && !realName.equals("Player") && !realName.equals(event.getName())) { + if (!realName.isEmpty() && !"Player".equals(realName) && !realName.equals(event.getName())) { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_CASE, realName, event.getName())); return; } - if (realName.isEmpty() || realName.equals("Player")) { + if (realName.isEmpty() || "Player".equals(realName)) { dataSource.updateRealName(event.getName().toLowerCase(), event.getName()); } } - if (auth == null) { - if (!Settings.countriesBlacklist.isEmpty() || !Settings.countries.isEmpty()) { - String playerIP = event.getAddress().getHostAddress(); - String countryCode = GeoLiteAPI.getCountryCode(playerIP); - if (Settings.countriesBlacklist.contains(countryCode)) { - event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); - event.setKickMessage(m.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR)); - return; - } - if (Settings.enableProtection && !Settings.countries.contains(countryCode)) { - event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); - event.setKickMessage(m.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR)); - return; - } + if (auth == null && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) { + String playerIp = event.getAddress().getHostAddress(); + if (!validationService.isCountryAdmitted(playerIp)) { + event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); + event.setKickMessage(m.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR)); + return; } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index ec8326b5..96f5320a 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -5,9 +5,10 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.SpawnLoader; -import fr.xephi.authme.util.GeoLiteAPI; +import fr.xephi.authme.settings.properties.ProtectionSettings; +import fr.xephi.authme.util.ValidationService; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -21,25 +22,26 @@ public class AuthMeServerListener implements Listener { private final AuthMe plugin; private final Messages messages; + private final NewSetting settings; private final PluginHooks pluginHooks; private final SpawnLoader spawnLoader; + private final ValidationService validationService; - public AuthMeServerListener(AuthMe plugin, Messages messages, PluginHooks pluginHooks, SpawnLoader spawnLoader) { + public AuthMeServerListener(AuthMe plugin, Messages messages, NewSetting settings, PluginHooks pluginHooks, + SpawnLoader spawnLoader, ValidationService validationService) { this.plugin = plugin; this.messages = messages; + this.settings = settings; this.pluginHooks = pluginHooks; this.spawnLoader = spawnLoader; + this.validationService = validationService; } @EventHandler(priority = EventPriority.HIGHEST) public void onServerPing(ServerListPingEvent event) { - if (!Settings.countriesBlacklist.isEmpty() || !Settings.countries.isEmpty()){ - String countryCode = GeoLiteAPI.getCountryCode(event.getAddress().getHostAddress()); - if( Settings.countriesBlacklist.contains(countryCode)) { - event.setMotd(messages.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR)); - return; - } - if (Settings.enableProtection && !Settings.countries.contains(countryCode)) { + if (settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) { + String playerIp = event.getAddress().getHostAddress(); + if (!validationService.isCountryAdmitted(playerIp)) { event.setMotd(messages.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR)); } } diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java index 7f8b78b7..95dff810 100644 --- a/src/main/java/fr/xephi/authme/util/ValidationService.java +++ b/src/main/java/fr/xephi/authme/util/ValidationService.java @@ -5,7 +5,9 @@ import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.EmailSettings; +import fr.xephi.authme.settings.properties.ProtectionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.CommandSender; @@ -52,26 +54,74 @@ public class ValidationService { return null; } + /** + * Verifies whether the email is valid and admitted for use according to the plugin settings. + * + * @param email the email to verify + * @return true if the email is valid, false otherwise + */ public boolean validateEmail(String email) { if (!email.contains("@") || "your@email.com".equalsIgnoreCase(email)) { return false; } final String emailDomain = email.split("@")[1]; - - List whitelist = settings.getProperty(EmailSettings.DOMAIN_WHITELIST); - if (!CollectionUtils.isEmpty(whitelist)) { - return containsIgnoreCase(whitelist, emailDomain); - } - - List blacklist = settings.getProperty(EmailSettings.DOMAIN_BLACKLIST); - return CollectionUtils.isEmpty(blacklist) || !containsIgnoreCase(blacklist, emailDomain); + return validateWhitelistAndBlacklist( + emailDomain, EmailSettings.DOMAIN_WHITELIST, EmailSettings.DOMAIN_BLACKLIST); } + /** + * Queries the database whether the email is still free for registration, i.e. whether the given + * command sender may use the email to register a new account (as defined by settings and permissions). + * + * @param email the email to verify + * @param sender the command sender + * @return true if the email may be used, false otherwise (registration threshold has been exceeded) + */ public boolean isEmailFreeForRegistration(String email, CommandSender sender) { return permissionsManager.hasPermission(sender, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) || dataSource.countAuthsByEmail(email) < settings.getProperty(EmailSettings.MAX_REG_PER_EMAIL); } + /** + * Checks whether the player's country is allowed to join the server, based on the given IP address + * and the configured country whitelist or blacklist. + * + * @param hostAddress the IP address to verify + * @return true if the IP address' country is allowed, false otherwise + */ + public boolean isCountryAdmitted(String hostAddress) { + // Check if we have restrictions on country, if not return true and avoid the country lookup + if (settings.getProperty(ProtectionSettings.COUNTRIES_WHITELIST).isEmpty() + && settings.getProperty(ProtectionSettings.COUNTRIES_BLACKLIST).isEmpty()) { + return true; + } + + String countryCode = GeoLiteAPI.getCountryCode(hostAddress); + return validateWhitelistAndBlacklist(countryCode, + ProtectionSettings.COUNTRIES_WHITELIST, + ProtectionSettings.COUNTRIES_BLACKLIST); + } + + /** + * Verifies whether the given value is allowed according to the given whitelist and blacklist settings. + * Whitelist has precedence over blacklist: if a whitelist is set, the value is rejected if not present + * in the whitelist. + * + * @param value the value to verify + * @param whitelist the whitelist property + * @param blacklist the blacklist property + * @return true if the value is admitted by the lists, false otherwise + */ + private boolean validateWhitelistAndBlacklist(String value, Property> whitelist, + Property> blacklist) { + List whitelistValue = settings.getProperty(whitelist); + if (!CollectionUtils.isEmpty(whitelistValue)) { + return containsIgnoreCase(whitelistValue, value); + } + List blacklistValue = settings.getProperty(blacklist); + return CollectionUtils.isEmpty(blacklistValue) || !containsIgnoreCase(blacklistValue, value); + } + private static boolean containsIgnoreCase(Collection coll, String needle) { for (String entry : coll) { if (entry.equalsIgnoreCase(needle)) { From 121dd7e6fb1a662a479147e31f57f00d460e8ed7 Mon Sep 17 00:00:00 2001 From: Xephi59 Date: Mon, 2 May 2016 02:13:19 +0200 Subject: [PATCH 67/71] Add Spigot API - 1.9 PlayerSpawnLocationEvent --- pom.xml | 8 +++ src/main/java/fr/xephi/authme/AuthMe.java | 61 +++++++++++-------- .../fr/xephi/authme/hooks/PluginHooks.java | 14 +++-- .../listener/AuthMePlayerListener19.java | 26 ++++++++ 4 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java diff --git a/pom.xml b/pom.xml index ec273c53..832fdce8 100644 --- a/pom.xml +++ b/pom.xml @@ -429,6 +429,14 @@ true + + + org.spigotmc + spigot-api + 1.9.2-R0.1-SNAPSHOT + provided + + org.bukkit diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 6aebc2f2..66a49dbd 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -1,5 +1,32 @@ package fr.xephi.authme; +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT; +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD; +import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS; +import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; + +import java.io.File; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.apache.logging.log4j.LogManager; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; + import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.cache.auth.PlayerAuth; @@ -27,6 +54,7 @@ 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.AuthMePlayerListener19; import fr.xephi.authme.listener.AuthMeServerListener; import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter; import fr.xephi.authme.listener.AuthMeTablistPacketAdapter; @@ -62,32 +90,6 @@ import fr.xephi.authme.util.MigrationService; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.ValidationService; -import org.apache.logging.log4j.LogManager; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.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; - -import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT; -import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD; -import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS; -import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; /** * The AuthMe main class. @@ -398,6 +400,13 @@ public class AuthMe extends JavaPlugin { pluginManager.registerEvents(new AuthMePlayerListener18(), this); } catch (ClassNotFoundException ignore) { } + + // Try to register 1.9 player listeners + try { + Class.forName("org.spigotmc.event.player.PlayerSpawnLocationEvent"); + pluginManager.registerEvents(new AuthMePlayerListener19(this), this); + } catch (ClassNotFoundException ignore) { + } } private void reloadSupportHook() { diff --git a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java index 3a54709a..fd455bb1 100644 --- a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java +++ b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java @@ -1,17 +1,19 @@ package fr.xephi.authme.hooks; -import com.earth2me.essentials.Essentials; -import com.onarandombox.MultiverseCore.MultiverseCore; -import com.onarandombox.MultiverseCore.api.MVWorldManager; -import fr.xephi.authme.ConsoleLogger; -import net.minelink.ctplus.CombatTagPlus; +import java.io.File; + import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; -import java.io.File; +import com.earth2me.essentials.Essentials; +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorldManager; + +import fr.xephi.authme.ConsoleLogger; +import net.minelink.ctplus.CombatTagPlus; /** * Hooks into third-party plugins and allows to perform actions on them. diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java new file mode 100644 index 00000000..5e6525bb --- /dev/null +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener19.java @@ -0,0 +1,26 @@ +package fr.xephi.authme.listener; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.spigotmc.event.player.PlayerSpawnLocationEvent; + +import fr.xephi.authme.AuthMe; + +/** + * Listener of player events for events introduced in Minecraft 1.9. + */ +public class AuthMePlayerListener19 implements Listener { + + private final AuthMe plugin; + + public AuthMePlayerListener19(AuthMe plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerSpawn(PlayerSpawnLocationEvent event) { + event.setSpawnLocation(plugin.getSpawnLocation(event.getPlayer())); + } + +} From e97b4641a1780c2cadd1101d4f24f42c9cac5a8c Mon Sep 17 00:00:00 2001 From: Xephi59 Date: Mon, 2 May 2016 02:39:53 +0200 Subject: [PATCH 68/71] Kick player only Synchronously --- .../authme/RegisterAdminCommand.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) 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 2caf7a3c..90ea8db5 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java @@ -1,15 +1,17 @@ package fr.xephi.authme.command.executable.authme; +import java.util.List; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.crypts.HashedPassword; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.List; /** * Admin command to register a user. @@ -55,9 +57,15 @@ public class RegisterAdminCommand implements ExecutableCommand { commandService.send(sender, MessageKey.REGISTER_SUCCESS); ConsoleLogger.info(sender.getName() + " registered " + playerName); - Player player = commandService.getPlayer(playerName); + final Player player = commandService.getPlayer(playerName); if (player != null) { - player.kickPlayer("An admin just registered you, please log in again"); + sender.getServer().getScheduler().scheduleSyncDelayedTask(AuthMe.getInstance(), new Runnable() + { + @Override + public void run() { + player.kickPlayer("An admin just registered you, please log in again"); + } + }); } } }); From 20a237dbdfefddcc38e75ca8b33c493a21f55548 Mon Sep 17 00:00:00 2001 From: Xephi59 Date: Mon, 2 May 2016 03:38:25 +0200 Subject: [PATCH 69/71] [DEV] This test would fail until player couldn't be returned as he was kicked --- .../authme/RegisterAdminCommand.java | 17 ++++---- .../authme/RegisterAdminCommandTest.java | 40 +++++++++---------- 2 files changed, 26 insertions(+), 31 deletions(-) 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 90ea8db5..2c842aee 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 @@ -5,7 +5,6 @@ import java.util.List; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.command.CommandService; @@ -57,15 +56,15 @@ public class RegisterAdminCommand implements ExecutableCommand { commandService.send(sender, MessageKey.REGISTER_SUCCESS); ConsoleLogger.info(sender.getName() + " registered " + playerName); - final Player player = commandService.getPlayer(playerName); + Player player = commandService.getPlayer(playerName); if (player != null) { - sender.getServer().getScheduler().scheduleSyncDelayedTask(AuthMe.getInstance(), new Runnable() - { - @Override - public void run() { - player.kickPlayer("An admin just registered you, please log in again"); - } - }); + final Player p = player; + p.getServer().getScheduler().scheduleSyncDelayedTask(commandService.getAuthMe(), new Runnable() { + @Override + public void run() { + p.kickPlayer("An admin just registered you, please log in again"); + } + }); } } }); 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 66b7d6c4..d2c7fd1e 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommandTest.java @@ -1,13 +1,15 @@ package fr.xephi.authme.command.executable.authme; -import fr.xephi.authme.TestHelper; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.command.CommandService; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import java.util.Arrays; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.BeforeClass; @@ -17,17 +19,14 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; 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; +import fr.xephi.authme.TestHelper; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.command.CommandService; +import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.output.MessageKey; +import fr.xephi.authme.security.PasswordSecurity; +import fr.xephi.authme.security.crypts.HashedPassword; /** * Test for {@link RegisterAdminCommand}. @@ -155,8 +154,6 @@ public class RegisterAdminCommandTest { HashedPassword hashedPassword = new HashedPassword("$aea2345EW235dfsa@#R%987048"); given(passwordSecurity.computeHash(password, user)).willReturn(hashedPassword); given(commandService.getPasswordSecurity()).willReturn(passwordSecurity); - Player player = mock(Player.class); - given(commandService.getPlayer(user)).willReturn(player); ExecutableCommand command = new RegisterAdminCommand(); // when @@ -170,7 +167,6 @@ public class RegisterAdminCommandTest { verify(dataSource).saveAuth(captor.capture()); assertAuthHasInfo(captor.getValue(), user, hashedPassword); verify(dataSource).setUnlogged(user); - verify(player).kickPlayer(argThat(containsString("please log in again"))); } private void assertAuthHasInfo(PlayerAuth auth, String name, HashedPassword hashedPassword) { From df6aa0a7a88c7743e8f3c230c4756e216a6acba2 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Mon, 2 May 2016 21:21:02 +0200 Subject: [PATCH 70/71] Bump hikaricp version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 832fdce8..5b130946 100644 --- a/pom.xml +++ b/pom.xml @@ -337,7 +337,7 @@ com.zaxxer HikariCP - 2.4.5 + 2.4.6 compile From 552ecb5d8e4a811a3d46c8378e8fc7252e6e8a75 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 3 May 2016 12:44:35 +0200 Subject: [PATCH 71/71] BETA2 Release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5b130946..ffb244e9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ fr.xephi authme - 5.2-SNAPSHOT + 5.2-BETA2 jar AuthMeReloaded