diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/CommandNodeFactory.java b/proxy/src/main/java/com/velocitypowered/proxy/command/CommandNodeFactory.java index 5f0c9fdff..0229a43e6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/CommandNodeFactory.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/CommandNodeFactory.java @@ -46,6 +46,10 @@ public interface CommandNodeFactory { }, (context, builder) -> { String[] args = BrigadierUtils.getSplitArguments(context); + if (!command.hasPermission(context.getSource(), args)) { + return builder.buildFuture(); + } + return command.suggestAsync(context.getSource(), args).thenApply(values -> { for (String value : values) { builder.suggest(value); @@ -82,6 +86,9 @@ public interface CommandNodeFactory { (context, builder) -> { I invocation = createInvocation(context); + if (!command.hasPermission(invocation)) { + return builder.buildFuture(); + } return command.suggestAsync(invocation).thenApply(values -> { for (String value : values) { builder.suggest(value); diff --git a/proxy/src/test/java/com/velocitypowered/proxy/command/CommandManagerTests.java b/proxy/src/test/java/com/velocitypowered/proxy/command/CommandManagerTests.java index d5dc457a9..ae8fa8343 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/command/CommandManagerTests.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/command/CommandManagerTests.java @@ -25,6 +25,7 @@ import com.velocitypowered.api.command.SimpleCommand; import com.velocitypowered.proxy.plugin.MockEventManager; import com.velocitypowered.proxy.plugin.VelocityEventManager; import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.checkerframework.checker.nullness.qual.NonNull; @@ -487,6 +488,54 @@ public class CommandManagerTests { manager.offerSuggestions(MockCommandSource.INSTANCE, "foo2 baz ").join()); } + @Test + void testSuggestionPermissions() throws ExecutionException, InterruptedException { + VelocityCommandManager manager = createManager(); + RawCommand rawCommand = new RawCommand() { + @Override + public void execute(final Invocation invocation) { + fail("The Command should not be executed while testing suggestions"); + } + + @Override + public boolean hasPermission(Invocation invocation) { + return invocation.arguments().length() > 0; + } + + @Override + public List suggest(final Invocation invocation) { + return ImmutableList.of("suggestion"); + } + }; + + manager.register(rawCommand, "foo"); + + assertTrue(manager.offerSuggestions(MockCommandSource.INSTANCE, "foo").get().isEmpty()); + assertFalse(manager.offerSuggestions(MockCommandSource.INSTANCE, "foo bar").get().isEmpty()); + + Command oldCommand = new Command() { + @Override + public void execute(CommandSource source, String @NonNull [] args) { + fail("The Command should not be executed while testing suggestions"); + } + + @Override + public boolean hasPermission(CommandSource source, String @NonNull [] args) { + return args.length > 0; + } + + @Override + public List suggest(CommandSource source, String @NonNull [] currentArgs) { + return ImmutableList.of("suggestion"); + } + }; + + manager.register(oldCommand, "bar"); + + assertTrue(manager.offerSuggestions(MockCommandSource.INSTANCE, "bar").get().isEmpty()); + assertFalse(manager.offerSuggestions(MockCommandSource.INSTANCE, "bar foo").get().isEmpty()); + } + static class NoopSimpleCommand implements SimpleCommand { @Override public void execute(final Invocation invocation) {