mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-28 19:19:15 +00:00
Fixed an issue with send-floodgate-data and player linking
This commit is contained in:
@@ -30,10 +30,8 @@ import io.netty.util.AttributeKey;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.api.inject.InjectorAddon;
|
||||
import org.geysermc.floodgate.core.addon.data.PacketBlocker;
|
||||
import org.geysermc.floodgate.core.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateHandshakeHandler;
|
||||
|
||||
@@ -41,7 +39,6 @@ import org.geysermc.floodgate.core.connection.FloodgateHandshakeHandler;
|
||||
public class BungeeDataAddon implements InjectorAddon {
|
||||
@Inject private FloodgateHandshakeHandler handshakeHandler;
|
||||
@Inject private ProxyFloodgateConfig config;
|
||||
@Inject private ProxyFloodgateApi api;
|
||||
|
||||
@Inject
|
||||
@Named("packetHandler")
|
||||
@@ -59,18 +56,13 @@ public class BungeeDataAddon implements InjectorAddon {
|
||||
@Named("kickMessageAttribute")
|
||||
private AttributeKey<String> kickMessageAttribute;
|
||||
|
||||
@Inject
|
||||
@Named("playerAttribute")
|
||||
private AttributeKey<Connection> playerAttribute;
|
||||
@Inject BungeeServerDataHandler serverDataHandler;
|
||||
|
||||
@Override
|
||||
public void onInject(Channel channel, boolean toServer) {
|
||||
if (toServer) {
|
||||
if (config.sendFloodgateData()) {
|
||||
channel.pipeline().addAfter(
|
||||
packetEncoder, "floodgate_data_handler",
|
||||
new BungeeServerDataHandler(api, playerAttribute)
|
||||
);
|
||||
channel.pipeline().addAfter(packetEncoder, "floodgate_data_handler", serverDataHandler);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,12 +27,15 @@ package org.geysermc.floodgate.bungee.addon.data;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.AttributeKey;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.lang.reflect.Field;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.ServerConnector;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
@@ -40,13 +43,13 @@ import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.core.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateConnection;
|
||||
import org.geysermc.floodgate.core.crypto.FloodgateDataCodec;
|
||||
import org.geysermc.floodgate.core.util.ReflectionUtils;
|
||||
import org.geysermc.floodgate.util.BedrockData;
|
||||
|
||||
@Singleton
|
||||
@ChannelHandler.Sharable
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeServerDataHandler extends ChannelOutboundHandlerAdapter {
|
||||
private static final Field HANDLER;
|
||||
private static final Field USER_CONNECTION;
|
||||
@@ -64,11 +67,14 @@ public class BungeeServerDataHandler extends ChannelOutboundHandlerAdapter {
|
||||
requireNonNull(CHANNEL_WRAPPER, "ChannelWrapper field cannot be null");
|
||||
}
|
||||
|
||||
private final ProxyFloodgateApi api;
|
||||
private final AttributeKey<Connection> playerAttribute;
|
||||
@Inject FloodgateDataCodec dataCodec;
|
||||
|
||||
@Inject
|
||||
@Named("playerAttribute")
|
||||
AttributeKey<Connection> playerAttribute;
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) {
|
||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
||||
if (packet instanceof Handshake) {
|
||||
// get the Proxy <-> Player channel from the Proxy <-> Server channel
|
||||
HandlerBoss handlerBoss = ctx.pipeline().get(HandlerBoss.class);
|
||||
@@ -80,14 +86,12 @@ public class BungeeServerDataHandler extends ChannelOutboundHandlerAdapter {
|
||||
return;
|
||||
}
|
||||
|
||||
UserConnection connection = ReflectionUtils.getCastedValue(handler, USER_CONNECTION);
|
||||
ChannelWrapper wrapper = ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER);
|
||||
UserConnection userConnection = ReflectionUtils.getCastedValue(handler, USER_CONNECTION);
|
||||
ChannelWrapper wrapper = ReflectionUtils.getCastedValue(userConnection, CHANNEL_WRAPPER);
|
||||
|
||||
Connection player = wrapper.getHandle().attr(playerAttribute).get();
|
||||
|
||||
if (player != null) {
|
||||
BedrockData data = ((FloodgateConnection) player).toBedrockData();
|
||||
String encryptedData = api.createEncryptedDataString(data);
|
||||
Connection connection = wrapper.getHandle().attr(playerAttribute).get();
|
||||
if (connection != null) {
|
||||
String encodedData = dataCodec.encodeToString((FloodgateConnection) connection);
|
||||
|
||||
Handshake handshake = (Handshake) packet;
|
||||
String address = handshake.getHost();
|
||||
@@ -104,7 +108,7 @@ public class BungeeServerDataHandler extends ChannelOutboundHandlerAdapter {
|
||||
remaining = "";
|
||||
}
|
||||
|
||||
handshake.setHost(originalAddress + '\0' + encryptedData + remaining);
|
||||
handshake.setHost(originalAddress + '\0' + encodedData + remaining);
|
||||
// Bungeecord will add its data after our data
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ import net.md_5.bungee.event.EventPriority;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.bungee.player.BungeeConnectionManager;
|
||||
import org.geysermc.floodgate.core.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
|
||||
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.listener.McListener;
|
||||
import org.geysermc.floodgate.core.skin.SkinApplier;
|
||||
@@ -64,7 +64,7 @@ public final class BungeeListener implements Listener, McListener {
|
||||
|
||||
@Inject BungeeConnectionManager connectionManager;
|
||||
@Inject ProxyFloodgateConfig config;
|
||||
@Inject ProxyFloodgateApi api;
|
||||
@Inject SimpleFloodgateApi api;
|
||||
@Inject LanguageManager languageManager;
|
||||
@Inject FloodgateLogger logger;
|
||||
@Inject SkinApplier skinApplier;
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2023 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.core.api;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.geysermc.floodgate.core.crypto.FloodgateFormatCodec;
|
||||
import org.geysermc.floodgate.core.scope.ProxyOnly;
|
||||
import org.geysermc.floodgate.util.BedrockData;
|
||||
|
||||
@ProxyOnly
|
||||
@Singleton
|
||||
public final class ProxyFloodgateApi extends SimpleFloodgateApi {
|
||||
@Inject FloodgateFormatCodec dataCodec;
|
||||
|
||||
public byte[] createEncryptedData(BedrockData bedrockData) {
|
||||
try {
|
||||
return dataCodec.encodeFromString(bedrockData.toString());
|
||||
} catch (Exception exception) {
|
||||
throw new IllegalStateException("We failed to create the encrypted data, " +
|
||||
"but creating encrypted data is mandatory!", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public String createEncryptedDataString(BedrockData bedrockData) {
|
||||
return new String(createEncryptedData(bedrockData), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -46,9 +46,7 @@ import org.geysermc.floodgate.core.http.xbox.XboxClient;
|
||||
import org.geysermc.floodgate.core.pluginmessage.PluginMessageManager;
|
||||
import org.geysermc.floodgate.core.pluginmessage.channel.FormChannel;
|
||||
import org.geysermc.floodgate.core.pluginmessage.channel.TransferChannel;
|
||||
import org.geysermc.floodgate.core.scope.ServerOnly;
|
||||
|
||||
@ServerOnly
|
||||
@Singleton
|
||||
public class SimpleFloodgateApi implements GeyserApiBase {
|
||||
@Inject ConnectionManager connectionManager;
|
||||
|
||||
@@ -111,7 +111,6 @@ public final class FloodgateHandshakeHandler {
|
||||
@NonNull String floodgateDataString,
|
||||
@NonNull String hostname
|
||||
) {
|
||||
System.out.println("received: " + floodgateDataString);
|
||||
byte[] floodgateData = floodgateDataString.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
@@ -132,7 +131,7 @@ public final class FloodgateHandshakeHandler {
|
||||
throw callHandlerAndReturnResult(INVALID_DATA, channel, hostname);
|
||||
} catch (Exception exception) {
|
||||
// all the other exceptions are caused by invalid/tempered Floodgate data
|
||||
if (config.debug() || true) {
|
||||
if (config.debug()) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -235,7 +234,7 @@ public final class FloodgateHandshakeHandler {
|
||||
return link.fetchLink(Utils.getJavaUuid(data.xuid()))
|
||||
.thenApply(link -> {
|
||||
if (link == null) {
|
||||
return null;
|
||||
return data;
|
||||
}
|
||||
var linked = LinkedPlayer.of(link.javaUsername(), link.javaUniqueId(), link.bedrockId());
|
||||
return new FloodgateConnectionBuilder(config).linkedPlayer(linked).build();
|
||||
|
||||
@@ -30,11 +30,9 @@ import io.netty.util.AttributeKey;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.api.inject.InjectorAddon;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.addon.data.PacketBlocker;
|
||||
import org.geysermc.floodgate.core.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateHandshakeHandler;
|
||||
|
||||
@@ -42,7 +40,6 @@ import org.geysermc.floodgate.core.connection.FloodgateHandshakeHandler;
|
||||
public final class VelocityDataAddon implements InjectorAddon {
|
||||
@Inject FloodgateHandshakeHandler handshakeHandler;
|
||||
@Inject ProxyFloodgateConfig config;
|
||||
@Inject ProxyFloodgateApi api;
|
||||
@Inject FloodgateLogger logger;
|
||||
|
||||
@Inject
|
||||
@@ -62,17 +59,13 @@ public final class VelocityDataAddon implements InjectorAddon {
|
||||
AttributeKey<String> kickMessageAttribute;
|
||||
|
||||
@Inject
|
||||
@Named("playerAttribute")
|
||||
AttributeKey<Connection> playerAttribute;
|
||||
VelocityServerDataHandler serverDataHandler;
|
||||
|
||||
@Override
|
||||
public void onInject(Channel channel, boolean toServer) {
|
||||
if (toServer) {
|
||||
if (config.sendFloodgateData()) {
|
||||
channel.pipeline().addAfter(
|
||||
packetEncoder, "floodgate_data_handler",
|
||||
new VelocityServerDataHandler(api)
|
||||
);
|
||||
channel.pipeline().addAfter(packetEncoder, "floodgate_data_handler", serverDataHandler);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,16 +35,23 @@ import static org.geysermc.floodgate.core.util.ReflectionUtils.invoke;
|
||||
import static org.geysermc.floodgate.core.util.ReflectionUtils.setValue;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.AttributeKey;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.core.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateConnection;
|
||||
import org.geysermc.floodgate.util.BedrockData;
|
||||
import org.geysermc.floodgate.core.crypto.FloodgateDataCodec;
|
||||
|
||||
@Singleton
|
||||
@ChannelHandler.Sharable
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public final class VelocityServerDataHandler extends ChannelOutboundHandlerAdapter {
|
||||
private static final Class<?> HANDSHAKE_PACKET;
|
||||
@@ -70,30 +77,30 @@ public final class VelocityServerDataHandler extends ChannelOutboundHandlerAdapt
|
||||
requireNonNull(GET_PLAYER, "getPlayer in VelocityServerConnection cannot be null");
|
||||
}
|
||||
|
||||
private final ProxyFloodgateApi api;
|
||||
@Inject SimpleFloodgateApi api;
|
||||
@Inject FloodgateDataCodec dataCodec;
|
||||
|
||||
public VelocityServerDataHandler(ProxyFloodgateApi api) {
|
||||
this.api = api;
|
||||
}
|
||||
@Inject
|
||||
@Named("playerAttribute")
|
||||
AttributeKey<Connection> playerAttribute;
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise)
|
||||
throws Exception {
|
||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
||||
if (HANDSHAKE_PACKET.isInstance(packet)) {
|
||||
String address = getCastedValue(packet, HANDSHAKE_ADDRESS);
|
||||
|
||||
// The connection to the backend server is not the same connection as the client to the proxy.
|
||||
// This gets the client to proxy Connection from the backend server connection.
|
||||
|
||||
// get the FloodgatePlayer from the ConnectedPlayer
|
||||
Object minecraftConnection = ctx.pipeline().get("handler");
|
||||
Object association = invoke(minecraftConnection, GET_ASSOCIATION);
|
||||
Player velocityPlayer = castedInvoke(association, GET_PLAYER);
|
||||
|
||||
//noinspection ConstantConditions
|
||||
Connection player = api.connectionByUuid(velocityPlayer.getUniqueId());
|
||||
|
||||
if (player != null) {
|
||||
Connection connection = api.connectionByUuid(velocityPlayer.getUniqueId());
|
||||
if (connection != null) {
|
||||
// Player is a Floodgate player
|
||||
BedrockData data = ((FloodgateConnection) player).toBedrockData();
|
||||
String encryptedData = api.createEncryptedDataString(data);
|
||||
String encodedData = dataCodec.encodeToString((FloodgateConnection) connection);
|
||||
|
||||
// use the same system that we use on bungee, our data goes before all the other data
|
||||
int addressFinished = address.indexOf('\0');
|
||||
@@ -109,8 +116,7 @@ public final class VelocityServerDataHandler extends ChannelOutboundHandlerAdapt
|
||||
remaining = address.substring(addressFinished);
|
||||
}
|
||||
|
||||
setValue(packet, HANDSHAKE_ADDRESS, originalAddress + '\0' + encryptedData
|
||||
+ remaining);
|
||||
setValue(packet, HANDSHAKE_ADDRESS, originalAddress + '\0' + encodedData + remaining);
|
||||
}
|
||||
|
||||
ctx.pipeline().remove(this);
|
||||
|
||||
@@ -42,7 +42,7 @@ import java.util.Collections;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
|
||||
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.listener.McListener;
|
||||
import org.geysermc.floodgate.core.util.LanguageManager;
|
||||
@@ -52,7 +52,7 @@ import org.geysermc.floodgate.velocity.player.VelocityConnectionManager;
|
||||
public final class VelocityListener implements McListener {
|
||||
@Inject VelocityConnectionManager connectionManager;
|
||||
@Inject ProxyFloodgateConfig config;
|
||||
@Inject ProxyFloodgateApi api;
|
||||
@Inject SimpleFloodgateApi api;
|
||||
@Inject LanguageManager languageManager;
|
||||
@Inject FloodgateLogger logger;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user