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 extends DebugSection> sectionClass : sectionClasses) {
+ for (Class extends DebugSection> 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;