From edcfb50b7fc83cb204aed8a2e3de76af46dcc3be Mon Sep 17 00:00:00 2001 From: GoodTimes14 Date: Sun, 21 Jun 2026 09:56:26 +0200 Subject: [PATCH 1/5] feat: Added proxy side login/logout/auto-login events --- .../authme/bungee/BungeeProxyBridge.java | 43 +++++++ .../events/AuthMeBungeeAutoLoginEvent.java | 30 +++++ .../bungee/events/AuthMeBungeeLoginEvent.java | 24 ++++ .../events/AuthMeBungeeLogoutEvent.java | 17 +++ .../authme/bungee/BungeeProxyBridgeTest.java | 104 ++++++++++++++++- .../authme/velocity/VelocityProxyBridge.java | 110 ++++++++++++------ .../events/AuthMeVelocityLoginEvent.java | 23 ++++ .../events/AuthMeVelocityLogoutEvent.java | 16 +++ .../events/AuthmeVelocityAutoLoginEvent.java | 30 +++++ .../velocity/VelocityProxyBridgeTest.java | 62 +++++++++- 10 files changed, 417 insertions(+), 42 deletions(-) create mode 100644 authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java create mode 100644 authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java create mode 100644 authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java create mode 100644 authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java create mode 100644 authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java create mode 100644 authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthmeVelocityAutoLoginEvent.java diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java index 8945d9059..7a75aa2e8 100644 --- a/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java @@ -3,6 +3,9 @@ import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import fr.xephi.authme.bungee.events.AuthMeBungeeAutoLoginEvent; +import fr.xephi.authme.bungee.events.AuthMeBungeeLoginEvent; +import fr.xephi.authme.bungee.events.AuthMeBungeeLogoutEvent; import fr.xephi.authme.bungee.premium.BungeePremiumOnlineModeHandler; import fr.xephi.authme.bungee.premium.BungeePremiumVerificationManager; import net.md_5.bungee.api.ChatColor; @@ -15,6 +18,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.event.PlayerHandshakeEvent; import net.md_5.bungee.api.event.PluginMessageEvent; +import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerSwitchEvent; import net.md_5.bungee.api.plugin.Listener; @@ -70,6 +74,7 @@ public final class BungeeProxyBridge implements Listener { private List premiumListBuffer = new ArrayList<>(); // Players with a pending premium verification (ran /premium but not yet confirmed via reconnect) private volatile Set pendingPremiumUsernames = ConcurrentHashMap.newKeySet(); + private final Map uniqueIdCache = new ConcurrentHashMap<>(); private final BungeePremiumOnlineModeHandler premiumOnlineModeHandler; private final BungeePremiumVerificationManager premiumVerificationManager; private final ScheduledExecutorService retryScheduler = Executors.newSingleThreadScheduledExecutor(r -> { @@ -244,11 +249,21 @@ public void onPluginMessage(PluginMessageEvent event) { return; } + String playerName = normalizeName(parsedMessage.playerName()); + if (LOGIN_MESSAGE.equals(parsedMessage.typeId())) { if (configuration.isAuthServer(server.getInfo())) { logger.info("Player " + parsedMessage.playerName() + " authenticated on auth server '" + server.getInfo().getName() + "'"); + + ProxiedPlayer player = proxyServer.getPlayer(playerName); + if (player != null) { + boolean premium = requiresPremiumVerification(parsedMessage.playerName()); + proxyServer.getPluginManager().callEvent(new AuthMeBungeeLoginEvent(player, premium)); + } + authenticationStore.markAuthenticated(parsedMessage.playerName()); + sendAutoLoginIfAlreadySwitched(parsedMessage.playerName(), server.getInfo()); redirectToLoginServer(parsedMessage.playerName()); } else if (pendingAutoLogins.containsKey(parsedMessage.playerName())) { @@ -259,6 +274,11 @@ public void onPluginMessage(PluginMessageEvent event) { } } else if (LOGOUT_MESSAGE.equals(parsedMessage.typeId())) { authenticationStore.markLoggedOut(parsedMessage.playerName()); + ProxiedPlayer player = proxyServer.getPlayer(playerName); + if (player != null) { + proxyServer.getPluginManager().callEvent(new AuthMeBungeeLogoutEvent(player)); + } + redirectLoggedOutPlayer(parsedMessage.playerName()); } else if (PERFORM_LOGIN_ACK_MESSAGE.equals(parsedMessage.typeId())) { logger.info("Auto-login ACK received for " + parsedMessage.playerName() @@ -350,6 +370,12 @@ public void onServerSwitch(ServerSwitchEvent event) { logger.fine("PacketEvents-verified premium player " + normalizedName + " joining auth server — sending perform.login immediately"); } + AuthMeBungeeAutoLoginEvent autoLoginEvent = new AuthMeBungeeAutoLoginEvent(player); + proxyServer.getPluginManager().callEvent(autoLoginEvent); + if (autoLoginEvent.isCancelled()) { + logger.fine("Auto-login cancelled for player " + normalizedName + " via event"); + return; + } String serverName = currentServer.getInfo().getName(); logger.info("Sending auto-login request to server '" + serverName + "' for player " + normalizedName); @@ -447,6 +473,14 @@ private void sendAutoLoginIfAlreadySwitched(String normalizedName, ServerInfo au // Still on auth server — normal flow, ServerSwitchEvent will handle it on switch return; } + + AuthMeBungeeAutoLoginEvent autoLoginEvent = new AuthMeBungeeAutoLoginEvent(player); + proxyServer.getPluginManager().callEvent(autoLoginEvent); + if (autoLoginEvent.isCancelled()) { + logger.fine("Auto-login cancelled for player " + normalizedName + " (via event)"); + return; + } + String currentServerName = currentConn.getInfo().getName(); logger.info("Player " + normalizedName + " already on server '" + currentServerName + "' when login message arrived — sending auto-login immediately"); @@ -508,6 +542,15 @@ private void scheduleRetry(String normalizedName) { logger.fine("Auto-login retry cancelled for " + normalizedName + " (player has no active server)"); return; } + + AuthMeBungeeAutoLoginEvent autoLoginEvent = new AuthMeBungeeAutoLoginEvent(player); + proxyServer.getPluginManager().callEvent(autoLoginEvent); + if (autoLoginEvent.isCancelled()) { + logger.fine("Auto-login cancelled for player " + normalizedName + " (via event)"); + cancelPendingLogin(normalizedName); + return; + } + String serverName = server.getInfo().getName(); logger.fine("Retrying auto-login for " + normalizedName + " on server '" + serverName + "' (attempt " + (current + 1) + "/" + MAX_RETRIES + ")"); diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java new file mode 100644 index 000000000..dd5511c58 --- /dev/null +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java @@ -0,0 +1,30 @@ +package fr.xephi.authme.bungee.events; + +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.plugin.Cancellable; +import net.md_5.bungee.api.plugin.Event; + +public class AuthMeBungeeAutoLoginEvent extends Event implements Cancellable { + + private final ProxiedPlayer player; + + private boolean cancel; + + public AuthMeBungeeAutoLoginEvent(ProxiedPlayer player) { + this.player = player; + } + + public ProxiedPlayer getPlayer() { + return player; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java new file mode 100644 index 000000000..653bef52f --- /dev/null +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java @@ -0,0 +1,24 @@ +package fr.xephi.authme.bungee.events; + +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.plugin.Event; + +public class AuthMeBungeeLoginEvent extends Event { + + private final ProxiedPlayer player; + + private final boolean premium; + + public AuthMeBungeeLoginEvent(ProxiedPlayer player, boolean premium) { + this.player = player; + this.premium = premium; + } + + public boolean isPremium() { + return premium; + } + + public ProxiedPlayer getPlayer() { + return player; + } +} diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java new file mode 100644 index 000000000..14e85a75c --- /dev/null +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java @@ -0,0 +1,17 @@ +package fr.xephi.authme.bungee.events; + +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.plugin.Event; + +public class AuthMeBungeeLogoutEvent extends Event { + + private final ProxiedPlayer player; + + public AuthMeBungeeLogoutEvent(ProxiedPlayer player) { + this.player = player; + } + + public ProxiedPlayer getPlayer() { + return player; + } +} diff --git a/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java b/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java index 51732e092..a2fe3cfcb 100644 --- a/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java +++ b/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java @@ -2,6 +2,9 @@ import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import fr.xephi.authme.bungee.events.AuthMeBungeeAutoLoginEvent; +import fr.xephi.authme.bungee.events.AuthMeBungeeLoginEvent; +import fr.xephi.authme.bungee.events.AuthMeBungeeLogoutEvent; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.PendingConnection; @@ -13,6 +16,7 @@ import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerSwitchEvent; +import net.md_5.bungee.api.plugin.PluginManager; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -29,6 +33,8 @@ import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -85,6 +91,9 @@ class BungeeProxyBridgeTest { @Mock private PendingConnection pendingConnection; + @Mock + private PluginManager pluginManager; + @Captor private ArgumentCaptor payloadCaptor; @@ -101,6 +110,7 @@ void shouldTrackAuthenticatedPlayerAndForwardPerformLoginOnServerSwitch() { given(currentServer.getInfo()).willReturn(authServerInfo); given(authServerInfo.getName()).willReturn("lobby"); + stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerSwitch(serverSwitchEvent); @@ -160,6 +170,7 @@ void shouldRedirectPlayerOnLogoutWhenConfigured() { given(proxyServer.getPlayer("alice")).willReturn(player); given(proxyServer.getServerInfo("limbo")).willReturn(nonAuthServerInfo); + stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge( proxyServer, logger, new BungeeProxyConfiguration( Set.of("lobby"), false, true, Set.of("/login"), true, true, @@ -196,6 +207,7 @@ void shouldCancelPendingLoginOnExplicitAck() { given(currentServer.getInfo()).willReturn(authServerInfo); given(serverSwitchEvent.getFrom()).willReturn(null); + stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerSwitch(serverSwitchEvent); @@ -204,8 +216,8 @@ void shouldCancelPendingLoginOnExplicitAck() { given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("perform.login.ack", "Alice")); bridge.onPluginMessage(pluginMessageEvent); - // getPlayer called exactly once by sendAutoLoginIfAlreadySwitched (on login), not by any retry - verify(proxyServer, org.mockito.Mockito.times(1)).getPlayer("alice"); + // getPlayer called twice: once by login event lookup, once by sendAutoLoginIfAlreadySwitched — not by any retry + verify(proxyServer, org.mockito.Mockito.times(2)).getPlayer("alice"); } @Test @@ -220,6 +232,7 @@ void shouldCancelPendingLoginOnImplicitAckFromNonAuthServer() { given(player.getServer()).willReturn(currentServer); given(currentServer.getInfo()).willReturn(authServerInfo); + stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); // Mark authenticated via auth server login @@ -233,8 +246,8 @@ void shouldCancelPendingLoginOnImplicitAckFromNonAuthServer() { given(sourceServer.getInfo()).willReturn(nonAuthServerInfo); bridge.onPluginMessage(pluginMessageEvent); - // getPlayer called exactly once by sendAutoLoginIfAlreadySwitched (on login from auth server), not by retries - verify(proxyServer, org.mockito.Mockito.times(1)).getPlayer("alice"); + // getPlayer called twice: once by login event lookup, once by sendAutoLoginIfAlreadySwitched — not by retries + verify(proxyServer, org.mockito.Mockito.times(2)).getPlayer("alice"); } @Test @@ -349,7 +362,6 @@ void shouldNotForwardPerformLoginToNonAuthServers() { given(sourceServer.getInfo()).willReturn(authServerInfo); given(authServerInfo.getName()).willReturn("lobby"); given(serverSwitchEvent.getPlayer()).willReturn(player); - given(player.getName()).willReturn("Alice"); given(player.getServer()).willReturn(currentServer); given(currentServer.getInfo()).willReturn(nonAuthServerInfo); given(nonAuthServerInfo.getName()).willReturn("survival"); @@ -376,6 +388,7 @@ void shouldForwardPerformLoginWhenLeavingAuthServer() { given(serverSwitchEvent.getFrom()).willReturn(authServerInfo); given(authServerInfo.getName()).willReturn("lobby"); + stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerSwitch(serverSwitchEvent); @@ -439,6 +452,7 @@ void shouldSendAutoLoginImmediatelyWhenPlayerAlreadySwitchedBeforeLoginMessage() given(currentServer.getInfo()).willReturn(nonAuthServerInfo); given(nonAuthServerInfo.getName()).willReturn("survival"); + stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); bridge.onPluginMessage(pluginMessageEvent); @@ -480,6 +494,81 @@ void shouldForceOnlineModeForPremiumHandshakeAfterChunkedPremiumListResync() { verify(pendingConnection).setOnlineMode(true); } + @Test + void shouldFireLoginEventWhenPlayerAuthenticatesOnAuthServer() { + given(pluginMessageEvent.isCancelled()).willReturn(false); + given(pluginMessageEvent.getTag()).willReturn(BungeeProxyBridge.AUTHME_CHANNEL); + given(pluginMessageEvent.getSender()).willReturn(sourceServer); + given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("login", "Alice")); + given(sourceServer.getInfo()).willReturn(authServerInfo); + given(authServerInfo.getName()).willReturn("lobby"); + given(proxyServer.getPlayer("alice")).willReturn(player); + given(player.getServer()).willReturn(currentServer); + given(currentServer.getInfo()).willReturn(authServerInfo); + + stubEventsAllowed(); + + BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); + bridge.onPluginMessage(pluginMessageEvent); + + ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(AuthMeBungeeLoginEvent.class); + verify(pluginManager).callEvent(eventCaptor.capture()); + assertSame(player, eventCaptor.getValue().getPlayer()); + assertFalse(eventCaptor.getValue().isPremium()); + } + + @Test + void shouldFireLogoutEventWhenPlayerLogsOut() { + given(pluginMessageEvent.isCancelled()).willReturn(false); + given(pluginMessageEvent.getTag()).willReturn(BungeeProxyBridge.AUTHME_CHANNEL); + given(pluginMessageEvent.getSender()).willReturn(sourceServer); + given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("logout", "Alice")); + given(proxyServer.getPlayer("alice")).willReturn(player); + + stubEventsAllowed(); + + BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); + bridge.onPluginMessage(pluginMessageEvent); + + ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(AuthMeBungeeLogoutEvent.class); + verify(pluginManager).callEvent(eventCaptor.capture()); + assertSame(player, eventCaptor.getValue().getPlayer()); + } + + @Test + void shouldNotSendPerformLoginWhenAutoLoginEventIsCancelled() { + given(pluginMessageEvent.isCancelled()).willReturn(false); + given(pluginMessageEvent.getTag()).willReturn(BungeeProxyBridge.AUTHME_CHANNEL); + given(pluginMessageEvent.getSender()).willReturn(sourceServer); + given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("login", "Alice")); + given(sourceServer.getInfo()).willReturn(authServerInfo); + given(serverSwitchEvent.getPlayer()).willReturn(player); + given(player.getName()).willReturn("Alice"); + given(player.getServer()).willReturn(currentServer); + given(currentServer.getInfo()).willReturn(nonAuthServerInfo); + given(nonAuthServerInfo.getName()).willReturn("survival"); + given(serverSwitchEvent.getFrom()).willReturn(authServerInfo); + given(authServerInfo.getName()).willReturn("lobby"); + + given(proxyServer.getPluginManager()).willReturn(pluginManager); + given(pluginManager.callEvent(any(AuthMeBungeeAutoLoginEvent.class))) + .willAnswer(inv -> { + AuthMeBungeeAutoLoginEvent event = inv.getArgument(0); + event.setCancelled(true); + return event; + }); + + BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); + bridge.onPluginMessage(pluginMessageEvent); + bridge.onServerSwitch(serverSwitchEvent); + + ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(AuthMeBungeeAutoLoginEvent.class); + verify(pluginManager).callEvent(eventCaptor.capture()); + assertSame(player, eventCaptor.getValue().getPlayer()); + assertTrue(eventCaptor.getValue().isCancelled()); + verify(nonAuthServerInfo, never()).sendData(any(String.class), any(byte[].class), eq(false)); + } + private static byte[] createChunkPayload(int seq, boolean last, String csv) { ByteArrayDataOutput output = ByteStreams.newDataOutput(); output.writeUTF("premium.list.chunk"); @@ -487,6 +576,11 @@ private static byte[] createChunkPayload(int seq, boolean last, String csv) { return output.toByteArray(); } + private void stubEventsAllowed() { + given(proxyServer.getPluginManager()).willReturn(pluginManager); + given(pluginManager.callEvent(any())).willAnswer(inv -> inv.getArgument(0)); + } + private static BungeeProxyConfiguration createConfiguration() { return new BungeeProxyConfiguration( Set.of("lobby"), false, true, Set.of("/login", "/register", "/l", "/reg", "/email", "/captcha", "/2fa", "/totp", "/log"), diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java index e2fc5ec6f..bf52f59da 100644 --- a/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java @@ -19,6 +19,9 @@ import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.server.RegisteredServer; +import fr.xephi.authme.velocity.events.AuthMeVelocityLoginEvent; +import fr.xephi.authme.velocity.events.AuthMeVelocityLogoutEvent; +import fr.xephi.authme.velocity.events.AuthmeVelocityAutoLoginEvent; import fr.xephi.authme.velocity.premium.VelocityPremiumVerificationManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -242,11 +245,20 @@ void onPluginMessage(PluginMessageEvent event) { return; } + String normalizedName = normalizeName(parsedMessage.playerName()); String serverName = serverConnection.getServer().getServerInfo().getName(); if (LOGIN_MESSAGE.equals(parsedMessage.typeId())) { if (configuration.isAuthServer(serverConnection.getServer())) { logger.info("Player {} authenticated on auth server '{}'", parsedMessage.playerName(), serverName); + + proxyServer.getPlayer(normalizedName).ifPresent(player -> { + boolean premium = requiresPremiumVerification(normalizeName(parsedMessage.playerName())); + AuthMeVelocityLoginEvent loginEvent = new AuthMeVelocityLoginEvent(player, premium); + + proxyServer.getEventManager().fireAndForget(loginEvent); + }); + authenticationStore.markAuthenticated(parsedMessage.playerName()); sendAutoLoginIfAlreadySwitched(parsedMessage.playerName(), serverConnection.getServer()); redirectToLoginServer(parsedMessage.playerName()); @@ -262,6 +274,11 @@ void onPluginMessage(PluginMessageEvent event) { } else if (LOGOUT_MESSAGE.equals(parsedMessage.typeId())) { logger.info("Player {} logged out (notified by server '{}')", parsedMessage.playerName(), serverName); authenticationStore.markLoggedOut(parsedMessage.playerName()); + proxyServer.getPlayer(normalizedName).ifPresent(player -> { + AuthMeVelocityLogoutEvent loginEvent = new AuthMeVelocityLogoutEvent(player); + proxyServer.getEventManager().fireAndForget(loginEvent); + }); + redirectLoggedOutPlayer(parsedMessage.playerName()); } else if (PERFORM_LOGIN_ACK_MESSAGE.equals(parsedMessage.typeId())) { logger.info("Auto-login ACK received for {} from server '{}'", @@ -352,25 +369,34 @@ void onServerConnected(ServerConnectedEvent event) { normalizedName); } - Optional currentServer = event.getPlayer().getCurrentServer(); - if (currentServer.isEmpty()) { - // Velocity hasn't registered the new connection yet; let the retry mechanism handle it - logger.debug("Player {} has no active server connection in ServerConnectedEvent; scheduling auto-login retry", normalizedName); - initiatePendingLogin(normalizedName); - return; - } + AuthmeVelocityAutoLoginEvent autoLoginEvent = new AuthmeVelocityAutoLoginEvent(event.getPlayer()); + proxyServer.getEventManager().fire(autoLoginEvent).thenAccept((auto) -> { - String serverName = currentServer.get().getServer().getServerInfo().getName(); - boolean sent = currentServer.get().sendPluginMessage( - AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); - if (sent) { - logger.info("Sending auto-login request to server '{}' for player {} (verifiedPremiumUuid={})", - serverName, normalizedName, verifiedPremiumUuid); - initiatePendingLogin(normalizedName); - } else { - logger.warn("Failed to send auto-login request to server '{}' for player {}; scheduling retry", serverName, normalizedName); - initiatePendingLogin(normalizedName); - } + if (!auto.getResult().isAllowed()) { + logger.debug("Auto-login cancelled for Player {} via event result", normalizedName); + return; + } + + Optional currentServer = event.getPlayer().getCurrentServer(); + if (currentServer.isEmpty()) { + // Velocity hasn't registered the new connection yet; let the retry mechanism handle it + logger.debug("Player {} has no active server connection in ServerConnectedEvent; scheduling auto-login retry", normalizedName); + initiatePendingLogin(normalizedName); + return; + } + + String serverName = currentServer.get().getServer().getServerInfo().getName(); + boolean sent = currentServer.get().sendPluginMessage( + AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); + if (sent) { + logger.info("Sending auto-login request to server '{}' for player {} (verifiedPremiumUuid={})", + serverName, normalizedName, verifiedPremiumUuid); + initiatePendingLogin(normalizedName); + } else { + logger.warn("Failed to send auto-login request to server '{}' for player {}; scheduling retry", serverName, normalizedName); + initiatePendingLogin(normalizedName); + } + }); } void onPreLogin(PreLoginEvent event) { @@ -485,14 +511,21 @@ private void sendAutoLoginIfAlreadySwitched(String normalizedName, RegisteredSer String currentServerName = currentServer.getServerInfo().getName(); logger.info("Player {} already on server '{}' when login message arrived — sending auto-login immediately", normalizedName, currentServerName); - UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); - boolean sent = currentConn.get().sendPluginMessage( - AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); - if (sent) { - initiatePendingLogin(normalizedName); - } else { - logger.warn("Failed to send auto-login to '{}' for {} (race condition path)", currentServerName, normalizedName); - } + AuthmeVelocityAutoLoginEvent autoLoginEvent = new AuthmeVelocityAutoLoginEvent(playerOpt.get()); + proxyServer.getEventManager().fire(autoLoginEvent).thenAccept(auto -> { + if (!auto.getResult().isAllowed()) { + logger.debug("Auto-login cancelled for {} via event (already-switched path)", normalizedName); + return; + } + UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); + boolean sent = currentConn.get().sendPluginMessage( + AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); + if (sent) { + initiatePendingLogin(normalizedName); + } else { + logger.warn("Failed to send auto-login to '{}' for {} (race condition path)", currentServerName, normalizedName); + } + }); } private void sendProxyStartedHandshakeIfPending(RegisteredServer server) { @@ -564,13 +597,24 @@ private void scheduleRetry(String normalizedName) { logger.warn("No auto-login ACK received for {} after {} retries; giving up", normalizedName, MAX_RETRIES); return; } - String serverName = serverOpt.get().getServer().getServerInfo().getName(); - logger.debug("Retrying auto-login for {} on server '{}' (attempt {}/{})", - normalizedName, serverName, current + 1, MAX_RETRIES); - UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); - serverOpt.get().sendPluginMessage(AUTHME_CHANNEL, - createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); - scheduleRetry(normalizedName); + AuthmeVelocityAutoLoginEvent autoLoginEvent = new AuthmeVelocityAutoLoginEvent(playerOpt.get()); + proxyServer.getEventManager().fire(autoLoginEvent).thenAccept(auto -> { + if (!auto.getResult().isAllowed()) { + logger.debug("Auto-login cancelled for {} via event (retry {})", normalizedName, current + 1); + cancelPendingLogin(normalizedName); + return; + } + + String serverName = serverOpt.get().getServer().getServerInfo().getName(); + logger.debug("Retrying auto-login for {} on server '{}' (attempt {}/{})", + normalizedName, serverName, current + 1, MAX_RETRIES); + + UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); + serverOpt.get().sendPluginMessage(AUTHME_CHANNEL, + createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); + + scheduleRetry(normalizedName); + }); }, 1, TimeUnit.SECONDS); } diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java new file mode 100644 index 000000000..0f7d78ea7 --- /dev/null +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java @@ -0,0 +1,23 @@ +package fr.xephi.authme.velocity.events; + +import com.velocitypowered.api.proxy.Player; + +public class AuthMeVelocityLoginEvent { + + + private final Player player; + private final boolean premium; + + public AuthMeVelocityLoginEvent(Player player, boolean premium) { + this.player = player; + this.premium = premium; + } + + public Player getPlayer() { + return player; + } + + public boolean isPremium() { + return premium; + } +} diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java new file mode 100644 index 000000000..0970287d2 --- /dev/null +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java @@ -0,0 +1,16 @@ +package fr.xephi.authme.velocity.events; + +import com.velocitypowered.api.proxy.Player; + +public class AuthMeVelocityLogoutEvent { + + private final Player player; + + public AuthMeVelocityLogoutEvent(Player player) { + this.player = player; + } + + public Player getPlayer() { + return player; + } +} diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthmeVelocityAutoLoginEvent.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthmeVelocityAutoLoginEvent.java new file mode 100644 index 000000000..0ea3190d7 --- /dev/null +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthmeVelocityAutoLoginEvent.java @@ -0,0 +1,30 @@ +package fr.xephi.authme.velocity.events; + +import com.velocitypowered.api.event.ResultedEvent; +import com.velocitypowered.api.proxy.Player; + +public class AuthmeVelocityAutoLoginEvent implements ResultedEvent { + + private final Player player; + + private GenericResult result = GenericResult.allowed(); + + public AuthmeVelocityAutoLoginEvent(Player player) { + this.player = player; + } + + + public Player getPlayer() { + return player; + } + + @Override + public GenericResult getResult() { + return result; + } + + @Override + public void setResult(GenericResult result) { + this.result = result; + } +} diff --git a/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java b/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java index 975869161..3c6bee2ff 100644 --- a/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java +++ b/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java @@ -3,6 +3,7 @@ import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; import com.velocitypowered.api.command.CommandSource; +import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.command.CommandExecuteEvent; import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.connection.DisconnectEvent; @@ -18,6 +19,9 @@ import com.velocitypowered.api.proxy.messages.ChannelRegistrar; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; +import fr.xephi.authme.velocity.events.AuthMeVelocityLoginEvent; +import fr.xephi.authme.velocity.events.AuthMeVelocityLogoutEvent; +import fr.xephi.authme.velocity.events.AuthmeVelocityAutoLoginEvent; import net.kyori.adventure.text.Component; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -31,6 +35,7 @@ import java.util.Optional; import java.util.Set; +import java.util.concurrent.CompletableFuture; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -92,6 +97,9 @@ class VelocityProxyBridgeTest { @Mock private CommandSource consoleSource; + @Mock + private EventManager eventManager; + @Captor private ArgumentCaptor payloadCaptor; @@ -121,6 +129,7 @@ void shouldTrackAuthenticatedPlayerAndForwardPerformLoginOnServerConnect() { .willReturn(true); VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); + stubAutoLoginAllowed(); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, authServer, null)); @@ -195,8 +204,10 @@ proxyServer, logger, new VelocityProxyConfiguration(Set.of("lobby"), false, true "Authentication required.", true, true, "limbo", true, Set.of("/login", "/register"), true, "", "", false), new VelocityAuthenticationStore(), null); + given(proxyServer.getEventManager()).willReturn(eventManager); bridge.onPluginMessage(pluginMessageEvent); + verify(eventManager).fireAndForget(any(AuthMeVelocityLogoutEvent.class)); verify(connectionRequest).fireAndForget(); } @@ -229,6 +240,7 @@ void shouldCancelPendingLoginOnExplicitAck() { given(proxyServer.getPlayer("alice")).willReturn(Optional.of(player)); VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); + stubAutoLoginAllowed(); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, authServer, null)); @@ -236,9 +248,11 @@ void shouldCancelPendingLoginOnExplicitAck() { given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("perform.login.ack", "Alice")); bridge.onPluginMessage(pluginMessageEvent); - // After ACK, proxyServer.getPlayer should have been called exactly once (by sendAutoLoginIfAlreadySwitched, + // After ACK, proxyServer.getPlayer should have been called twice + // (one for the AuthMeVelocityLoginEvent and the other by sendAutoLoginIfAlreadySwitched, // not by any retry) — the pending login was cancelled before any retry could fire. - verify(proxyServer, org.mockito.Mockito.times(1)).getPlayer("alice"); + verify(proxyServer, org.mockito.Mockito.times(2)).getPlayer("alice"); + verify(eventManager).fireAndForget(any(AuthMeVelocityLoginEvent.class)); } @Test @@ -262,6 +276,7 @@ void shouldCancelPendingLoginOnImplicitAckFromNonAuthServer() { // Mark authenticated via auth server login given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("login", "Alice")); given(sourceConnection.getServer()).willReturn(authServer); + stubAutoLoginAllowed(); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, authServer, null)); @@ -270,9 +285,10 @@ void shouldCancelPendingLoginOnImplicitAckFromNonAuthServer() { given(sourceConnection.getServer()).willReturn(nonAuthServer); bridge.onPluginMessage(pluginMessageEvent); - // Pending is now cancelled; proxyServer.getPlayer was called exactly once (by sendAutoLoginIfAlreadySwitched), + // Pending is now cancelled; proxyServer.getPlayer was called twice + // (one for the AuthMeVelocityLoginEvent calling and the other by sendAutoLoginIfAlreadySwitched), // not again by any retry. - verify(proxyServer, org.mockito.Mockito.times(1)).getPlayer("alice"); + verify(proxyServer, org.mockito.Mockito.times(2)).getPlayer("alice"); } @Test @@ -357,6 +373,7 @@ void shouldForwardPerformLoginWhenSwitchingFromAuthServerToNonAuthServer() { .willReturn(true); VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); + stubAutoLoginAllowed(); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, nonAuthServer, authServer)); @@ -364,6 +381,28 @@ void shouldForwardPerformLoginWhenSwitchingFromAuthServerToNonAuthServer() { assertPerformLoginPayload(payloadCaptor.getValue(), "alice", "test-secret"); } + @Test + void shouldNotForwardPerformLoginWhenAutoLoginEventIsDenied() { + given(pluginMessageEvent.getResult()).willReturn(PluginMessageEvent.ForwardResult.forward()); + given(pluginMessageEvent.getIdentifier()).willReturn(VelocityProxyBridge.AUTHME_CHANNEL); + given(pluginMessageEvent.getSource()).willReturn(sourceConnection); + given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("login", "Alice")); + given(sourceConnection.getServer()).willReturn(authServer); + given(authServer.getServerInfo()).willReturn(authServerInfo); + given(authServerInfo.getName()).willReturn("lobby"); + given(nonAuthServer.getServerInfo()).willReturn(nonAuthServerInfo); + given(nonAuthServerInfo.getName()).willReturn("survival"); + given(proxyServer.getPlayer("alice")).willReturn(Optional.of(player)); + given(player.getCurrentServer()).willReturn(Optional.of(currentServer)); + given(currentServer.getServer()).willReturn(nonAuthServer); + stubAutoLoginDenied(); + + VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); + bridge.onPluginMessage(pluginMessageEvent); + + verify(currentServer, never()).sendPluginMessage(any(), any(byte[].class)); + } + // --- Command blocking tests --- @Test @@ -561,6 +600,21 @@ private static byte[] createChunkPayload(int seq, boolean last, String csv) { return output.toByteArray(); } + private void stubAutoLoginAllowed() { + given(proxyServer.getEventManager()).willReturn(eventManager); + given(eventManager.fire(any(AuthmeVelocityAutoLoginEvent.class))) + .willAnswer(inv -> CompletableFuture.completedFuture(inv.getArgument(0))); + } + + private void stubAutoLoginDenied() { + given(proxyServer.getEventManager()).willReturn(eventManager); + given(eventManager.fire(any(AuthmeVelocityAutoLoginEvent.class))).willAnswer(inv -> { + AuthmeVelocityAutoLoginEvent event = inv.getArgument(0); + event.setResult(AuthmeVelocityAutoLoginEvent.GenericResult.denied()); + return CompletableFuture.completedFuture(event); + }); + } + private static VelocityProxyConfiguration createConfiguration() { return new VelocityProxyConfiguration(Set.of("lobby"), false, true, "Authentication required.", true, false, "", true, From 106d6dfd12a579f09a64c8ad1341db34df224a9a Mon Sep 17 00:00:00 2001 From: GoodTimes14 Date: Sun, 21 Jun 2026 09:58:14 +0200 Subject: [PATCH 2/5] chore: Removed unused import and unused string -> uuid cache map --- .../src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java index 7a75aa2e8..5b46a2041 100644 --- a/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java @@ -18,7 +18,6 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.event.PlayerHandshakeEvent; import net.md_5.bungee.api.event.PluginMessageEvent; -import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerSwitchEvent; import net.md_5.bungee.api.plugin.Listener; @@ -74,7 +73,6 @@ public final class BungeeProxyBridge implements Listener { private List premiumListBuffer = new ArrayList<>(); // Players with a pending premium verification (ran /premium but not yet confirmed via reconnect) private volatile Set pendingPremiumUsernames = ConcurrentHashMap.newKeySet(); - private final Map uniqueIdCache = new ConcurrentHashMap<>(); private final BungeePremiumOnlineModeHandler premiumOnlineModeHandler; private final BungeePremiumVerificationManager premiumVerificationManager; private final ScheduledExecutorService retryScheduler = Executors.newSingleThreadScheduledExecutor(r -> { From 1060344ca55eb3b72c062210afbb2e12c7afed64 Mon Sep 17 00:00:00 2001 From: GoodTimes14 Date: Sun, 21 Jun 2026 10:10:47 +0200 Subject: [PATCH 3/5] fix: Corrected class name casing for `AuthMeVelocityAutoLoginEvent` --- .../fr/xephi/authme/velocity/VelocityProxyBridge.java | 8 ++++---- ...ginEvent.java => AuthMeVelocityAutoLoginEvent.java} | 4 ++-- .../xephi/authme/velocity/VelocityProxyBridgeTest.java | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) rename authme-velocity/src/main/java/fr/xephi/authme/velocity/events/{AuthmeVelocityAutoLoginEvent.java => AuthMeVelocityAutoLoginEvent.java} (82%) diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java index bf52f59da..9cc866958 100644 --- a/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java @@ -21,7 +21,7 @@ import com.velocitypowered.api.proxy.server.RegisteredServer; import fr.xephi.authme.velocity.events.AuthMeVelocityLoginEvent; import fr.xephi.authme.velocity.events.AuthMeVelocityLogoutEvent; -import fr.xephi.authme.velocity.events.AuthmeVelocityAutoLoginEvent; +import fr.xephi.authme.velocity.events.AuthMeVelocityAutoLoginEvent; import fr.xephi.authme.velocity.premium.VelocityPremiumVerificationManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -369,7 +369,7 @@ void onServerConnected(ServerConnectedEvent event) { normalizedName); } - AuthmeVelocityAutoLoginEvent autoLoginEvent = new AuthmeVelocityAutoLoginEvent(event.getPlayer()); + AuthMeVelocityAutoLoginEvent autoLoginEvent = new AuthMeVelocityAutoLoginEvent(event.getPlayer()); proxyServer.getEventManager().fire(autoLoginEvent).thenAccept((auto) -> { if (!auto.getResult().isAllowed()) { @@ -511,7 +511,7 @@ private void sendAutoLoginIfAlreadySwitched(String normalizedName, RegisteredSer String currentServerName = currentServer.getServerInfo().getName(); logger.info("Player {} already on server '{}' when login message arrived — sending auto-login immediately", normalizedName, currentServerName); - AuthmeVelocityAutoLoginEvent autoLoginEvent = new AuthmeVelocityAutoLoginEvent(playerOpt.get()); + AuthMeVelocityAutoLoginEvent autoLoginEvent = new AuthMeVelocityAutoLoginEvent(playerOpt.get()); proxyServer.getEventManager().fire(autoLoginEvent).thenAccept(auto -> { if (!auto.getResult().isAllowed()) { logger.debug("Auto-login cancelled for {} via event (already-switched path)", normalizedName); @@ -597,7 +597,7 @@ private void scheduleRetry(String normalizedName) { logger.warn("No auto-login ACK received for {} after {} retries; giving up", normalizedName, MAX_RETRIES); return; } - AuthmeVelocityAutoLoginEvent autoLoginEvent = new AuthmeVelocityAutoLoginEvent(playerOpt.get()); + AuthMeVelocityAutoLoginEvent autoLoginEvent = new AuthMeVelocityAutoLoginEvent(playerOpt.get()); proxyServer.getEventManager().fire(autoLoginEvent).thenAccept(auto -> { if (!auto.getResult().isAllowed()) { logger.debug("Auto-login cancelled for {} via event (retry {})", normalizedName, current + 1); diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthmeVelocityAutoLoginEvent.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityAutoLoginEvent.java similarity index 82% rename from authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthmeVelocityAutoLoginEvent.java rename to authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityAutoLoginEvent.java index 0ea3190d7..ab023ce59 100644 --- a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthmeVelocityAutoLoginEvent.java +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityAutoLoginEvent.java @@ -3,13 +3,13 @@ import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.proxy.Player; -public class AuthmeVelocityAutoLoginEvent implements ResultedEvent { +public class AuthMeVelocityAutoLoginEvent implements ResultedEvent { private final Player player; private GenericResult result = GenericResult.allowed(); - public AuthmeVelocityAutoLoginEvent(Player player) { + public AuthMeVelocityAutoLoginEvent(Player player) { this.player = player; } diff --git a/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java b/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java index 3c6bee2ff..5c24dca3a 100644 --- a/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java +++ b/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java @@ -21,7 +21,7 @@ import com.velocitypowered.api.proxy.server.ServerInfo; import fr.xephi.authme.velocity.events.AuthMeVelocityLoginEvent; import fr.xephi.authme.velocity.events.AuthMeVelocityLogoutEvent; -import fr.xephi.authme.velocity.events.AuthmeVelocityAutoLoginEvent; +import fr.xephi.authme.velocity.events.AuthMeVelocityAutoLoginEvent; import net.kyori.adventure.text.Component; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -602,15 +602,15 @@ private static byte[] createChunkPayload(int seq, boolean last, String csv) { private void stubAutoLoginAllowed() { given(proxyServer.getEventManager()).willReturn(eventManager); - given(eventManager.fire(any(AuthmeVelocityAutoLoginEvent.class))) + given(eventManager.fire(any(AuthMeVelocityAutoLoginEvent.class))) .willAnswer(inv -> CompletableFuture.completedFuture(inv.getArgument(0))); } private void stubAutoLoginDenied() { given(proxyServer.getEventManager()).willReturn(eventManager); - given(eventManager.fire(any(AuthmeVelocityAutoLoginEvent.class))).willAnswer(inv -> { - AuthmeVelocityAutoLoginEvent event = inv.getArgument(0); - event.setResult(AuthmeVelocityAutoLoginEvent.GenericResult.denied()); + given(eventManager.fire(any(AuthMeVelocityAutoLoginEvent.class))).willAnswer(inv -> { + AuthMeVelocityAutoLoginEvent event = inv.getArgument(0); + event.setResult(AuthMeVelocityAutoLoginEvent.GenericResult.denied()); return CompletableFuture.completedFuture(event); }); } From 64fd212c53a9aab03fe10d9c30cc5779cae77e7c Mon Sep 17 00:00:00 2001 From: GoodTimes14 Date: Sun, 21 Jun 2026 10:51:04 +0200 Subject: [PATCH 4/5] refactor: Removed actually useless auto-login event classes --- .../authme/bungee/BungeeProxyBridge.java | 23 ----- .../events/AuthMeBungeeAutoLoginEvent.java | 30 ------ .../authme/bungee/BungeeProxyBridgeTest.java | 39 -------- .../authme/velocity/VelocityProxyBridge.java | 92 +++++++------------ .../events/AuthMeVelocityAutoLoginEvent.java | 30 ------ .../velocity/VelocityProxyBridgeTest.java | 45 +-------- 6 files changed, 35 insertions(+), 224 deletions(-) delete mode 100644 authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java delete mode 100644 authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityAutoLoginEvent.java diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java index 5b46a2041..024edc204 100644 --- a/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/BungeeProxyBridge.java @@ -3,7 +3,6 @@ import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; -import fr.xephi.authme.bungee.events.AuthMeBungeeAutoLoginEvent; import fr.xephi.authme.bungee.events.AuthMeBungeeLoginEvent; import fr.xephi.authme.bungee.events.AuthMeBungeeLogoutEvent; import fr.xephi.authme.bungee.premium.BungeePremiumOnlineModeHandler; @@ -368,13 +367,6 @@ public void onServerSwitch(ServerSwitchEvent event) { logger.fine("PacketEvents-verified premium player " + normalizedName + " joining auth server — sending perform.login immediately"); } - AuthMeBungeeAutoLoginEvent autoLoginEvent = new AuthMeBungeeAutoLoginEvent(player); - proxyServer.getPluginManager().callEvent(autoLoginEvent); - if (autoLoginEvent.isCancelled()) { - logger.fine("Auto-login cancelled for player " + normalizedName + " via event"); - return; - } - String serverName = currentServer.getInfo().getName(); logger.info("Sending auto-login request to server '" + serverName + "' for player " + normalizedName); currentServer.getInfo().sendData( @@ -472,13 +464,6 @@ private void sendAutoLoginIfAlreadySwitched(String normalizedName, ServerInfo au return; } - AuthMeBungeeAutoLoginEvent autoLoginEvent = new AuthMeBungeeAutoLoginEvent(player); - proxyServer.getPluginManager().callEvent(autoLoginEvent); - if (autoLoginEvent.isCancelled()) { - logger.fine("Auto-login cancelled for player " + normalizedName + " (via event)"); - return; - } - String currentServerName = currentConn.getInfo().getName(); logger.info("Player " + normalizedName + " already on server '" + currentServerName + "' when login message arrived — sending auto-login immediately"); @@ -541,14 +526,6 @@ private void scheduleRetry(String normalizedName) { return; } - AuthMeBungeeAutoLoginEvent autoLoginEvent = new AuthMeBungeeAutoLoginEvent(player); - proxyServer.getPluginManager().callEvent(autoLoginEvent); - if (autoLoginEvent.isCancelled()) { - logger.fine("Auto-login cancelled for player " + normalizedName + " (via event)"); - cancelPendingLogin(normalizedName); - return; - } - String serverName = server.getInfo().getName(); logger.fine("Retrying auto-login for " + normalizedName + " on server '" + serverName + "' (attempt " + (current + 1) + "/" + MAX_RETRIES + ")"); diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java deleted file mode 100644 index dd5511c58..000000000 --- a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeAutoLoginEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.xephi.authme.bungee.events; - -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.plugin.Cancellable; -import net.md_5.bungee.api.plugin.Event; - -public class AuthMeBungeeAutoLoginEvent extends Event implements Cancellable { - - private final ProxiedPlayer player; - - private boolean cancel; - - public AuthMeBungeeAutoLoginEvent(ProxiedPlayer player) { - this.player = player; - } - - public ProxiedPlayer getPlayer() { - return player; - } - - @Override - public boolean isCancelled() { - return cancel; - } - - @Override - public void setCancelled(boolean cancel) { - this.cancel = cancel; - } -} diff --git a/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java b/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java index a2fe3cfcb..c01371562 100644 --- a/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java +++ b/authme-bungee/src/test/java/fr/xephi/authme/bungee/BungeeProxyBridgeTest.java @@ -2,7 +2,6 @@ import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; -import fr.xephi.authme.bungee.events.AuthMeBungeeAutoLoginEvent; import fr.xephi.authme.bungee.events.AuthMeBungeeLoginEvent; import fr.xephi.authme.bungee.events.AuthMeBungeeLogoutEvent; import net.md_5.bungee.api.ProxyServer; @@ -110,7 +109,6 @@ void shouldTrackAuthenticatedPlayerAndForwardPerformLoginOnServerSwitch() { given(currentServer.getInfo()).willReturn(authServerInfo); given(authServerInfo.getName()).willReturn("lobby"); - stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerSwitch(serverSwitchEvent); @@ -207,7 +205,6 @@ void shouldCancelPendingLoginOnExplicitAck() { given(currentServer.getInfo()).willReturn(authServerInfo); given(serverSwitchEvent.getFrom()).willReturn(null); - stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerSwitch(serverSwitchEvent); @@ -232,7 +229,6 @@ void shouldCancelPendingLoginOnImplicitAckFromNonAuthServer() { given(player.getServer()).willReturn(currentServer); given(currentServer.getInfo()).willReturn(authServerInfo); - stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); // Mark authenticated via auth server login @@ -388,7 +384,6 @@ void shouldForwardPerformLoginWhenLeavingAuthServer() { given(serverSwitchEvent.getFrom()).willReturn(authServerInfo); given(authServerInfo.getName()).willReturn("lobby"); - stubEventsAllowed(); BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerSwitch(serverSwitchEvent); @@ -535,40 +530,6 @@ void shouldFireLogoutEventWhenPlayerLogsOut() { assertSame(player, eventCaptor.getValue().getPlayer()); } - @Test - void shouldNotSendPerformLoginWhenAutoLoginEventIsCancelled() { - given(pluginMessageEvent.isCancelled()).willReturn(false); - given(pluginMessageEvent.getTag()).willReturn(BungeeProxyBridge.AUTHME_CHANNEL); - given(pluginMessageEvent.getSender()).willReturn(sourceServer); - given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("login", "Alice")); - given(sourceServer.getInfo()).willReturn(authServerInfo); - given(serverSwitchEvent.getPlayer()).willReturn(player); - given(player.getName()).willReturn("Alice"); - given(player.getServer()).willReturn(currentServer); - given(currentServer.getInfo()).willReturn(nonAuthServerInfo); - given(nonAuthServerInfo.getName()).willReturn("survival"); - given(serverSwitchEvent.getFrom()).willReturn(authServerInfo); - given(authServerInfo.getName()).willReturn("lobby"); - - given(proxyServer.getPluginManager()).willReturn(pluginManager); - given(pluginManager.callEvent(any(AuthMeBungeeAutoLoginEvent.class))) - .willAnswer(inv -> { - AuthMeBungeeAutoLoginEvent event = inv.getArgument(0); - event.setCancelled(true); - return event; - }); - - BungeeProxyBridge bridge = new BungeeProxyBridge(proxyServer, logger, createConfiguration(), new BungeeAuthenticationStore(), null); - bridge.onPluginMessage(pluginMessageEvent); - bridge.onServerSwitch(serverSwitchEvent); - - ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(AuthMeBungeeAutoLoginEvent.class); - verify(pluginManager).callEvent(eventCaptor.capture()); - assertSame(player, eventCaptor.getValue().getPlayer()); - assertTrue(eventCaptor.getValue().isCancelled()); - verify(nonAuthServerInfo, never()).sendData(any(String.class), any(byte[].class), eq(false)); - } - private static byte[] createChunkPayload(int seq, boolean last, String csv) { ByteArrayDataOutput output = ByteStreams.newDataOutput(); output.writeUTF("premium.list.chunk"); diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java index 9cc866958..2177a41dc 100644 --- a/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/VelocityProxyBridge.java @@ -21,7 +21,6 @@ import com.velocitypowered.api.proxy.server.RegisteredServer; import fr.xephi.authme.velocity.events.AuthMeVelocityLoginEvent; import fr.xephi.authme.velocity.events.AuthMeVelocityLogoutEvent; -import fr.xephi.authme.velocity.events.AuthMeVelocityAutoLoginEvent; import fr.xephi.authme.velocity.premium.VelocityPremiumVerificationManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -369,34 +368,25 @@ void onServerConnected(ServerConnectedEvent event) { normalizedName); } - AuthMeVelocityAutoLoginEvent autoLoginEvent = new AuthMeVelocityAutoLoginEvent(event.getPlayer()); - proxyServer.getEventManager().fire(autoLoginEvent).thenAccept((auto) -> { - - if (!auto.getResult().isAllowed()) { - logger.debug("Auto-login cancelled for Player {} via event result", normalizedName); - return; - } - - Optional currentServer = event.getPlayer().getCurrentServer(); - if (currentServer.isEmpty()) { - // Velocity hasn't registered the new connection yet; let the retry mechanism handle it - logger.debug("Player {} has no active server connection in ServerConnectedEvent; scheduling auto-login retry", normalizedName); - initiatePendingLogin(normalizedName); - return; - } + Optional currentServer = event.getPlayer().getCurrentServer(); + if (currentServer.isEmpty()) { + // Velocity hasn't registered the new connection yet; let the retry mechanism handle it + logger.debug("Player {} has no active server connection in ServerConnectedEvent; scheduling auto-login retry", normalizedName); + initiatePendingLogin(normalizedName); + return; + } - String serverName = currentServer.get().getServer().getServerInfo().getName(); - boolean sent = currentServer.get().sendPluginMessage( - AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); - if (sent) { - logger.info("Sending auto-login request to server '{}' for player {} (verifiedPremiumUuid={})", - serverName, normalizedName, verifiedPremiumUuid); - initiatePendingLogin(normalizedName); - } else { - logger.warn("Failed to send auto-login request to server '{}' for player {}; scheduling retry", serverName, normalizedName); - initiatePendingLogin(normalizedName); - } - }); + String serverName = currentServer.get().getServer().getServerInfo().getName(); + boolean sent = currentServer.get().sendPluginMessage( + AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); + if (sent) { + logger.info("Sending auto-login request to server '{}' for player {} (verifiedPremiumUuid={})", + serverName, normalizedName, verifiedPremiumUuid); + initiatePendingLogin(normalizedName); + } else { + logger.warn("Failed to send auto-login request to server '{}' for player {}; scheduling retry", serverName, normalizedName); + initiatePendingLogin(normalizedName); + } } void onPreLogin(PreLoginEvent event) { @@ -511,21 +501,14 @@ private void sendAutoLoginIfAlreadySwitched(String normalizedName, RegisteredSer String currentServerName = currentServer.getServerInfo().getName(); logger.info("Player {} already on server '{}' when login message arrived — sending auto-login immediately", normalizedName, currentServerName); - AuthMeVelocityAutoLoginEvent autoLoginEvent = new AuthMeVelocityAutoLoginEvent(playerOpt.get()); - proxyServer.getEventManager().fire(autoLoginEvent).thenAccept(auto -> { - if (!auto.getResult().isAllowed()) { - logger.debug("Auto-login cancelled for {} via event (already-switched path)", normalizedName); - return; - } - UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); - boolean sent = currentConn.get().sendPluginMessage( - AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); - if (sent) { - initiatePendingLogin(normalizedName); - } else { - logger.warn("Failed to send auto-login to '{}' for {} (race condition path)", currentServerName, normalizedName); - } - }); + UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); + boolean sent = currentConn.get().sendPluginMessage( + AUTHME_CHANNEL, createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); + if (sent) { + initiatePendingLogin(normalizedName); + } else { + logger.warn("Failed to send auto-login to '{}' for {} (race condition path)", currentServerName, normalizedName); + } } private void sendProxyStartedHandshakeIfPending(RegisteredServer server) { @@ -597,24 +580,15 @@ private void scheduleRetry(String normalizedName) { logger.warn("No auto-login ACK received for {} after {} retries; giving up", normalizedName, MAX_RETRIES); return; } - AuthMeVelocityAutoLoginEvent autoLoginEvent = new AuthMeVelocityAutoLoginEvent(playerOpt.get()); - proxyServer.getEventManager().fire(autoLoginEvent).thenAccept(auto -> { - if (!auto.getResult().isAllowed()) { - logger.debug("Auto-login cancelled for {} via event (retry {})", normalizedName, current + 1); - cancelPendingLogin(normalizedName); - return; - } - - String serverName = serverOpt.get().getServer().getServerInfo().getName(); - logger.debug("Retrying auto-login for {} on server '{}' (attempt {}/{})", - normalizedName, serverName, current + 1, MAX_RETRIES); + String serverName = serverOpt.get().getServer().getServerInfo().getName(); + logger.debug("Retrying auto-login for {} on server '{}' (attempt {}/{})", + normalizedName, serverName, current + 1, MAX_RETRIES); - UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); - serverOpt.get().sendPluginMessage(AUTHME_CHANNEL, - createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); + UUID verifiedPremiumUuid = premiumVerificationManager.getVerifiedPremiumUuid(normalizedName); + serverOpt.get().sendPluginMessage(AUTHME_CHANNEL, + createPerformLoginMessage(normalizedName, verifiedPremiumUuid)); - scheduleRetry(normalizedName); - }); + scheduleRetry(normalizedName); }, 1, TimeUnit.SECONDS); } diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityAutoLoginEvent.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityAutoLoginEvent.java deleted file mode 100644 index ab023ce59..000000000 --- a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityAutoLoginEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.xephi.authme.velocity.events; - -import com.velocitypowered.api.event.ResultedEvent; -import com.velocitypowered.api.proxy.Player; - -public class AuthMeVelocityAutoLoginEvent implements ResultedEvent { - - private final Player player; - - private GenericResult result = GenericResult.allowed(); - - public AuthMeVelocityAutoLoginEvent(Player player) { - this.player = player; - } - - - public Player getPlayer() { - return player; - } - - @Override - public GenericResult getResult() { - return result; - } - - @Override - public void setResult(GenericResult result) { - this.result = result; - } -} diff --git a/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java b/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java index 5c24dca3a..9be849168 100644 --- a/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java +++ b/authme-velocity/src/test/java/fr/xephi/authme/velocity/VelocityProxyBridgeTest.java @@ -21,7 +21,6 @@ import com.velocitypowered.api.proxy.server.ServerInfo; import fr.xephi.authme.velocity.events.AuthMeVelocityLoginEvent; import fr.xephi.authme.velocity.events.AuthMeVelocityLogoutEvent; -import fr.xephi.authme.velocity.events.AuthMeVelocityAutoLoginEvent; import net.kyori.adventure.text.Component; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -35,7 +34,6 @@ import java.util.Optional; import java.util.Set; -import java.util.concurrent.CompletableFuture; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -129,7 +127,6 @@ void shouldTrackAuthenticatedPlayerAndForwardPerformLoginOnServerConnect() { .willReturn(true); VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); - stubAutoLoginAllowed(); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, authServer, null)); @@ -240,7 +237,7 @@ void shouldCancelPendingLoginOnExplicitAck() { given(proxyServer.getPlayer("alice")).willReturn(Optional.of(player)); VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); - stubAutoLoginAllowed(); + given(proxyServer.getEventManager()).willReturn(eventManager); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, authServer, null)); @@ -276,7 +273,7 @@ void shouldCancelPendingLoginOnImplicitAckFromNonAuthServer() { // Mark authenticated via auth server login given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("login", "Alice")); given(sourceConnection.getServer()).willReturn(authServer); - stubAutoLoginAllowed(); + given(proxyServer.getEventManager()).willReturn(eventManager); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, authServer, null)); @@ -373,7 +370,6 @@ void shouldForwardPerformLoginWhenSwitchingFromAuthServerToNonAuthServer() { .willReturn(true); VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); - stubAutoLoginAllowed(); bridge.onPluginMessage(pluginMessageEvent); bridge.onServerConnected(new ServerConnectedEvent(player, nonAuthServer, authServer)); @@ -381,28 +377,6 @@ void shouldForwardPerformLoginWhenSwitchingFromAuthServerToNonAuthServer() { assertPerformLoginPayload(payloadCaptor.getValue(), "alice", "test-secret"); } - @Test - void shouldNotForwardPerformLoginWhenAutoLoginEventIsDenied() { - given(pluginMessageEvent.getResult()).willReturn(PluginMessageEvent.ForwardResult.forward()); - given(pluginMessageEvent.getIdentifier()).willReturn(VelocityProxyBridge.AUTHME_CHANNEL); - given(pluginMessageEvent.getSource()).willReturn(sourceConnection); - given(pluginMessageEvent.getData()).willReturn(createAuthMePayload("login", "Alice")); - given(sourceConnection.getServer()).willReturn(authServer); - given(authServer.getServerInfo()).willReturn(authServerInfo); - given(authServerInfo.getName()).willReturn("lobby"); - given(nonAuthServer.getServerInfo()).willReturn(nonAuthServerInfo); - given(nonAuthServerInfo.getName()).willReturn("survival"); - given(proxyServer.getPlayer("alice")).willReturn(Optional.of(player)); - given(player.getCurrentServer()).willReturn(Optional.of(currentServer)); - given(currentServer.getServer()).willReturn(nonAuthServer); - stubAutoLoginDenied(); - - VelocityProxyBridge bridge = new VelocityProxyBridge(proxyServer, logger, createConfiguration(), new VelocityAuthenticationStore(), null); - bridge.onPluginMessage(pluginMessageEvent); - - verify(currentServer, never()).sendPluginMessage(any(), any(byte[].class)); - } - // --- Command blocking tests --- @Test @@ -600,21 +574,6 @@ private static byte[] createChunkPayload(int seq, boolean last, String csv) { return output.toByteArray(); } - private void stubAutoLoginAllowed() { - given(proxyServer.getEventManager()).willReturn(eventManager); - given(eventManager.fire(any(AuthMeVelocityAutoLoginEvent.class))) - .willAnswer(inv -> CompletableFuture.completedFuture(inv.getArgument(0))); - } - - private void stubAutoLoginDenied() { - given(proxyServer.getEventManager()).willReturn(eventManager); - given(eventManager.fire(any(AuthMeVelocityAutoLoginEvent.class))).willAnswer(inv -> { - AuthMeVelocityAutoLoginEvent event = inv.getArgument(0); - event.setResult(AuthMeVelocityAutoLoginEvent.GenericResult.denied()); - return CompletableFuture.completedFuture(event); - }); - } - private static VelocityProxyConfiguration createConfiguration() { return new VelocityProxyConfiguration(Set.of("lobby"), false, true, "Authentication required.", true, false, "", true, From 5c24c0628eace8c836cad2ba73ed0dfecb61f1e8 Mon Sep 17 00:00:00 2001 From: GoodTimes14 Date: Sun, 21 Jun 2026 11:29:40 +0200 Subject: [PATCH 5/5] docs: Added Javadoc comments to login/logout events --- .../authme/bungee/events/AuthMeBungeeLoginEvent.java | 10 ++++++++++ .../authme/bungee/events/AuthMeBungeeLogoutEvent.java | 5 +++++ .../velocity/events/AuthMeVelocityLoginEvent.java | 11 +++++++++++ .../velocity/events/AuthMeVelocityLogoutEvent.java | 5 +++++ 4 files changed, 31 insertions(+) diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java index 653bef52f..8795554e4 100644 --- a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLoginEvent.java @@ -14,10 +14,20 @@ public AuthMeBungeeLoginEvent(ProxiedPlayer player, boolean premium) { this.premium = premium; } + /** + * Return whether this player required Premium verification for login + * + * @return if the player required premium verification + */ public boolean isPremium() { return premium; } + /** + * Return the player concerned by this event. + * + * @return The player who logged in correctly in the backend + */ public ProxiedPlayer getPlayer() { return player; } diff --git a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java index 14e85a75c..f1687f5b8 100644 --- a/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java +++ b/authme-bungee/src/main/java/fr/xephi/authme/bungee/events/AuthMeBungeeLogoutEvent.java @@ -11,6 +11,11 @@ public AuthMeBungeeLogoutEvent(ProxiedPlayer player) { this.player = player; } + /** + * Return the player concerned by this event. + * + * @return The player who logged out correctly in the backend + */ public ProxiedPlayer getPlayer() { return player; } diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java index 0f7d78ea7..c41141295 100644 --- a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLoginEvent.java @@ -13,10 +13,21 @@ public AuthMeVelocityLoginEvent(Player player, boolean premium) { this.premium = premium; } + /** + * Return the player concerned by this event. + * + * @return The player who logged in correctly in the backend + */ public Player getPlayer() { return player; } + + /** + * Return whether this player required Premium verification for login + * + * @return if the player required premium verification + */ public boolean isPremium() { return premium; } diff --git a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java index 0970287d2..d6e157900 100644 --- a/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java +++ b/authme-velocity/src/main/java/fr/xephi/authme/velocity/events/AuthMeVelocityLogoutEvent.java @@ -10,6 +10,11 @@ public AuthMeVelocityLogoutEvent(Player player) { this.player = player; } + /** + * Return the player concerned by this event. + * + * @return The player who logged out correctly in the backend + */ public Player getPlayer() { return player; }