diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 08a1945c1..6aebc2f2a 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 a17eacd58..e37537937 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 ec8326b56..96f5320ad 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 7f8b78b7a..95dff810f 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)) {