From baec0349097c1b88ee44d1b680ee5b57888f435d Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 21 Apr 2018 13:02:14 +0200 Subject: [PATCH] #1555 Add RegisterEvent and AuthMeAsyncPreRegisterEvent (#1559) * #1555 Add RegisterEvent and AuthMeAsyncPreRegisterEvent * Add missing javadoc --- .../events/AuthMeAsyncPreRegisterEvent.java | 70 +++++++++++++++++++ .../fr/xephi/authme/events/RegisterEvent.java | 47 +++++++++++++ .../process/register/AsyncRegister.java | 30 ++++++-- .../register/ProcessSyncEmailRegister.java | 6 ++ .../register/ProcessSyncPasswordRegister.java | 6 ++ .../process/login/AsynchronousLoginTest.java | 9 +-- .../process/register/AsyncRegisterTest.java | 34 +++++++++ 7 files changed, 191 insertions(+), 11 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/events/AuthMeAsyncPreRegisterEvent.java create mode 100644 src/main/java/fr/xephi/authme/events/RegisterEvent.java diff --git a/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreRegisterEvent.java b/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreRegisterEvent.java new file mode 100644 index 00000000..af26ad51 --- /dev/null +++ b/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreRegisterEvent.java @@ -0,0 +1,70 @@ +package fr.xephi.authme.events; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * This event is called when a player uses the register command, + * it's fired even when a user does a /register with invalid arguments. + * {@link #setCanRegister(boolean) event.setCanRegister(false)} prevents the player from registering. + */ +public class AuthMeAsyncPreRegisterEvent extends CustomEvent { + + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private boolean canRegister = true; + + /** + * Constructor. + * + * @param player The player + * @param isAsync True if the event is async, false otherwise + */ + public AuthMeAsyncPreRegisterEvent(Player player, boolean isAsync) { + super(isAsync); + this.player = player; + } + + /** + * Return the player concerned by this event. + * + * @return The player who executed a valid {@code /login} command + */ + public Player getPlayer() { + return player; + } + + /** + * Return whether the player is allowed to register. + * + * @return True if the player can log in, false otherwise + */ + public boolean canRegister() { + return canRegister; + } + + /** + * Define whether or not the player may register. + * + * @param canRegister True to allow the player to log in; false to prevent him + */ + public void setCanRegister(boolean canRegister) { + this.canRegister = canRegister; + } + + /** + * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. + * + * @return The list of handlers + */ + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + +} diff --git a/src/main/java/fr/xephi/authme/events/RegisterEvent.java b/src/main/java/fr/xephi/authme/events/RegisterEvent.java new file mode 100644 index 00000000..2a98d054 --- /dev/null +++ b/src/main/java/fr/xephi/authme/events/RegisterEvent.java @@ -0,0 +1,47 @@ +package fr.xephi.authme.events; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * Event fired when a player has successfully registered. + */ +public class RegisterEvent extends CustomEvent { + + private static final HandlerList handlers = new HandlerList(); + private final Player player; + + /** + * Constructor. + * + * @param player The player + */ + public RegisterEvent(Player player) { + this.player = player; + } + + /** + * Return the player that has successfully logged in or registered. + * + * @return The player + */ + public Player getPlayer() { + return player; + } + + /** + * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. + * + * @return The list of handlers + */ + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + +} diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java index d50fe9a3..78eaa567 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -4,14 +4,17 @@ import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.events.AuthMeAsyncPreRegisterEvent; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.process.AsynchronousProcess; import fr.xephi.authme.process.register.executors.RegistrationExecutor; import fr.xephi.authme.process.register.executors.RegistrationMethod; import fr.xephi.authme.process.register.executors.RegistrationParameters; +import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; import fr.xephi.authme.service.bungeecord.BungeeSender; import fr.xephi.authme.service.bungeecord.MessageType; +import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.PlayerUtils; @@ -32,6 +35,8 @@ public class AsyncRegister implements AsynchronousProcess { @Inject private PlayerCache playerCache; @Inject + private BukkitService bukkitService; + @Inject private CommonService service; @Inject private SingletonStore registrationExecutorFactory; @@ -44,9 +49,9 @@ public class AsyncRegister implements AsynchronousProcess { /** * Performs the registration process for the given player. * - * @param variant the registration method + * @param variant the registration method * @param parameters the parameters - * @param

parameters type + * @param

parameters type */ public

