mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-19 14:59:20 +00:00
Developers can now change some Floodgate related data during handshake
This commit is contained in:
@@ -27,6 +27,7 @@ package org.geysermc.floodgate.api;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
|
|
||||||
@@ -34,10 +35,16 @@ public final class InstanceHolder {
|
|||||||
@Getter private static FloodgateApi instance;
|
@Getter private static FloodgateApi instance;
|
||||||
@Getter private static PlayerLink playerLink;
|
@Getter private static PlayerLink playerLink;
|
||||||
@Getter private static PlatformInjector injector;
|
@Getter private static PlatformInjector injector;
|
||||||
|
@Getter private static HandshakeHandlers handshakeHandlers;
|
||||||
private static UUID key;
|
private static UUID key;
|
||||||
|
|
||||||
public static boolean setInstance(FloodgateApi floodgateApi, PlayerLink link,
|
public static boolean setInstance(
|
||||||
PlatformInjector platformInjector, UUID key) {
|
FloodgateApi floodgateApi,
|
||||||
|
PlayerLink link,
|
||||||
|
PlatformInjector platformInjector,
|
||||||
|
HandshakeHandlers handshakeHandlers,
|
||||||
|
UUID key
|
||||||
|
) {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
InstanceHolder.key = key;
|
InstanceHolder.key = key;
|
||||||
} else if (!InstanceHolder.key.equals(key)) {
|
} else if (!InstanceHolder.key.equals(key)) {
|
||||||
@@ -46,6 +53,7 @@ public final class InstanceHolder {
|
|||||||
instance = floodgateApi;
|
instance = floodgateApi;
|
||||||
playerLink = link;
|
playerLink = link;
|
||||||
injector = platformInjector;
|
injector = platformInjector;
|
||||||
|
InstanceHolder.handshakeHandlers = handshakeHandlers;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.api.handshake;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
|
import org.geysermc.floodgate.util.RawSkin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For advanced users only! You shouldn't play with this unless you know what you're doing.<br>
|
||||||
|
* <br>
|
||||||
|
* This class allows you change specific things of a Bedrock player before it is applied to the
|
||||||
|
* server. Note that at the time I'm writing this that the HandshakeData is created after requesting
|
||||||
|
* the player link. So the link is present here, if applicable.
|
||||||
|
*/
|
||||||
|
public interface HandshakeData {
|
||||||
|
/**
|
||||||
|
* Returns the Channel holding the connection between the client and the server.
|
||||||
|
*/
|
||||||
|
Channel getChannel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given player is a Floodgate player, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isFloodgatePlayer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the decrypted BedrockData sent by Geyser or null if the player isn't a Floodgate
|
||||||
|
* player.
|
||||||
|
*/
|
||||||
|
BedrockData getBedrockData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the linked account associated with the client or null if the player isn't linked or
|
||||||
|
* not a Floodgate player.
|
||||||
|
*/
|
||||||
|
LinkedPlayer getLinkedPlayer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the LinkedPlayer. This will be ignored if the player isn't a Floodgate player
|
||||||
|
*
|
||||||
|
* @param player the player to use as link
|
||||||
|
*/
|
||||||
|
void setLinkedPlayer(LinkedPlayer player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the skin of the client. Can be null even though the player is a Floodgate player.
|
||||||
|
*/
|
||||||
|
RawSkin getRawSkin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually set the skin of the client.
|
||||||
|
*
|
||||||
|
* @param rawSkin the skin of the client
|
||||||
|
*/
|
||||||
|
void setRawSkin(RawSkin rawSkin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hostname used in the handshake packet. This is the hostname after Floodgate
|
||||||
|
* removed the data.
|
||||||
|
*/
|
||||||
|
String getHostname();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the hostname of the handshake packet. Changing it here will also change it in the
|
||||||
|
* handshake packet.
|
||||||
|
*
|
||||||
|
* @param hostname the new hostname
|
||||||
|
*/
|
||||||
|
void setHostname(String hostname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reason to disconnect the current player.
|
||||||
|
*/
|
||||||
|
String getDisconnectReason();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reason to disconnect the current player.
|
||||||
|
*
|
||||||
|
* @param reason the reason to disconnect
|
||||||
|
*/
|
||||||
|
void setDisconnectReason(String reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the player should be disconnected
|
||||||
|
*/
|
||||||
|
default boolean shouldDisconnect() {
|
||||||
|
return getDisconnectReason() != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.api.handshake;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class allows you to change and/or get specific data of the Bedrock client before Floodgate
|
||||||
|
* does something with this data. This means that Floodgate decrypts the data, then calls the
|
||||||
|
* handshake handlers and then applies the data to the connection.<br>
|
||||||
|
* <br>
|
||||||
|
* /!\ Note that this class will be called for both Java and Bedrock connections, but {@link
|
||||||
|
* HandshakeData#isFloodgatePlayer()} will be false and Floodgate related methods will return null
|
||||||
|
* for Java players
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface HandshakeHandler {
|
||||||
|
/**
|
||||||
|
* Method that will be called during the time that Floodgate handles the handshake.
|
||||||
|
*
|
||||||
|
* @param data the data usable during the handshake
|
||||||
|
*/
|
||||||
|
void handle(HandshakeData data);
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.api.handshake;
|
||||||
|
|
||||||
|
public interface HandshakeHandlers {
|
||||||
|
/**
|
||||||
|
* Register a custom handshake handler. This can be used to check and edit the player during the
|
||||||
|
* handshake handling.
|
||||||
|
*
|
||||||
|
* @param handshakeHandler the handshake handler to register
|
||||||
|
* @return a random (unique) int to identify this handshake handler or -1 if null
|
||||||
|
*/
|
||||||
|
int addHandshakeHandler(HandshakeHandler handshakeHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a custom handshake handler by id.
|
||||||
|
*
|
||||||
|
* @param handshakeHandlerId the id of the handshake handler to remove
|
||||||
|
*/
|
||||||
|
void removeHandshakeHandler(int handshakeHandlerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a custom handshake handler by instance.
|
||||||
|
*
|
||||||
|
* @param handshakeHandler the instance to remove
|
||||||
|
*/
|
||||||
|
void removeHandshakeHandler(Class<? extends HandshakeHandler> handshakeHandler);
|
||||||
|
}
|
||||||
@@ -73,7 +73,7 @@ public interface PlatformInjector {
|
|||||||
*
|
*
|
||||||
* @param addon the class of the addon to remove from the addon list
|
* @param addon the class of the addon to remove from the addon list
|
||||||
* @param <T> the addon type
|
* @param <T> the addon type
|
||||||
* @return the instance that was present when removing
|
* @return the removed addon instance
|
||||||
*/
|
*/
|
||||||
<T extends InjectorAddon> T removeAddon(Class<T> addon);
|
<T extends InjectorAddon> T removeAddon(Class<T> addon);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,4 +89,9 @@ public interface FloodgateLogger {
|
|||||||
* this method, but they will be hidden from the console.
|
* this method, but they will be hidden from the console.
|
||||||
*/
|
*/
|
||||||
void disableDebug();
|
void disableDebug();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if debugging is enabled
|
||||||
|
*/
|
||||||
|
boolean isDebug();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
import static org.geysermc.floodgate.player.HandshakeHandler.ResultType;
|
import static org.geysermc.floodgate.player.HandshakeHandler.ResultType;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.name.Named;
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.util.AttributeKey;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.connection.PendingConnection;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.event.PreLoginEvent;
|
import net.md_5.bungee.api.event.PreLoginEvent;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.protocol.packet.Handshake;
|
import net.md_5.bungee.protocol.packet.Handshake;
|
||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
@@ -81,10 +81,6 @@ public final class BungeeDataHandler {
|
|||||||
checkNotNull(CACHED_HANDSHAKE_PACKET, "Cached handshake packet field cannot be null");
|
checkNotNull(CACHED_HANDSHAKE_PACKET, "Cached handshake packet field cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
|
||||||
@Named("playerAttribute")
|
|
||||||
private AttributeKey<FloodgatePlayer> playerAttribute;
|
|
||||||
|
|
||||||
@Inject private Plugin plugin;
|
@Inject private Plugin plugin;
|
||||||
@Inject private ProxyFloodgateConfig config;
|
@Inject private ProxyFloodgateConfig config;
|
||||||
@Inject private ProxyFloodgateApi api;
|
@Inject private ProxyFloodgateApi api;
|
||||||
@@ -94,16 +90,22 @@ public final class BungeeDataHandler {
|
|||||||
public void handlePreLogin(PreLoginEvent event) {
|
public void handlePreLogin(PreLoginEvent event) {
|
||||||
event.registerIntent(plugin);
|
event.registerIntent(plugin);
|
||||||
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||||
String extraData = ReflectionUtils.getCastedValue(
|
PendingConnection connection = event.getConnection();
|
||||||
event.getConnection(), EXTRA_HANDSHAKE_DATA
|
|
||||||
);
|
|
||||||
|
|
||||||
Object channelWrapper =
|
String extraData = ReflectionUtils.getCastedValue(connection, EXTRA_HANDSHAKE_DATA);
|
||||||
ReflectionUtils.getValue(event.getConnection(), PLAYER_CHANNEL_WRAPPER);
|
|
||||||
|
|
||||||
|
Object channelWrapper = ReflectionUtils.getValue(connection, PLAYER_CHANNEL_WRAPPER);
|
||||||
Channel channel = ReflectionUtils.getCastedValue(channelWrapper, PLAYER_CHANNEL);
|
Channel channel = ReflectionUtils.getCastedValue(channelWrapper, PLAYER_CHANNEL);
|
||||||
|
|
||||||
HandshakeResult result = handler.handle(channel, extraData);
|
HandshakeResult result = handler.handle(channel, extraData);
|
||||||
|
HandshakeData handshakeData = result.getHandshakeData();
|
||||||
|
|
||||||
|
if (handshakeData.getDisconnectReason() != null) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
channel.close(); // todo disconnect with message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (result.getResultType()) {
|
switch (result.getResultType()) {
|
||||||
case EXCEPTION:
|
case EXCEPTION:
|
||||||
event.setCancelReason(config.getDisconnect().getInvalidKey());
|
event.setCancelReason(config.getDisconnect().getInvalidKey());
|
||||||
@@ -124,12 +126,10 @@ public final class BungeeDataHandler {
|
|||||||
|
|
||||||
FloodgatePlayer player = result.getFloodgatePlayer();
|
FloodgatePlayer player = result.getFloodgatePlayer();
|
||||||
|
|
||||||
event.getConnection().setOnlineMode(false);
|
connection.setOnlineMode(false);
|
||||||
event.getConnection().setUniqueId(player.getCorrectUniqueId());
|
connection.setUniqueId(player.getCorrectUniqueId());
|
||||||
|
|
||||||
ReflectionUtils.setValue(
|
ReflectionUtils.setValue(connection, PLAYER_NAME, player.getCorrectUsername());
|
||||||
event.getConnection(), PLAYER_NAME, player.getCorrectUsername()
|
|
||||||
);
|
|
||||||
|
|
||||||
SocketAddress remoteAddress =
|
SocketAddress remoteAddress =
|
||||||
ReflectionUtils.getCastedValue(channelWrapper, PLAYER_REMOTE_ADDRESS);
|
ReflectionUtils.getCastedValue(channelWrapper, PLAYER_REMOTE_ADDRESS);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.InstanceHolder;
|
import org.geysermc.floodgate.api.InstanceHolder;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
@@ -64,8 +65,12 @@ public class FloodgatePlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void init(@Named("dataDirectory") Path dataDirectory, ConfigLoader configLoader,
|
public void init(
|
||||||
FloodgateConfigHolder configHolder) {
|
@Named("dataDirectory") Path dataDirectory,
|
||||||
|
ConfigLoader configLoader,
|
||||||
|
FloodgateConfigHolder configHolder,
|
||||||
|
HandshakeHandlers handshakeHandlers
|
||||||
|
) {
|
||||||
|
|
||||||
if (!Files.isDirectory(dataDirectory)) {
|
if (!Files.isDirectory(dataDirectory)) {
|
||||||
try {
|
try {
|
||||||
@@ -85,7 +90,7 @@ public class FloodgatePlatform {
|
|||||||
guice = guice.createChildInjector(new ConfigLoadedModule(config));
|
guice = guice.createChildInjector(new ConfigLoadedModule(config));
|
||||||
PlayerLink link = guice.getInstance(PlayerLinkLoader.class).load();
|
PlayerLink link = guice.getInstance(PlayerLinkLoader.class).load();
|
||||||
|
|
||||||
InstanceHolder.setInstance(api, link, this.injector, KEY);
|
InstanceHolder.setInstance(api, link, this.injector, handshakeHandlers, KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean enable(Module... postInitializeModules) {
|
public boolean enable(Module... postInitializeModules) {
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.addon.data;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
|
import org.geysermc.floodgate.util.RawSkin;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class HandshakeDataImpl implements HandshakeData {
|
||||||
|
private final Channel channel;
|
||||||
|
private final boolean floodgatePlayer;
|
||||||
|
private final BedrockData bedrockData;
|
||||||
|
|
||||||
|
@Setter private LinkedPlayer linkedPlayer;
|
||||||
|
@Setter private RawSkin rawSkin;
|
||||||
|
@Setter private String hostname;
|
||||||
|
@Setter private String disconnectReason;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.addon.data;
|
||||||
|
|
||||||
|
import io.netty.util.collection.IntObjectHashMap;
|
||||||
|
import io.netty.util.collection.IntObjectMap;
|
||||||
|
import java.util.Random;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeHandler;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
|
|
||||||
|
public class HandshakeHandlersImpl implements HandshakeHandlers {
|
||||||
|
private final Random random = new Random();
|
||||||
|
private final IntObjectMap<HandshakeHandler> handshakeHandlers = new IntObjectHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int addHandshakeHandler(HandshakeHandler handshakeHandler) {
|
||||||
|
if (handshakeHandler == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int key;
|
||||||
|
do {
|
||||||
|
key = random.nextInt(Integer.MAX_VALUE);
|
||||||
|
} while (handshakeHandlers.putIfAbsent(key, handshakeHandler) != null);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeHandshakeHandler(int handshakeHandlerId) {
|
||||||
|
// key is always positive
|
||||||
|
if (handshakeHandlerId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handshakeHandlers.remove(handshakeHandlerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeHandshakeHandler(Class<? extends HandshakeHandler> handshakeHandler) {
|
||||||
|
if (HandshakeHandler.class == handshakeHandler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handshakeHandlers.values().removeIf(handler -> handler.getClass() == handshakeHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callHandshakeHandlers(HandshakeData handshakeData) {
|
||||||
|
for (HandshakeHandler handshakeHandler : handshakeHandlers.values()) {
|
||||||
|
handshakeHandler.handle(handshakeData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ import org.geysermc.cumulus.util.FormBuilder;
|
|||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
|
import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
|
||||||
import org.geysermc.floodgate.player.FloodgatePlayerImpl;
|
import org.geysermc.floodgate.player.FloodgatePlayerImpl;
|
||||||
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SimpleFloodgateApi implements FloodgateApi {
|
public class SimpleFloodgateApi implements FloodgateApi {
|
||||||
@@ -66,7 +67,7 @@ public class SimpleFloodgateApi implements FloodgateApi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID createJavaPlayerId(long xuid) {
|
public UUID createJavaPlayerId(long xuid) {
|
||||||
return new UUID(0, xuid);
|
return Utils.getJavaUuid(xuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -26,52 +26,50 @@
|
|||||||
package org.geysermc.floodgate.link;
|
package org.geysermc.floodgate.link;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.inject.Inject;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
|
||||||
import org.geysermc.floodgate.api.link.LinkRequestResult;
|
import org.geysermc.floodgate.api.link.LinkRequestResult;
|
||||||
import org.geysermc.floodgate.util.HttpUtils;
|
import org.geysermc.floodgate.util.HttpUtils;
|
||||||
import org.geysermc.floodgate.util.HttpUtils.HttpResponse;
|
import org.geysermc.floodgate.util.HttpUtils.HttpResponse;
|
||||||
import org.geysermc.floodgate.util.LinkedPlayer;
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
public class GlobalPlayerLinking extends CommonPlayerLink {
|
public class GlobalPlayerLinking extends CommonPlayerLink {
|
||||||
private static final String GET_BEDROCK_LINK = "http://localhost:4000/api/link/bedrock?xuid=";
|
private static final String GET_BEDROCK_LINK = "http://localhost:4000/api/link/bedrock?xuid=";
|
||||||
|
|
||||||
@Inject private FloodgateApi api;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() {}
|
public void load() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<LinkedPlayer> getLinkedPlayer(UUID bedrockId) {
|
public CompletableFuture<LinkedPlayer> getLinkedPlayer(UUID bedrockId) {
|
||||||
return CompletableFuture.supplyAsync(
|
return CompletableFuture.supplyAsync(
|
||||||
() -> {
|
() -> {
|
||||||
HttpResponse response =
|
HttpResponse response =
|
||||||
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
|
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
|
||||||
|
|
||||||
// both on code != 200 and fails with 200 'success' will be false
|
// both on code != 200 and fails with 200 'success' will be false
|
||||||
if (!response.getResponse().get("success").getAsBoolean()) {
|
if (!response.getResponse().get("success").getAsBoolean()) {
|
||||||
getLogger().error(
|
getLogger().error(
|
||||||
"Failed to request link for {}: {}",
|
"Failed to request link for {}: {}",
|
||||||
bedrockId.getLeastSignificantBits(),
|
bedrockId.getLeastSignificantBits(),
|
||||||
response.getResponse().get("message").getAsString());
|
response.getResponse().get("message").getAsString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject data = response.getResponse().getAsJsonObject("data");
|
JsonObject data = response.getResponse().getAsJsonObject("data");
|
||||||
|
|
||||||
// no link if data is empty
|
// no link if data is empty
|
||||||
if (data.size() == 0) {
|
if (data.size() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LinkedPlayer.of(
|
return LinkedPlayer.of(
|
||||||
data.get("javaName").getAsString(),
|
data.get("javaName").getAsString(),
|
||||||
UUID.fromString(data.get("javaId").getAsString()),
|
UUID.fromString(data.get("javaId").getAsString()),
|
||||||
api.createJavaPlayerId(data.get("bedrockId").getAsLong()));
|
Utils.getJavaUuid(data.get("bedrockId").getAsLong()));
|
||||||
},
|
},
|
||||||
getExecutorService());
|
getExecutorService());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -117,8 +115,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
|
|||||||
public CompletableFuture<?> createLinkRequest(
|
public CompletableFuture<?> createLinkRequest(
|
||||||
UUID javaId,
|
UUID javaId,
|
||||||
String javaUsername,
|
String javaUsername,
|
||||||
String bedrockUsername
|
String bedrockUsername) {
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,8 +124,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
|
|||||||
UUID bedrockId,
|
UUID bedrockId,
|
||||||
String javaUsername,
|
String javaUsername,
|
||||||
String bedrockUsername,
|
String bedrockUsername,
|
||||||
String code
|
String code) {
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,4 +86,9 @@ public final class JavaUtilFloodgateLogger implements FloodgateLogger {
|
|||||||
logger.setLevel(originLevel);
|
logger.setLevel(originLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebug() {
|
||||||
|
return logger.getLevel() == Level.ALL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ import com.google.inject.name.Named;
|
|||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
@@ -60,6 +62,7 @@ public class CommonModule extends AbstractModule {
|
|||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(FloodgateApi.class).to(SimpleFloodgateApi.class);
|
bind(FloodgateApi.class).to(SimpleFloodgateApi.class);
|
||||||
bind(PlatformInjector.class).to(CommonPlatformInjector.class);
|
bind(PlatformInjector.class).to(CommonPlatformInjector.class);
|
||||||
|
bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -120,15 +123,30 @@ public class CommonModule extends AbstractModule {
|
|||||||
return new LanguageManager(configHolder, logger);
|
return new LanguageManager(configHolder, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
public HandshakeHandlersImpl handshakeHandlers() {
|
||||||
|
return new HandshakeHandlersImpl();
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public HandshakeHandler handshakeHandler(
|
public HandshakeHandler handshakeHandler(
|
||||||
|
HandshakeHandlersImpl handshakeHandlers,
|
||||||
SimpleFloodgateApi api,
|
SimpleFloodgateApi api,
|
||||||
FloodgateCipher cipher,
|
FloodgateCipher cipher,
|
||||||
FloodgateConfigHolder configHolder,
|
FloodgateConfigHolder configHolder,
|
||||||
@Named("playerAttribute") AttributeKey<FloodgatePlayer> playerAttribute
|
@Named("playerAttribute") AttributeKey<FloodgatePlayer> playerAttribute,
|
||||||
|
FloodgateLogger logger
|
||||||
) {
|
) {
|
||||||
return new HandshakeHandler(api, cipher, configHolder, playerAttribute);
|
return new HandshakeHandler(
|
||||||
|
handshakeHandlers,
|
||||||
|
api,
|
||||||
|
cipher,
|
||||||
|
configHolder,
|
||||||
|
playerAttribute,
|
||||||
|
logger
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import lombok.Setter;
|
|||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.InstanceHolder;
|
import org.geysermc.floodgate.api.InstanceHolder;
|
||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
@@ -49,6 +50,7 @@ import org.geysermc.floodgate.util.InputMode;
|
|||||||
import org.geysermc.floodgate.util.LinkedPlayer;
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
import org.geysermc.floodgate.util.RawSkin;
|
import org.geysermc.floodgate.util.RawSkin;
|
||||||
import org.geysermc.floodgate.util.UiProfile;
|
import org.geysermc.floodgate.util.UiProfile;
|
||||||
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
@@ -79,8 +81,11 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
|
|||||||
*/
|
*/
|
||||||
@Setter private boolean login = true;
|
@Setter private boolean login = true;
|
||||||
|
|
||||||
protected static FloodgatePlayerImpl from(BedrockData data, RawSkin skin,
|
protected static FloodgatePlayerImpl from(
|
||||||
FloodgateConfigHolder configHolder) {
|
BedrockData data,
|
||||||
|
HandshakeData handshakeData,
|
||||||
|
FloodgateConfigHolder configHolder) {
|
||||||
|
|
||||||
FloodgateApi api = FloodgateApi.getInstance();
|
FloodgateApi api = FloodgateApi.getInstance();
|
||||||
FloodgateConfig config = configHolder.get();
|
FloodgateConfig config = configHolder.get();
|
||||||
|
|
||||||
@@ -91,22 +96,14 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
|
|||||||
javaUsername = javaUsername.replaceAll(" ", "_");
|
javaUsername = javaUsername.replaceAll(" ", "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID javaUniqueId = api.createJavaPlayerId(Long.parseLong(data.getXuid()));
|
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
|
||||||
|
|
||||||
DeviceOs deviceOs = DeviceOs.getById(data.getDeviceOs());
|
DeviceOs deviceOs = DeviceOs.getById(data.getDeviceOs());
|
||||||
UiProfile uiProfile = UiProfile.getById(data.getUiProfile());
|
UiProfile uiProfile = UiProfile.getById(data.getUiProfile());
|
||||||
InputMode inputMode = InputMode.getById(data.getInputMode());
|
InputMode inputMode = InputMode.getById(data.getInputMode());
|
||||||
|
|
||||||
LinkedPlayer linkedPlayer;
|
LinkedPlayer linkedPlayer = handshakeData.getLinkedPlayer();
|
||||||
|
RawSkin skin = handshakeData.getRawSkin();
|
||||||
// we'll use the LinkedPlayer provided by Bungee or Velocity (if they included one)
|
|
||||||
if (data.hasPlayerLink()) {
|
|
||||||
linkedPlayer = data.getLinkedPlayer();
|
|
||||||
} else {
|
|
||||||
// every implementation (Bukkit, Bungee and Velocity) run this constructor async,
|
|
||||||
// so we should be fine doing this synchronised.
|
|
||||||
linkedPlayer = fetchLinkedPlayer(api.getPlayerLink(), javaUniqueId);
|
|
||||||
}
|
|
||||||
|
|
||||||
FloodgatePlayerImpl player = new FloodgatePlayerImpl(
|
FloodgatePlayerImpl player = new FloodgatePlayerImpl(
|
||||||
data.getVersion(), data.getUsername(), javaUsername, javaUniqueId, data.getXuid(),
|
data.getVersion(), data.getUsername(), javaUsername, javaUniqueId, data.getXuid(),
|
||||||
@@ -149,8 +146,9 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
|
|||||||
* isn't enabled
|
* isn't enabled
|
||||||
* @see #fetchLinkedPlayer(PlayerLink, UUID) for the sync version
|
* @see #fetchLinkedPlayer(PlayerLink, UUID) for the sync version
|
||||||
*/
|
*/
|
||||||
public static CompletableFuture<LinkedPlayer> fetchLinkedPlayerAsync(PlayerLink link,
|
public static CompletableFuture<LinkedPlayer> fetchLinkedPlayerAsync(
|
||||||
UUID javaUniqueId) {
|
PlayerLink link,
|
||||||
|
UUID javaUniqueId) {
|
||||||
return link.isEnabled() ?
|
return link.isEnabled() ?
|
||||||
link.getLinkedPlayer(javaUniqueId) :
|
link.getLinkedPlayer(javaUniqueId) :
|
||||||
CompletableFuture.completedFuture(null);
|
CompletableFuture.completedFuture(null);
|
||||||
|
|||||||
@@ -31,12 +31,18 @@ import com.google.common.base.Charsets;
|
|||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.geysermc.floodgate.addon.data.HandshakeDataImpl;
|
||||||
|
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
|
||||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||||
|
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.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
||||||
@@ -45,29 +51,39 @@ import org.geysermc.floodgate.crypto.FloodgateCipher;
|
|||||||
import org.geysermc.floodgate.util.Base64Utils;
|
import org.geysermc.floodgate.util.Base64Utils;
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
import org.geysermc.floodgate.util.InvalidFormatException;
|
import org.geysermc.floodgate.util.InvalidFormatException;
|
||||||
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
import org.geysermc.floodgate.util.RawSkin;
|
import org.geysermc.floodgate.util.RawSkin;
|
||||||
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public final class HandshakeHandler {
|
public final class HandshakeHandler {
|
||||||
|
private final HandshakeHandlersImpl handshakeHandlers;
|
||||||
private final SimpleFloodgateApi api;
|
private final SimpleFloodgateApi api;
|
||||||
private final FloodgateCipher cipher;
|
private final FloodgateCipher cipher;
|
||||||
private final FloodgateConfigHolder configHolder;
|
private final FloodgateConfigHolder configHolder;
|
||||||
private final AttributeKey<FloodgatePlayer> playerAttribute;
|
private final AttributeKey<FloodgatePlayer> playerAttribute;
|
||||||
|
private final FloodgateLogger logger;
|
||||||
|
|
||||||
public HandshakeResult handle(Channel channel, @NonNull String handshakeData) {
|
public HandshakeResult handle(Channel channel, @NonNull String hostname) {
|
||||||
try {
|
try {
|
||||||
String[] dataArray = handshakeData.split("\0");
|
String[] split = hostname.split("\0");
|
||||||
|
|
||||||
String data = null;
|
String data = null;
|
||||||
for (String value : dataArray) {
|
|
||||||
if (FloodgateCipher.hasHeader(value)) {
|
StringBuilder hostnameBuilder = new StringBuilder();
|
||||||
|
for (String value : split) {
|
||||||
|
if (data == null && FloodgateCipher.hasHeader(value)) {
|
||||||
data = value;
|
data = value;
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
hostnameBuilder.append(value);
|
||||||
}
|
}
|
||||||
|
// hostname now doesn't have Floodgate data anymore if it had
|
||||||
|
hostname = hostnameBuilder.toString();
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return ResultType.NOT_FLOODGATE_DATA.getCachedResult();
|
return callHandlerAndReturnResult(
|
||||||
|
ResultType.NOT_FLOODGATE_DATA,
|
||||||
|
channel, null, hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
// header + base64 iv - 0x21 - encrypted data - 0x21 - RawSkin
|
// header + base64 iv - 0x21 - encrypted data - 0x21 - RawSkin
|
||||||
@@ -91,7 +107,9 @@ public final class HandshakeHandler {
|
|||||||
BedrockData bedrockData = BedrockData.fromString(decrypted);
|
BedrockData bedrockData = BedrockData.fromString(decrypted);
|
||||||
|
|
||||||
if (bedrockData.getDataLength() != EXPECTED_LENGTH) {
|
if (bedrockData.getDataLength() != EXPECTED_LENGTH) {
|
||||||
return ResultType.INVALID_DATA_LENGTH.getCachedResult();
|
return callHandlerAndReturnResult(
|
||||||
|
ResultType.INVALID_DATA_LENGTH,
|
||||||
|
channel, bedrockData, hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
RawSkin rawSkin = null;
|
RawSkin rawSkin = null;
|
||||||
@@ -102,7 +120,29 @@ public final class HandshakeHandler {
|
|||||||
rawSkin = RawSkin.decode(rawSkinData);
|
rawSkin = RawSkin.decode(rawSkinData);
|
||||||
}
|
}
|
||||||
|
|
||||||
FloodgatePlayer player = FloodgatePlayerImpl.from(bedrockData, rawSkin, configHolder);
|
LinkedPlayer linkedPlayer;
|
||||||
|
|
||||||
|
// we'll use the LinkedPlayer provided by Bungee or Velocity (if they included one)
|
||||||
|
if (bedrockData.hasPlayerLink()) {
|
||||||
|
linkedPlayer = bedrockData.getLinkedPlayer();
|
||||||
|
} else {
|
||||||
|
// every implementation (Bukkit, Bungee and Velocity) run this constructor async,
|
||||||
|
// so we should be fine doing this synchronised.
|
||||||
|
linkedPlayer = fetchLinkedPlayer(Utils.getJavaUuid(bedrockData.getXuid()));
|
||||||
|
}
|
||||||
|
|
||||||
|
HandshakeData handshakeData = new HandshakeDataImpl(channel, true, bedrockData.clone(),
|
||||||
|
linkedPlayer != null ? linkedPlayer.clone() : null, rawSkin, hostname, null);
|
||||||
|
handshakeHandlers.callHandshakeHandlers(handshakeData);
|
||||||
|
|
||||||
|
UUID javaUuid = Utils.getJavaUuid(bedrockData.getXuid());
|
||||||
|
handshakeData.setHostname(correctHostname(
|
||||||
|
handshakeData.getHostname(), bedrockData, javaUuid
|
||||||
|
));
|
||||||
|
|
||||||
|
FloodgatePlayer player =
|
||||||
|
FloodgatePlayerImpl.from(bedrockData, handshakeData, configHolder);
|
||||||
|
|
||||||
api.addPlayer(player.getJavaUniqueId(), player);
|
api.addPlayer(player.getJavaUniqueId(), player);
|
||||||
|
|
||||||
channel.attr(playerAttribute).set(player);
|
channel.attr(playerAttribute).set(player);
|
||||||
@@ -111,19 +151,76 @@ public final class HandshakeHandler {
|
|||||||
InetSocketAddress socketAddress = new InetSocketAddress(bedrockData.getIp(), port);
|
InetSocketAddress socketAddress = new InetSocketAddress(bedrockData.getIp(), port);
|
||||||
player.addProperty(PropertyKey.SOCKET_ADDRESS, socketAddress);
|
player.addProperty(PropertyKey.SOCKET_ADDRESS, socketAddress);
|
||||||
|
|
||||||
return new HandshakeResult(ResultType.SUCCESS, dataArray, bedrockData, player);
|
return new HandshakeResult(ResultType.SUCCESS, handshakeData, bedrockData, player);
|
||||||
|
|
||||||
} catch (InvalidFormatException formatException) {
|
} catch (InvalidFormatException formatException) {
|
||||||
// only header exceptions should return 'not floodgate data',
|
// only header exceptions should return 'not floodgate data',
|
||||||
// all the other format exceptions are because of invalid/tempered Floodgate data
|
// all the other format exceptions are because of invalid/tempered Floodgate data
|
||||||
if (formatException.isHeader()) {
|
if (formatException.isHeader()) {
|
||||||
return ResultType.NOT_FLOODGATE_DATA.getCachedResult();
|
return callHandlerAndReturnResult(
|
||||||
|
ResultType.NOT_FLOODGATE_DATA,
|
||||||
|
channel, null, hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
formatException.printStackTrace();
|
formatException.printStackTrace();
|
||||||
return ResultType.EXCEPTION.getCachedResult();
|
|
||||||
|
return callHandlerAndReturnResult(
|
||||||
|
ResultType.EXCEPTION,
|
||||||
|
channel, null, hostname);
|
||||||
|
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
return ResultType.EXCEPTION.getCachedResult();
|
|
||||||
|
return callHandlerAndReturnResult(
|
||||||
|
ResultType.EXCEPTION,
|
||||||
|
channel, null, hostname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HandshakeResult callHandlerAndReturnResult(
|
||||||
|
ResultType resultType,
|
||||||
|
Channel channel,
|
||||||
|
BedrockData bedrockData,
|
||||||
|
String hostname
|
||||||
|
) {
|
||||||
|
HandshakeData handshakeData = new HandshakeDataImpl(channel, bedrockData != null,
|
||||||
|
bedrockData, null, null, hostname, null);
|
||||||
|
handshakeHandlers.callHandshakeHandlers(handshakeData);
|
||||||
|
|
||||||
|
if (bedrockData != null) {
|
||||||
|
UUID javaUuid = Utils.getJavaUuid(bedrockData.getXuid());
|
||||||
|
handshakeData.setHostname(correctHostname(
|
||||||
|
handshakeData.getHostname(), bedrockData, javaUuid
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HandshakeResult(resultType, handshakeData, bedrockData, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String correctHostname(String hostname, BedrockData data, UUID correctUuid) {
|
||||||
|
// replace the ip and uuid with the Bedrock client IP and an uuid based of the xuid
|
||||||
|
String[] split = hostname.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] = data.getIp();
|
||||||
|
split[2] = correctUuid.toString();
|
||||||
|
}
|
||||||
|
return String.join("\0", split);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedPlayer fetchLinkedPlayer(UUID javaUniqueId) {
|
||||||
|
if (!api.getPlayerLink().isEnabled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return api.getPlayerLink().getLinkedPlayer(javaUniqueId).get();
|
||||||
|
} catch (InterruptedException | ExecutionException exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,21 +228,14 @@ public final class HandshakeHandler {
|
|||||||
EXCEPTION,
|
EXCEPTION,
|
||||||
NOT_FLOODGATE_DATA,
|
NOT_FLOODGATE_DATA,
|
||||||
INVALID_DATA_LENGTH,
|
INVALID_DATA_LENGTH,
|
||||||
SUCCESS;
|
SUCCESS
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final HandshakeResult cachedResult;
|
|
||||||
|
|
||||||
ResultType() {
|
|
||||||
cachedResult = new HandshakeResult(this, null, null, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
public static class HandshakeResult {
|
public static class HandshakeResult {
|
||||||
private final ResultType resultType;
|
private final ResultType resultType;
|
||||||
private final String[] handshakeData;
|
private final HandshakeData handshakeData;
|
||||||
private final BedrockData bedrockData;
|
private final BedrockData bedrockData;
|
||||||
private final FloodgatePlayer floodgatePlayer;
|
private final FloodgatePlayer floodgatePlayer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
/**
|
/**
|
||||||
@@ -62,8 +63,9 @@ public class Utils {
|
|||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
if (line == null)
|
if (line == null) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
result.add(line);
|
result.add(line);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -79,4 +81,12 @@ public class Utils {
|
|||||||
public static String getLocale(Locale locale) {
|
public static String getLocale(Locale locale) {
|
||||||
return locale.getLanguage() + "_" + locale.getCountry();
|
return locale.getLanguage() + "_" + locale.getCountry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UUID getJavaUuid(long xuid) {
|
||||||
|
return new UUID(0, xuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UUID getJavaUuid(String xuid) {
|
||||||
|
return getJavaUuid(Long.parseLong(xuid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
@@ -159,7 +160,7 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
|
|||||||
private final HandshakeHandler handshakeHandler;
|
private final HandshakeHandler handshakeHandler;
|
||||||
private final FloodgateLogger logger;
|
private final FloodgateLogger logger;
|
||||||
private Object networkManager;
|
private Object networkManager;
|
||||||
private FloodgatePlayer fPlayer;
|
private FloodgatePlayer player;
|
||||||
private boolean bungeeData;
|
private boolean bungeeData;
|
||||||
private boolean done;
|
private boolean done;
|
||||||
|
|
||||||
@@ -180,6 +181,13 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
|
|||||||
|
|
||||||
String handshakeValue = getCastedValue(packet, HANDSHAKE_HOST);
|
String handshakeValue = getCastedValue(packet, HANDSHAKE_HOST);
|
||||||
HandshakeResult result = handshakeHandler.handle(ctx.channel(), handshakeValue);
|
HandshakeResult result = handshakeHandler.handle(ctx.channel(), handshakeValue);
|
||||||
|
HandshakeData handshakeData = result.getHandshakeData();
|
||||||
|
|
||||||
|
if (handshakeData.getDisconnectReason() != null) {
|
||||||
|
ctx.close(); // todo disconnect with message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (result.getResultType()) {
|
switch (result.getResultType()) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
break;
|
break;
|
||||||
@@ -195,24 +203,18 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fPlayer = result.getFloodgatePlayer();
|
player = result.getFloodgatePlayer();
|
||||||
BedrockData bedrockData = result.getBedrockData();
|
|
||||||
|
|
||||||
String[] data = result.getHandshakeData();
|
|
||||||
bungeeData = isBungeeData();
|
bungeeData = isBungeeData();
|
||||||
|
|
||||||
InetSocketAddress correctAddress = fPlayer.getProperty(PropertyKey.SOCKET_ADDRESS);
|
setValue(packet, HANDSHAKE_HOST, handshakeData.getHostname());
|
||||||
|
|
||||||
if (bungeeData) {
|
if (!bungeeData) {
|
||||||
setValue(packet, HANDSHAKE_HOST, data[0] + '\0' +
|
|
||||||
bedrockData.getIp() + '\0' +
|
|
||||||
fPlayer.getCorrectUniqueId() +
|
|
||||||
(data.length == 5 ? '\0' + data[4] : ""));
|
|
||||||
} else {
|
|
||||||
// Use a spoofedUUID for initUUID (just like Bungeecord)
|
// Use a spoofedUUID for initUUID (just like Bungeecord)
|
||||||
setValue(networkManager, "spoofedUUID", fPlayer.getCorrectUniqueId());
|
setValue(networkManager, "spoofedUUID", player.getCorrectUniqueId());
|
||||||
|
|
||||||
// Use the player his IP for stuff instead of Geyser his IP
|
// Use the player his IP for stuff instead of Geyser his IP
|
||||||
setValue(networkManager, SOCKET_ADDRESS, correctAddress);
|
InetSocketAddress address = player.getProperty(PropertyKey.SOCKET_ADDRESS);
|
||||||
|
setValue(networkManager, SOCKET_ADDRESS, address);
|
||||||
}
|
}
|
||||||
} else if (isLogin) {
|
} else if (isLogin) {
|
||||||
if (!bungeeData) {
|
if (!bungeeData) {
|
||||||
@@ -227,7 +229,7 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
|
|||||||
|
|
||||||
// set the player his GameProfile, we can't change the username without this
|
// set the player his GameProfile, we can't change the username without this
|
||||||
Object gameProfile = GAME_PROFILE_CONSTRUCTOR.newInstance(
|
Object gameProfile = GAME_PROFILE_CONSTRUCTOR.newInstance(
|
||||||
fPlayer.getCorrectUniqueId(), fPlayer.getCorrectUsername()
|
player.getCorrectUniqueId(), player.getCorrectUsername()
|
||||||
);
|
);
|
||||||
setValue(loginListener, LOGIN_PROFILE, gameProfile);
|
setValue(loginListener, LOGIN_PROFILE, gameProfile);
|
||||||
|
|
||||||
@@ -251,7 +253,7 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
|
|||||||
ctx.fireChannelRead(packet);
|
ctx.fireChannelRead(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHandshake && bungeeData || isLogin && !bungeeData || fPlayer == null) {
|
if (isHandshake && bungeeData || isLogin && !bungeeData || player == null) {
|
||||||
// we're done, we'll just wait for the loginSuccessCall
|
// we're done, we'll just wait for the loginSuccessCall
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import io.netty.util.AttributeKey;
|
|||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.inject.InjectorAddon;
|
import org.geysermc.floodgate.api.inject.InjectorAddon;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
|
||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||||
import org.geysermc.floodgate.player.HandshakeHandler;
|
import org.geysermc.floodgate.player.HandshakeHandler;
|
||||||
import org.geysermc.floodgate.util.Utils;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
@@ -51,10 +50,6 @@ public final class VelocityDataAddon implements InjectorAddon {
|
|||||||
@Named("packetEncoder")
|
@Named("packetEncoder")
|
||||||
private String packetEncoder;
|
private String packetEncoder;
|
||||||
|
|
||||||
@Inject
|
|
||||||
@Named("playerAttribute")
|
|
||||||
private AttributeKey<FloodgatePlayer> playerAttribute;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Named("kickMessageAttribute")
|
@Named("kickMessageAttribute")
|
||||||
private AttributeKey<String> kickMessageAttribute;
|
private AttributeKey<String> kickMessageAttribute;
|
||||||
@@ -71,10 +66,7 @@ public final class VelocityDataAddon implements InjectorAddon {
|
|||||||
// The handler is already added so we should add our handler before it
|
// The handler is already added so we should add our handler before it
|
||||||
channel.pipeline().addBefore(
|
channel.pipeline().addBefore(
|
||||||
packetHandler, "floodgate_data_handler",
|
packetHandler, "floodgate_data_handler",
|
||||||
new VelocityProxyDataHandler(
|
new VelocityProxyDataHandler(config, handshakeHandler, kickMessageAttribute, logger)
|
||||||
config, api, handshakeHandler, playerAttribute,
|
|
||||||
kickMessageAttribute, logger
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue;
|
import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue;
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getField;
|
import static org.geysermc.floodgate.util.ReflectionUtils.getField;
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass;
|
import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass;
|
||||||
|
import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
@@ -36,9 +37,10 @@ import io.netty.util.AttributeKey;
|
|||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||||
import org.geysermc.floodgate.player.HandshakeHandler;
|
import org.geysermc.floodgate.player.HandshakeHandler;
|
||||||
import org.geysermc.floodgate.player.HandshakeHandler.HandshakeResult;
|
import org.geysermc.floodgate.player.HandshakeHandler.HandshakeResult;
|
||||||
@@ -48,6 +50,7 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
|
|||||||
private static final Field HANDSHAKE;
|
private static final Field HANDSHAKE;
|
||||||
private static final Class<?> HANDSHAKE_PACKET;
|
private static final Class<?> HANDSHAKE_PACKET;
|
||||||
private static final Field HANDSHAKE_SERVER_ADDRESS;
|
private static final Field HANDSHAKE_SERVER_ADDRESS;
|
||||||
|
private static final Field REMOTE_ADDRESS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Class<?> iic = getPrefixedClass("connection.client.InitialInboundConnection");
|
Class<?> iic = getPrefixedClass("connection.client.InitialInboundConnection");
|
||||||
@@ -61,12 +64,13 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
|
|||||||
|
|
||||||
HANDSHAKE_SERVER_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress");
|
HANDSHAKE_SERVER_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress");
|
||||||
checkNotNull(HANDSHAKE_SERVER_ADDRESS, "Address in the Handshake packet cannot be null");
|
checkNotNull(HANDSHAKE_SERVER_ADDRESS, "Address in the Handshake packet cannot be null");
|
||||||
|
|
||||||
|
Class<?> minecraftConnection = getPrefixedClass("connection.MinecraftConnection");
|
||||||
|
REMOTE_ADDRESS = getField(minecraftConnection, "remoteAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ProxyFloodgateConfig config;
|
private final ProxyFloodgateConfig config;
|
||||||
private final ProxyFloodgateApi api;
|
|
||||||
private final HandshakeHandler handshakeHandler;
|
private final HandshakeHandler handshakeHandler;
|
||||||
private final AttributeKey<FloodgatePlayer> playerAttribute;
|
|
||||||
private final AttributeKey<String> kickMessageAttribute;
|
private final AttributeKey<String> kickMessageAttribute;
|
||||||
private final FloodgateLogger logger;
|
private final FloodgateLogger logger;
|
||||||
private boolean done;
|
private boolean done;
|
||||||
@@ -90,6 +94,13 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
|
|||||||
String address = getCastedValue(packet, HANDSHAKE_SERVER_ADDRESS);
|
String address = getCastedValue(packet, HANDSHAKE_SERVER_ADDRESS);
|
||||||
|
|
||||||
HandshakeResult result = handshakeHandler.handle(ctx.channel(), address);
|
HandshakeResult result = handshakeHandler.handle(ctx.channel(), address);
|
||||||
|
HandshakeData handshakeData = result.getHandshakeData();
|
||||||
|
|
||||||
|
if (handshakeData.getDisconnectReason() != null) {
|
||||||
|
ctx.channel().attr(kickMessageAttribute).set(handshakeData.getDisconnectReason());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (result.getResultType()) {
|
switch (result.getResultType()) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
break;
|
break;
|
||||||
@@ -99,12 +110,17 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
|
|||||||
ctx.channel().attr(kickMessageAttribute)
|
ctx.channel().attr(kickMessageAttribute)
|
||||||
.set(config.getDisconnect().getInvalidArgumentsLength());
|
.set(config.getDisconnect().getInvalidArgumentsLength());
|
||||||
return;
|
return;
|
||||||
default:
|
default: // only continue when SUCCESS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FloodgatePlayer player = result.getFloodgatePlayer();
|
FloodgatePlayer player = result.getFloodgatePlayer();
|
||||||
|
|
||||||
|
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",
|
logger.info("Floodgate player who is logged in as {} {} joined",
|
||||||
player.getCorrectUsername(), player.getCorrectUniqueId());
|
player.getCorrectUsername(), player.getCorrectUniqueId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,4 +87,9 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
|
|||||||
Configurator.setLevel(logger.getName(), Level.INFO);
|
Configurator.setLevel(logger.getName(), Level.INFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebug() {
|
||||||
|
return logger.isDebugEnabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user