diff --git a/.checkstyle.xml b/.checkstyle.xml index 00141bd6..017242e3 100644 --- a/.checkstyle.xml +++ b/.checkstyle.xml @@ -177,6 +177,7 @@ + diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 00beaf51..f74d5606 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -288,8 +288,7 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.warning("Note: You have set Email.useTls to false but this only affects mail over port 25"); } - // Unsalted hashes will be deprecated in 5.4 (see Github issue #1016). Exclude RoyalAuth from this check because - // it is needed to hook into an existing system. + // Unsalted hashes will be deprecated in 5.4 (see Github issue #1016) HashAlgorithm hash = settings.getProperty(SecuritySettings.PASSWORD_HASH); if (OnStartupTasks.isHashDeprecatedIn54(hash)) { ConsoleLogger.warning("You are using an unsalted hash (" + hash + "). Support for this will be removed " diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java index 5cd7fb4f..fc7cd429 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java @@ -16,13 +16,14 @@ import java.util.TreeMap; */ public class DebugCommand implements ExecutableCommand { + private static final Set> SECTION_CLASSES = ImmutableSet.of( + PermissionGroups.class, DataStatistics.class, CountryLookup.class, PlayerAuthViewer.class, InputValidator.class, + LimboPlayerViewer.class, CountryLookup.class, HasPermissionChecker.class, TestEmailSender.class, + SpawnLocationViewer.class); + @Inject private Factory debugSectionFactory; - private Set> sectionClasses = ImmutableSet.of(PermissionGroups.class, - DataStatistics.class, CountryLookup.class, PlayerAuthViewer.class, LimboPlayerViewer.class, CountryLookup.class, - HasPermissionChecker.class, TestEmailSender.class); - private Map sections; @Override @@ -48,7 +49,7 @@ public class DebugCommand implements ExecutableCommand { private Map getSections() { if (sections == null) { Map sections = new TreeMap<>(); - for (Class sectionClass : sectionClasses) { + for (Class sectionClass : SECTION_CLASSES) { DebugSection section = debugSectionFactory.newInstance(sectionClass); sections.put(section.getName(), section); } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/InputValidator.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/InputValidator.java new file mode 100644 index 00000000..47202506 --- /dev/null +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/InputValidator.java @@ -0,0 +1,115 @@ +package fr.xephi.authme.command.executable.authme.debug; + +import fr.xephi.authme.listener.FailedVerificationException; +import fr.xephi.authme.listener.OnJoinVerifier; +import fr.xephi.authme.message.Messages; +import fr.xephi.authme.service.ValidationService; +import fr.xephi.authme.service.ValidationService.ValidationResult; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +import javax.inject.Inject; +import java.util.Arrays; +import java.util.List; + +import static fr.xephi.authme.command.executable.authme.debug.InputValidator.ValidationObject.MAIL; +import static fr.xephi.authme.command.executable.authme.debug.InputValidator.ValidationObject.NAME; +import static fr.xephi.authme.command.executable.authme.debug.InputValidator.ValidationObject.PASS; + +/** + * Checks if a sample username, email or password is valid according to the AuthMe settings. + */ +class InputValidator implements DebugSection { + + @Inject + private ValidationService validationService; + + @Inject + private Messages messages; + + @Inject + private OnJoinVerifier onJoinVerifier; + + + @Override + public String getName() { + return "valid"; + } + + @Override + public String getDescription() { + return "Check if email / password is valid according to your settings"; + } + + @Override + public void execute(CommandSender sender, List arguments) { + if (arguments.size() < 2 || !ValidationObject.matchesAny(arguments.get(0))) { + displayUsageHint(sender); + + } else if (PASS.matches(arguments.get(0))) { + validatePassword(sender, arguments.get(1)); + + } else if (MAIL.matches(arguments.get(0))) { + validateEmail(sender, arguments.get(1)); + + } else if (NAME.matches(arguments.get(0))) { + validateUsername(sender, arguments.get(1)); + + } else { + throw new IllegalStateException("Unexpected validation object with arg[0] = '" + arguments.get(0) + "'"); + } + } + + private void displayUsageHint(CommandSender sender) { + sender.sendMessage("You can define forbidden emails and passwords in your config.yml"); + sender.sendMessage("This command allows you to test some of the values:"); + sender.sendMessage("/authme debug valid pass test1234 -- test if 'test1234' is allowed password"); + sender.sendMessage("/authme debug valid mail t@t.tld -- test if 't@t.tld' is allowed email"); + sender.sendMessage("/authme debug valid name bobby1 -- test if 'bobby1' is allowed username"); + } + + private void validatePassword(CommandSender sender, String password) { + ValidationResult validationResult = validationService.validatePassword(password, ""); + sender.sendMessage("Validation of password '" + password + "' returned:"); + if (validationResult.hasError()) { + messages.send(sender, validationResult.getMessageKey(), validationResult.getArgs()); + } else { + sender.sendMessage(ChatColor.DARK_GREEN + "Valid password!"); + } + } + + private void validateEmail(CommandSender sender, String email) { + boolean isValidEmail = validationService.validateEmail(email); + sender.sendMessage("Validation of email '" + email + "' returned:"); + if (isValidEmail) { + sender.sendMessage(ChatColor.DARK_GREEN + "Valid email!"); + } else { + sender.sendMessage(ChatColor.DARK_RED + "Email is not valid!"); + } + } + + private void validateUsername(CommandSender sender, String username) { + sender.sendMessage("Validation of username '" + username + "' returned:"); + try { + onJoinVerifier.checkIsValidName(username); + sender.sendMessage("Valid username!"); + } catch (FailedVerificationException failedVerificationEx) { + messages.send(sender, failedVerificationEx.getReason(), failedVerificationEx.getArgs()); + } + } + + + enum ValidationObject { + + PASS, MAIL, NAME; + + static boolean matchesAny(String arg) { + return Arrays.stream(values()).anyMatch(vo -> vo.matches(arg)); + } + + boolean matches(String arg) { + return name().equalsIgnoreCase(arg); + } + } + +} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/LimboPlayerViewer.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/LimboPlayerViewer.java index bf7f9b3c..a8c62e68 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/LimboPlayerViewer.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/LimboPlayerViewer.java @@ -3,6 +3,7 @@ package fr.xephi.authme.command.executable.authme.debug; import fr.xephi.authme.data.limbo.LimboPlayer; import fr.xephi.authme.data.limbo.LimboService; import fr.xephi.authme.data.limbo.persistence.LimboPersistence; +import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.service.BukkitService; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -31,6 +32,9 @@ class LimboPlayerViewer implements DebugSection { @Inject private BukkitService bukkitService; + @Inject + private PermissionsManager permissionsManager; + @Override public String getName() { return "limbo"; @@ -64,8 +68,7 @@ class LimboPlayerViewer implements DebugSection { .sendEntry("Can fly", LimboPlayer::isCanFly, Player::getAllowFlight) .sendEntry("Fly speed", LimboPlayer::getFlySpeed, Player::getFlySpeed) .sendEntry("Location", l -> formatLocation(l.getLocation()), p -> formatLocation(p.getLocation())) - .sendEntry("Group", LimboPlayer::getGroup, p -> ""); - sender.sendMessage("Note: group is not shown for Player. Use /authme debug groups"); + .sendEntry("Group", LimboPlayer::getGroup, permissionsManager::getPrimaryGroup); } /** diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/PermissionGroups.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/PermissionGroups.java index e3876ff0..a7bf19eb 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/PermissionGroups.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/PermissionGroups.java @@ -35,6 +35,7 @@ class PermissionGroups implements DebugSection { } else { sender.sendMessage("Player " + name + " has permission groups: " + String.join(", ", permissionsManager.getGroups(player))); + sender.sendMessage("Primary group is: " + permissionsManager.getGroups(player)); } } } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/SpawnLocationViewer.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/SpawnLocationViewer.java new file mode 100644 index 00000000..0262055e --- /dev/null +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/SpawnLocationViewer.java @@ -0,0 +1,78 @@ +package fr.xephi.authme.command.executable.authme.debug; + +import fr.xephi.authme.service.BukkitService; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.SpawnLoader; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import javax.inject.Inject; +import java.util.List; + +import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.formatLocation; + +/** + * Shows the spawn location that AuthMe is configured to use. + */ +class SpawnLocationViewer implements DebugSection { + + @Inject + private SpawnLoader spawnLoader; + + @Inject + private Settings settings; + + @Inject + private BukkitService bukkitService; + + + @Override + public String getName() { + return "spawn"; + } + + @Override + public String getDescription() { + return "Shows the spawn location that AuthMe will use"; + } + + @Override + public void execute(CommandSender sender, List arguments) { + if (arguments.isEmpty()) { + showGeneralInfo(sender); + } else if ("?".equals(arguments.get(0))) { + showHelp(sender); + } else { + showPlayerSpawn(sender, arguments.get(0)); + } + } + + private void showGeneralInfo(CommandSender sender) { + sender.sendMessage("Spawn priority: " + + String.join(", ", settings.getProperty(RestrictionSettings.SPAWN_PRIORITY))); + sender.sendMessage("AuthMe spawn location: " + formatLocation(spawnLoader.getSpawn())); + sender.sendMessage("AuthMe first spawn location: " + formatLocation(spawnLoader.getFirstSpawn())); + sender.sendMessage("AuthMe (first)spawn are only used depending on the configured priority!"); + sender.sendMessage("Use '/authme debug spawn ?' for further help"); + } + + private void showHelp(CommandSender sender) { + sender.sendMessage("Use /authme spawn and /authme firstspawn to teleport to the spawns."); + sender.sendMessage("/authme set(first)spawn sets the (first) spawn to your current location."); + sender.sendMessage("Use /authme debug spawn to view where a player would be teleported to."); + sender.sendMessage("Read more at https://github.com/AuthMe/AuthMeReloaded/wiki/Spawn-Handling"); + } + + private void showPlayerSpawn(CommandSender sender, String playerName) { + Player player = bukkitService.getPlayerExact(playerName); + if (player == null) { + sender.sendMessage("Player '" + playerName + "' is not online!"); + } else { + Location spawn = spawnLoader.getSpawnLocation(player); + sender.sendMessage("Player '" + playerName + "' has spawn location: " + formatLocation(spawn)); + sender.sendMessage("Note: this check excludes the AuthMe firstspawn."); + } + } +} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java index 95ce4fb2..04ba276a 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java @@ -4,6 +4,7 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.mail.SendMailSsl; +import fr.xephi.authme.util.StringUtils; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.HtmlEmail; import org.bukkit.ChatColor; @@ -76,7 +77,7 @@ class TestEmailSender implements DebugSection { return email; } else { String email = arguments.get(0); - if (email.contains("@")) { + if (StringUtils.isInsideString('@', email)) { return email; } sender.sendMessage(ChatColor.RED + "Invalid email! Usage: /authme debug mail test@example.com"); diff --git a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java index 06a8761a..c7644e08 100644 --- a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java +++ b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java @@ -29,7 +29,7 @@ import java.util.regex.Pattern; /** * Service for performing various verifications when a player joins. */ -class OnJoinVerifier implements Reloadable { +public class OnJoinVerifier implements Reloadable { @Inject private Settings settings;