Retrieve and use Floodgate username in Velocity PreLoginEvent

This commit is contained in:
Smart123s
2024-07-06 18:10:26 +02:00
parent bdd7af8290
commit 2d177e3df5
2 changed files with 85 additions and 0 deletions

View File

@ -230,4 +230,8 @@ public class FastLoginVelocity implements PlatformPlugin<CommandSource> {
public UUID getProxyId() {
return proxyId;
}
public ProxyServer getServer() {
return server;
}
}

View File

@ -36,6 +36,8 @@ import com.github.games647.fastlogin.velocity.VelocityLoginSession;
import com.github.games647.fastlogin.velocity.task.AsyncPremiumCheck;
import com.github.games647.fastlogin.velocity.task.FloodgateAuthTask;
import com.github.games647.fastlogin.velocity.task.ForceLoginTask;
import com.google.common.cache.Cache;
import com.google.common.collect.ListMultimap;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
@ -43,15 +45,18 @@ import com.velocitypowered.api.event.connection.PreLoginEvent;
import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult;
import com.velocitypowered.api.event.player.GameProfileRequestEvent;
import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.api.util.GameProfile.Property;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.ArrayList;
@ -61,6 +66,8 @@ import java.util.UUID;
public class ConnectListener {
private static final String FLOODGATE_PLUGIN_NAME = "org.geysermc.floodgate.VelocityPlugin";
private final FastLoginVelocity plugin;
private final AntiBotService antiBotService;
@ -80,6 +87,16 @@ public class ConnectListener {
InetSocketAddress address = connection.getRemoteAddress();
plugin.getLog().info("Incoming login request for {} from {}", username, address);
// FloodgateVelocity only sets the correct username in GetProfileRequestEvent, but we need it here too.
if (plugin.getFloodgateService() != null) {
String floodgateUsername = getFloodgateUsername(preLoginEvent, connection);
if (floodgateUsername != null) {
plugin.getLog().info("Found player's Floodgate: {}", floodgateUsername);
username = floodgateUsername;
}
}
Action action = antiBotService.onIncomingConnection(address, username);
switch (action) {
case Ignore:
@ -177,4 +194,68 @@ public class ConnectListener {
Player player = disconnectEvent.getPlayer();
plugin.getCore().getPendingConfirms().remove(player.getUniqueId());
}
/**
* Get the Floodgate username from the Floodgate plugin's playerCache using lots of reflections
* @param preLoginEvent
* @param connection
* @return the Floodgate username or null if not found
*/
private String getFloodgateUsername(PreLoginEvent preLoginEvent, InboundConnection connection) {
try {
// Get Velocity's event manager
Object eventManager = plugin.getServer().getEventManager();
Field handlerField = eventManager.getClass().getDeclaredField("handlersByType");
handlerField.setAccessible(true);
@SuppressWarnings("rawtypes")
ListMultimap handlersByType = (ListMultimap) handlerField.get(eventManager);
handlerField.setAccessible(false);
// Get all registered PreLoginEvent handlers
@SuppressWarnings({ "rawtypes", "unchecked" })
List preLoginEventHandlres = handlersByType.get(preLoginEvent.getClass());
Field pluginField = preLoginEventHandlres.get(0).getClass().getDeclaredField("plugin");
pluginField.setAccessible(true);
Object floodgateEventHandlerRegistration = null;
// Find the Floodgate plugin's PreLoginEvent handler
for (Object handler : preLoginEventHandlres) {
PluginContainer eventHandlerPlugin = (PluginContainer) pluginField.get(handler);
String eventHandlerPluginName = eventHandlerPlugin.getInstance().get().getClass().getName();
if (eventHandlerPluginName.equals(FLOODGATE_PLUGIN_NAME)) {
floodgateEventHandlerRegistration = handler;
break;
}
}
pluginField.setAccessible(false);
if (floodgateEventHandlerRegistration == null) {
return null;
}
// Extract the EventHandler instance from Velocity's internal registration handler storage
Field eventHandlerField = floodgateEventHandlerRegistration.getClass().getDeclaredField("instance");
eventHandlerField.setAccessible(true);
Object floodgateEventHandler = eventHandlerField.get(floodgateEventHandlerRegistration);
eventHandlerField.setAccessible(false);
// Get the Floodgate playerCache field
Field playerCacheField = floodgateEventHandler.getClass().getDeclaredField("playerCache");
playerCacheField.setAccessible(true);
@SuppressWarnings("unchecked")
Cache<InboundConnection, FloodgatePlayer> playerCache =
(Cache<InboundConnection, FloodgatePlayer>) playerCacheField.get(floodgateEventHandler);
playerCacheField.setAccessible(false);
// Find the FloodgatePlayer instance in playerCache
FloodgatePlayer floodgatePlayer = playerCache.getIfPresent(connection);
if (floodgatePlayer == null) {
return null;
}
return floodgatePlayer.getCorrectUsername();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}