diff --git a/bukkit/pom.xml b/bukkit/pom.xml index 39ca1f921..0151a804a 100644 --- a/bukkit/pom.xml +++ b/bukkit/pom.xml @@ -376,8 +376,8 @@ io.netty netty-transport ${nettyVersion} - test - + provided + io.netty diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java index b2bc397c9..63de673b0 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java @@ -30,7 +30,6 @@ import com.github.games647.fastlogin.bukkit.command.PremiumCommand; import com.github.games647.fastlogin.bukkit.listener.ConnectionListener; import com.github.games647.fastlogin.bukkit.listener.PaperCacheListener; -import com.github.games647.fastlogin.bukkit.listener.protocollib.ManualNameChange; import com.github.games647.fastlogin.bukkit.listener.protocollib.ProtocolLibListener; import com.github.games647.fastlogin.bukkit.listener.protocollib.SkinApplyListener; import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSupportListener; @@ -119,10 +118,6 @@ public void onEnable() { } else if (pluginManager.isPluginEnabled("ProtocolLib")) { ProtocolLibListener.register(this, core.getAntiBot(), core.getConfig().getBoolean("verifyClientKeys")); - if (isPluginInstalled("floodgate")) { - printFloodgateWarning(); - } - //if server is using paper - we need to set the skin at pre login anyway, so no need for this listener if (!PaperLib.isPaper() && getConfig().getBoolean("forwardSkin")) { pluginManager.registerEvents(new SkinApplyListener(this), this); @@ -152,23 +147,6 @@ public void onEnable() { premiumPlaceholder = new PremiumPlaceholder(this); premiumPlaceholder.register(); } - - dependencyWarnings(); - } - - private void printFloodgateWarning() { - if (getConfig().getBoolean("floodgatePrefixWorkaround")) { - ManualNameChange.register(this, floodgateService); - logger.info("Floodgate prefix injection workaround has been enabled."); - logger.info("If you have problems joining the server, try disabling it in the configuration."); - } else { - logger.warn("We have detected that you are running FastLogin alongside Floodgate and ProtocolLib."); - logger.warn("Currently there is an issue with FastLogin that prevents Floodgate name prefixes from " - + "showing up when it is together used with ProtocolLib."); - logger.warn("If you would like to use Floodgate name prefixes, you can enable an experimental " - + "workaround by changing the value 'floodgatePrefixWorkaround' to true in config.yml."); - logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493"); - } } private boolean initializeFloodgate() { @@ -326,18 +304,4 @@ public BedrockService getBedrockService() { } return geyserService; } - - /** - * Send warning messages to log if incompatible plugins are used - */ - private void dependencyWarnings() { - if (isPluginInstalled("floodgate-bukkit")) { - logger.warn("We have detected that you are running Floodgate 1.0 which is not supported by the Bukkit " - + "version of FastLogin."); - logger.warn("If you would like to use FastLogin with Floodgate, you can download development builds of " - + "Floodgate 2.0 from https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/dev%252F2.0/"); - logger.warn("Don't forget to update Geyser to a supported version as well from " - + "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/floodgate-2.0/"); - } - } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ManualNameChange.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ManualNameChange.java deleted file mode 100644 index d62dbf035..000000000 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ManualNameChange.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * The MIT License (MIT) - * - * Copyright (c) 2015-2022 games647 and contributors - * - * 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. - */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; - -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.wrappers.WrappedGameProfile; -import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService; - -import java.util.UUID; - -import org.geysermc.floodgate.api.FloodgateApi; - -import static com.comphenix.protocol.PacketType.Login.Client.START; - -/** - * Manually inject Floodgate player name prefixes. - *
- * This is used as a workaround, because Floodgate fails to inject - * the prefixes when it's used together with ProtocolLib and FastLogin. - *
- * For more information visit: ... - */ -public class ManualNameChange extends PacketAdapter { - - private final FloodgateService floodgate; - - public ManualNameChange(FastLoginBukkit plugin, FloodgateService floodgate) { - super(params() - .plugin(plugin) - .types(START)); - - this.plugin = plugin; - this.floodgate = floodgate; - } - - public static void register(FastLoginBukkit plugin, FloodgateService floodgate) { - // they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError - ProtocolLibrary.getProtocolManager() - .getAsynchronousManager() - .registerAsyncHandler(new ManualNameChange(plugin, floodgate)) - .start(); - } - - @Override - public void onPacketReceiving(PacketEvent packetEvent) { - PacketContainer packet = packetEvent.getPacket(); - String username = readUsername(packet); - - if (floodgate.getBedrockPlayer(username) == null) { - //not a Floodgate player, no need to add a prefix - return; - } - - packet.setMeta("original_name", username); - String prefixedName = FloodgateApi.getInstance().getPlayerPrefix() + username; - setUsername(packet, prefixedName); - } - - private void setUsername(PacketContainer packet, String name) { - if (packet.getGameProfiles().size() > 0) { - WrappedGameProfile updatedProfile = new WrappedGameProfile(UUID.randomUUID(), name); - packet.getGameProfiles().write(0, updatedProfile); - } else { - packet.getStrings().write(0, name); - } - } - - private String readUsername(PacketContainer packet) { - if (packet.getGameProfiles().size() > 0) { - return packet.getGameProfiles().read(0).getName(); - } else { - return packet.getStrings().read(0); - } - } -} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java index 18322389d..bdc640217 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java @@ -30,6 +30,8 @@ import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.injector.PacketFilterManager; +import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.wrappers.BukkitConverters; @@ -42,6 +44,7 @@ import com.github.games647.fastlogin.core.antibot.AntiBotService.Action; import com.mojang.datafixers.util.Either; +import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.security.InvalidKeyException; import java.security.KeyPair; @@ -58,8 +61,12 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.util.AttributeKey; import lombok.val; import org.bukkit.entity.Player; +import org.geysermc.floodgate.api.player.FloodgatePlayer; import static com.comphenix.protocol.PacketType.Login.Client.ENCRYPTION_BEGIN; import static com.comphenix.protocol.PacketType.Login.Client.START; @@ -67,6 +74,7 @@ public class ProtocolLibListener extends PacketAdapter { private final FastLoginBukkit plugin; + private final PlayerInjectionHandler handler; //just create a new once on plugin enable. This used for verify token generation private final SecureRandom random = new SecureRandom(); @@ -85,6 +93,7 @@ public ProtocolLibListener(FastLoginBukkit plugin, AntiBotService antiBotService this.plugin = plugin; this.antiBotService = antiBotService; this.verifyClientKeys = verifyClientKeys; + this.handler = getHandler(); } public static void register(FastLoginBukkit plugin, AntiBotService antiBotService, boolean verifyClientKeys) { @@ -109,6 +118,15 @@ public void onPacketReceiving(PacketEvent packetEvent) { Player sender = packetEvent.getPlayer(); PacketType packetType = packetEvent.getPacketType(); if (packetType == START) { + + if (plugin.getFloodgateService() != null) { + boolean success = processFloodgateTasks(packetEvent); + // don't continue execution if the player was kicked by Floodgate + if (!success) { + return; + } + } + PacketContainer packet = packetEvent.getPacket(); InetSocketAddress address = sender.getAddress(); @@ -201,11 +219,6 @@ private void onLoginStart(PacketEvent packetEvent, Player player, String usernam //remove old data every time on a new login in order to keep the session only for one person plugin.removeSession(player.getAddress()); - if (packetEvent.getPacket().getMeta("original_name").isPresent()) { - //username has been injected by ManualNameChange.java - username = (String) packetEvent.getPacket().getMeta("original_name").get(); - } - PacketContainer packet = packetEvent.getPacket(); val profileKey = packet.getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter()) .optionRead(0); @@ -254,4 +267,65 @@ private String getUsername(PacketContainer packet) { //player.getName() won't work at this state return profile.getName(); } + + private static PlayerInjectionHandler getHandler() { + try { + PacketFilterManager manager = (PacketFilterManager) ProtocolLibrary.getProtocolManager(); + Field f = manager.getClass().getDeclaredField("playerInjectionHandler"); + f.setAccessible(true); + PlayerInjectionHandler handler = (PlayerInjectionHandler) f.get(manager); + f.setAccessible(false); + return handler; + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private FloodgatePlayer getFloodgatePlayer(Player player) { + Channel channel = handler.getChannel(player); + AttributeKey floodgateAttribute = AttributeKey.valueOf("floodgate-player"); + return channel.attr(floodgateAttribute).get(); + } + + /** + * Reimplementation of the tasks injected Floodgate in ProtocolLib that are not run due to a bug + * @see Issue Floodgate#143 + * @see Floodgate/SpigotDataHandler + * @param packetEvent the PacketEvent that won't be processed by Floodgate + * @return false if the player was kicked + */ + private boolean processFloodgateTasks(PacketEvent packetEvent) { + PacketContainer packet = packetEvent.getPacket(); + Player player = packetEvent.getPlayer(); + FloodgatePlayer floodgatePlayer = getFloodgatePlayer(player); + if (floodgatePlayer == null) { + return true; + } + + // kick the player, if necessary + Channel channel = handler.getChannel(packetEvent.getPlayer()); + AttributeKey kickMessageAttribute = AttributeKey.valueOf("floodgate-kick-message"); + String kickMessage = channel.attr(kickMessageAttribute).get(); + if (kickMessage != null) { + player.kickPlayer(kickMessage); + return false; + } + + // add prefix + String username = floodgatePlayer.getCorrectUsername(); + if (packet.getGameProfiles().size() > 0) { + packet.getGameProfiles().write(0, + new WrappedGameProfile(floodgatePlayer.getCorrectUniqueId(), username)); + } else { + packet.getStrings().write(0, username); + } + + // remove real Floodgate data handler + ChannelHandler floodgateHandler = channel.pipeline().get("floodgate_data_handler"); + channel.pipeline().remove(floodgateHandler); + + return true; + } } diff --git a/checkstyle.xml b/checkstyle.xml index f38f86153..0a882add8 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -101,6 +101,7 @@ + diff --git a/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java b/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java index 9ef8985c5..267a02675 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java @@ -99,23 +99,11 @@ public boolean performChecks(String username, LoginSource source) { * The FloodgateApi does not support querying players by name, so this function * iterates over every online FloodgatePlayer and checks if the requested * username can be found - *
- * Falls back to non-prefixed name checks, if ProtocolLib is installed * * @param prefixedUsername the name of the player with the prefix appended * @return FloodgatePlayer if found, null otherwise */ public FloodgatePlayer getBedrockPlayer(String prefixedUsername) { - //prefixes are broken with ProtocolLib, so fall back to name checks without prefixes - //this should be removed if #493 gets fixed - if (core.getPlugin().isPluginInstalled("ProtocolLib")) { - for (FloodgatePlayer floodgatePlayer : floodgate.getPlayers()) { - if (floodgatePlayer.getUsername().equals(prefixedUsername)) { - return floodgatePlayer; - } - } - return null; - } for (FloodgatePlayer floodgatePlayer : floodgate.getPlayers()) { if (floodgatePlayer.getCorrectUsername().equals(prefixedUsername)) { return floodgatePlayer; diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 8ac92822c..5132bb2b9 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -236,8 +236,6 @@ autoLoginFloodgate: false # # To prevent conflicts from two different players having the same name, it is highly recommended using a # 'username-prefix' in floodgate/config.yml -# Note: 'username-prefix' is currently broken when used with FastLogin and ProtocolLib. -# A solution to this is to enable 'floodgatePrefixWorkaround' below. # # Possible values: # false: Kick Bedrock players, if they are using an existing Premium Java account's name @@ -264,14 +262,6 @@ allowFloodgateNameConflict: false # Enabling this might lead to people gaining unauthorized access to other's accounts! autoRegisterFloodgate: false -# Make FastLogin inject the Floodgate name prefixes, instead of Floodgate. -# This can fix prefixes, if you are using Floodgate alongside ProtocolLib. -# If either of those plugins are not installed, this option will have no effect. -# For more information visit: https://github.com/games647/FastLogin/issues/493 -# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!! -# Enabling this might lead to people gaining unauthorized access to other's accounts! -floodgatePrefixWorkaround: false - # This option resembles the vanilla configuration option 'enforce-secure-profile' in the 'server.properties' file. # It verifies if the incoming cryptographic key in the login request from the player is signed by Mojang. This key # is necessary for servers where you or other in-game players want to verify that a chat message sent and signed by