Merge branch 'master' of https://github.com/AuthMe/AuthMeReloaded into 5.4-Dev

This commit is contained in:
ljacqu 2017-07-23 12:12:16 +02:00
commit 870810a230
51 changed files with 1200 additions and 411 deletions

View File

@ -150,7 +150,7 @@
<property name="scope" value="package"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="minLineCount" value="4"/>
<property name="allowedAnnotations" value="Override, Test, SectionComments, EventHandler"/>
<property name="allowedAnnotations" value="Override, Test, SectionComments, EventHandler, Before, BeforeClass"/>
<property name="tokens" value="METHOD_DEF, ANNOTATION_FIELD_DEF"/> <!-- exclude CTOR_DEF -->
</module>
<module name="JavadocMethod">

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Thu Jul 06 18:45:51 CEST 2017. See docs/config/config.tpl.md -->
<!-- File auto-generated on Sat Jul 15 19:32:28 CEST 2017. See docs/config/config.tpl.md -->
## AuthMe Configuration
The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder,
@ -58,6 +58,9 @@ DataSource:
mySQLlastlocPitch: 'pitch'
# Overrides the size of the DB Connection Pool, -1 = Auto
poolSize: -1
# The maximum lifetime of a connection in the pool, default = 1800 seconds
# You should set this at least 30 seconds less than mysql server wait_timeout
maxLifetime: 1800
ExternalBoardOptions:
# Column for storing players passwords salts
mySQLColumnSalt: ''
@ -194,8 +197,10 @@ settings:
maxJoinPerIp: 0
# AuthMe will NEVER teleport players if set to true!
noTeleport: false
# Regex syntax for allowed chars in passwords
allowedPasswordCharacters: '[\x21-\x7E]*'
# Regex syntax for allowed chars in passwords. The default [!-~] allows all visible ASCII
# characters, which is what we recommend. See also http://asciitable.com
# You can test your regex with https://regex101.com
allowedPasswordCharacters: '[!-~]*'
# Threshold of the other accounts command, a value less than 2 means disabled.
otherAccountsCmdThreshold: 0
# Command to run when a user has more accounts than the configured threshold.
@ -476,8 +481,9 @@ limbo:
# Note: if you change this setting all data will be migrated. If you have a lot of data,
# change this setting only on server restart, not with /authme reload.
distributionSize: 'SIXTEEN'
# Whether the player is allowed to fly: RESTORE, ENABLE, DISABLE.
# RESTORE sets back the old property from the player.
# Whether the player is allowed to fly: RESTORE, ENABLE, DISABLE, NOTHING.
# RESTORE sets back the old property from the player. NOTHING will prevent AuthMe
# from modifying the 'allow flight' property on the player.
restoreAllowFlight: 'RESTORE'
# Restore fly speed: RESTORE, DEFAULT, MAX_RESTORE, RESTORE_NO_ZERO.
# RESTORE: restore the speed the player had;
@ -487,7 +493,7 @@ limbo:
restoreFlySpeed: 'RESTORE_NO_ZERO'
# Restore walk speed: RESTORE, DEFAULT, MAX_RESTORE, RESTORE_NO_ZERO.
# See above for a description of the values.
restoreWalkSpeed: 'MAX_RESTORE'
restoreWalkSpeed: 'RESTORE_NO_ZERO'
BackupSystem:
# General configuration for backups: if false, no backups are possible
ActivateBackup: false
@ -528,4 +534,4 @@ To change settings on a running server, save your changes to config.yml and use
---
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Thu Jul 06 18:45:51 CEST 2017
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Jul 15 19:32:28 CEST 2017

View File

@ -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:

View File

