diff --git a/docs/commands.md b/docs/commands.md index 3d978090d..2e5743f09 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,5 +1,5 @@ - + ## AuthMe Commands You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >` @@ -34,6 +34,8 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
Requires `authme.admin.setfirstspawn` - **/authme purge** <days> [all]: Purge old AuthMeReloaded data longer than the specified number of days ago.
Requires `authme.admin.purge` +- **/authme purgeplayer** <player> [options]: Purges data of the given player. +
Requires `authme.admin.purgeplayer` - **/authme backup**: Creates a backup of the registered users.
Requires `authme.admin.backup` - **/authme resetpos** <player/*>: Purge the last know position of the specified player or all of them. @@ -87,4 +89,4 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`). --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Apr 23 19:29:43 CEST 2017 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Apr 29 18:27:38 CEST 2017 diff --git a/docs/config.md b/docs/config.md index 8da66c1a4..1200fe2ed 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,5 +1,5 @@ - + ## AuthMe Configuration The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, @@ -52,6 +52,10 @@ DataSource: mySQLlastlocZ: 'z' # Column for storing player LastLocation - World Name mySQLlastlocWorld: 'world' + # Column for storing player LastLocation - Yaw + mySQLlastlocYaw: 'yaw' + # Column for storing player LastLocation - Pitch + mySQLlastlocPitch: 'pitch' # Overrides the size of the DB Connection Pool, -1 = Auto poolSize: -1 ExternalBoardOptions: @@ -390,7 +394,7 @@ Purge: removePlayerDat: false # Do we need to remove the Essentials/userdata/player.yml file during purge process? removeEssentialsFile: false - # World where are players.dat stores + # World in which the players.dat are stored defaultWorld: 'world' # Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge? removeLimitedCreativesInventories: false @@ -507,4 +511,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 Sun Apr 23 19:30:08 CEST 2017 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Apr 29 18:27:38 CEST 2017 diff --git a/docs/hash_algorithms.md b/docs/hash_algorithms.md index ef05a2515..23a90616a 100644 --- a/docs/hash_algorithms.md +++ b/docs/hash_algorithms.md @@ -1,5 +1,5 @@ - + ## Hash Algorithms AuthMe supports the following hash algorithms for storing your passwords safely. @@ -7,7 +7,7 @@ AuthMe supports the following hash algorithms for storing your passwords safely. Algorithm | Recommendation | Hash length | ASCII | | Salt type | Length | Separate? --------- | -------------- | ----------- | ----- | --- | --------- | ------ | --------- -ARGON2 | Recommended | 96 | | | None | | +ARGON2 | Recommended | 96 | | | Text | 16 | BCRYPT | Recommended | 60 | | | Text | | BCRYPT2Y | Recommended | 60 | | | Text | 22 | CRAZYCRYPT1 | Do not use | 128 | | | Username | | @@ -83,4 +83,4 @@ or bad. --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Fri Apr 14 01:40:05 CEST 2017 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Apr 29 18:27:40 CEST 2017 diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md index 4bf2c0118..5a537e9f2 100644 --- a/docs/permission_nodes.md +++ b/docs/permission_nodes.md @@ -1,5 +1,5 @@ - + ## AuthMe Permission Nodes The following are the permission nodes that are currently supported by the latest dev builds. @@ -19,6 +19,7 @@ The following are the permission nodes that are currently supported by the lates - **authme.admin.purge** – Administrator command to purge old user data. - **authme.admin.purgebannedplayers** – Administrator command to purge all data associated with banned players. - **authme.admin.purgelastpos** – Administrator command to purge the last position of a user. +- **authme.admin.purgeplayer** – Administrator command to purge a given player. - **authme.admin.register** – Administrator command to register a new user. - **authme.admin.reload** – Administrator command to reload the plugin configuration. - **authme.admin.seeotheraccounts** – Permission to see the other accounts of the players that log in. @@ -60,4 +61,4 @@ The following are the permission nodes that are currently supported by the lates --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Apr 23 19:32:06 CEST 2017 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Apr 29 18:27:41 CEST 2017 diff --git a/docs/translations.md b/docs/translations.md index 66493be46..a4d956a8f 100644 --- a/docs/translations.md +++ b/docs/translations.md @@ -1,5 +1,5 @@ - + # AuthMe Translations The following translations are available in AuthMe. Set `messagesLanguage` to the language code @@ -9,33 +9,34 @@ Code | Language | Translated |   ---- | -------- | ---------: | ------ [en](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_en.yml) | English | 100% | bar [bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 95% | bar -[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 85% | bar +[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 100% | bar [cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 85% | bar [de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 85% | bar -[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 95% | bar +[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% | bar [eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 53% | bar [fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 56% | bar [fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 95% | bar [gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 60% | bar -[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 84% | bar -[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 60% | bar -[it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 95% | bar -[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 61% | bar +[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 100% | bar +[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 59% | bar +[it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% | bar +[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 60% | bar [lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Lithuanian | 45% | bar -[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 85% | bar +[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 100% | bar [pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 95% | bar -[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 95% | bar +[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 100% | bar [ro](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ro.yml) | Romanian | 84% | bar [ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 95% | bar [sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 39% | bar [tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 95% | bar [uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 79% | bar [vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 85% | bar -[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 95% | bar -[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 69% | bar -[zhmc](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhmc.yml) | Chinese (Macau) | 82% | bar -[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 69% | bar +[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 100% | bar +[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 68% | bar +[zhmc](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhmc.yml) | Chinese (Macau) | 81% | bar +[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 68% | bar + --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Wed Mar 22 23:10:32 CET 2017 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Apr 29 18:27:41 CEST 2017 diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index 70dfe734e..0e8c28aba 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -16,6 +16,7 @@ import fr.xephi.authme.command.executable.authme.MessagesCommand; import fr.xephi.authme.command.executable.authme.PurgeBannedPlayersCommand; import fr.xephi.authme.command.executable.authme.PurgeCommand; import fr.xephi.authme.command.executable.authme.PurgeLastPositionCommand; +import fr.xephi.authme.command.executable.authme.PurgePlayerCommand; import fr.xephi.authme.command.executable.authme.RegisterAdminCommand; import fr.xephi.authme.command.executable.authme.ReloadCommand; import fr.xephi.authme.command.executable.authme.SetEmailCommand; @@ -234,6 +235,18 @@ public class CommandInitializer { .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) diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommand.java new file mode 100644 index 000000000..0905458a8 --- /dev/null +++ b/src/main/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommand.java @@ -0,0 +1,46 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.service.BukkitService; +import fr.xephi.authme.task.purge.PurgeExecutor; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; + +import javax.inject.Inject; +import java.util.List; + +import static java.util.Collections.singletonList; + +/** + * Command to purge a player. + */ +public class PurgePlayerCommand implements ExecutableCommand { + + @Inject + private PurgeExecutor purgeExecutor; + + @Inject + private BukkitService bukkitService; + + @Inject + private DataSource dataSource; + + @Override + public void executeCommand(CommandSender sender, List arguments) { + String option = arguments.size() > 1 ? arguments.get(1) : null; + bukkitService.runTaskOptionallyAsync( + () -> executeCommand(sender, arguments.get(0), option)); + } + + private void executeCommand(CommandSender sender, String name, String option) { + if ("force".equals(option) || !dataSource.isAuthAvailable(name)) { + OfflinePlayer offlinePlayer = bukkitService.getOfflinePlayer(name); + purgeExecutor.executePurge(singletonList(offlinePlayer), singletonList(name.toLowerCase())); + sender.sendMessage("Purged data for player " + name); + } else { + sender.sendMessage("This player is still registered! Are you sure you want to proceed? " + + "Use '/authme purgeplayer " + name + " force' to run the command anyway"); + } + } +} diff --git a/src/main/java/fr/xephi/authme/permission/AdminPermission.java b/src/main/java/fr/xephi/authme/permission/AdminPermission.java index 4f0957a0a..14baf3ae9 100644 --- a/src/main/java/fr/xephi/authme/permission/AdminPermission.java +++ b/src/main/java/fr/xephi/authme/permission/AdminPermission.java @@ -85,6 +85,11 @@ public enum AdminPermission implements PermissionNode { */ PURGE_BANNED_PLAYERS("authme.admin.purgebannedplayers"), + /** + * Administrator command to purge a given player. + */ + PURGE_PLAYER("authme.admin.purgeplayer"), + /** * Administrator command to toggle the AntiBot protection status. */ diff --git a/src/main/java/fr/xephi/authme/service/BukkitService.java b/src/main/java/fr/xephi/authme/service/BukkitService.java index 45ea4b4b8..f5b03348a 100644 --- a/src/main/java/fr/xephi/authme/service/BukkitService.java +++ b/src/main/java/fr/xephi/authme/service/BukkitService.java @@ -198,6 +198,23 @@ public class BukkitService implements SettingsDependent { return authMe.getServer().getPlayerExact(name); } + /** + * Gets the player by the given name, regardless if they are offline or + * online. + *

+ * This method may involve a blocking web request to get the UUID for the + * given name. + *

+ * This will return an object even if the player does not exist. To this + * method, all players will exist. + * + * @param name the name the player to retrieve + * @return an offline player + */ + public OfflinePlayer getOfflinePlayer(String name) { + return authMe.getServer().getOfflinePlayer(name); + } + /** * Gets a set containing all banned players. * diff --git a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java index 2c62454c8..0064fd40f 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java @@ -24,7 +24,7 @@ public final class PurgeSettings implements SettingsHolder { public static final Property REMOVE_ESSENTIALS_FILES = newProperty("Purge.removeEssentialsFile", false); - @Comment("World where are players.dat stores") + @Comment("World in which the players.dat are stored") public static final Property DEFAULT_WORLD = newProperty("Purge.defaultWorld", "world"); diff --git a/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java b/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java index 0fddecd57..6e6e5836f 100644 --- a/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java +++ b/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java @@ -21,7 +21,7 @@ import static fr.xephi.authme.util.FileUtils.makePath; /** * Executes the purge operations. */ -class PurgeExecutor { +public class PurgeExecutor { @Inject private Settings settings; diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8629a4535..9822005f1 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -17,7 +17,7 @@ softdepend: commands: authme: description: AuthMe op commands - usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|spawn|setspawn|firstspawn|setfirstspawn|purge|backup|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages|debug + usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|spawn|setspawn|firstspawn|setfirstspawn|purge|purgeplayer|backup|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages|debug login: description: Login command usage: /login @@ -67,6 +67,7 @@ permissions: authme.admin.purge: true authme.admin.purgebannedplayers: true authme.admin.purgelastpos: true + authme.admin.purgeplayer: true authme.admin.register: true authme.admin.reload: true authme.admin.seeotheraccounts: true @@ -118,6 +119,9 @@ permissions: authme.admin.purgelastpos: description: Administrator command to purge the last position of a user. default: op + authme.admin.purgeplayer: + description: Administrator command to purge a given player. + default: op authme.admin.register: description: Administrator command to register a new user. default: op diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommandTest.java new file mode 100644 index 000000000..c37317cf5 --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommandTest.java @@ -0,0 +1,91 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.service.BukkitService; +import fr.xephi.authme.task.purge.PurgeExecutor; +import org.bukkit.OfflinePlayer; +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 static fr.xephi.authme.TestHelper.runOptionallyAsyncTask; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.hamcrest.Matchers.containsString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.hamcrest.MockitoHamcrest.argThat; + +/** + * Test for {@link PurgePlayerCommand}. + */ +@RunWith(MockitoJUnitRunner.class) +public class PurgePlayerCommandTest { + + @InjectMocks + private PurgePlayerCommand command; + + @Mock + private BukkitService bukkitService; + + @Mock + private PurgeExecutor purgeExecutor; + + @Mock + private DataSource dataSource; + + @Test + public void shouldNotExecutePurgeForRegisteredPlayer() { + // given + String name = "Bobby"; + given(dataSource.isAuthAvailable(name)).willReturn(true); + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, singletonList(name)); + runOptionallyAsyncTask(bukkitService); + + // then + verify(sender).sendMessage(argThat(containsString("This player is still registered"))); + verifyZeroInteractions(purgeExecutor); + } + + @Test + public void shouldExecutePurge() { + // given + String name = "Frank"; + given(dataSource.isAuthAvailable(name)).willReturn(false); + OfflinePlayer player = mock(OfflinePlayer.class); + given(bukkitService.getOfflinePlayer(name)).willReturn(player); + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, singletonList(name)); + runOptionallyAsyncTask(bukkitService); + + // then + verify(dataSource).isAuthAvailable(name); + verify(purgeExecutor).executePurge(singletonList(player), singletonList(name.toLowerCase())); + } + + @Test + public void shouldExecutePurgeOfRegisteredPlayer() { + // given + String name = "GhiJKlmn7"; + OfflinePlayer player = mock(OfflinePlayer.class); + given(bukkitService.getOfflinePlayer(name)).willReturn(player); + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, asList(name, "force")); + runOptionallyAsyncTask(bukkitService); + + // then + verify(purgeExecutor).executePurge(singletonList(player), singletonList(name.toLowerCase())); + } +}