mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-19 14:59:20 +00:00
Added whitelist command, allow handler to set IP of non-Java players
This commit is contained in:
@@ -90,20 +90,20 @@ public interface HandshakeData {
|
||||
void setHostname(String hostname);
|
||||
|
||||
/**
|
||||
* Returns the IP address of the Bedrock client. The initial value is {@link
|
||||
* BedrockData#getIp()} (or null if BedrockData is null) but will return the changed IP if it
|
||||
* has been changed using {@link #setBedrockIp(String)}
|
||||
* Returns the IP address of the client. The initial value is {@link BedrockData#getIp()} when
|
||||
* BedrockData isn't null, or null if BedrockData is null. This method will return the changed
|
||||
* IP if it has been changed using {@link #setIp(String)}
|
||||
*/
|
||||
String getBedrockIp();
|
||||
String getIp();
|
||||
|
||||
/**
|
||||
* Set the IP address of the Bedrock client. Floodgate doesn't perform any checks if the
|
||||
* Set the IP address of the connected client. Floodgate doesn't perform any checks if the
|
||||
* provided data is valid (hence one of the reasons why this class has been made for advanced
|
||||
* users), thank you for not abusing Floodgate's trust in you :)
|
||||
*
|
||||
* @param address the IP address of the Bedrock client
|
||||
* @param address the IP address of the client
|
||||
*/
|
||||
void setBedrockIp(String address);
|
||||
void setIp(String address);
|
||||
|
||||
/**
|
||||
* Returns the reason to disconnect the current player.
|
||||
|
||||
@@ -41,7 +41,6 @@ import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.PacketWrapper;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
|
||||
@@ -93,10 +92,10 @@ public class BungeeProxyDataHandler extends ChannelInboundHandlerAdapter {
|
||||
HandshakeResult result = handler.handle(ctx.channel(), data);
|
||||
HandshakeData handshakeData = result.getHandshakeData();
|
||||
|
||||
// we'll change the IP address from the proxy to the IP of the Bedrock client very early on
|
||||
// so that almost every plugin will use the IP of the Bedrock client
|
||||
if (result.getFloodgatePlayer() != null) {
|
||||
|
||||
// we'll change the IP address from the proxy to the real IP of the client very early on
|
||||
// so that almost every plugin will use the real IP of the client
|
||||
InetSocketAddress newIp = result.getNewIp(ctx.channel());
|
||||
if (newIp != null) {
|
||||
HandlerBoss handlerBoss = ctx.pipeline().get(HandlerBoss.class);
|
||||
// InitialHandler extends PacketHandler and implements PendingConnection
|
||||
InitialHandler connection = ReflectionUtils.getCastedValue(handlerBoss, HANDLER);
|
||||
@@ -104,10 +103,7 @@ public class BungeeProxyDataHandler extends ChannelInboundHandlerAdapter {
|
||||
ChannelWrapper channelWrapper =
|
||||
ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER);
|
||||
|
||||
InetSocketAddress address =
|
||||
result.getFloodgatePlayer().getProperty(PropertyKey.SOCKET_ADDRESS);
|
||||
|
||||
channelWrapper.setRemoteAddress(address);
|
||||
channelWrapper.setRemoteAddress(newIp);
|
||||
}
|
||||
|
||||
if (handshakeData.getDisconnectReason() != null) {
|
||||
|
||||
@@ -45,7 +45,7 @@ public class HandshakeDataImpl implements HandshakeData {
|
||||
|
||||
@Setter private LinkedPlayer linkedPlayer;
|
||||
@Setter private String hostname;
|
||||
@Setter private String bedrockIp;
|
||||
@Setter private String ip;
|
||||
@Setter private String disconnectReason;
|
||||
|
||||
public HandshakeDataImpl(
|
||||
@@ -74,7 +74,7 @@ public class HandshakeDataImpl implements HandshakeData {
|
||||
}
|
||||
|
||||
javaUniqueId = Utils.getJavaUuid(bedrockData.getXuid());
|
||||
this.bedrockIp = bedrockData.getIp();
|
||||
this.ip = bedrockData.getIp();
|
||||
}
|
||||
|
||||
this.javaUsername = javaUsername;
|
||||
|
||||
@@ -27,9 +27,9 @@ package org.geysermc.floodgate.command;
|
||||
|
||||
import static org.geysermc.floodgate.command.CommonCommandMessage.CHECK_CONSOLE;
|
||||
|
||||
import cloud.commandframework.ArgumentDescription;
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.CommandManager;
|
||||
import cloud.commandframework.Description;
|
||||
import cloud.commandframework.arguments.standard.StringArgument;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import com.google.inject.Inject;
|
||||
@@ -55,7 +55,7 @@ public final class LinkAccountCommand implements FloodgateCommand {
|
||||
@Override
|
||||
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
|
||||
return commandManager.commandBuilder("linkaccount",
|
||||
Description.of("Link your Java account with your Bedrock account"))
|
||||
ArgumentDescription.of("Link your Java account with your Bedrock account"))
|
||||
.senderType(PlayerAudience.class)
|
||||
.permission("floodgate.command.linkaccount")
|
||||
.argument(UserAudienceArgument.of("player", true))
|
||||
|
||||
@@ -27,9 +27,9 @@ package org.geysermc.floodgate.command;
|
||||
|
||||
import static org.geysermc.floodgate.command.CommonCommandMessage.CHECK_CONSOLE;
|
||||
|
||||
import cloud.commandframework.ArgumentDescription;
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.CommandManager;
|
||||
import cloud.commandframework.Description;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import com.google.inject.Inject;
|
||||
import lombok.Getter;
|
||||
@@ -49,7 +49,7 @@ public final class UnlinkAccountCommand implements FloodgateCommand {
|
||||
@Override
|
||||
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
|
||||
return commandManager.commandBuilder("unlinkaccount",
|
||||
Description.of("Unlink your Java account from your Bedrock account"))
|
||||
ArgumentDescription.of("Unlink your Java account from your Bedrock account"))
|
||||
.senderType(PlayerAudience.class)
|
||||
.permission("floodgate.command.unlinkaccount")
|
||||
.handler(this::execute)
|
||||
|
||||
@@ -25,15 +25,18 @@
|
||||
|
||||
package org.geysermc.floodgate.command;
|
||||
|
||||
import static org.geysermc.floodgate.command.CommonCommandMessage.CHECK_CONSOLE;
|
||||
|
||||
import cloud.commandframework.ArgumentDescription;
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.CommandManager;
|
||||
import cloud.commandframework.Description;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.inject.Inject;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.platform.command.CommandMessage;
|
||||
import org.geysermc.floodgate.platform.command.CommandUtil;
|
||||
import org.geysermc.floodgate.platform.command.FloodgateCommand;
|
||||
import org.geysermc.floodgate.player.UserAudience;
|
||||
@@ -48,7 +51,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
@Override
|
||||
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
|
||||
Command.Builder<UserAudience> builder = commandManager.commandBuilder("fwhitelist",
|
||||
Description.of("Easy way to whitelist Bedrock players"))
|
||||
ArgumentDescription.of("Easy way to whitelist Bedrock players"))
|
||||
.permission("floodgate.command.fwhitelist");
|
||||
|
||||
commandManager.command(builder
|
||||
@@ -73,8 +76,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
}
|
||||
|
||||
if (name.length() < 1 || name.length() > 16) {
|
||||
sender.sendMessage(Component.text(
|
||||
"The given username '" + name + "' is not a valid username."));
|
||||
sender.sendMessage(Message.INVALID_USERNAME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,8 +87,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
HttpUtils.asyncGet(Constants.GET_XUID_URL + name)
|
||||
.whenComplete((result, error) -> {
|
||||
if (error != null) {
|
||||
sender.sendMessage(Component.text(
|
||||
"An error occurred. See the console for more info"));
|
||||
sender.sendMessage(Message.API_UNAVAILABLE);
|
||||
error.printStackTrace();
|
||||
return;
|
||||
}
|
||||
@@ -95,8 +96,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
boolean success = response.get("success").getAsBoolean();
|
||||
|
||||
if (!success) {
|
||||
sender.sendMessage(Component.text(
|
||||
"An error occurred. See the console for more info"));
|
||||
sender.sendMessage(Message.UNEXPECTED_ERROR);
|
||||
logger.error(
|
||||
"Got an error from requesting the xuid of a Bedrock player: {}",
|
||||
response.get("message").getAsString());
|
||||
@@ -105,8 +105,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
|
||||
JsonObject data = response.getAsJsonObject("data");
|
||||
if (data.size() == 0) {
|
||||
sender.sendMessage(Component.text(
|
||||
"Couldn't find the user '" + tempName + "'"));
|
||||
sender.sendMessage(Message.USER_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -114,12 +113,18 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
CommandUtil commandUtil = context.get("CommandUtil");
|
||||
|
||||
try {
|
||||
if (add && commandUtil.whitelistPlayer(xuid, tempName)) {
|
||||
sender.sendMessage(Component.text("Player has been whitelisted :)"));
|
||||
} else if (!add && commandUtil.removePlayerFromWhitelist(xuid, tempName)) {
|
||||
sender.sendMessage(Component.text("Player has been removed :o"));
|
||||
if (add) {
|
||||
if (commandUtil.whitelistPlayer(xuid, tempName)) {
|
||||
sender.sendMessage(Message.PLAYER_ADDED);
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Player was already whitelisted :o"));
|
||||
sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED);
|
||||
}
|
||||
} else {
|
||||
if (commandUtil.removePlayerFromWhitelist(xuid, tempName)) {
|
||||
sender.sendMessage(Message.PLAYER_REMOVED);
|
||||
} else {
|
||||
sender.sendMessage(Message.PLAYER_NOT_WHITELISTED);
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
logger.error(
|
||||
@@ -133,4 +138,24 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
public void execute(CommandContext<UserAudience> context) {
|
||||
// ignored, all the logic is in the other method
|
||||
}
|
||||
|
||||
@Getter
|
||||
public enum Message implements CommandMessage {
|
||||
INVALID_USERNAME("floodgate.command.fwhitelist.invalid_username"),
|
||||
API_UNAVAILABLE("floodgate.command.fwhitelist.api_unavailable " + CHECK_CONSOLE),
|
||||
USER_NOT_FOUND("floodgate.command.fwhitelist.user_not_found"),
|
||||
PLAYER_ADDED("floodgate.command.fwhitelist.player_added"),
|
||||
PLAYER_REMOVED("floodgate.command.fwhitelist.player_removed"),
|
||||
PLAYER_ALREADY_WHITELISTED("floodgate.command.fwhitelist.player_already_whitelisted"),
|
||||
PLAYER_NOT_WHITELISTED("floodgate.command.fwhitelist.player_not_whitelisted"),
|
||||
UNEXPECTED_ERROR("floodgate.command.fwhitelist.unexpected_error " + CHECK_CONSOLE);
|
||||
|
||||
private final String rawMessage;
|
||||
private final String[] translateParts;
|
||||
|
||||
Message(String rawMessage) {
|
||||
this.rawMessage = rawMessage;
|
||||
this.translateParts = rawMessage.split(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,10 +150,7 @@ public final class FloodgateHandshakeHandler {
|
||||
bedrockData.getVerifyCode());
|
||||
}
|
||||
|
||||
UUID javaUuid = Utils.getJavaUuid(bedrockData.getXuid());
|
||||
handshakeData.setHostname(correctHostname(
|
||||
handshakeData.getHostname(), bedrockData, javaUuid
|
||||
));
|
||||
correctHostname(handshakeData);
|
||||
|
||||
FloodgatePlayer player =
|
||||
FloodgatePlayerImpl.from(bedrockData, handshakeData);
|
||||
@@ -163,8 +160,7 @@ public final class FloodgateHandshakeHandler {
|
||||
channel.attr(playerAttribute).set(player);
|
||||
|
||||
int port = ((InetSocketAddress) channel.remoteAddress()).getPort();
|
||||
InetSocketAddress socketAddress = new InetSocketAddress(handshakeData.getBedrockIp(),
|
||||
port);
|
||||
InetSocketAddress socketAddress = new InetSocketAddress(handshakeData.getIp(), port);
|
||||
player.addProperty(PropertyKey.SOCKET_ADDRESS, socketAddress);
|
||||
|
||||
return new HandshakeResult(ResultType.SUCCESS, handshakeData, bedrockData, player);
|
||||
@@ -204,27 +200,27 @@ public final class FloodgateHandshakeHandler {
|
||||
handshakeHandlers.callHandshakeHandlers(handshakeData);
|
||||
|
||||
if (bedrockData != null) {
|
||||
UUID javaUuid = Utils.getJavaUuid(bedrockData.getXuid());
|
||||
handshakeData.setHostname(correctHostname(
|
||||
handshakeData.getHostname(), bedrockData, javaUuid
|
||||
));
|
||||
correctHostname(handshakeData);
|
||||
}
|
||||
|
||||
return new HandshakeResult(resultType, handshakeData, bedrockData, null);
|
||||
}
|
||||
|
||||
private String correctHostname(String hostname, BedrockData data, UUID correctUuid) {
|
||||
private void correctHostname(HandshakeData handshakeData) {
|
||||
BedrockData bedrockData = handshakeData.getBedrockData();
|
||||
UUID correctUuid = Utils.getJavaUuid(bedrockData.getXuid());
|
||||
|
||||
// replace the ip and uuid with the Bedrock client IP and an uuid based of the xuid
|
||||
String[] split = hostname.split("\0");
|
||||
String[] split = handshakeData.getHostname().split("\0");
|
||||
if (split.length >= 3) {
|
||||
if (logger.isDebug()) {
|
||||
logger.info("Replacing hostname arg1 '{}' with '{}' and arg2 '{}' with '{}'",
|
||||
split[1], data.getIp(), split[2], correctUuid.toString());
|
||||
split[1], bedrockData.getIp(), split[2], correctUuid.toString());
|
||||
}
|
||||
split[1] = data.getIp();
|
||||
split[1] = bedrockData.getIp();
|
||||
split[2] = correctUuid.toString();
|
||||
}
|
||||
return String.join("\0", split);
|
||||
handshakeData.setHostname(String.join("\0", split));
|
||||
}
|
||||
|
||||
private LinkedPlayer fetchLinkedPlayer(UUID javaUniqueId) {
|
||||
@@ -255,5 +251,16 @@ public final class FloodgateHandshakeHandler {
|
||||
private final HandshakeData handshakeData;
|
||||
private final BedrockData bedrockData;
|
||||
private final FloodgatePlayer floodgatePlayer;
|
||||
|
||||
public InetSocketAddress getNewIp(Channel channel) {
|
||||
if (floodgatePlayer != null) {
|
||||
return floodgatePlayer.getProperty(PropertyKey.SOCKET_ADDRESS);
|
||||
}
|
||||
if (handshakeData.getIp() != null) {
|
||||
int port = ((InetSocketAddress) channel.remoteAddress()).getPort();
|
||||
return new InetSocketAddress(handshakeData.getIp(), port);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
|
||||
@@ -182,10 +181,15 @@ public final class SpigotDataHandler extends ChannelInboundHandlerAdapter {
|
||||
HandshakeData handshakeData = result.getHandshakeData();
|
||||
|
||||
setValue(packet, HANDSHAKE_HOST, handshakeData.getHostname());
|
||||
logger.info(handshakeData.getHostname());
|
||||
|
||||
InetSocketAddress newIp = result.getNewIp(ctx.channel());
|
||||
if (newIp != null) {
|
||||
setValue(networkManager, SOCKET_ADDRESS, newIp);
|
||||
//todo the socket address will be overridden when bungeeData is true
|
||||
}
|
||||
|
||||
if (handshakeData.getDisconnectReason() != null) {
|
||||
ctx.close(); // todo disconnect with message
|
||||
ctx.close(); //todo disconnect with message
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,10 +224,6 @@ public final class SpigotDataHandler extends ChannelInboundHandlerAdapter {
|
||||
if (!bungeeData) {
|
||||
// Use a spoofedUUID for initUUID (just like Bungeecord)
|
||||
setValue(networkManager, "spoofedUUID", player.getCorrectUniqueId());
|
||||
|
||||
// Use the player his IP for stuff instead of Geyser his IP
|
||||
InetSocketAddress address = player.getProperty(PropertyKey.SOCKET_ADDRESS);
|
||||
setValue(networkManager, SOCKET_ADDRESS, address);
|
||||
}
|
||||
} else if (isLogin) {
|
||||
if (!bungeeData) {
|
||||
|
||||
@@ -36,11 +36,11 @@ import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.util.AttributeKey;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetSocketAddress;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
|
||||
@@ -97,6 +97,12 @@ public final class VelocityProxyDataHandler extends ChannelInboundHandlerAdapter
|
||||
HandshakeResult result = handshakeHandler.handle(ctx.channel(), address);
|
||||
HandshakeData handshakeData = result.getHandshakeData();
|
||||
|
||||
InetSocketAddress newIp = result.getNewIp(ctx.channel());
|
||||
if (newIp != null) {
|
||||
Object connection = ctx.pipeline().get("handler");
|
||||
setValue(connection, REMOTE_ADDRESS, newIp);
|
||||
}
|
||||
|
||||
if (handshakeData.getDisconnectReason() != null) {
|
||||
ctx.channel().attr(kickMessageAttribute).set(handshakeData.getDisconnectReason());
|
||||
return;
|
||||
@@ -124,9 +130,6 @@ public final class VelocityProxyDataHandler extends ChannelInboundHandlerAdapter
|
||||
|
||||
setValue(packet, HANDSHAKE_SERVER_ADDRESS, handshakeData.getHostname());
|
||||
|
||||
Object connection = ctx.pipeline().get("handler");
|
||||
setValue(connection, REMOTE_ADDRESS, player.getProperty(PropertyKey.SOCKET_ADDRESS));
|
||||
|
||||
logger.info("Floodgate player who is logged in as {} {} joined",
|
||||
player.getCorrectUsername(), player.getCorrectUniqueId());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user