From 01df0283e98232027d8100f5d98cbbf5bcccc3d4 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 1 Dec 2020 23:18:22 +0100 Subject: [PATCH] GeyserDump and legacy Spigot versions support. Made proxy data flexible --- .../geysermc/floodgate/HandshakeHandler.java | 26 +++---- .../config/FloodgateConfigHolder.java | 2 + .../addon/data/SpigotDataHandler.java | 23 ++++-- .../command/SpigotCommandRegistration.java | 23 +++--- .../module/SpigotPlatformModule.java | 12 +++- .../pluginmessage/SpigotSkinHandler.java | 8 ++- .../util/SpigotVersionSpecificMethods.java | 72 +++++++++++++++++++ 7 files changed, 131 insertions(+), 35 deletions(-) create mode 100644 spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java diff --git a/common/src/main/java/org/geysermc/floodgate/HandshakeHandler.java b/common/src/main/java/org/geysermc/floodgate/HandshakeHandler.java index c2aa84e5..eaac44cc 100644 --- a/common/src/main/java/org/geysermc/floodgate/HandshakeHandler.java +++ b/common/src/main/java/org/geysermc/floodgate/HandshakeHandler.java @@ -52,31 +52,31 @@ public final class HandshakeHandler { try { String[] dataArray = handshakeData.split("\0"); - boolean isBungeeData = dataArray.length == 5; - // this can be Bungee data (without skin) or Floodgate data - if (dataArray.length == 4) { - isBungeeData = FloodgateCipher.hasHeader(dataArray[3]); + String data = null; + for (String value : dataArray) { + if (FloodgateCipher.hasHeader(value)) { + data = value; + break; + } } - boolean proxy = configHolder.get().isProxy(); - //todo remove this check - if (proxy && isBungeeData || !isBungeeData && dataArray.length != 2) { + if (data == null) { return ResultType.NOT_FLOODGATE_DATA.getCachedResult(); } // calculate the expected Base64 encoded IV length. int expectedIvLength = 4 * ((AesCipher.IV_LENGTH + 2) / 3); - int lastSplitIndex = dataArray[1].lastIndexOf(0x21); + int lastSplitIndex = data.lastIndexOf(0x21); byte[] floodgateData; byte[] rawSkinData = null; // if it has a RawSkin if (lastSplitIndex - expectedIvLength != 0) { - floodgateData = dataArray[1].substring(0, lastSplitIndex).getBytes(Charsets.UTF_8); - rawSkinData = dataArray[1].substring(lastSplitIndex + 1).getBytes(Charsets.UTF_8); + floodgateData = data.substring(0, lastSplitIndex).getBytes(Charsets.UTF_8); + rawSkinData = data.substring(lastSplitIndex + 1).getBytes(Charsets.UTF_8); } else { - floodgateData = dataArray[1].getBytes(Charsets.UTF_8); + floodgateData = data.getBytes(Charsets.UTF_8); } // actual decryption @@ -137,9 +137,5 @@ public final class HandshakeHandler { private final String[] handshakeData; private final BedrockData bedrockData; private final FloodgatePlayer floodgatePlayer; - - public boolean isBungeeData() { - return handshakeData.length == 4 || handshakeData.length == 5; - } } } diff --git a/common/src/main/java/org/geysermc/floodgate/config/FloodgateConfigHolder.java b/common/src/main/java/org/geysermc/floodgate/config/FloodgateConfigHolder.java index 447b68d7..3fa8c67c 100644 --- a/common/src/main/java/org/geysermc/floodgate/config/FloodgateConfigHolder.java +++ b/common/src/main/java/org/geysermc/floodgate/config/FloodgateConfigHolder.java @@ -51,5 +51,7 @@ public class FloodgateConfigHolder { public void set(FloodgateConfig config) { this.config = config; + // for Geyser dump + org.geysermc.floodgate.util.FloodgateConfigHolder.setConfig(config); } } diff --git a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java index 07933da3..e1c71aa9 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java +++ b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java @@ -27,6 +27,7 @@ package org.geysermc.floodgate.addon.data; import static com.google.common.base.Preconditions.checkNotNull; import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue; +import static org.geysermc.floodgate.util.ReflectionUtils.getField; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; import static org.geysermc.floodgate.util.ReflectionUtils.getMethod; import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass; @@ -53,6 +54,7 @@ import org.geysermc.floodgate.util.ReflectionUtils; @RequiredArgsConstructor public final class SpigotDataHandler extends SimpleChannelInboundHandler { + private static final Field IS_BUNGEE_DATA; private static final Field SOCKET_ADDRESS; private static final Class HANDSHAKE_PACKET; private static final Field HANDSHAKE_HOST; @@ -74,6 +76,10 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler private static final Object READY_TO_ACCEPT_PROTOCOL_STATE; static { + Class spigotConfig = ReflectionUtils.getClass("org.spigotmc.SpigotConfig"); + IS_BUNGEE_DATA = getField(spigotConfig, "bungee"); + checkNotNull(IS_BUNGEE_DATA, "bungee field cannot be null. Are you using CraftBukkit?"); + Class networkManager = getPrefixedClass("NetworkManager"); checkNotNull(networkManager, "NetworkManager class cannot be null"); @@ -155,7 +161,7 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler private final FloodgateLogger logger; private Object networkManager; private FloodgatePlayer fPlayer; - private boolean bungee; + private boolean bungeeData; private boolean done; @Override @@ -194,9 +200,11 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler fPlayer = result.getFloodgatePlayer(); BedrockData bedrockData = result.getBedrockData(); - String[] data = result.getHandshakeData(); - if (bungee = result.isBungeeData()) { + String[] data = result.getHandshakeData(); + bungeeData = isBungeeData(); + + if (bungeeData) { setValue(packet, HANDSHAKE_HOST, data[0] + '\0' + bedrockData.getIp() + '\0' + fPlayer.getCorrectUniqueId() + @@ -213,7 +221,7 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler setValue(networkManager, SOCKET_ADDRESS, newAddress); } } else if (isLogin) { - if (!bungee) { + if (!bungeeData) { // we have to fake the offline player (login) cycle Object loginListener = PACKET_LISTENER.get(networkManager); @@ -249,7 +257,7 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler ctx.fireChannelRead(packet); } - if (isHandshake && bungee || isLogin && !bungee || fPlayer == null) { + if (isHandshake && bungeeData || isLogin && !bungeeData || fPlayer == null) { // we're done, we'll just wait for the loginSuccessCall done = true; } @@ -261,4 +269,9 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler super.exceptionCaught(ctx, cause); cause.printStackTrace(); } + + @SuppressWarnings("ConstantConditions") + private boolean isBungeeData() { + return ReflectionUtils.getCastedValue(null, IS_BUNGEE_DATA); + } } diff --git a/spigot/src/main/java/org/geysermc/floodgate/command/SpigotCommandRegistration.java b/spigot/src/main/java/org/geysermc/floodgate/command/SpigotCommandRegistration.java index 7b658dab..e2f67817 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/command/SpigotCommandRegistration.java +++ b/spigot/src/main/java/org/geysermc/floodgate/command/SpigotCommandRegistration.java @@ -36,13 +36,17 @@ import org.geysermc.floodgate.platform.command.Command; import org.geysermc.floodgate.platform.command.CommandRegistration; import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.util.ReflectionUtils; +import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; public final class SpigotCommandRegistration implements CommandRegistration { + private final SpigotVersionSpecificMethods versionSpecificMethods; private final JavaPlugin plugin; private final CommandUtil commandUtil; private final CommandMap commandMap; - public SpigotCommandRegistration(JavaPlugin plugin, CommandUtil commandUtil) { + public SpigotCommandRegistration(SpigotVersionSpecificMethods versionSpecificMethods, + JavaPlugin plugin, CommandUtil commandUtil) { + this.versionSpecificMethods = versionSpecificMethods; this.plugin = plugin; this.commandUtil = commandUtil; this.commandMap = ReflectionUtils.getCastedValue(Bukkit.getPluginManager(), "commandMap"); @@ -50,16 +54,21 @@ public final class SpigotCommandRegistration implements CommandRegistration { @Override public void register(Command command) { - commandMap.register("floodgate", new SpigotCommand(plugin, commandUtil, command)); + SpigotCommand spigotCommand = + new SpigotCommand(versionSpecificMethods, plugin, commandUtil, command); + commandMap.register("floodgate", spigotCommand); } protected static class SpigotCommand extends org.bukkit.command.Command { + private final SpigotVersionSpecificMethods versionSpecificMethods; private final JavaPlugin plugin; private final CommandUtil commandUtil; private final Command command; - protected SpigotCommand(JavaPlugin plugin, CommandUtil commandUtil, Command command) { + protected SpigotCommand(SpigotVersionSpecificMethods versionSpecificMethods, + JavaPlugin plugin, CommandUtil commandUtil, Command command) { super(command.getName(), command.getDescription(), "", Collections.emptyList()); + this.versionSpecificMethods = versionSpecificMethods; this.plugin = plugin; this.commandUtil = commandUtil; this.command = command; @@ -90,13 +99,7 @@ public final class SpigotCommandRegistration implements CommandRegistration { } Player player = (Player) sender; - String locale; - try { - locale = player.getLocale(); - } catch (Exception exception) { - // server is older then 1.12.0 - locale = player.spigot().getLocale(); - } + String locale = versionSpecificMethods.getLocale(player); command.execute(sender, player.getUniqueId(), sender.getName(), locale, args); } diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java index b2cc50e9..200a07b4 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java @@ -51,6 +51,7 @@ import org.geysermc.floodgate.pluginmessage.SpigotSkinHandler; import org.geysermc.floodgate.skin.SkinHandler; import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.SpigotCommandUtil; +import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; @RequiredArgsConstructor public final class SpigotPlatformModule extends AbstractModule { @@ -87,8 +88,10 @@ public final class SpigotPlatformModule extends AbstractModule { @Provides @Singleton - public CommandRegistration commandRegistration(CommandUtil commandUtil) { - return new SpigotCommandRegistration(plugin, commandUtil); + public CommandRegistration commandRegistration( + SpigotVersionSpecificMethods versionSpecificMethods, + CommandUtil commandUtil) { + return new SpigotCommandRegistration(versionSpecificMethods, plugin, commandUtil); } @Provides @@ -114,8 +117,11 @@ public final class SpigotPlatformModule extends AbstractModule { @Provides @Singleton public SkinHandler skinHandler(PluginMessageHandler messageHandler, FloodgateLogger logger, + SpigotVersionSpecificMethods versionSpecificMethods, FloodgateConfigHolder configHolder) { - return new SpigotSkinHandler(messageHandler, logger, plugin, configHolder); + return new SpigotSkinHandler( + messageHandler, logger, versionSpecificMethods, plugin, configHolder + ); } /* diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinHandler.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinHandler.java index d08dd42f..760b695b 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinHandler.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinHandler.java @@ -40,6 +40,7 @@ import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler; import org.geysermc.floodgate.skin.SkinHandler; import org.geysermc.floodgate.skin.SkinUploader.UploadResult; import org.geysermc.floodgate.util.ReflectionUtils; +import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; public class SpigotSkinHandler extends SkinHandler { private static final Method GET_PROFILE_METHOD; @@ -51,12 +52,15 @@ public class SpigotSkinHandler extends SkinHandler { GET_PROFILE_METHOD = ReflectionUtils.getMethod(craftPlayerClass, "getProfile"); } + private final SpigotVersionSpecificMethods versionSpecificMethods; private final SpigotPlugin plugin; private final FloodgateConfigHolder configHolder; public SpigotSkinHandler(PluginMessageHandler messageHandler, FloodgateLogger logger, + SpigotVersionSpecificMethods versionSpecificMethods, SpigotPlugin plugin, FloodgateConfigHolder configHolder) { super(messageHandler, logger); + this.versionSpecificMethods = versionSpecificMethods; this.plugin = plugin; this.configHolder = configHolder; } @@ -86,8 +90,8 @@ public class SpigotSkinHandler extends SkinHandler { plugin.getServer().getScheduler().runTask(plugin, () -> { for (Player p : Bukkit.getOnlinePlayers()) { if (p != player) { - p.hidePlayer(plugin, player); - p.showPlayer(plugin, player); + versionSpecificMethods.hidePlayer(p, player); + versionSpecificMethods.showPlayer(p, player); } } }); diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java new file mode 100644 index 00000000..389e1086 --- /dev/null +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Floodgate + */ + +package org.geysermc.floodgate.util; + +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.geysermc.floodgate.SpigotPlugin; + +public final class SpigotVersionSpecificMethods { + private static final boolean NEW_GET_LOCALE; + private static final boolean NEW_VISIBILITY; + + static { + NEW_GET_LOCALE = ReflectionUtils.getMethod(Player.class, "getLocale") != null; + NEW_VISIBILITY = null != ReflectionUtils.getMethod( + Player.class, "hidePlayer", + Plugin.class, Player.class + ); + } + + private final SpigotPlugin plugin; + + public SpigotVersionSpecificMethods(SpigotPlugin plugin) { + this.plugin = plugin; + } + + public String getLocale(Player player) { + if (NEW_GET_LOCALE) { + return player.getLocale(); + } + return player.spigot().getLocale(); + } + + public void hidePlayer(Player hideFor, Player playerToHide) { + if (NEW_VISIBILITY) { + hideFor.hidePlayer(plugin, playerToHide); + return; + } + hideFor.hidePlayer(playerToHide); + } + + public void showPlayer(Player showFor, Player playerToShow) { + if (NEW_VISIBILITY) { + showFor.hidePlayer(plugin, playerToShow); + return; + } + showFor.hidePlayer(playerToShow); + } +}