1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-19 14:59:20 +00:00

Paper added an option to disable username validation for a connection

Co-authored-by: Camotoy <20743703+camotoy@users.noreply.github.com>
This commit is contained in:
Tim203
2022-01-18 16:57:37 +01:00
parent b6a7087dc7
commit a3e6c09166
5 changed files with 165 additions and 10 deletions

View File

@@ -28,6 +28,7 @@ package org.geysermc.floodgate;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.module.PluginMessageModule;
import org.geysermc.floodgate.module.ServerCommonModule;
@@ -35,6 +36,7 @@ import org.geysermc.floodgate.module.SpigotAddonModule;
import org.geysermc.floodgate.module.SpigotCommandModule;
import org.geysermc.floodgate.module.SpigotListenerModule;
import org.geysermc.floodgate.module.SpigotPlatformModule;
import org.geysermc.floodgate.util.SpigotHandshakeHandler;
import org.geysermc.floodgate.util.SpigotProtocolSupportHandler;
import org.geysermc.floodgate.util.SpigotProtocolSupportListener;
@@ -66,6 +68,10 @@ public final class SpigotPlugin extends JavaPlugin {
new PluginMessageModule()
);
//todo add proper support for disabling things on shutdown and enabling this on enable
injector.getInstance(HandshakeHandlers.class)
.addHandshakeHandler(injector.getInstance(SpigotHandshakeHandler.class));
// add ProtocolSupport support (hack)
if (getServer().getPluginManager().getPlugin("ProtocolSupport") != null) {
injector.getInstance(SpigotProtocolSupportHandler.class);

View File

@@ -37,10 +37,12 @@ import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
import org.geysermc.floodgate.util.ClassNames;
import org.geysermc.floodgate.util.ProxyUtils;
public final class SpigotDataHandler extends CommonDataHandler {
private Object networkManager;
private FloodgatePlayer player;
private boolean proxyData;
public SpigotDataHandler(
FloodgateHandshakeHandler handshakeHandler,
@@ -72,13 +74,18 @@ public final class SpigotDataHandler extends CommonDataHandler {
return true;
}
// Paper now has username validation, so we have to help Paper to bypass the check.
// The username is only validated in the login start packet, and that packet doesn't reach
// the server handler when we call our own login cycle.
// the server will do all the work if BungeeCord mode is enabled,
// otherwise we have to help the server.
proxyData = ProxyUtils.isProxyData();
// After internal discussion, we've decided to require assistance for all Spigot platforms,
// in case Spigot decides to add username validation as well.
return false;
if (!proxyData) {
// Use a spoofedUUID for initUUID (just like Bungeecord)
setValue(networkManager, "spoofedUUID", player.getCorrectUniqueId());
}
// we can only remove the handler if the data is proxy data and username validation doesn't
// exist. Otherwise, we need to wait and disable it.
return proxyData && ClassNames.PAPER_DISABLE_USERNAME_VALIDATION == null;
}
@Override
@@ -131,16 +138,22 @@ public final class SpigotDataHandler extends CommonDataHandler {
return true;
}
if (ClassNames.PAPER_DISABLE_USERNAME_VALIDATION != null) {
// ensure that Paper will not be checking
setValue(packetListener, ClassNames.PAPER_DISABLE_USERNAME_VALIDATION, true);
if (proxyData) {
// the server will handle the rest if we have proxy data
ctx.pipeline().remove(this);
return false;
}
}
// set the player his GameProfile, we can't change the username without this
GameProfile gameProfile = new GameProfile(
player.getCorrectUniqueId(), player.getCorrectUsername()
);
setValue(packetListener, ClassNames.LOGIN_PROFILE, gameProfile);
//todo we can remove this line + the initUUID line, but then if a skin has been sent
// from a proxy using bungee data, we won't be able to show it
setValue(networkManager, "spoofedUUID", player.getCorrectUniqueId());
// we have to fake the offline player (login) cycle
// just like on Spigot:

View File

@@ -25,6 +25,7 @@
package org.geysermc.floodgate.util;
import static org.geysermc.floodgate.util.ReflectionUtils.getField;
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
import static org.geysermc.floodgate.util.ReflectionUtils.getMethod;
@@ -37,6 +38,7 @@ import java.lang.reflect.Method;
import java.net.SocketAddress;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.checkerframework.checker.nullness.qual.Nullable;
@SuppressWarnings("PMD.SystemPrintln")
public class ClassNames {
@@ -56,6 +58,8 @@ public class ClassNames {
public static final Field HANDSHAKE_HOST;
public static final Field LOGIN_PROFILE;
public static final Field PACKET_LISTENER;
@Nullable
public static final Field PAPER_DISABLE_USERNAME_VALIDATION;
public static final Method GET_PROFILE_METHOD;
public static final Method LOGIN_DISCONNECT;
@@ -157,6 +161,13 @@ public class ClassNames {
FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents");
checkNotNull(FIRE_LOGIN_EVENTS, "fireEvents from LoginHandler");
PAPER_DISABLE_USERNAME_VALIDATION = getField(LOGIN_LISTENER,
"iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation");
if (Constants.DEBUG_MODE) {
System.out.println("Paper disable username validation field exists? " +
(PAPER_DISABLE_USERNAME_VALIDATION != null));
}
}
private static Class<?> getClassOrFallBack(String className, String fallbackName) {

View File

@@ -0,0 +1,69 @@
/*
* 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.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.util.ReflectionUtils.getField;
import java.lang.reflect.Field;
@SuppressWarnings("ConstantConditions")
public final class ProxyUtils {
private static final Field IS_BUNGEE_DATA;
private static final Field IS_MODERN_FORWARDING;
static {
Class<?> spigotConfig = ReflectionUtils.getClass("org.spigotmc.SpigotConfig");
IS_BUNGEE_DATA = getField(spigotConfig, "bungee");
checkNotNull(IS_BUNGEE_DATA, "bungee field cannot be null. Are you using CraftBukkit?");
Field velocitySupport;
try {
Class<?> paperConfig = Class.forName("com.destroystokyo.paper.PaperConfig");
velocitySupport = getField(paperConfig, "velocitySupport");
} catch (ClassNotFoundException e) {
// We're not on a platform that has modern forwarding
velocitySupport = null; // NOPMD - there's really not a better way around this unless you want to use an optional
}
IS_MODERN_FORWARDING = velocitySupport;
}
public static boolean isProxyData() {
return isBungeeData() || isVelocitySupport();
}
private static boolean isBungeeData() {
return ReflectionUtils.getCastedValue(null, IS_BUNGEE_DATA);
}
private static boolean isVelocitySupport() {
if (IS_MODERN_FORWARDING == null) {
return false;
}
return ReflectionUtils.getCastedValue(null, IS_MODERN_FORWARDING);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.util;
import com.google.inject.Inject;
import java.util.UUID;
import org.geysermc.floodgate.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.handshake.HandshakeHandler;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
public class SpigotHandshakeHandler implements HandshakeHandler {
@Inject
private FloodgateLogger logger;
@Override
public void handle(HandshakeData data) {
BedrockData bedrockData = data.getBedrockData();
UUID correctUuid = data.getCorrectUniqueId();
// replace the ip and uuid with the Bedrock client IP and an uuid based of the xuid
String[] split = data.getHostname().split("\0");
if (split.length >= 3) {
if (logger.isDebug()) {
logger.info("Replacing hostname arg1 '{}' with '{}' and arg2 '{}' with '{}'",
split[1], bedrockData.getIp(), split[2], correctUuid.toString()
);
}
split[1] = bedrockData.getIp();
split[2] = correctUuid.toString();
}
data.setHostname(String.join("\0", split));
}
}