From f88350b06d5a19352d46e482c509f607c8c1bb37 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 16 Jul 2017 23:07:13 +0200 Subject: [PATCH] Fix Checkstyle violations - Mostly missing Javadoc on large methods - CommandInitializer: split command building method into multiple methods --- .checkstyle.xml | 2 +- .../xephi/authme/command/CommandHandler.java | 6 + .../authme/command/CommandInitializer.java | 629 +++++++++--------- .../DistributedFilesPersistenceHandler.java | 2 +- .../IndividualFilesPersistenceHandler.java | 2 +- .../fr/xephi/authme/datasource/FlatFile.java | 14 +- .../authme/process/join/AsynchronousJoin.java | 38 +- .../executors/TwoFactorRegisterExecutor.java | 2 +- .../authme/security/crypts/TwoFactor.java | 24 +- .../authme/security/crypts/XfBCrypt.java | 6 + .../fr/xephi/authme/settings/Settings.java | 2 +- .../authme/security/crypts/TwoFactorTest.java | 2 +- .../authme/service/MigrationServiceTest.java | 1 - .../commandconfig/CommandManagerTest.java | 13 + .../EncryptionMethodInfoGatherer.java | 5 +- .../commandconfig/commands.incomplete.yml | 4 + 16 files changed, 421 insertions(+), 331 deletions(-) diff --git a/.checkstyle.xml b/.checkstyle.xml index 9a91018c8..d12ab0d40 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 083d8a531..acbb47570 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 2e18cb1a0..948582fe1 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 b3c0cc905..16b919633 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 880c463e7..1ff61c835 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 4d85a31c1..bb9aa3ef2 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 d5dbeaca4..043d5c174 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 027a5fa68..c84a70ab2 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 bf5545290..3ef4e4301 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 980f2adde..f2a722510 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 9b2dddfff..cdc252670 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 11a0f253f..c62b0b40d 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 e1795dc1a..ebf92726f 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 0a1d3fa59..646d8d371 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 a1e9060f7..8bde4aab1 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