From 3f88f20272ee0a663f77d9e3be8614771045f328 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 31 Oct 2021 19:46:51 -0400 Subject: [PATCH] Refactor perms and upstream (#35) * refactor permissions * upstream * remove shutdown from the command list * make FabricWorldManager#getPlayer() private --- .../platform/fabric/GeyserFabricMod.java | 28 ++++++++++----- .../fabric/GeyserFabricPermissions.java | 7 ++++ .../fabric/command/FabricCommandSender.java | 15 ++++++++ .../command/GeyserFabricCommandExecutor.java | 35 ++++++++++++++----- .../world/GeyserFabricWorldManager.java | 21 ++++++++++- .../fabric/src/main/resources/permissions.yml | 6 ++-- 6 files changed, 93 insertions(+), 19 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 0ff2a0123..339c5a9e9 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -67,9 +67,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private GeyserConnector connector; private Path dataFolder; - private List playerCommands; private MinecraftServer server; + /** + * Commands that don't require any permission level to ran + */ + private List playerCommands; + private final List commandExecutors = new ArrayList<>(); + private GeyserFabricCommandManager geyserCommandManager; private GeyserFabricConfiguration geyserConfig; private GeyserFabricLogger geyserLogger; @@ -167,14 +172,17 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { // Start command building // Set just "geyser" as the help command - LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") - .executes(new GeyserFabricCommandExecutor(connector, connector.getCommandManager().getCommands().get("help"), - !playerCommands.contains("help"))); + GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(connector, + connector.getCommandManager().getCommands().get("help"), !playerCommands.contains("help")); + commandExecutors.add(helpExecutor); + LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser").executes(helpExecutor); + + // Register all subcommands as valid for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { - // Register all subcommands as valid - builder.then(net.minecraft.server.command.CommandManager.literal( - command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getValue(), - !playerCommands.contains(command.getKey())))); + GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(connector, command.getValue(), + !playerCommands.contains(command.getKey())); + commandExecutors.add(executor); + builder.then(net.minecraft.server.command.CommandManager.literal(command.getKey()).executes(executor)); } server.getCommandManager().getDispatcher().register(builder); } @@ -258,6 +266,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { return file; } + public List getCommandExecutors() { + return commandExecutors; + } + public static GeyserFabricMod getInstance() { return instance; } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java index 1a446bca6..fc08b052a 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java @@ -25,6 +25,7 @@ package org.geysermc.platform.fabric; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -34,6 +35,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) public class GeyserFabricPermissions { + /** + * The minimum permission level a command source must have in order for it to run commands that are restricted + */ + @JsonIgnore + public static final int RESTRICTED_MIN_LEVEL = 2; + @JsonProperty("commands") private String[] commands; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java index d49a07625..1dbec0492 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -31,6 +31,7 @@ import net.minecraft.text.LiteralText; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.ChatColor; +import org.geysermc.platform.fabric.GeyserFabricMod; public class FabricCommandSender implements CommandSender { @@ -58,4 +59,18 @@ public class FabricCommandSender implements CommandSender { public boolean isConsole() { return !(source.getEntity() instanceof ServerPlayerEntity); } + + @Override + public boolean hasPermission(String s) { + // Mostly copied from fabric's world manager since the method there takes a GeyserSession + + // Workaround for our commands because fabric doesn't have native permissions + for (GeyserFabricCommandExecutor executor : GeyserFabricMod.getInstance().getCommandExecutors()) { + if (executor.getCommand().getPermission().equals(s)) { + return executor.canRun(source); + } + } + + return false; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java index a8469364f..bd2cdcad2 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -35,6 +35,7 @@ import org.geysermc.connector.common.ChatColor; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.GeyserFabricMod; +import org.geysermc.platform.fabric.GeyserFabricPermissions; public class GeyserFabricCommandExecutor extends CommandExecutor implements Command { @@ -50,11 +51,22 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm this.requiresPermission = requiresPermission; } + /** + * Determine whether or not a command source is allowed to run a given executor. + * + * @param source The command source attempting to run the command + * @return True if the command source is allowed to + */ + public boolean canRun(ServerCommandSource source) { + return !requiresPermission() || source.hasPermissionLevel(GeyserFabricPermissions.RESTRICTED_MIN_LEVEL); + } + @Override public int run(CommandContext context) { ServerCommandSource source = (ServerCommandSource) context.getSource(); FabricCommandSender sender = new FabricCommandSender(source); - if (requiresPermission && !source.hasPermissionLevel(2)) { + GeyserSession session = getGeyserSession(sender); + if (!canRun(source)) { sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); return 0; } @@ -62,15 +74,22 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm GeyserFabricMod.getInstance().setReloading(true); } - GeyserSession session = null; - if (command.isBedrockOnly()) { - session = getGeyserSession(sender); - if (session == null) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); - return 0; - } + if (command.isBedrockOnly() && session == null) { + sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); + return 0; } command.execute(session, sender, new String[0]); return 0; } + + public GeyserCommand getCommand() { + return command; + } + + /** + * Returns whether the command requires permission level of {@link GeyserFabricPermissions#RESTRICTED_MIN_LEVEL} or higher to be ran + */ + public boolean requiresPermission() { + return requiresPermission; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java index dd0d629c8..412266bb4 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java @@ -42,6 +42,8 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.network.translators.world.GeyserWorldManager; import org.geysermc.connector.utils.BlockEntityUtils; +import org.geysermc.platform.fabric.GeyserFabricMod; +import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import java.util.ArrayList; import java.util.List; @@ -63,7 +65,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { Runnable lecternGet = () -> { // Mostly a reimplementation of Spigot lectern support - PlayerEntity player = server.getPlayerManager().getPlayer(session.getPlayerEntity().getUuid()); + PlayerEntity player = getPlayer(session); if (player != null) { BlockEntity blockEntity = player.world.getBlockEntity(new BlockPos(x, y, z)); if (!(blockEntity instanceof LecternBlockEntity lectern)) { @@ -119,4 +121,21 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { } return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); } + + @Override + public boolean hasPermission(GeyserSession session, String permission) { + + // Workaround for our commands because fabric doesn't have native permissions + for (GeyserFabricCommandExecutor executor : GeyserFabricMod.getInstance().getCommandExecutors()) { + if (executor.getCommand().getPermission().equals(permission)) { + return executor.canRun(getPlayer(session).getCommandSource()); + } + } + + return false; + } + + private PlayerEntity getPlayer(GeyserSession session) { + return server.getPlayerManager().getPlayer(session.getPlayerEntity().getUuid()); + } } diff --git a/bootstrap/fabric/src/main/resources/permissions.yml b/bootstrap/fabric/src/main/resources/permissions.yml index a51d3169a..8a995f8dc 100644 --- a/bootstrap/fabric/src/main/resources/permissions.yml +++ b/bootstrap/fabric/src/main/resources/permissions.yml @@ -1,10 +1,12 @@ # Uncomment any commands that you wish to be run by clients # Commented commands require an OP permission of 2 or greater commands: -# - dump - help + - advancements + - statistics + - settings - offhand # - list # - reload -# - shutdown # - version +# - dump \ No newline at end of file