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) { default List<String> suggest(@NonNull CommandSource source, @NonNull String[] currentArgs) {
return ImmutableList.of(); 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 * @param permission the permission
* @return the value the permission is set to * @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 * @param permission the permission to check for
* @return whether or not the subject has the permission * @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.EventManager;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.plugin.PluginManager;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
@ -40,6 +41,7 @@ import net.kyori.text.serializer.ComponentSerializers;
import net.kyori.text.serializer.GsonComponentSerializer; import net.kyori.text.serializer.GsonComponentSerializer;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.file.Files; import java.nio.file.Files;
@ -78,8 +80,8 @@ public class VelocityServer implements ProxyServer {
} }
@Override @Override
public boolean hasPermission(String permission) { public @NonNull Tristate getPermissionValue(@NonNull String permission) {
return true; return Tristate.TRUE;
} }
}; };
private Ratelimiter ipAttemptLimiter; private Ratelimiter ipAttemptLimiter;

View File

@ -3,6 +3,7 @@ package com.velocitypowered.proxy.command;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection; 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.ClickEvent;
import net.kyori.text.event.HoverEvent; import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor; import net.kyori.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -88,4 +90,9 @@ public class ServerCommand implements Command {
return ImmutableList.of(); 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 com.velocitypowered.proxy.VelocityServer;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor; import net.kyori.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
public class ShutdownCommand implements Command { public class ShutdownCommand implements Command {
private final VelocityServer server; private final VelocityServer server;
@ -21,4 +22,9 @@ public class ShutdownCommand implements Command {
} }
server.shutdown(); 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.Command;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent; import net.kyori.text.event.ClickEvent;
import net.kyori.text.format.TextColor; import net.kyori.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
public class VelocityCommand implements Command { public class VelocityCommand implements Command {
@Override @Override
@ -37,4 +39,9 @@ public class VelocityCommand implements Command {
source.sendMessage(velocityInfo); source.sendMessage(velocityInfo);
source.sendMessage(velocityWebsite); 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 { try {
if (!command.hasPermission(source, actualArgs)) {
return false;
}
command.execute(source, actualArgs); command.execute(source, actualArgs);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
@ -62,24 +66,29 @@ public class VelocityCommandManager implements CommandManager {
return Optional.empty(); return Optional.empty();
} }
String command = split[0]; String alias = split[0];
if (split.length == 1) { if (split.length == 1) {
return Optional.of(commands.keySet().stream() return Optional.of(commands.entrySet().stream()
.filter(cmd -> cmd.regionMatches(true, 0, command, 0, command.length())) .filter(ent -> ent.getKey().regionMatches(true, 0, alias, 0, alias.length()))
.map(cmd -> "/" + cmd) .filter(ent -> ent.getValue().hasPermission(source, new String[0]))
.map(ent -> "/" + ent.getKey())
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
String[] actualArgs = Arrays.copyOfRange(split, 1, split.length); String[] actualArgs = Arrays.copyOfRange(split, 1, split.length);
Command executor = commands.get(command); Command command = commands.get(alias.toLowerCase(Locale.ENGLISH));
if (executor == null) { if (command == null) {
return Optional.empty(); return Optional.empty();
} }
try { 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) { } 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.event.player.ServerPreConnectEvent;
import com.velocitypowered.api.permission.PermissionFunction; import com.velocitypowered.api.permission.PermissionFunction;
import com.velocitypowered.api.permission.PermissionProvider; import com.velocitypowered.api.permission.PermissionProvider;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.ConnectionRequestBuilder; import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
@ -390,8 +391,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
} }
@Override @Override
public boolean hasPermission(String permission) { public @NonNull Tristate getPermissionValue(@NonNull String permission) {
return permissionFunction.getPermissionSetting(permission).asBoolean(); return permissionFunction.getPermissionValue(permission);
} }
@Override @Override