Merge pull request #99 from lucko/feature/command-permissions

Implement optional permission check method for commands
This commit is contained in:
Andrew Steinborn 2018-09-21 16:06:50 -04:00 committed by GitHub
commit ef578ff69b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 71 additions and 14 deletions

View File

@ -26,4 +26,19 @@ public interface Command {
default List<String> suggest(@NonNull CommandSource source, @NonNull String[] currentArgs) {
return ImmutableList.of();
}
/**
* Tests to check if the {@code source} has permission to use this command
* with the provided {@code args}.
*
* <p>If this method returns false, the handling will be forwarded onto
* the players current server.</p>
*
* @param source the source of the command
* @param args the arguments for this command
* @return whether the source has permission
*/
default boolean hasPermission(@NonNull CommandSource source, @NonNull String[] args) {
return true;
}
}

View File

@ -29,5 +29,5 @@ public interface PermissionFunction {
* @param permission the permission
* @return the value the permission is set to
*/
@NonNull Tristate getPermissionSetting(@NonNull String permission);
@NonNull Tristate getPermissionValue(@NonNull String permission);
}

View File

@ -12,5 +12,15 @@ public interface PermissionSubject {
* @param permission the permission to check for
* @return whether or not the subject has the permission
*/
boolean hasPermission(@NonNull String permission);
default boolean hasPermission(@NonNull String permission) {
return getPermissionValue(permission).asBoolean();
}
/**
* Gets the subjects setting for a particular permission.
*
* @param permission the permission
* @return the value the permission is set to
*/
@NonNull Tristate getPermissionValue(@NonNull String permission);
}

View File

@ -8,6 +8,7 @@ import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.plugin.PluginManager;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
@ -40,6 +41,7 @@ import net.kyori.text.serializer.ComponentSerializers;
import net.kyori.text.serializer.GsonComponentSerializer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.net.InetSocketAddress;
import java.nio.file.Files;
@ -78,8 +80,8 @@ public class VelocityServer implements ProxyServer {
}
@Override
public boolean hasPermission(String permission) {
return true;
public @NonNull Tristate getPermissionValue(@NonNull String permission) {
return Tristate.TRUE;
}
};
private Ratelimiter ipAttemptLimiter;

View File

@ -3,6 +3,7 @@ package com.velocitypowered.proxy.command;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection;
@ -12,6 +13,7 @@ import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
import java.util.Optional;
@ -88,4 +90,9 @@ public class ServerCommand implements Command {
return ImmutableList.of();
}
}
@Override
public boolean hasPermission(@NonNull CommandSource source, @NonNull String[] args) {
return source.getPermissionValue("velocity.command.server") != Tristate.FALSE;
}
}

View File

@ -5,6 +5,7 @@ import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.proxy.VelocityServer;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
public class ShutdownCommand implements Command {
private final VelocityServer server;
@ -21,4 +22,9 @@ public class ShutdownCommand implements Command {
}
server.shutdown();
}
@Override
public boolean hasPermission(@NonNull CommandSource source, @NonNull String[] args) {
return source == server.getConsoleCommandSource();
}
}

View File

@ -2,10 +2,12 @@ package com.velocitypowered.proxy.command;
import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.proxy.VelocityServer;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
public class VelocityCommand implements Command {
@Override
@ -37,4 +39,9 @@ public class VelocityCommand implements Command {
source.sendMessage(velocityInfo);
source.sendMessage(velocityWebsite);
}
@Override
public boolean hasPermission(@NonNull CommandSource source, @NonNull String[] args) {
return source.getPermissionValue("velocity.command.info") != Tristate.FALSE;
}
}

View File

@ -46,6 +46,10 @@ public class VelocityCommandManager implements CommandManager {
}
try {
if (!command.hasPermission(source, actualArgs)) {
return false;
}
command.execute(source, actualArgs);
return true;
} catch (Exception e) {
@ -62,24 +66,29 @@ public class VelocityCommandManager implements CommandManager {
return Optional.empty();
}
String command = split[0];
String alias = split[0];
if (split.length == 1) {
return Optional.of(commands.keySet().stream()
.filter(cmd -> cmd.regionMatches(true, 0, command, 0, command.length()))
.map(cmd -> "/" + cmd)
return Optional.of(commands.entrySet().stream()
.filter(ent -> ent.getKey().regionMatches(true, 0, alias, 0, alias.length()))
.filter(ent -> ent.getValue().hasPermission(source, new String[0]))
.map(ent -> "/" + ent.getKey())
.collect(Collectors.toList()));
}
String[] actualArgs = Arrays.copyOfRange(split, 1, split.length);
Command executor = commands.get(command);
if (executor == null) {
Command command = commands.get(alias.toLowerCase(Locale.ENGLISH));
if (command == null) {
return Optional.empty();
}
try {
return Optional.of(executor.suggest(source, actualArgs));
if (!command.hasPermission(source, actualArgs)) {
return Optional.empty();
}
return Optional.of(command.suggest(source, actualArgs));
} catch (Exception e) {
throw new RuntimeException("Unable to invoke suggestions for command " + command + " for " + source, e);
throw new RuntimeException("Unable to invoke suggestions for command " + alias + " for " + source, e);
}
}
}

View File

@ -7,6 +7,7 @@ import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
import com.velocitypowered.api.permission.PermissionFunction;
import com.velocitypowered.api.permission.PermissionProvider;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
@ -390,8 +391,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
}
@Override
public boolean hasPermission(String permission) {
return permissionFunction.getPermissionSetting(permission).asBoolean();
public @NonNull Tristate getPermissionValue(@NonNull String permission) {
return permissionFunction.getPermissionValue(permission);
}
@Override