1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-29 03:39:22 +00:00

Feature: Forward commands with no permission to the backend server on Standalone/ViaProxy (#5566)

* Feature: Forward commands with no permission to the backend server on Standalone/ViaProxy

* Address review
This commit is contained in:
chris
2025-06-08 18:39:10 +02:00
committed by GitHub
parent 8442728677
commit 726bd86d92
3 changed files with 45 additions and 23 deletions

View File

@@ -97,6 +97,9 @@ public class CommandRegistry implements EventRegistrar {
private static final String GEYSER_ROOT_PERMISSION = "geyser.command";
public final static boolean STANDALONE_COMMAND_MANAGER = GeyserImpl.getInstance().getPlatformType() == PlatformType.STANDALONE ||
GeyserImpl.getInstance().getPlatformType() == PlatformType.VIAPROXY;
protected final GeyserImpl geyser;
private final CommandManager<GeyserCommandSource> cloud;
private final boolean applyRootPermission;
@@ -274,12 +277,15 @@ public class CommandRegistry implements EventRegistrar {
cloud.command(builder.handler(context -> {
GeyserCommandSource source = context.sender();
if (!source.hasPermission(help.permission())) {
// delegate if possible - otherwise we have nothing else to offer the user.
if (source.hasPermission(help.permission())) {
// Delegate to help if possible
help.execute(source);
} else if (STANDALONE_COMMAND_MANAGER && source instanceof GeyserSession session) {
// If we are on an appropriate platform, forward the command to the backend
session.sendCommand(context.rawInput().input());
} else {
source.sendLocaleString(ExceptionHandlers.PERMISSION_FAIL_LANG_KEY);
return;
}
help.execute(source);
}));
}

View File

@@ -28,10 +28,12 @@ package org.geysermc.geyser.command;
import io.leangen.geantyref.GenericTypeReflector;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.exception.ArgumentParseException;
import org.incendo.cloud.exception.CommandExecutionException;
import org.incendo.cloud.exception.InvalidCommandSenderException;
@@ -71,36 +73,51 @@ final class ExceptionHandlers {
controller.clearHandlers();
registerExceptionHandler(InvalidSyntaxException.class,
(src, e) -> src.sendLocaleString("geyser.command.invalid_syntax", e.correctSyntax()));
(ctx, e) -> ctx.sender().sendLocaleString("geyser.command.invalid_syntax", e.correctSyntax()));
registerExceptionHandler(InvalidCommandSenderException.class, (src, e) -> {
registerExceptionHandler(InvalidCommandSenderException.class, (ctx, e) -> {
// We currently don't use cloud sender type requirements anywhere.
// This can be implemented better in the future if necessary.
Type type = e.requiredSenderTypes().iterator().next(); // just grab the first
String typeString = GenericTypeReflector.getTypeName(type);
src.sendLocaleString("geyser.command.invalid_sender", e.commandSender().getClass().getSimpleName(), typeString);
ctx.sender().sendLocaleString("geyser.command.invalid_sender", e.commandSender().getClass().getSimpleName(), typeString);
});
registerExceptionHandler(NoPermissionException.class, ExceptionHandlers::handleNoPermission);
registerExceptionHandler(NoSuchCommandException.class,
(src, e) -> src.sendLocaleString("geyser.command.not_found"));
(ctx, e) -> {
// Let backend server receive & handle the command
if (CommandRegistry.STANDALONE_COMMAND_MANAGER && ctx.sender() instanceof GeyserSession session) {
session.sendCommand(ctx.rawInput().input());
} else {
ctx.sender().sendLocaleString("geyser.command.not_found");
}
});
registerExceptionHandler(ArgumentParseException.class,
(src, e) -> src.sendLocaleString("geyser.command.invalid_argument", e.getCause().getMessage()));
(ctx, e) -> ctx.sender().sendLocaleString("geyser.command.invalid_argument", e.getCause().getMessage()));
registerExceptionHandler(CommandExecutionException.class,
(src, e) -> handleUnexpectedThrowable(src, e.getCause()));
(ctx, e) -> handleUnexpectedThrowable(ctx.sender(), e.getCause()));
registerExceptionHandler(Throwable.class,
(src, e) -> handleUnexpectedThrowable(src, e.getCause()));
(ctx, e) -> handleUnexpectedThrowable(ctx.sender(), e.getCause()));
}
private <E extends Throwable> void registerExceptionHandler(Class<E> type, BiConsumer<GeyserCommandSource, E> handler) {
controller.registerHandler(type, context -> handler.accept(context.context().sender(), context.exception()));
private <E extends Throwable> void registerExceptionHandler(Class<E> type, BiConsumer<CommandContext<GeyserCommandSource>, E> handler) {
controller.registerHandler(type, context -> handler.accept(context.context(), context.exception()));
}
private static void handleNoPermission(GeyserCommandSource source, NoPermissionException exception) {
private static void handleNoPermission(CommandContext<GeyserCommandSource> context, NoPermissionException exception) {
GeyserCommandSource source = context.sender();
// Let backend server receive & handle the command
if (CommandRegistry.STANDALONE_COMMAND_MANAGER && source instanceof GeyserSession session) {
session.sendCommand(context.rawInput().input());
return;
}
// custom handling if the source can't use the command because of additional requirements
if (exception.permissionResult() instanceof GeyserPermission.Result result) {
if (result.meta() == GeyserPermission.Result.Meta.NOT_BEDROCK) {

View File

@@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.bedrock;
import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.command.CommandRegistry;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
@@ -44,10 +43,12 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
}
static void handleCommand(GeyserSession session, String command) {
if (session.getGeyser().getPlatformType() == PlatformType.STANDALONE ||
session.getGeyser().getPlatformType() == PlatformType.VIAPROXY) {
// try to handle the command within the standalone/viaproxy command manager
if (MessageTranslator.isTooLong(command, session)) {
return;
}
if (CommandRegistry.STANDALONE_COMMAND_MANAGER) {
// try to handle the command within the standalone/viaproxy command manager
String[] args = command.split(" ");
if (args.length > 0) {
String root = args[0];
@@ -55,15 +56,13 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
CommandRegistry registry = GeyserImpl.getInstance().commandRegistry();
if (registry.rootCommands().contains(root)) {
registry.runCommand(session, command);
return; // don't pass the command to the java server
// don't pass the command to the java server here
// will pass it through later if the user lacks permission
return;
}
}
}
if (MessageTranslator.isTooLong(command, session)) {
return;
}
session.sendCommand(command);
}
}