void register(RegistrationMethod

variant, P parameters) { if (preRegisterCheck(parameters.getPlayer())) { @@ -57,6 +62,13 @@ public class AsyncRegister implements AsynchronousProcess { } } + /** + * Checks if the player is able to register, in that case the {@link AuthMeAsyncPreRegisterEvent} is invoked. + * + * @param player the player which is trying to register. + * + * @return true if the checks are successful and the event hasn't marked the action as denied, false otherwise. + */ private boolean preRegisterCheck(Player player) { final String name = player.getName().toLowerCase(); if (playerCache.isAuthenticated(name)) { @@ -70,6 +82,13 @@ public class AsyncRegister implements AsynchronousProcess { return false; } + boolean isAsync = service.getProperty(PluginSettings.USE_ASYNC_TASKS); + AuthMeAsyncPreRegisterEvent event = new AuthMeAsyncPreRegisterEvent(player, isAsync); + bukkitService.callEvent(event); + if (!event.canRegister()) { + return false; + } + return isPlayerIpAllowedToRegister(player); } @@ -77,11 +96,11 @@ public class AsyncRegister implements AsynchronousProcess { * Executes the registration. * * @param parameters the registration parameters - * @param executor the executor to perform the registration process with - * @param

registration params type + * @param executor the executor to perform the registration process with + * @param

registration params type */ private

- void executeRegistration(P parameters, RegistrationExecutor

executor) { + void executeRegistration(P parameters, RegistrationExecutor

executor) { PlayerAuth auth = executor.buildPlayerAuth(parameters); if (database.saveAuth(auth)) { executor.executePostPersistAction(parameters); @@ -95,6 +114,7 @@ public class AsyncRegister implements AsynchronousProcess { * Checks whether the registration threshold has been exceeded for the given player's IP address. * * @param player the player to check + * * @return true if registration may take place, false otherwise (IP check failed) */ private boolean isPlayerIpAllowedToRegister(Player player) { diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java index 6ab4a874..e740a0de 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java @@ -2,8 +2,10 @@ package fr.xephi.authme.process.register; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.limbo.LimboService; +import fr.xephi.authme.events.RegisterEvent; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.process.SynchronousProcess; +import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; import fr.xephi.authme.util.PlayerUtils; import org.bukkit.entity.Player; @@ -15,6 +17,9 @@ import javax.inject.Inject; */ public class ProcessSyncEmailRegister implements SynchronousProcess { + @Inject + private BukkitService bukkitService; + @Inject private CommonService service; @@ -34,6 +39,7 @@ public class ProcessSyncEmailRegister implements SynchronousProcess { limboService.replaceTasksAfterRegistration(player); player.saveData(); + bukkitService.callEvent(new RegisterEvent(player)); ConsoleLogger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player)); } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 30e7f59a..dc8aa136 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -2,8 +2,10 @@ package fr.xephi.authme.process.register; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.limbo.LimboService; +import fr.xephi.authme.events.RegisterEvent; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.process.SynchronousProcess; +import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; import fr.xephi.authme.service.bungeecord.BungeeSender; import fr.xephi.authme.settings.commandconfig.CommandManager; @@ -31,6 +33,9 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { @Inject private CommandManager commandManager; + @Inject + private BukkitService bukkitService; + ProcessSyncPasswordRegister() { } @@ -60,6 +65,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess { } player.saveData(); + bukkitService.callEvent(new RegisterEvent(player)); ConsoleLogger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player)); // Kick Player after Registration is enabled, kick the player diff --git a/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java b/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java index 9f21b7ba..9b57fb31 100644 --- a/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java +++ b/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java @@ -156,12 +156,9 @@ public class AsynchronousLoginTest { given(commonService.getProperty(DatabaseSettings.MYSQL_COL_GROUP)).willReturn(""); given(commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)).willReturn(true); doReturn(false).when(asynchronousLogin).hasReachedMaxLoggedInPlayersForIp(any(Player.class), anyString()); - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - ((AuthMeAsyncPreLoginEvent) invocation.getArgument(0)).setCanLogin(false); - return null; - } + doAnswer((Answer) invocation -> { + ((AuthMeAsyncPreLoginEvent) invocation.getArgument(0)).setCanLogin(false); + return null; }).when(bukkitService).callEvent(any(AuthMeAsyncPreLoginEvent.class)); // when diff --git a/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java b/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java index 77f91ca8..59c384bb 100644 --- a/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java +++ b/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java @@ -4,12 +4,15 @@ import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.TestHelper; import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.events.AuthMeAsyncPreRegisterEvent; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.process.register.executors.PasswordRegisterParams; import fr.xephi.authme.process.register.executors.RegistrationExecutor; import fr.xephi.authme.process.register.executors.RegistrationMethod; import fr.xephi.authme.process.register.executors.TwoFactorRegisterParams; +import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; +import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import org.bukkit.entity.Player; @@ -18,9 +21,11 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.only; import static org.mockito.Mockito.verify; @@ -40,6 +45,8 @@ public class AsyncRegisterTest { @Mock private CommonService commonService; @Mock + private BukkitService bukkitService; + @Mock private DataSource dataSource; @Mock private SingletonStore registrationExecutorStore; @@ -102,6 +109,32 @@ public class AsyncRegisterTest { @Test @SuppressWarnings("unchecked") public void shouldStopForFailedExecutorCheck() { + // given + String name = "edbert"; + Player player = mockPlayerWithName(name); + TestHelper.mockPlayerIp(player, "33.44.55.66"); + given(playerCache.isAuthenticated(name)).willReturn(false); + given(commonService.getProperty(RegistrationSettings.IS_ENABLED)).willReturn(true); + given(dataSource.isAuthAvailable(name)).willReturn(false); + given(commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)).willReturn(true); + RegistrationExecutor executor = mock(RegistrationExecutor.class); + TwoFactorRegisterParams params = TwoFactorRegisterParams.of(player); + singletonStoreWillReturn(registrationExecutorStore, executor); + doAnswer((Answer) invocation -> { + ((AuthMeAsyncPreRegisterEvent) invocation.getArgument(0)).setCanRegister(false); + return null; + }).when(bukkitService).callEvent(any(AuthMeAsyncPreRegisterEvent.class)); + + // when + asyncRegister.register(RegistrationMethod.TWO_FACTOR_REGISTRATION, params); + + // then + verify(dataSource, only()).isAuthAvailable(name); + } + + @Test + @SuppressWarnings("unchecked") + public void shouldStopForCancelledEvent() { // given String name = "edbert"; Player player = mockPlayerWithName(name); @@ -110,6 +143,7 @@ public class AsyncRegisterTest { given(commonService.getProperty(RegistrationSettings.IS_ENABLED)).willReturn(true); given(commonService.getProperty(RestrictionSettings.MAX_REGISTRATION_PER_IP)).willReturn(0); given(dataSource.isAuthAvailable(name)).willReturn(false); + given(commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)).willReturn(true); RegistrationExecutor executor = mock(RegistrationExecutor.class); TwoFactorRegisterParams params = TwoFactorRegisterParams.of(player); given(executor.isRegistrationAdmitted(params)).willReturn(false);