@ -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<CommandDescription> 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<CommandDescription> 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;
}
/**

View File

@ -5,7 +5,6 @@ import org.bukkit.ChatColor;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Utility functions for {@link CommandDescription} objects.
@ -76,19 +75,14 @@ public final class CommandUtils {
}
/**
* Returns a textual representation of the command, including its arguments.
* For example: {@code /authme purge <days> [includeZero]}.
* Constructs a command path with color formatting, based on the supplied labels. This includes
* the command's arguments, as defined in the provided command description. The list of labels
* must contain all labels to be used.
*
* @param command the command to create a usage string for
* @return the command's path and arguments
* @param command the command to read arguments from
* @param correctLabels the labels to use (must be complete)
* @return formatted command syntax incl. arguments
*/
public static String buildSyntax(CommandDescription command) {
String arguments = command.getArguments().stream()
.map(arg -> formatArgument(arg))
.collect(Collectors.joining(" "));
return (constructCommandPath(command) + " " + arguments).trim();
}
public static String buildSyntax(CommandDescription command, List<String> correctLabels) {
String commandSyntax = ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW;
for (int i = 1; i < correctLabels.size(); ++i) {
@ -106,7 +100,7 @@ public final class CommandUtils {
* @param argument the argument to format
* @return the formatted argument
*/
private static String formatArgument(CommandArgumentDescription argument) {
public static String formatArgument(CommandArgumentDescription argument) {
if (argument.isOptional()) {
return "[" + argument.getName() + "]";
}

View File

@ -119,7 +119,7 @@ public class TempbanManager implements SettingsDependent, HasCleanup {
this.isEnabled = settings.getProperty(SecuritySettings.TEMPBAN_ON_MAX_LOGINS);
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TEMPBAN);
this.length = settings.getProperty(SecuritySettings.TEMPBAN_LENGTH);
this.resetThreshold = settings.getProperty(TEMPBAN_MINUTES_BEFORE_RESET) * MILLIS_PER_MINUTE;
this.resetThreshold = settings.getProperty(TEMPBAN_MINUTES_BEFORE_RESET);
}
@Override

View File

@ -2,8 +2,6 @@ package fr.xephi.authme.data.limbo;
import org.bukkit.entity.Player;
import java.util.function.Function;
/**
* Possible types to restore the "allow flight" property
* from LimboPlayer to Bukkit Player.
@ -11,24 +9,41 @@ import java.util.function.Function;
public enum AllowFlightRestoreType {
/** Set value from LimboPlayer to Player. */
RESTORE(LimboPlayer::isCanFly),
RESTORE {
@Override
public void restoreAllowFlight(Player player, LimboPlayer limbo) {
player.setAllowFlight(limbo.isCanFly());
}
},
/** Always set flight enabled to true. */
ENABLE(l -> true),
ENABLE {
@Override
public void restoreAllowFlight(Player player, LimboPlayer limbo) {
player.setAllowFlight(true);
}
},
/** Always set flight enabled to false. */
DISABLE(l -> false);
DISABLE {
@Override
public void restoreAllowFlight(Player player, LimboPlayer limbo) {
player.setAllowFlight(false);
}
},
private final Function<LimboPlayer, Boolean> valueGetter;
/** Always set flight enabled to false. */
NOTHING {
@Override
public void restoreAllowFlight(Player player, LimboPlayer limbo) {
// noop
}
/**
* Constructor.
*
* @param valueGetter function with which the value to set on the player can be retrieved
*/
AllowFlightRestoreType(Function<LimboPlayer, Boolean> valueGetter) {
this.valueGetter = valueGetter;
}
@Override
public void processPlayer(Player player) {
// noop
}
};
/**
* Restores the "allow flight" property from the LimboPlayer to the Player.
@ -37,7 +52,15 @@ public enum AllowFlightRestoreType {
* @param player the player to modify
* @param limbo the limbo player to read from
*/
public void restoreAllowFlight(Player player, LimboPlayer limbo) {
player.setAllowFlight(valueGetter.apply(limbo));
public abstract void restoreAllowFlight(Player player, LimboPlayer limbo);
/**
* Processes the player when a LimboPlayer instance is created based on him. Typically this
* method revokes the {@code allowFlight} property to be restored again later.
*
* @param player the player to process
*/
public void processPlayer(Player player) {
player.setAllowFlight(false);
}
}

View File

@ -4,6 +4,7 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.LimboSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@ -59,7 +60,8 @@ class LimboServiceHelper {
*/
void revokeLimboStates(Player player) {
player.setOp(false);
player.setAllowFlight(false);
settings.getProperty(LimboSettings.RESTORE_ALLOW_FLIGHT)
.processPlayer(player);
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
player.setFlySpeed(0.0f);

View File

@ -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);
}

View File

@ -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);

View File

@ -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<String> 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) {

View File

@ -41,6 +41,7 @@ public class MySQL implements DataSource {
private String database;
private String tableName;
private int poolSize;
private int maxLifetime;
private List<String> columnOthers;
private Columns col;
private HashAlgorithm hashAlgorithm;
@ -116,6 +117,7 @@ public class MySQL implements DataSource {
if (poolSize == -1) {
poolSize = Utils.getCoreCount() * 3;
}
this.maxLifetime = settings.getProperty(DatabaseSettings.MYSQL_CONNECTION_MAX_LIFETIME);
this.useSsl = settings.getProperty(DatabaseSettings.MYSQL_USE_SSL);
}
@ -126,8 +128,10 @@ public class MySQL implements DataSource {
ds = new HikariDataSource();
ds.setPoolName("AuthMeMYSQLPool");
// Pool size
// Pool Settings
ds.setMaximumPoolSize(poolSize);
ds.setMaxLifetime(maxLifetime * 1000);
// Database URL
ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database);

View File

@ -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(() -> {

View File

@ -37,7 +37,7 @@ class TwoFactorRegisterExecutor extends AbstractPasswordRegisterExecutor<TwoFact
// to two-factor authentication. Therefore, the hashed password is the result of the TwoFactor EncryptionMethod
// implementation (contains the TOTP secret).
String hash = params.getHashedPassword().getHash();
String qrCodeUrl = TwoFactor.getQRBarcodeURL(params.getPlayerName(), Bukkit.getIp(), hash);
String qrCodeUrl = TwoFactor.getQrBarcodeUrl(params.getPlayerName(), Bukkit.getIp(), hash);
commonService.send(params.getPlayer(), MessageKey.TWO_FACTOR_CREATE, hash, qrCodeUrl);
}
}

View File

@ -19,6 +19,11 @@ import java.util.Arrays;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
/**
* Two factor authentication.
*
* @see <a href="http://thegreyblog.blogspot.com/2011/12/google-authenticator-using-it-in-your.html">Original source</a>
*/
@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) {

View File

@ -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);

View File

@ -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);
}

View File

@ -10,7 +10,7 @@ import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
public final class DatabaseSettings implements SettingsHolder {
@Comment({"What type of database do you want to use?",
"Valid values: SQLITE, MYSQL"})
"Valid values: SQLITE, MYSQL"})
public static final Property<DataSourceType> BACKEND =
newProperty(DataSourceType.class, "DataSource.backend", DataSourceType.SQLITE);
@ -114,6 +114,11 @@ public final class DatabaseSettings implements SettingsHolder {
public static final Property<Integer> MYSQL_POOL_SIZE =
newProperty("DataSource.poolSize", -1);
@Comment({"The maximum lifetime of a connection in the pool, default = 1800 seconds",
"You should set this at least 30 seconds less than mysql server wait_timeout"})
public static final Property<Integer> MYSQL_CONNECTION_MAX_LIFETIME =
newProperty("DataSource.maxLifetime", 1800);
private DatabaseSettings() {
}

View File

@ -45,8 +45,9 @@ public final class LimboSettings implements SettingsHolder {
newProperty(SegmentSize.class, "limbo.persistence.distributionSize", SegmentSize.SIXTEEN);
@Comment({
"Whether the player is allowed to fly: RESTORE, ENABLE, DISABLE.",
"RESTORE sets back the old property from the player."
"Whether the player is allowed to fly: RESTORE, ENABLE, DISABLE, NOTHING.",
"RESTORE sets back the old property from the player. NOTHING will prevent AuthMe",
"from modifying the 'allow flight' property on the player."
})
public static final Property<AllowFlightRestoreType> RESTORE_ALLOW_FLIGHT =
newProperty(AllowFlightRestoreType.class, "limbo.restoreAllowFlight", AllowFlightRestoreType.RESTORE);
@ -66,7 +67,7 @@ public final class LimboSettings implements SettingsHolder {
"See above for a description of the values."
})
public static final Property<WalkFlySpeedRestoreType> RESTORE_WALK_SPEED =
newProperty(WalkFlySpeedRestoreType.class, "limbo.restoreWalkSpeed", WalkFlySpeedRestoreType.MAX_RESTORE);
newProperty(WalkFlySpeedRestoreType.class, "limbo.restoreWalkSpeed", WalkFlySpeedRestoreType.RESTORE_NO_ZERO);
private LimboSettings() {
}

View File

@ -156,9 +156,13 @@ public final class RestrictionSettings implements SettingsHolder {
public static final Property<Boolean> NO_TELEPORT =
newProperty("settings.restrictions.noTeleport", false);
@Comment("Regex syntax for allowed chars in passwords")
@Comment({
"Regex syntax for allowed chars in passwords. The default [!-~] allows all visible ASCII",
"characters, which is what we recommend. See also http://asciitable.com",
"You can test your regex with https://regex101.com"
})
public static final Property<String> ALLOWED_PASSWORD_REGEX =
newProperty("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*");
newProperty("settings.restrictions.allowedPasswordCharacters", "[!-~]*");
@Comment("Force survival gamemode when player joins?")
public static final Property<Boolean> FORCE_SURVIVAL_MODE =

View File

@ -169,7 +169,6 @@ public class PurgeExecutor {
return;
}
int i = 0;
File essentialsDataFolder = pluginHookService.getEssentialsDataFolder();
if (essentialsDataFolder == null) {
ConsoleLogger.info("Cannot purge Essentials: plugin is not loaded");
@ -181,14 +180,15 @@ public class PurgeExecutor {
return;
}
int deletedFiles = 0;
for (OfflinePlayer offlinePlayer : cleared) {
File playerFile = new File(userDataFolder, PlayerUtils.getUuidOrName(offlinePlayer) + ".yml");
if (playerFile.exists() && playerFile.delete()) {
i++;
deletedFiles++;
}
}
ConsoleLogger.info("AutoPurge: Removed " + i + " EssentialsFiles");
ConsoleLogger.info("AutoPurge: Removed " + deletedFiles + " EssentialsFiles");
}
// TODO #676: What is this method for? Is it correct?

View File

@ -61,7 +61,7 @@ public final class FileUtils {
ConsoleLogger.warning("Could not create directory '" + dir + "'");
return false;
}
return true;
return dir.isDirectory();
}
/**

View File

@ -5,11 +5,11 @@ import java.util.regex.Pattern;
/**
* Utility class about the InternetProtocol
*/
public class InternetProtocolUtils {
public final class InternetProtocolUtils {
private final static Pattern LOCAL_ADDRESS_PATTERN =
Pattern.compile("(^127\\.)|(^(0)?10\\.)|(^172\\.(0)?1[6-9]\\.)|(^172\\.(0)?2[0-9]\\.)" +
"|(^172\\.(0)?3[0-1]\\.)|(^169\\.254\\.)|(^192\\.168\\.)");
private static final Pattern LOCAL_ADDRESS_PATTERN =
Pattern.compile("(^127\\.)|(^(0)?10\\.)|(^172\\.(0)?1[6-9]\\.)|(^172\\.(0)?2[0-9]\\.)"
+ "|(^172\\.(0)?3[0-1]\\.)|(^169\\.254\\.)|(^192\\.168\\.)");
// Utility class
private InternetProtocolUtils() {

View File

@ -0,0 +1,213 @@
# AuthmeReloaded帮助文件汉化
# Translated By CH1
# -------------------------------------------------------
common:
header: '==========[ AuthMeReloaded ]=========='
optional: '可选'
hasPermission: '您拥有权限去使用这个指令'
noPermission: '您没有权限使用这个指令'
default: '默认'
result: '您的权限'
defaultPermissions:
notAllowed: '任何人不能使用'
opOnly: 'OP拥有此权限'
allowed: '所有人都可以使用'
section:
command: '指令'
description: '功能'
detailedDescription: '功能详情'
arguments: '参数'
permissions: '权限'
alternatives: '别名'
children: '子命令'
commands:
authme.register:
description: '注册一个玩家'
detailedDescription: '注册一个玩家'
arg1:
label: '玩家'
description: '玩家名称'
arg2:
label: '密码'
description: '密码'
authme.unregister:
description: '注销一个玩家'
detailedDescription: '注销一个玩家'
arg1:
label: '玩家'
description: '玩家'
authme.forcelogin:
description: '强制玩家重新登录'
detailedDescription: '强制使指定玩家重新登录'
arg1:
label: '玩家'
description: '玩家'
authme.password:
description: '改变某个玩家的密码'
detailedDescription: '改变某个玩家的密码'
arg1:
label: '玩家'
description: '玩家'
arg2:
label: '新密码'
description: '新密码'
authme.lastlogin:
description: '查看玩家最后登录时间'
detailedDescription: '查看玩家最后登录时间'
arg1:
label: '玩家'
description: '玩家'
authme.accounts:
description: '查看玩家IP下的账户'
detailedDescription: '查看玩家IP下的账户'
arg1:
label: '玩家或IP'
description: '玩家或IP'
authme.email:
description: '查看玩家的邮箱'
detailedDescription: '查看玩家的邮箱'
arg1:
label: '玩家'
description: '玩家'
authme.setemail:
description: '改变玩家的邮箱'
detailedDescription: '改变玩家的邮箱'
arg1:
label: '玩家'
description: '玩家'
arg2:
label: '邮箱'
description: '邮箱'
authme.getip:
description: '获取玩家IP'
detailedDescription: '获取玩家IP'
arg1:
label: '玩家'
description: '玩家'
authme.spawn:
description: '传送到AuthMe出生点'
detailedDescription: '传送到AuthMe出生点'
authme.setspawn:
description: '改变AuthMe出生点'
detailedDescription: '改变AuthMe出生点'
authme.firstspawn:
description: '传送到第一次进入游戏出生点'
detailedDescription: '传送到第一次进入游戏出生点'
authme.setfirstspawn:
description: '设置第一次进入游戏的出生点'
detailedDescription: '设置第一次进入游戏的出生点'
authme.purge:
description: '删除指定天数之前没登录的玩家登陆数据'
detailedDescription: '删除指定天数之前没登录的玩家登陆数据'
arg1:
label: '天数'
description: '天数'
arg2:
label: 'all'
description: '添加all到最后来清理最后登录为0的玩家'
authme.resetpos:
description: '重置玩家登出位置'
detailedDescription: '重置玩家登出位置'
arg1:
label: '玩家/*'
description: '玩家名称或所有玩家'
authme.purgebannedplayers:
description: '删除已经被封禁的玩家数据'
detailedDescription: '删除已经被封禁的玩家数据'
authme.switchantibot:
description: '改变AntiBot的状态'
detailedDescription: '改变AntiBot的状态'
arg1:
label: '开关'
description: '选项: ON/OFF'
authme.reload:
description: '重载插件'
detailedDescription: '重载插件'
authme.version:
description: '查看版本信息'
detailedDescription: '查看AuthmeReload版本,开发者,贡献者和许可'
authme.converter:
description: '转换数据命令'
detailedDescription: '转换数据命令'
arg1:
label: '类型'
description: '转换类型:xauth/crazylogin/rakamak/royalauth/vauth/sqliteToSql/mysqlToSqlite'
authme.messages:
description: '添加信息'
detailedDescription: '在语言文件夹中添加缺少的信息'
authme.help:
description: '查看帮助'
detailedDescription: '查看帮助'
arg1:
label: '子命令'
description: '查看的指令'
unregister:
description: '注销您的账户'
detailedDescription: '注销您的账户'
arg1:
label: '密码'
description: '密码'
changepassword:
description: '更改您的密码'
detailedDescription: '更改您的密码'
arg1:
label: '旧的密码'
description: '旧的密码'
arg2:
label: '新的密码'
description: '新的密码'
email:
description: '绑定邮箱或更改密码'
detailedDescription: '绑定邮箱或更改密码'
email.show:
description: '查看邮箱'
detailedDescription: '查看您的邮箱地址'
email.add:
description: '绑定邮箱'
detailedDescription: '为您的账户绑定邮箱'
arg1:
label: '邮箱'
description: '邮箱地址'
arg2:
label: '邮箱'
description: '重新输入邮箱地址'
email.change:
description: '改变邮箱地址'
detailedDescription: '更改您账户的邮箱地址'
arg1:
label: '旧邮箱'
description: '旧的邮箱地址'
arg2:
label: '新邮箱'
description: '新的邮箱地址'
email.recover:
description: '通过邮箱改变密码'
detailedDescription: '通过邮箱改变密码'
arg1:
label: '邮箱'
description: '邮箱地址'
arg2:
label: '验证码'
description: '验证码'
email.help:
description: '查看帮助'
detailedDescription: '查看邮箱帮助'
arg1:
label: '子命令'
description: '指令'
captcha:
description: '验证码'
detailedDescription: '验证码'
arg1:
label: '验证码'
description: '验证码'
captcha.help:
description: '查看验证码帮助'
detailedDescription: '查看验证码帮助'
arg1:
label: '子命令'
description: '指令'

View File

@ -16,7 +16,7 @@ password_error: '&c비밀번호가 일치하지 않습니다, 다시 확인해
password_error_nick: '&c자신의 닉네임을 비밀번호로 사용할 수 없습니다, 다른 비밀번호를 사용하세요...'
password_error_unsafe: '&c이 비밀번호는 안전하지 않습니다, 다른 비밀번호를 사용하세요...'
password_error_chars: '&4비밀번호에 잘못된 문자가 있습니다. 허용된 문자: REG_EX'
pass_len: '&c너의 비번은 좆같이 길거나 좆같이 작아! 제발 다른걸 써줘!'
pass_len: '&c비밀번호가 너무 짧거나 작습니다!'
# 로그인
usage_log: '&c사용법: /login <비밀번호>'
@ -76,7 +76,7 @@ usage_email_add: '&c사용법: /email add <이메일 주소> <이메일 주소
usage_email_change: '&c사용법: /email change <예전 이메일 주소> <새 이메일 주소>'
usage_email_recovery: '&c사용법: /email recovery <이메일 주소>'
new_email_invalid: '&c새 이메일 주소가 잘못되었습니다, 다시 시도해보세요!'
old_email_invalid: '&c전 이메일 주소가 잘못되었습니다, 다시 시도해보세요!'
old_email_invalid: '&c전 이메일 주소가 잘못되었습니다, 다시 시도해보세요!'
email_invalid: '&c이메일 주소가 잘못되었습니다, 다시 시도해보세요!'
email_added: '&2계정에 이메일 주소를 추가했습니다!'
email_confirm: '&c이메일 주소를 확인해주세요!'

View File

@ -1,11 +1,11 @@
# Registration
reg_msg: '&2Proszę się zarejestrować przy użyciu &6/register <hasło> <powtórz_hasło>'
usage_reg: '&4Użycie: /register <hasło> <powtórz_hasło>'
reg_only: '&fTylko zarejestrowani użytkownicy maja do tego dostęp!'
reg_only: '&fTylko zarejestrowani użytkownicy mają do tego dostęp!'
kicked_admin_registered: 'Administrator zarejestrował Ciebie, możesz się zalogować.'
registered: '&aPomyślnie zarejestrowany!'
reg_disabled: '&4Rejestracja jest wyłączona'
user_regged: '&4Gracz już jest zarejestrowany'
reg_disabled: '&4Rejestracja jest wyłączona.'
user_regged: '&4Gracz już jest zarejestrowany.'
# Password errors on registration
password_error: '&fHasło niepoprawne!'
@ -18,29 +18,29 @@ pass_len: '&fTwoje hasło jest za krótkie lub za długie! Spróbuj ponownie...'
usage_log: '&cUżycie: /login hasło'
wrong_pwd: '&cNiepoprawne hasło.'
login: '&aHasło zaakceptowane!'
login_msg: '&2Prosze się zalogować przy użyciu &6/login <hasło>'
login_msg: '&2Proszę się zalogować przy użyciu &6/login <hasło>'
timeout: '&cUpłynął limit czasu zalogowania'
# Errors
unknown_user: '&fGracz nie jest zarejestrowany'
unknown_user: '&fGracz nie jest zarejestrowany.'
denied_command: '&cAby użyć tej komendy musisz się zalogować!'
denied_chat: '&cAby pisać na chacie musisz się zalogować!'
not_logged_in: '&4Nie jesteś zalogowany!'
tempban_max_logins: '&cZostałeś tymczasowo zbanowany za dużą liczbę nieudanych logowań!'
max_reg: '&cPrzekroczyłeś limit zarejestrowanych kont na serwerze &8(&e%reg_count/%max_acc %reg_names&8) &cdla twojego połączenia.'
no_perm: '&4Nie posiadasz wymaganych uprawnień.'
error: '&fWystąpił błąd, prosimy napisać do administracji'
error: '&fWystąpił błąd, prosimy skontaktować się z administracją serwera.'
kick_forvip: '&cGracz VIP dołączył do gry!'
# AntiBot
kick_antibot: 'AntyBot został włączony, musisz poczekać minute przed dołączeniem do serwera'
kick_antibot: '&cAntyBot został włączony, musisz poczekać minutę przed dołączeniem do serwera.'
antibot_auto_enabled: '&4[AntiBot] &aAntyBot włączony z powodu dużej liczby połączeń!'
antibot_auto_disabled: '&2[AntiBot] &aAntyBot zostanie wyłączony za &7%m &aminut!'
# Other messages
unregistered: '&4Pomyslnie wyrejestrowany!'
accounts_owned_self: 'Posiadasz %count kont:'
accounts_owned_other: 'Gracz %name posiada %count kont:'
unregistered: '&4Pomyślnie wyrejestrowany!'
accounts_owned_self: '&7Posiadasz %count kont:'
accounts_owned_other: '&7Gracz %name posiada %count kont:'
two_factor_create: '&2Twój sekretny kod to %code. Możesz zeskanować go tutaj: %url'
recovery_code_sent: 'Kod odzyskiwania hasła został wysłany na adres email przypisany do konta.'
recovery_code_incorrect: '&cKod odzyskiwania hasła jest błędny! &4Pozostałe próby: %count.'
@ -66,8 +66,8 @@ country_banned: '&4Ten kraj jest zbanowany na tym serwerze'
not_owner_error: '&cNie jesteś właścicielem tego konta, wybierz inny nick!'
kick_fullserver: '&cSerwer jest teraz zapełniony, przepraszamy!'
same_nick: '&fTen nick już gra na serwerze!'
invalid_name_case: 'Powinieneś dołączyć do serwera z nicku %valid, a nie %invalid.'
same_ip_online: 'Gracz z takim samym adresem ip jest aktualnie w grze!'
invalid_name_case: '&cPowinieneś dołączyć do serwera z nicku %valid, a nie %invalid.'
same_ip_online: '&cGracz z takim samym adresem ip jest aktualnie w grze!'
# Email
usage_email_add: '&fWpisz: /email add <email> <powtórz_email> '

View File

@ -55,7 +55,7 @@ public class ClassesConsistencyTest {
/** Classes excluded from the field visibility test. */
private static final Set<Class<?>> CLASSES_EXCLUDED_FROM_VISIBILITY_TEST = ImmutableSet.of(
Whirlpool.class, // not our implementation, so we don't touch it
Columns.class // uses non-final String constants, which is safe
Columns.class // uses non-static String constants, which is safe
);
/**

View File

@ -22,7 +22,7 @@ public class CommandUtilsTest {
@BeforeClass
public static void setUpTestCommands() {
commands = TestCommandsUtil.generateCommands();
commands = Collections.unmodifiableCollection(TestCommandsUtil.generateCommands());
}
@Test
@ -49,10 +49,6 @@ public class CommandUtilsTest {
assertThat(commandPath, equalTo("/authme help"));
}
// ------
// min / max arguments
// ------
@Test
public void shouldComputeMinAndMaxOnEmptyCommand() {
// given

View File

@ -0,0 +1,39 @@
package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.service.BackupService;
import org.bukkit.command.CommandSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Test for {@link BackupCommand}.
*/
@RunWith(MockitoJUnitRunner.class)
public class BackupCommandTest {
@InjectMocks
private BackupCommand command;
@Mock
private BackupService backupService;
@Test
public void shouldStartBackup() {
// given
CommandSender sender = mock(CommandSender.class);
// when
command.executeCommand(sender, Collections.emptyList());
// then
verify(backupService).doBackup(BackupService.BackupCause.COMMAND, sender);
}
}

View File

@ -0,0 +1,116 @@
package fr.xephi.authme.command.executable.authme.debug;
import com.google.common.cache.LoadingCache;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.data.limbo.LimboPlayer;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.datasource.CacheDataSource;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.HasCleanup;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.initialization.factory.SingletonStore;
import org.bukkit.command.CommandSender;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Test for {@link DataStatistics}.
*/
@RunWith(MockitoJUnitRunner.class)
public class DataStatisticsTest {
@InjectMocks
private DataStatistics dataStatistics;
@Mock
private DataSource dataSource;
@Mock
private PlayerCache playerCache;
@Mock
private LimboService limboService;
@Mock
private SingletonStore<Object> singletonStore;
@Before
public void setUpLimboCacheMap() {
Map<String, LimboPlayer> limboMap = new HashMap<>();
limboMap.put("test", mock(LimboPlayer.class));
ReflectionTestUtils.setField(LimboService.class, limboService, "entries", limboMap);
}
@Test
public void shouldOutputStatistics() {
// given
CommandSender sender = mock(CommandSender.class);
given(singletonStore.retrieveAllOfType()).willReturn(mockListOfSize(Object.class, 7));
given(singletonStore.retrieveAllOfType(Reloadable.class)).willReturn(mockListOfSize(Reloadable.class, 4));
given(singletonStore.retrieveAllOfType(SettingsDependent.class)).willReturn(mockListOfSize(SettingsDependent.class, 3));
given(singletonStore.retrieveAllOfType(HasCleanup.class)).willReturn(mockListOfSize(HasCleanup.class, 2));
given(dataSource.getAccountsRegistered()).willReturn(219);
given(playerCache.getLogged()).willReturn(12);
// when
dataStatistics.execute(sender, Collections.emptyList());
// then
ArgumentCaptor<String> stringCaptor = ArgumentCaptor.forClass(String.class);
verify(sender, atLeastOnce()).sendMessage(stringCaptor.capture());
assertThat(stringCaptor.getAllValues(), containsInAnyOrder(
"Singleton Java classes: 7 (Reloadable: 4 / SettingsDependent: 3 / HasCleanup: 2)",
"LimboPlayers in memory: 1",
"Total players in DB: 219",
"PlayerCache size: 12 (= logged in players)"));
}
@Test
public void shouldOutputCachedDataSourceStatistics() {
// given
CacheDataSource cacheDataSource = mock(CacheDataSource.class);
LoadingCache<String, Optional<PlayerAuth>> cache = mock(LoadingCache.class);
given(cache.size()).willReturn(11L);
given(cacheDataSource.getCachedAuths()).willReturn(cache);
ReflectionTestUtils.setField(DataStatistics.class, dataStatistics, "dataSource", cacheDataSource);
CommandSender sender = mock(CommandSender.class);
// when
dataStatistics.execute(sender, Collections.emptyList());
// then
ArgumentCaptor<String> stringCaptor = ArgumentCaptor.forClass(String.class);
verify(sender, atLeastOnce()).sendMessage(stringCaptor.capture());
assertThat(stringCaptor.getAllValues(), hasItem("Cached PlayerAuth objects: 11"));
}
private static <T> List<T> mockListOfSize(Class<T> mockClass, int size) {
T mock = mock(mockClass);
List<T> mocks = new ArrayList<>(size);
for (int i = 0; i < size; ++i) {
mocks.add(mock);
}
return mocks;
}
}

View File

@ -5,6 +5,7 @@ import fr.xephi.authme.TestHelper;
import fr.xephi.authme.data.limbo.LimboPlayer;
import fr.xephi.authme.data.limbo.LimboService;
import org.bukkit.Location;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
@ -12,6 +13,7 @@ import java.util.Map;
import java.util.function.Function;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
@ -21,6 +23,11 @@ import static org.mockito.Mockito.mock;
*/
public class DebugSectionUtilsTest {
@Before
public void initMockLogger() {
TestHelper.setupLogger();
}
@Test
public void shouldFormatLocation() {
// given / when
@ -66,4 +73,20 @@ public class DebugSectionUtilsTest {
// then
assertThat(map, sameInstance(limboMap));
}
@Test
public void shouldHandleErrorGracefully() {
// given
LimboService limboService = mock(LimboService.class);
Map<String, LimboPlayer> limboMap = new HashMap<>();
ReflectionTestUtils.setField(LimboService.class, limboService, "entries", limboMap);
// when
Object result = DebugSectionUtils.applyToLimboPlayersMap(limboService, map -> {
throw new IllegalStateException();
});
// then
assertThat(result, nullValue());
}
}

View File

@ -19,6 +19,8 @@ import java.util.Arrays;
import java.util.Collections;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
@ -106,11 +108,16 @@ public class ChangePasswordCommandTest {
verify(management).performPasswordChange(player, oldPass, newPass);
}
@Test
public void shouldDefineArgumentMismatchMessage() {
// given / when / then
assertThat(command.getArgumentsMismatchMessage(), equalTo(MessageKey.USAGE_CHANGE_PASSWORD));
}
private Player initPlayerWithName(String name, boolean loggedIn) {
Player player = mock(Player.class);
when(player.getName()).thenReturn(name);
when(playerCache.isAuthenticated(name)).thenReturn(loggedIn);
return player;
}
}

View File

@ -15,6 +15,8 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@ -73,4 +75,9 @@ public class AddEmailCommandTest {
verify(commandService).send(sender, MessageKey.CONFIRM_EMAIL_MESSAGE);
}
@Test
public void shouldDefineArgumentMismatchMessage() {
// given / when / then
assertThat(command.getArgumentsMismatchMessage(), equalTo(MessageKey.USAGE_ADD_EMAIL));
}
}

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
@ -10,9 +11,11 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@ -36,7 +39,7 @@ public class ChangeEmailCommandTest {
CommandSender sender = mock(BlockCommandSender.class);
// when
command.executeCommand(sender, new ArrayList<String>());
command.executeCommand(sender, Collections.emptyList());
// then
verifyZeroInteractions(management);
@ -54,4 +57,9 @@ public class ChangeEmailCommandTest {
verify(management).performChangeEmail(sender, "new.mail@example.org", "old_mail@example.org");
}
@Test
public void shouldDefineArgumentMismatchMessage() {
// given / when / then
assertThat(command.getArgumentsMismatchMessage(), equalTo(MessageKey.USAGE_CHANGE_EMAIL));
}
}

View File

@ -0,0 +1,49 @@
package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandMapper;
import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.command.help.HelpProvider;
import org.bukkit.command.CommandSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Test for {@link EmailBaseCommand}.
*/
@RunWith(MockitoJUnitRunner.class)
public class EmailBaseCommandTest {
@InjectMocks
private EmailBaseCommand command;
@Mock
private HelpProvider helpProvider;
@Mock
private CommandMapper commandMapper;
@Test
public void shouldDisplayHelp() {
// given
CommandSender sender = mock(CommandSender.class);
FoundCommandResult result = mock(FoundCommandResult.class);
given(commandMapper.mapPartsToCommand(eq(sender), anyList())).willReturn(result);
// when
command.executeCommand(sender, Collections.emptyList());
// then
verify(commandMapper).mapPartsToCommand(sender, Collections.singletonList("email"));
verify(helpProvider).outputHelp(sender, result, HelpProvider.SHOW_CHILDREN);
}
}

View File

@ -22,6 +22,8 @@ import org.mockito.Mock;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@ -208,4 +210,10 @@ public class RecoverEmailCommandTest {
verify(dataSource).getEmail(name);
verify(recoveryService).generateAndSendNewPassword(sender, email);
}
@Test
public void shouldDefineArgumentMismatchMessage() {
// given / when / then
assertThat(command.getArgumentsMismatchMessage(), equalTo(MessageKey.USAGE_RECOVER_EMAIL));
}
}

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.command.executable.login;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
@ -13,6 +14,8 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -57,4 +60,9 @@ public class LoginCommandTest {
verify(management).performLogin(eq(sender), eq("password"));
}
@Test
public void shouldDefineArgumentMismatchMessage() {
// given / when / then
assertThat(command.getArgumentsMismatchMessage(), equalTo(MessageKey.USAGE_LOGIN));
}
}

View File

@ -15,6 +15,8 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@ -87,4 +89,9 @@ public class UnregisterCommandTest {
verify(sender).sendMessage(argThat(containsString("/authme unregister <player>")));
}
@Test
public void shouldDefineArgumentMismatchMessage() {
// given / when / then
assertThat(command.getArgumentsMismatchMessage(), equalTo(MessageKey.USAGE_UNREGISTER));
}
}

View File

@ -10,6 +10,7 @@ import fr.xephi.authme.message.MessageFileHandlerProvider;
import fr.xephi.authme.permission.DefaultPermission;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.Collection;
@ -19,10 +20,13 @@ import static fr.xephi.authme.TestHelper.getJarFile;
import static fr.xephi.authme.command.TestCommandsUtil.getCommandWithLabel;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
/**
* Test for {@link HelpMessagesService}.
@ -46,6 +50,17 @@ public class HelpMessagesServiceTest {
given(messageFileHandlerProvider.initializeHandler(any(Function.class))).willReturn(handler);
}
@Test
@SuppressWarnings("unchecked")
public void shouldUseExistingFileAsTextFile() {
// given / when / then
ArgumentCaptor<Function<String, String>> functionCaptor = ArgumentCaptor.forClass(Function.class);
verify(messageFileHandlerProvider).initializeHandler(functionCaptor.capture());
Function<String, String> helpFilePathBuilder = functionCaptor.getValue();
String defaultFilePath = helpFilePathBuilder.apply("en");
assertThat(getClass().getClassLoader().getResource(defaultFilePath), not(nullValue()));
}
@Test
public void shouldReturnLocalizedCommand() {
// given

View File

@ -6,6 +6,7 @@ import org.junit.Test;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Test for {@link AllowFlightRestoreType}.
@ -64,6 +65,42 @@ public class AllowFlightRestoreTypeTest {
verify(player2).setAllowFlight(false);
}
@Test
public void shouldNotInteractWithPlayer() {
// given
LimboPlayer limboWithFly = newLimboWithAllowFlight(true);
LimboPlayer limboWithoutFly = newLimboWithAllowFlight(false);
Player player1 = mock(Player.class);
Player player2 = mock(Player.class);
// when
AllowFlightRestoreType.NOTHING.restoreAllowFlight(player1, limboWithFly);
AllowFlightRestoreType.NOTHING.restoreAllowFlight(player2, limboWithoutFly);
// then
verifyZeroInteractions(player1, player2);
}
@Test
public void shouldRemoveFlightExceptForNothingType() {
// given
AllowFlightRestoreType noInteractionType = AllowFlightRestoreType.NOTHING;
for (AllowFlightRestoreType type : AllowFlightRestoreType.values()) {
Player player = mock(Player.class);
// when
type.processPlayer(player);
// then
if (type == noInteractionType) {
verifyZeroInteractions(player);
} else {
verify(player).setAllowFlight(false);
}
}
}
private static LimboPlayer newLimboWithAllowFlight(boolean allowFlight) {
LimboPlayer limbo = mock(LimboPlayer.class);
given(limbo.isCanFly()).willReturn(allowFlight);

View File

@ -84,6 +84,7 @@ public class LimboServiceTest {
given(spawnLoader.getPlayerLocationOrSpawn(player)).willReturn(playerLoc);
given(permissionsManager.hasGroupSupport()).willReturn(true);
given(permissionsManager.getGroups(player)).willReturn(Collections.singletonList("permgrwp"));
given(settings.getProperty(LimboSettings.RESTORE_ALLOW_FLIGHT)).willReturn(AllowFlightRestoreType.ENABLE);
// when
limboService.createLimboPlayer(player, true);
@ -114,6 +115,7 @@ public class LimboServiceTest {
Location playerLoc = mock(Location.class);
given(spawnLoader.getPlayerLocationOrSpawn(player)).willReturn(playerLoc);
given(permissionsManager.hasGroupSupport()).willReturn(false);
given(settings.getProperty(LimboSettings.RESTORE_ALLOW_FLIGHT)).willReturn(AllowFlightRestoreType.RESTORE);
// when
limboService.createLimboPlayer(player, false);
@ -143,6 +145,7 @@ public class LimboServiceTest {
LimboPlayer existingLimbo = mock(LimboPlayer.class);
getLimboMap().put("carlos", existingLimbo);
Player player = newPlayer("Carlos");
given(settings.getProperty(LimboSettings.RESTORE_ALLOW_FLIGHT)).willReturn(AllowFlightRestoreType.ENABLE);
// when
limboService.createLimboPlayer(player, false);

View File

@ -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"

View File

@ -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}.

View File

@ -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

View File

@ -75,6 +75,20 @@ public class FileUtilsTest {
assertThat(file.exists(), equalTo(false));
}
@Test
public void shouldReturnFalseForParentInvalidParentFolders() throws IOException {
// given
File folder = temporaryFolder.newFolder();
new File(folder, "hello").createNewFile();
File fileToCreate = new File(folder, "hello/test");
// when
boolean result = FileUtils.copyFileFromResource(fileToCreate, "welcome.txt");
// then
assertThat(result, equalTo(false));
}
@Test
public void shouldPurgeDirectory() throws IOException {
// given
@ -137,6 +151,36 @@ public class FileUtilsTest {
assertThat(result, equalTo("path" + File.separator + "to" + File.separator + "test-file.txt"));
}
@Test
public void shouldCreateDirectory() throws IOException {
// given
File root = temporaryFolder.newFolder();
File dir = new File(root, "folder/folder2/myFolder");
// when
boolean result = FileUtils.createDirectory(dir);
// then
assertThat(result, equalTo(true));
assertThat(dir.exists(), equalTo(true));
assertThat(dir.isDirectory(), equalTo(true));
}
@Test
public void shouldReturnFalseOnDirectoryCreateFail() throws IOException {
// given
File root = temporaryFolder.newFolder();
File dirAsFile = new File(root, "file");
dirAsFile.createNewFile();
// when
boolean result = FileUtils.createDirectory(dirAsFile);
// then
assertThat(result, equalTo(false));
assertThat(dirAsFile.isFile(), equalTo(true));
}
@Test
public void shouldHaveHiddenConstructor() {
TestHelper.validateHasOnlyPrivateEmptyConstructor(FileUtils.class);

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.util;
import fr.xephi.authme.TestHelper;
import org.junit.Test;
import static org.junit.Assert.assertThat;
@ -19,4 +20,10 @@ public class InternetProtocolUtilsTest {
assertThat(InternetProtocolUtils.isLocalAddress("192.168.0.1"), equalTo(true));
assertThat(InternetProtocolUtils.isLocalAddress("94.32.34.5"), equalTo(false));
}
@Test
public void shouldHavePrivateConstructor() {
// given / when / then
TestHelper.validateHasOnlyPrivateEmptyConstructor(InternetProtocolUtils.class);
}
}

View File

@ -53,7 +53,7 @@ public class RandomStringUtilsTest {
// when / then
for (int length : lengths) {
String result = RandomStringUtils.generateHex(length);
String result = RandomStringUtils.generateLowerUpper(length);
assertThat("Result '" + result + "' should have length " + length,
result.length(), equalTo(length));
assertThat("Result '" + result + "' should only have characters a-z, A-Z, 0-9",

View File

@ -1,16 +1,22 @@
package fr.xephi.authme.util;
import fr.xephi.authme.TestHelper;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -99,6 +105,68 @@ public class UtilsTest {
verifyZeroInteractions(sender);
}
@Test
public void shouldCheckIfCollectionIsEmpty() {
// given
List<String> emptyList = Collections.emptyList();
Collection<Integer> nonEmptyColl = Arrays.asList(3, 4, 5);
// when / then
assertThat(Utils.isCollectionEmpty(emptyList), equalTo(true));
assertThat(Utils.isCollectionEmpty(nonEmptyColl), equalTo(false));
assertThat(Utils.isCollectionEmpty(null), equalTo(true));
}
@Test
public void shouldReturnCoreCount() {
// given / when / then
assertThat(Utils.getCoreCount(), greaterThan(0));
}
@Test
public void shouldLogAndSendWarning() {
// given
Logger logger = TestHelper.setupLogger();
String message = "Error while performing action";
CommandSender sender = mock(CommandSender.class);
// when
Utils.logAndSendWarning(sender, message);
// then
verify(logger).warning(message);
verify(sender).sendMessage(ChatColor.RED + message);
}
@Test
public void shouldLogWarningAndNotSendToConsoleSender() {
// given
Logger logger = TestHelper.setupLogger();
String message = "Error while performing action";
CommandSender sender = mock(ConsoleCommandSender.class);
// when
Utils.logAndSendWarning(sender, message);
// then
verify(logger).warning(message);
verifyZeroInteractions(sender);
}
@Test
public void shouldLogWarningAndHandleNullCommandSender() {
// given
Logger logger = TestHelper.setupLogger();
String message = "Error while performing action";
CommandSender sender = null;
// when
Utils.logAndSendWarning(sender, message);
// then
verify(logger).warning(message);
}
@Test
public void shouldCheckIfClassIsLoaded() {
// given / when / then

View File

@ -30,7 +30,7 @@ import static org.mockito.Mockito.when;
*/
public class EncryptionMethodInfoGatherer {
private final static Set<Class<? extends Annotation>> RELEVANT_ANNOTATIONS =
private static final Set<Class<? extends Annotation>> 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();

View File

@ -140,10 +140,15 @@ public class GeneratePluginYml implements AutoToolTask {
}
private static String buildUsage(CommandDescription command) {
if (!command.getArguments().isEmpty()) {
return CommandUtils.buildSyntax(command);
}
final String commandStart = "/" + command.getLabels().get(0);
if (!command.getArguments().isEmpty()) {
// Command has arguments, so generate something like /authme register <password> <confirmPass>
final String arguments = command.getArguments().stream()
.map(CommandUtils::formatArgument)
.collect(Collectors.joining(" "));
return commandStart + " " + arguments;
}
// Argument-less command, list all children: /authme register|login|firstspawn|spawn|...
String usage = commandStart + " " + command.getChildren()
.stream()
.filter(cmd -> !cmd.getLabels().contains("help"))

View File

@ -18,3 +18,7 @@ doesNotExist:
wrongEntry:
command: 'should be ignored'
executor: PLAYER
onUnregister:
farewell:
command: 'msg %p sad to see you go!'
executor: CONSOLE