From 0ee269785a0215d659fe6ef9002b9757c4ed5078 Mon Sep 17 00:00:00 2001 From: games647 Date: Mon, 18 May 2020 12:12:51 +0200 Subject: [PATCH] Set UUIDs using MethodHandles --- .../bungee/listener/ConnectListener.java | 80 +++++++++++++------ 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java index 0746ea8d..1215484f 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java @@ -8,8 +8,11 @@ import com.github.games647.fastlogin.bungee.task.ForceLoginTask; import com.github.games647.fastlogin.core.RateLimiter; import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.shared.LoginSession; +import com.google.common.base.Throwables; -import java.lang.reflect.Field; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; import java.util.UUID; import net.md_5.bungee.api.connection.PendingConnection; @@ -37,6 +40,26 @@ public class ConnectListener implements Listener { private final RateLimiter rateLimiter; + private static final MethodHandle uniqueIdSetter; + private static final MethodHandle uniqueIdGetter; + + private static final String UUID_FIELD_NAME = "uniqueId"; + + static { + MethodHandle setHandle = null; + MethodHandle getHandle = null; + try { + final Lookup lookup = MethodHandles.lookup(); + setHandle = lookup.findSetter(InitialHandler.class, UUID_FIELD_NAME, UUID.class); + getHandle = lookup.findGetter(InitialHandler.class, UUID_FIELD_NAME, UUID.class); + } catch (ReflectiveOperationException reflectiveOperationException) { + reflectiveOperationException.printStackTrace(); + } + + uniqueIdSetter = setHandle; + uniqueIdGetter = getHandle; + } + public ConnectListener(FastLoginBungee plugin, RateLimiter rateLimiter) { this.plugin = plugin; this.rateLimiter = rateLimiter; @@ -81,31 +104,7 @@ public class ConnectListener implements Listener { //bungeecord will do this automatically so override it on disabled option if (!plugin.getCore().getConfig().get("premiumUuid", true)) { - try { - final UUID oldPremiumId = connection.getUniqueId(); - final UUID offlineUUID = UUIDAdapter.generateOfflineId(username); - - // BungeeCord only allows setting the UUID in PreLogin events and before requesting online mode - // However if online mode is requested, it will override previous values - // So we have to do it with reflection - Field idField = InitialHandler.class.getDeclaredField("uniqueId"); - idField.setAccessible(true); - idField.set(connection, offlineUUID); - - String format = "Overridden UUID from {} to {} (based of {}) on {}"; - plugin.getLog().info(format, oldPremiumId, offlineUUID, username, connection); - - // check if the field was actually set correctly - UUID offlineResult = (UUID) idField.get(connection); - UUID connectionResult = connection.getUniqueId(); - if (!offlineUUID.equals(offlineResult) - || !offlineUUID.equals(connectionResult)) { - throw new RuntimeException("Inconsistent UUIDs: expected " + offlineUUID - + " got (Reflection, Connection)" + offlineResult + " and " + connection); - } - } catch (NoSuchFieldException | IllegalAccessException ex) { - plugin.getLog().error("Failed to set offline uuid of {}", username, ex); - } + setOfflineId(connection, username); } if (!plugin.getCore().getConfig().get("forwardSkin", true)) { @@ -118,6 +117,35 @@ public class ConnectListener implements Listener { } } + private void setOfflineId(PendingConnection connection, String username) { + try { + final UUID oldPremiumId = connection.getUniqueId(); + final UUID offlineUUID = UUIDAdapter.generateOfflineId(username); + + // BungeeCord only allows setting the UUID in PreLogin events and before requesting online mode + // However if online mode is requested, it will override previous values + // So we have to do it with reflection + uniqueIdSetter.invoke(connection, offlineUUID); + + String format = "Overridden UUID from {} to {} (based of {}) on {}"; + plugin.getLog().info(format, oldPremiumId, offlineUUID, username, connection); + + // check if the field was actually set correctly + UUID offlineResult = (UUID) uniqueIdGetter.invoke(connection); + UUID connectionResult = connection.getUniqueId(); + if (!offlineUUID.equals(offlineResult) + || !offlineUUID.equals(connectionResult)) { + throw new RuntimeException("Inconsistent UUIDs: expected " + offlineUUID + + " got (Reflection, Connection)" + offlineResult + " and " + connection); + } + } catch (Exception ex) { + plugin.getLog().error("Failed to set offline uuid of {}", username, ex); + } catch (Throwable throwable) { + // throw remaining exceptions like outofmemory that we shouldn't handle ourself + Throwables.throwIfUnchecked(throwable); + } + } + @EventHandler public void onServerConnected(ServerConnectedEvent serverConnectedEvent) { ProxiedPlayer player = serverConnectedEvent.getPlayer();