diff --git a/.checkstyle.xml b/.checkstyle.xml
index 9a91018c..d12ab0d4 100644
--- a/.checkstyle.xml
+++ b/.checkstyle.xml
@@ -150,7 +150,7 @@
-
+
diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java
index 083d8a53..acbb4757 100644
--- a/src/main/java/fr/xephi/authme/command/CommandHandler.java
+++ b/src/main/java/fr/xephi/authme/command/CommandHandler.java
@@ -69,6 +69,12 @@ public class CommandHandler {
return !FoundResultStatus.MISSING_BASE_COMMAND.equals(result.getResultStatus());
}
+ /**
+ * Processes the given {@link FoundCommandResult} for the provided command sender.
+ *
+ * @param sender the command sender who executed the command
+ * @param result the command mapping result
+ */
private void handleCommandResult(CommandSender sender, FoundCommandResult result) {
switch (result.getResultStatus()) {
case SUCCESS:
diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java
index 2e18cb1a..948582fe 100644
--- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java
+++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java
@@ -71,279 +71,13 @@ public class CommandInitializer {
/**
* Builds the command description objects for all available AuthMe commands.
*/
- @SuppressWarnings({"checkstyle:LocalVariableName", "checkstyle:AbbreviationAsWordInName"})
private void buildCommands() {
- // Register the base AuthMe Reloaded command
- final CommandDescription AUTHME_BASE = CommandDescription.builder()
- .labels("authme")
- .description("AuthMe op commands")
- .detailedDescription("The main AuthMeReloaded command. The root for all admin commands.")
- .executableCommand(AuthMeCommand.class)
- .register();
-
- // Register the register command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("register", "reg", "r")
- .description("Register a player")
- .detailedDescription("Register the specified player with the specified password.")
- .withArgument("player", "Player name", false)
- .withArgument("password", "Password", false)
- .permission(AdminPermission.REGISTER)
- .executableCommand(RegisterAdminCommand.class)
- .register();
-
- // Register the unregister command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("unregister", "unreg", "unr")
- .description("Unregister a player")
- .detailedDescription("Unregister the specified player.")
- .withArgument("player", "Player name", false)
- .permission(AdminPermission.UNREGISTER)
- .executableCommand(UnregisterAdminCommand.class)
- .register();
-
- // Register the forcelogin command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("forcelogin", "login")
- .description("Enforce login player")
- .detailedDescription("Enforce the specified player to login.")
- .withArgument("player", "Online player name", true)
- .permission(AdminPermission.FORCE_LOGIN)
- .executableCommand(ForceLoginCommand.class)
- .register();
-
- // Register the changepassword command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("password", "changepassword", "changepass", "cp")
- .description("Change a player's password")
- .detailedDescription("Change the password of a player.")
- .withArgument("player", "Player name", false)
- .withArgument("pwd", "New password", false)
- .permission(AdminPermission.CHANGE_PASSWORD)
- .executableCommand(ChangePasswordAdminCommand.class)
- .register();
-
- // Register the last login command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("lastlogin", "ll")
- .description("Player's last login")
- .detailedDescription("View the date of the specified players last login.")
- .withArgument("player", "Player name", true)
- .permission(AdminPermission.LAST_LOGIN)
- .executableCommand(LastLoginCommand.class)
- .register();
-
- // Register the accounts command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("accounts", "account")
- .description("Display player accounts")
- .detailedDescription("Display all accounts of a player by his player name or IP.")
- .withArgument("player", "Player name or IP", true)
- .permission(AdminPermission.ACCOUNTS)
- .executableCommand(AccountsCommand.class)
- .register();
-
- // Register the getemail command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("email", "mail", "getemail", "getmail")
- .description("Display player's email")
- .detailedDescription("Display the email address of the specified player if set.")
- .withArgument("player", "Player name", true)
- .permission(AdminPermission.GET_EMAIL)
- .executableCommand(GetEmailCommand.class)
- .register();
-
- // Register the setemail command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("setemail", "setmail", "chgemail", "chgmail")
- .description("Change player's email")
- .detailedDescription("Change the email address of the specified player.")
- .withArgument("player", "Player name", false)
- .withArgument("email", "Player email", false)
- .permission(AdminPermission.CHANGE_EMAIL)
- .executableCommand(SetEmailCommand.class)
- .register();
-
- // Register the getip command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("getip", "ip")
- .description("Get player's IP")
- .detailedDescription("Get the IP address of the specified online player.")
- .withArgument("player", "Player name", false)
- .permission(AdminPermission.GET_IP)
- .executableCommand(GetIpCommand.class)
- .register();
-
- // Register the spawn command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("spawn", "home")
- .description("Teleport to spawn")
- .detailedDescription("Teleport to the spawn.")
- .permission(AdminPermission.SPAWN)
- .executableCommand(SpawnCommand.class)
- .register();
-
- // Register the setspawn command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("setspawn", "chgspawn")
- .description("Change the spawn")
- .detailedDescription("Change the player's spawn to your current position.")
- .permission(AdminPermission.SET_SPAWN)
- .executableCommand(SetSpawnCommand.class)
- .register();
-
- // Register the firstspawn command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("firstspawn", "firsthome")
- .description("Teleport to first spawn")
- .detailedDescription("Teleport to the first spawn.")
- .permission(AdminPermission.FIRST_SPAWN)
- .executableCommand(FirstSpawnCommand.class)
- .register();
-
- // Register the setfirstspawn command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("setfirstspawn", "chgfirstspawn")
- .description("Change the first spawn")
- .detailedDescription("Change the first player's spawn to your current position.")
- .permission(AdminPermission.SET_FIRST_SPAWN)
- .executableCommand(SetFirstSpawnCommand.class)
- .register();
-
- // Register the purge command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("purge", "delete")
- .description("Purge old data")
- .detailedDescription("Purge old AuthMeReloaded data longer than the specified number of days ago.")
- .withArgument("days", "Number of days", false)
- .withArgument("all", "Add 'all' at the end to also purge players with lastlogin = 0", true)
- .permission(AdminPermission.PURGE)
- .executableCommand(PurgeCommand.class)
- .register();
-
- // Purge player command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("purgeplayer")
- .description("Purges the data of one player")
- .detailedDescription("Purges data of the given player.")
- .withArgument("player", "The player to purge", false)
- .withArgument("options", "'force' to run without checking if player is registered", true)
- .permission(AdminPermission.PURGE_PLAYER)
- .executableCommand(PurgePlayerCommand.class)
- .register();
-
- // Backup command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("backup")
- .description("Perform a backup")
- .detailedDescription("Creates a backup of the registered users.")
- .permission(AdminPermission.BACKUP)
- .executableCommand(BackupCommand.class)
- .register();
-
- // Register the purgelastposition command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("resetpos", "purgelastposition", "purgelastpos", "resetposition",
- "resetlastposition", "resetlastpos")
- .description("Purge player's last position")
- .detailedDescription("Purge the last know position of the specified player or all of them.")
- .withArgument("player/*", "Player name or * for all players", false)
- .permission(AdminPermission.PURGE_LAST_POSITION)
- .executableCommand(PurgeLastPositionCommand.class)
- .register();
-
- // Register the purgebannedplayers command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("purgebannedplayers", "purgebannedplayer", "deletebannedplayers", "deletebannedplayer")
- .description("Purge banned players data")
- .detailedDescription("Purge all AuthMeReloaded data for banned players.")
- .permission(AdminPermission.PURGE_BANNED_PLAYERS)
- .executableCommand(PurgeBannedPlayersCommand.class)
- .register();
-
- // Register the switchantibot command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("switchantibot", "toggleantibot", "antibot")
- .description("Switch AntiBot mode")
- .detailedDescription("Switch or toggle the AntiBot mode to the specified state.")
- .withArgument("mode", "ON / OFF", true)
- .permission(AdminPermission.SWITCH_ANTIBOT)
- .executableCommand(SwitchAntiBotCommand.class)
- .register();
-
- // Register the reload command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("reload", "rld")
- .description("Reload plugin")
- .detailedDescription("Reload the AuthMeReloaded plugin.")
- .permission(AdminPermission.RELOAD)
- .executableCommand(ReloadCommand.class)
- .register();
-
- // Register the version command
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("version", "ver", "v", "about", "info")
- .description("Version info")
- .detailedDescription("Show detailed information about the installed AuthMeReloaded version, the "
- + "developers, contributors, and license.")
- .executableCommand(VersionCommand.class)
- .register();
-
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("converter", "convert", "conv")
- .description("Converter command")
- .detailedDescription("Converter command for AuthMeReloaded.")
- .withArgument("job", "Conversion job: xauth / crazylogin / rakamak / "
- + "royalauth / vauth / sqliteToSql / mysqlToSqlite / loginsecurity", true)
- .permission(AdminPermission.CONVERTER)
- .executableCommand(ConverterCommand.class)
- .register();
-
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("messages", "msg")
- .description("Add missing messages")
- .detailedDescription("Adds missing messages to the current messages file.")
- .permission(AdminPermission.UPDATE_MESSAGES)
- .executableCommand(MessagesCommand.class)
- .register();
-
- CommandDescription.builder()
- .parent(AUTHME_BASE)
- .labels("debug", "dbg")
- .description("Debug features")
- .detailedDescription("Allows various operations for debugging.")
- .withArgument("child", "The child to execute", true)
- .withArgument("arg", "argument (depends on debug section)", true)
- .withArgument("arg", "argument (depends on debug section)", true)
- .permission(DebugSectionPermissions.DEBUG_COMMAND)
- .executableCommand(DebugCommand.class)
- .register();
+ // Register /authme and /email commands
+ CommandDescription authMeBase = buildAuthMeBaseCommand();
+ CommandDescription emailBase = buildEmailBaseCommand();
// Register the base login command
- final CommandDescription LOGIN_BASE = CommandDescription.builder()
+ CommandDescription loginBase = CommandDescription.builder()
.parent(null)
.labels("login", "l", "log")
.description("Login command")
@@ -354,7 +88,7 @@ public class CommandInitializer {
.register();
// Register the base logout command
- CommandDescription LOGOUT_BASE = CommandDescription.builder()
+ CommandDescription logoutBase = CommandDescription.builder()
.parent(null)
.labels("logout")
.description("Logout command")
@@ -364,7 +98,7 @@ public class CommandInitializer {
.register();
// Register the base register command
- final CommandDescription REGISTER_BASE = CommandDescription.builder()
+ CommandDescription registerBase = CommandDescription.builder()
.parent(null)
.labels("register", "reg")
.description("Register an account")
@@ -376,7 +110,7 @@ public class CommandInitializer {
.register();
// Register the base unregister command
- CommandDescription UNREGISTER_BASE = CommandDescription.builder()
+ CommandDescription unregisterBase = CommandDescription.builder()
.parent(null)
.labels("unregister", "unreg")
.description("Unregister an account")
@@ -387,7 +121,7 @@ public class CommandInitializer {
.register();
// Register the base changepassword command
- final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder()
+ CommandDescription changePasswordBase = CommandDescription.builder()
.parent(null)
.labels("changepassword", "changepass", "cp")
.description("Change password of an account")
@@ -398,8 +132,317 @@ public class CommandInitializer {
.executableCommand(ChangePasswordCommand.class)
.register();
+ // Register the base captcha command
+ CommandDescription captchaBase = CommandDescription.builder()
+ .parent(null)
+ .labels("captcha")
+ .description("Captcha Command")
+ .detailedDescription("Captcha command for AuthMeReloaded.")
+ .withArgument("captcha", "The Captcha", false)
+ .permission(PlayerPermission.CAPTCHA)
+ .executableCommand(CaptchaCommand.class)
+ .register();
+
+ List baseCommands = ImmutableList.of(
+ authMeBase,
+ emailBase,
+ loginBase,
+ logoutBase,
+ registerBase,
+ unregisterBase,
+ changePasswordBase,
+ captchaBase);
+
+ setHelpOnAllBases(baseCommands);
+ commands = baseCommands;
+ }
+
+ /**
+ * Creates a command description object for {@code /authme} including its children.
+ *
+ * @return the authme base command description
+ */
+ private CommandDescription buildAuthMeBaseCommand() {
+ // Register the base AuthMe Reloaded command
+ CommandDescription authmeBase = CommandDescription.builder()
+ .labels("authme")
+ .description("AuthMe op commands")
+ .detailedDescription("The main AuthMeReloaded command. The root for all admin commands.")
+ .executableCommand(AuthMeCommand.class)
+ .register();
+
+ // Register the register command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("register", "reg", "r")
+ .description("Register a player")
+ .detailedDescription("Register the specified player with the specified password.")
+ .withArgument("player", "Player name", false)
+ .withArgument("password", "Password", false)
+ .permission(AdminPermission.REGISTER)
+ .executableCommand(RegisterAdminCommand.class)
+ .register();
+
+ // Register the unregister command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("unregister", "unreg", "unr")
+ .description("Unregister a player")
+ .detailedDescription("Unregister the specified player.")
+ .withArgument("player", "Player name", false)
+ .permission(AdminPermission.UNREGISTER)
+ .executableCommand(UnregisterAdminCommand.class)
+ .register();
+
+ // Register the forcelogin command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("forcelogin", "login")
+ .description("Enforce login player")
+ .detailedDescription("Enforce the specified player to login.")
+ .withArgument("player", "Online player name", true)
+ .permission(AdminPermission.FORCE_LOGIN)
+ .executableCommand(ForceLoginCommand.class)
+ .register();
+
+ // Register the changepassword command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("password", "changepassword", "changepass", "cp")
+ .description("Change a player's password")
+ .detailedDescription("Change the password of a player.")
+ .withArgument("player", "Player name", false)
+ .withArgument("pwd", "New password", false)
+ .permission(AdminPermission.CHANGE_PASSWORD)
+ .executableCommand(ChangePasswordAdminCommand.class)
+ .register();
+
+ // Register the last login command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("lastlogin", "ll")
+ .description("Player's last login")
+ .detailedDescription("View the date of the specified players last login.")
+ .withArgument("player", "Player name", true)
+ .permission(AdminPermission.LAST_LOGIN)
+ .executableCommand(LastLoginCommand.class)
+ .register();
+
+ // Register the accounts command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("accounts", "account")
+ .description("Display player accounts")
+ .detailedDescription("Display all accounts of a player by his player name or IP.")
+ .withArgument("player", "Player name or IP", true)
+ .permission(AdminPermission.ACCOUNTS)
+ .executableCommand(AccountsCommand.class)
+ .register();
+
+ // Register the getemail command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("email", "mail", "getemail", "getmail")
+ .description("Display player's email")
+ .detailedDescription("Display the email address of the specified player if set.")
+ .withArgument("player", "Player name", true)
+ .permission(AdminPermission.GET_EMAIL)
+ .executableCommand(GetEmailCommand.class)
+ .register();
+
+ // Register the setemail command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("setemail", "setmail", "chgemail", "chgmail")
+ .description("Change player's email")
+ .detailedDescription("Change the email address of the specified player.")
+ .withArgument("player", "Player name", false)
+ .withArgument("email", "Player email", false)
+ .permission(AdminPermission.CHANGE_EMAIL)
+ .executableCommand(SetEmailCommand.class)
+ .register();
+
+ // Register the getip command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("getip", "ip")
+ .description("Get player's IP")
+ .detailedDescription("Get the IP address of the specified online player.")
+ .withArgument("player", "Player name", false)
+ .permission(AdminPermission.GET_IP)
+ .executableCommand(GetIpCommand.class)
+ .register();
+
+ // Register the spawn command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("spawn", "home")
+ .description("Teleport to spawn")
+ .detailedDescription("Teleport to the spawn.")
+ .permission(AdminPermission.SPAWN)
+ .executableCommand(SpawnCommand.class)
+ .register();
+
+ // Register the setspawn command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("setspawn", "chgspawn")
+ .description("Change the spawn")
+ .detailedDescription("Change the player's spawn to your current position.")
+ .permission(AdminPermission.SET_SPAWN)
+ .executableCommand(SetSpawnCommand.class)
+ .register();
+
+ // Register the firstspawn command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("firstspawn", "firsthome")
+ .description("Teleport to first spawn")
+ .detailedDescription("Teleport to the first spawn.")
+ .permission(AdminPermission.FIRST_SPAWN)
+ .executableCommand(FirstSpawnCommand.class)
+ .register();
+
+ // Register the setfirstspawn command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("setfirstspawn", "chgfirstspawn")
+ .description("Change the first spawn")
+ .detailedDescription("Change the first player's spawn to your current position.")
+ .permission(AdminPermission.SET_FIRST_SPAWN)
+ .executableCommand(SetFirstSpawnCommand.class)
+ .register();
+
+ // Register the purge command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("purge", "delete")
+ .description("Purge old data")
+ .detailedDescription("Purge old AuthMeReloaded data longer than the specified number of days ago.")
+ .withArgument("days", "Number of days", false)
+ .withArgument("all", "Add 'all' at the end to also purge players with lastlogin = 0", true)
+ .permission(AdminPermission.PURGE)
+ .executableCommand(PurgeCommand.class)
+ .register();
+
+ // Purge player command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("purgeplayer")
+ .description("Purges the data of one player")
+ .detailedDescription("Purges data of the given player.")
+ .withArgument("player", "The player to purge", false)
+ .withArgument("options", "'force' to run without checking if player is registered", true)
+ .permission(AdminPermission.PURGE_PLAYER)
+ .executableCommand(PurgePlayerCommand.class)
+ .register();
+
+ // Backup command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("backup")
+ .description("Perform a backup")
+ .detailedDescription("Creates a backup of the registered users.")
+ .permission(AdminPermission.BACKUP)
+ .executableCommand(BackupCommand.class)
+ .register();
+
+ // Register the purgelastposition command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("resetpos", "purgelastposition", "purgelastpos", "resetposition",
+ "resetlastposition", "resetlastpos")
+ .description("Purge player's last position")
+ .detailedDescription("Purge the last know position of the specified player or all of them.")
+ .withArgument("player/*", "Player name or * for all players", false)
+ .permission(AdminPermission.PURGE_LAST_POSITION)
+ .executableCommand(PurgeLastPositionCommand.class)
+ .register();
+
+ // Register the purgebannedplayers command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("purgebannedplayers", "purgebannedplayer", "deletebannedplayers", "deletebannedplayer")
+ .description("Purge banned players data")
+ .detailedDescription("Purge all AuthMeReloaded data for banned players.")
+ .permission(AdminPermission.PURGE_BANNED_PLAYERS)
+ .executableCommand(PurgeBannedPlayersCommand.class)
+ .register();
+
+ // Register the switchantibot command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("switchantibot", "toggleantibot", "antibot")
+ .description("Switch AntiBot mode")
+ .detailedDescription("Switch or toggle the AntiBot mode to the specified state.")
+ .withArgument("mode", "ON / OFF", true)
+ .permission(AdminPermission.SWITCH_ANTIBOT)
+ .executableCommand(SwitchAntiBotCommand.class)
+ .register();
+
+ // Register the reload command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("reload", "rld")
+ .description("Reload plugin")
+ .detailedDescription("Reload the AuthMeReloaded plugin.")
+ .permission(AdminPermission.RELOAD)
+ .executableCommand(ReloadCommand.class)
+ .register();
+
+ // Register the version command
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("version", "ver", "v", "about", "info")
+ .description("Version info")
+ .detailedDescription("Show detailed information about the installed AuthMeReloaded version, the "
+ + "developers, contributors, and license.")
+ .executableCommand(VersionCommand.class)
+ .register();
+
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("converter", "convert", "conv")
+ .description("Converter command")
+ .detailedDescription("Converter command for AuthMeReloaded.")
+ .withArgument("job", "Conversion job: xauth / crazylogin / rakamak / "
+ + "royalauth / vauth / sqliteToSql / mysqlToSqlite / loginsecurity", true)
+ .permission(AdminPermission.CONVERTER)
+ .executableCommand(ConverterCommand.class)
+ .register();
+
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("messages", "msg")
+ .description("Add missing messages")
+ .detailedDescription("Adds missing messages to the current messages file.")
+ .permission(AdminPermission.UPDATE_MESSAGES)
+ .executableCommand(MessagesCommand.class)
+ .register();
+
+ CommandDescription.builder()
+ .parent(authmeBase)
+ .labels("debug", "dbg")
+ .description("Debug features")
+ .detailedDescription("Allows various operations for debugging.")
+ .withArgument("child", "The child to execute", true)
+ .withArgument("arg", "argument (depends on debug section)", true)
+ .withArgument("arg", "argument (depends on debug section)", true)
+ .permission(DebugSectionPermissions.DEBUG_COMMAND)
+ .executableCommand(DebugCommand.class)
+ .register();
+
+ return authmeBase;
+ }
+
+ /**
+ * Creates a command description for {@code /email} including its children.
+ *
+ * @return the email base command description
+ */
+ private CommandDescription buildEmailBaseCommand() {
// Register the base Email command
- CommandDescription EMAIL_BASE = CommandDescription.builder()
+ CommandDescription emailBase = CommandDescription.builder()
.parent(null)
.labels("email")
.description("Add email or recover password")
@@ -409,7 +452,7 @@ public class CommandInitializer {
// Register the show command
CommandDescription.builder()
- .parent(EMAIL_BASE)
+ .parent(emailBase)
.labels("show", "myemail")
.description("Show Email")
.detailedDescription("Show your current email address.")
@@ -418,7 +461,7 @@ public class CommandInitializer {
// Register the add command
CommandDescription.builder()
- .parent(EMAIL_BASE)
+ .parent(emailBase)
.labels("add", "addemail", "addmail")
.description("Add Email")
.detailedDescription("Add a new email address to your account.")
@@ -430,7 +473,7 @@ public class CommandInitializer {
// Register the change command
CommandDescription.builder()
- .parent(EMAIL_BASE)
+ .parent(emailBase)
.labels("change", "changeemail", "changemail")
.description("Change Email")
.detailedDescription("Change an email address of your account.")
@@ -442,7 +485,7 @@ public class CommandInitializer {
// Register the recover command
CommandDescription.builder()
- .parent(EMAIL_BASE)
+ .parent(emailBase)
.labels("recover", "recovery", "recoveremail", "recovermail")
.description("Recover password using email")
.detailedDescription("Recover your account using an Email address by sending a mail containing "
@@ -454,7 +497,7 @@ public class CommandInitializer {
// Register the process recovery code command
CommandDescription.builder()
- .parent(EMAIL_BASE)
+ .parent(emailBase)
.labels("code")
.description("Submit code to recover password")
.detailedDescription("Recover your account by submitting a code delivered to your email.")
@@ -465,7 +508,7 @@ public class CommandInitializer {
// Register the change password after recovery command
CommandDescription.builder()
- .parent(EMAIL_BASE)
+ .parent(emailBase)
.labels("setpassword")
.description("Set new password after recovery")
.detailedDescription("Set a new password after successfully recovering your account.")
@@ -474,29 +517,7 @@ public class CommandInitializer {
.executableCommand(SetPasswordCommand.class)
.register();
- // Register the base captcha command
- CommandDescription CAPTCHA_BASE = CommandDescription.builder()
- .parent(null)
- .labels("captcha")
- .description("Captcha Command")
- .detailedDescription("Captcha command for AuthMeReloaded.")
- .withArgument("captcha", "The Captcha", false)
- .permission(PlayerPermission.CAPTCHA)
- .executableCommand(CaptchaCommand.class)
- .register();
-
- List baseCommands = ImmutableList.of(
- AUTHME_BASE,
- LOGIN_BASE,
- LOGOUT_BASE,
- REGISTER_BASE,
- UNREGISTER_BASE,
- CHANGE_PASSWORD_BASE,
- EMAIL_BASE,
- CAPTCHA_BASE);
-
- setHelpOnAllBases(baseCommands);
- commands = baseCommands;
+ return emailBase;
}
/**
diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java
index b3c0cc90..16b91963 100644
--- a/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java
+++ b/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java
@@ -114,7 +114,7 @@ class DistributedFilesPersistenceHandler implements LimboPersistenceHandler {
}
try {
- return gson.fromJson(Files.toString(file, StandardCharsets.UTF_8), LIMBO_MAP_TYPE);
+ return gson.fromJson(Files.asCharSource(file, StandardCharsets.UTF_8).read(), LIMBO_MAP_TYPE);
} catch (Exception e) {
ConsoleLogger.logException("Failed reading '" + file + "':", e);
}
diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/IndividualFilesPersistenceHandler.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/IndividualFilesPersistenceHandler.java
index 880c463e..1ff61c83 100644
--- a/src/main/java/fr/xephi/authme/data/limbo/persistence/IndividualFilesPersistenceHandler.java
+++ b/src/main/java/fr/xephi/authme/data/limbo/persistence/IndividualFilesPersistenceHandler.java
@@ -46,7 +46,7 @@ class IndividualFilesPersistenceHandler implements LimboPersistenceHandler {
}
try {
- String str = Files.toString(file, StandardCharsets.UTF_8);
+ String str = Files.asCharSource(file, StandardCharsets.UTF_8).read();
return gson.fromJson(str, LimboPlayer.class);
} catch (IOException e) {
ConsoleLogger.logException("Could not read player data on disk for '" + player.getName() + "'", e);
diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
index 4d85a31c..bb9aa3ef 100644
--- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java
+++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
@@ -6,7 +6,6 @@ import fr.xephi.authme.security.crypts.HashedPassword;
import java.io.BufferedReader;
import java.io.BufferedWriter;
-import java.io.Closeable;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
@@ -80,7 +79,9 @@ public class FlatFile implements DataSource {
return false;
}
try (BufferedWriter bw = new BufferedWriter(new FileWriter(source, true))) {
- bw.write(auth.getNickname() + ":" + auth.getPassword().getHash() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
+ bw.write(auth.getNickname() + ":" + auth.getPassword().getHash() + ":" + auth.getIp()
+ + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY()
+ + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
} catch (IOException ex) {
ConsoleLogger.warning(ex.getMessage());
return false;
@@ -203,7 +204,7 @@ public class FlatFile implements DataSource {
return false;
}
ArrayList lines = new ArrayList<>();
- try (BufferedReader br = new BufferedReader(new FileReader(source));) {
+ try (BufferedReader br = new BufferedReader(new FileReader(source))) {
String line;
while ((line = br.readLine()) != null) {
@@ -379,6 +380,13 @@ public class FlatFile implements DataSource {
throw new UnsupportedOperationException("Flat file no longer supported");
}
+ /**
+ * Creates a PlayerAuth object from the read data.
+ *
+ * @param args the data read from the line
+ * @return the player auth object with the data
+ */
+ @SuppressWarnings("checkstyle:NeedBraces")
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/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
index d5dbeaca..043d5c17 100644
--- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
+++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
@@ -73,6 +73,11 @@ public class AsynchronousJoin implements AsynchronousProcess {
AsynchronousJoin() {
}
+ /**
+ * Processes the given player that has just joined.
+ *
+ * @param player the player to process
+ */
public void processJoin(final Player player) {
final String name = player.getName().toLowerCase();
final String ip = PlayerUtils.getPlayerIp(player);
@@ -91,15 +96,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
}
if (!validationService.fulfillsNameRestrictions(player)) {
- bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
- @Override
- public void run() {
- player.kickPlayer(service.retrieveSingleMessage(MessageKey.NOT_OWNER_ERROR));
- if (service.getProperty(RestrictionSettings.BAN_UNKNOWN_IP)) {
- server.banIP(ip);
- }
- }
- });
+ handlePlayerWithUnmetNameRestriction(player, ip);
return;
}
@@ -124,7 +121,8 @@ public class AsynchronousJoin implements AsynchronousProcess {
if (canResumeSession(player)) {
service.send(player, MessageKey.SESSION_RECONNECTION);
// Run commands
- bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> commandManager.runCommandsOnSessionLogin(player));
+ bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(
+ () -> commandManager.runCommandsOnSessionLogin(player));
bukkitService.runTaskOptionallyAsync(() -> asynchronousLogin.forceLogin(player));
return;
}
@@ -133,6 +131,26 @@ public class AsynchronousJoin implements AsynchronousProcess {
return;
}
+ processJoinSync(player, isAuthAvailable);
+ }
+
+ private void handlePlayerWithUnmetNameRestriction(Player player, String ip) {
+ bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
+ player.kickPlayer(service.retrieveSingleMessage(MessageKey.NOT_OWNER_ERROR));
+ if (service.getProperty(RestrictionSettings.BAN_UNKNOWN_IP)) {
+ server.banIP(ip);
+ }
+ });
+ }
+
+ /**
+ * Performs various operations in sync mode for an unauthenticated player (such as blindness effect and
+ * limbo player creation).
+ *
+ * @param player the player to process
+ * @param isAuthAvailable true if the player is registered, false otherwise
+ */
+ private void processJoinSync(Player player, boolean isAuthAvailable) {
final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
diff --git a/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterExecutor.java b/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterExecutor.java
index 027a5fa6..c84a70ab 100644
--- a/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterExecutor.java
+++ b/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterExecutor.java
@@ -37,7 +37,7 @@ class TwoFactorRegisterExecutor extends AbstractPasswordRegisterExecutorOriginal source
+ */
@Recommendation(Usage.DOES_NOT_WORK)
@HasSalt(SaltType.NONE)
public class TwoFactor extends UnsaltedMethod {
@@ -30,7 +35,15 @@ public class TwoFactor extends UnsaltedMethod {
private static final int TIME_PRECISION = 3;
private static final String CRYPTO_ALGO = "HmacSHA1";
- public static String getQRBarcodeURL(String user, String host, String secret) {
+ /**
+ * Creates a link to a QR barcode with the provided secret.
+ *
+ * @param user the player's name
+ * @param host the server host
+ * @param secret the TOTP secret
+ * @return URL leading to a QR code
+ */
+ public static String getQrBarcodeUrl(String user, String host, String secret) {
String format = "https://www.google.com/chart?chs=130x130&chld=M%%7C0&cht=qr&chl="
+ "otpauth://totp/"
+ "%s@%s%%3Fsecret%%3D%s";
@@ -72,18 +85,17 @@ public class TwoFactor extends UnsaltedMethod {
}
long currentTime = Calendar.getInstance().getTimeInMillis() / TimeUnit.SECONDS.toMillis(30);
- return check_code(secretKey, code, currentTime);
+ return checkCode(secretKey, code, currentTime);
}
- private boolean check_code(String secret, long code, long t)
- throws NoSuchAlgorithmException, InvalidKeyException {
+ private boolean checkCode(String secret, long code, long t) throws NoSuchAlgorithmException, InvalidKeyException {
byte[] decodedKey = BaseEncoding.base32().decode(secret);
// Window is used to check codes generated in the near past.
// You can use this value to tune how far you're willing to go.
int window = TIME_PRECISION;
for (int i = -window; i <= window; ++i) {
- long hash = verify_code(decodedKey, t + i);
+ long hash = verifyCode(decodedKey, t + i);
if (hash == code) {
return true;
@@ -94,7 +106,7 @@ public class TwoFactor extends UnsaltedMethod {
return false;
}
- private int verify_code(byte[] key, long t) throws NoSuchAlgorithmException, InvalidKeyException {
+ private int verifyCode(byte[] key, long t) throws NoSuchAlgorithmException, InvalidKeyException {
byte[] data = new byte[8];
long value = t;
for (int i = 8; i-- > 0; value >>>= 8) {
diff --git a/src/main/java/fr/xephi/authme/security/crypts/XfBCrypt.java b/src/main/java/fr/xephi/authme/security/crypts/XfBCrypt.java
index bf554529..3ef4e430 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/XfBCrypt.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/XfBCrypt.java
@@ -42,6 +42,12 @@ public class XfBCrypt implements EncryptionMethod {
return false;
}
+ /**
+ * Extracts the password hash from the given BLOB.
+ *
+ * @param blob the blob to process
+ * @return the extracted hash
+ */
public static String getHashFromBlob(byte[] blob) {
String line = new String(blob);
Matcher m = HASH_PATTERN.matcher(line);
diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java
index 980f2add..f2a72251 100644
--- a/src/main/java/fr/xephi/authme/settings/Settings.java
+++ b/src/main/java/fr/xephi/authme/settings/Settings.java
@@ -76,7 +76,7 @@ public class Settings extends SettingsManager {
final File file = new File(pluginFolder, filename);
if (copyFileFromResource(file, filename)) {
try {
- return Files.toString(file, StandardCharsets.UTF_8);
+ return Files.asCharSource(file, StandardCharsets.UTF_8).read();
} catch (IOException e) {
ConsoleLogger.logException("Failed to read file '" + filename + "':", e);
}
diff --git a/src/test/java/fr/xephi/authme/security/crypts/TwoFactorTest.java b/src/test/java/fr/xephi/authme/security/crypts/TwoFactorTest.java
index 9b2dddff..cdc25267 100644
--- a/src/test/java/fr/xephi/authme/security/crypts/TwoFactorTest.java
+++ b/src/test/java/fr/xephi/authme/security/crypts/TwoFactorTest.java
@@ -25,7 +25,7 @@ public class TwoFactorTest {
String secret = "3AK6Y4KWGRLJMEQW";
// when
- String url = TwoFactor.getQRBarcodeURL(user, host, secret);
+ String url = TwoFactor.getQrBarcodeUrl(user, host, secret);
// then
String expected = "https://www.google.com/chart?chs=130x130&chld=M%7C0&cht=qr"
diff --git a/src/test/java/fr/xephi/authme/service/MigrationServiceTest.java b/src/test/java/fr/xephi/authme/service/MigrationServiceTest.java
index 11a0f253..c62b0b40 100644
--- a/src/test/java/fr/xephi/authme/service/MigrationServiceTest.java
+++ b/src/test/java/fr/xephi/authme/service/MigrationServiceTest.java
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
-import static fr.xephi.authme.AuthMeMatchers.equalToHash;
/**
* Test for {@link MigrationService}.
diff --git a/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java b/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java
index e1795dc1..ebf92726 100644
--- a/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java
+++ b/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java
@@ -178,6 +178,19 @@ public class CommandManagerTest {
verifyZeroInteractions(bukkitService, geoIpService);
}
+ @Test
+ public void shouldExecuteCommandOnUnregister() {
+ // given
+ copyJarFileAsCommandsYml(TEST_FILES_FOLDER + "commands.incomplete.yml");
+ initManager();
+
+ // when
+ manager.runCommandsOnUnregister(player);
+
+ // then
+ verify(bukkitService).dispatchConsoleCommand("msg Bobby sad to see you go!");
+ }
+
@Test
public void shouldHaveHiddenConstructorInSettingsHolderClass() {
// given / when / then
diff --git a/src/test/java/tools/docs/hashmethods/EncryptionMethodInfoGatherer.java b/src/test/java/tools/docs/hashmethods/EncryptionMethodInfoGatherer.java
index 0a1d3fa5..646d8d37 100644
--- a/src/test/java/tools/docs/hashmethods/EncryptionMethodInfoGatherer.java
+++ b/src/test/java/tools/docs/hashmethods/EncryptionMethodInfoGatherer.java
@@ -30,7 +30,7 @@ import static org.mockito.Mockito.when;
*/
public class EncryptionMethodInfoGatherer {
- private final static Set> RELEVANT_ANNOTATIONS =
+ private static final Set> RELEVANT_ANNOTATIONS =
ImmutableSet.of(HasSalt.class, Recommendation.class, AsciiRestricted.class);
private static Injector injector = createInitializer();
@@ -104,6 +104,9 @@ public class EncryptionMethodInfoGatherer {
/**
* Returns the super class of the given encryption method if it is also of EncryptionMethod type.
* (Anything beyond EncryptionMethod is not of interest.)
+ *
+ * @param methodClass the class to process
+ * @return the super class of the given class if it is also an EncryptionMethod type, otherwise null
*/
private static Class> getSuperClass(Class> methodClass) {
Class> zuper = methodClass.getSuperclass();
diff --git a/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.incomplete.yml b/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.incomplete.yml
index a1e9060f..8bde4aab 100644
--- a/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.incomplete.yml
+++ b/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.incomplete.yml
@@ -18,3 +18,7 @@ doesNotExist:
wrongEntry:
command: 'should be ignored'
executor: PLAYER
+onUnregister:
+ farewell:
+ command: 'msg %p sad to see you go!'
+ executor: CONSOLE