mirror of https://github.com/Minestom/Minestom.git
Command argument signing, TODO: Check where is it necessary to pass the signature to the context
This commit is contained in:
parent
e77050936f
commit
4a04d16bad
|
@ -1,6 +1,7 @@
|
|||
package net.minestom.demo;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
@ -8,12 +9,15 @@ import net.kyori.adventure.text.format.TextDecoration;
|
|||
import net.minestom.demo.commands.*;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.event.player.PlayerChatEvent;
|
||||
import net.minestom.server.event.player.PlayerChatPreviewEvent;
|
||||
import net.minestom.server.event.server.ServerListPingEvent;
|
||||
import net.minestom.server.extras.lan.OpenToLAN;
|
||||
import net.minestom.server.extras.lan.OpenToLANConfig;
|
||||
import net.minestom.server.extras.optifine.OptifineSupport;
|
||||
import net.minestom.server.instance.block.BlockManager;
|
||||
import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule;
|
||||
import net.minestom.server.message.MessageSender;
|
||||
import net.minestom.server.ping.ResponseData;
|
||||
import net.minestom.server.utils.identity.NamedAndIdentified;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
|
@ -52,6 +56,8 @@ public class Main {
|
|||
commandManager.register(new AutoViewCommand());
|
||||
commandManager.register(new SaveCommand());
|
||||
commandManager.register(new GamemodeCommand());
|
||||
commandManager.register(new CommandSignTest());
|
||||
commandManager.register(new ChatPreviewCommand());
|
||||
|
||||
|
||||
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
|
||||
|
@ -92,6 +98,22 @@ public class Main {
|
|||
// on legacy versions, colors will be converted to the section format so it'll work there too
|
||||
responseData.setDescription(Component.text("This is a Minestom Server", TextColor.color(0x66b3ff)));
|
||||
//responseData.setPlayersHidden(true);
|
||||
}).addListener(PlayerChatPreviewEvent.class, e -> {
|
||||
if (e.getQuery().contains("!")) {
|
||||
e.setResult(null);
|
||||
} else {
|
||||
e.setResult(Component.empty()
|
||||
.append(Component.text("PREPEND>", TextColor.color(255,0,255)))
|
||||
.append(Component.text(e.getQuery()))
|
||||
.append(Component.text("<APPEND", TextColor.color(255,0,255))));
|
||||
// e.setResult(Component.text(e.getQuery(), NamedTextColor.BLACK));
|
||||
}
|
||||
}).addListener(PlayerChatEvent.class, e -> {
|
||||
final MessageSender s = e.getSender();
|
||||
e.setSender(new MessageSender(
|
||||
s.displayName().clickEvent(ClickEvent.suggestCommand("/msg "+e.getPlayer().getUsername())).color(NamedTextColor.DARK_GREEN),
|
||||
Component.text("Team Name").color(NamedTextColor.GOLD)
|
||||
));
|
||||
});
|
||||
|
||||
PlayerInit.init();
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentType;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.ArgumentMessage;
|
||||
import net.minestom.server.crypto.MessageSignature;
|
||||
import net.minestom.server.crypto.SignatureValidator;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.message.ChatPosition;
|
||||
import net.minestom.server.message.Messenger;
|
||||
|
||||
public class CommandSignTest extends Command {
|
||||
private static final ArgumentMessage message = ArgumentType.Message("message");
|
||||
|
||||
public CommandSignTest() {
|
||||
super("sign");
|
||||
|
||||
addSyntax(((sender, context) -> {
|
||||
if (sender instanceof Player player) {
|
||||
final MessageSignature signature = context.getSignature().signatureOf(message, player.getUuid());
|
||||
final SignatureValidator validator = SignatureValidator.from(player);
|
||||
Messenger.sendSystemMessage(player,
|
||||
Component.text("Signature details: preview: ")
|
||||
.append(formatBoolean(context.getSignature().signedPreview()))
|
||||
.append(Component.text(", argument: "))
|
||||
.append(format(SignatureValidator.validate(validator, signature, Component.text(context.get(message)))))
|
||||
.append(Component.text(", preview: "))
|
||||
.append(format(SignatureValidator.validate(validator, signature, player.getLastPreviewedMessage()))),
|
||||
ChatPosition.CHAT);
|
||||
} else {
|
||||
// TODO Handle this case
|
||||
}
|
||||
}), message);
|
||||
}
|
||||
|
||||
private static Component format(boolean valid) {
|
||||
return valid ? Component.text("valid", NamedTextColor.GREEN) : Component.text("invalid", NamedTextColor.RED);
|
||||
}
|
||||
|
||||
private static Component formatBoolean(boolean value) {
|
||||
return value ? Component.text("true", NamedTextColor.GREEN) : Component.text("false", NamedTextColor.RED);
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ import java.util.*;
|
|||
/**
|
||||
* Manager used to register {@link Command commands}.
|
||||
* <p>
|
||||
* It is also possible to simulate a command using {@link #execute(CommandSender, String)}.
|
||||
* It is also possible to simulate a command using {@link #execute(CommandSender, String, ArgumentsSignature)}.
|
||||
*/
|
||||
public final class CommandManager {
|
||||
|
||||
|
@ -97,17 +97,17 @@ public final class CommandManager {
|
|||
* @param command the raw command string (without the command prefix)
|
||||
* @return the execution result
|
||||
*/
|
||||
public @NotNull CommandResult execute(@NotNull CommandSender sender, @NotNull String command) {
|
||||
public @NotNull CommandResult execute(@NotNull CommandSender sender, @NotNull String command, @Nullable ArgumentsSignature signature) {
|
||||
// Command event
|
||||
if (sender instanceof Player player) {
|
||||
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command);
|
||||
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command, signature);
|
||||
EventDispatcher.call(playerCommandEvent);
|
||||
if (playerCommandEvent.isCancelled())
|
||||
return CommandResult.of(CommandResult.Type.CANCELLED, command);
|
||||
command = playerCommandEvent.getCommand();
|
||||
}
|
||||
// Process the command
|
||||
final CommandResult result = dispatcher.execute(sender, command);
|
||||
final CommandResult result = dispatcher.execute(sender, command, signature);
|
||||
if (result.getType() == CommandResult.Type.UNKNOWN) {
|
||||
if (unknownCommandCallback != null) {
|
||||
this.unknownCommandCallback.apply(sender, command);
|
||||
|
@ -120,10 +120,10 @@ public final class CommandManager {
|
|||
* Executes the command using a {@link ServerSender}. This can be used
|
||||
* to run a silent command (nothing is printed to console).
|
||||
*
|
||||
* @see #execute(CommandSender, String)
|
||||
* @see #execute(CommandSender, String, ArgumentsSignature)
|
||||
*/
|
||||
public @NotNull CommandResult executeServerCommand(@NotNull String command) {
|
||||
return execute(serverSender, command);
|
||||
return execute(serverSender, command, null);
|
||||
}
|
||||
|
||||
public @NotNull CommandDispatcher getDispatcher() {
|
||||
|
@ -210,7 +210,7 @@ public final class CommandManager {
|
|||
}
|
||||
|
||||
final ArgumentQueryResult queryResult = CommandParser.findEligibleArgument(commandQueryResult.command(),
|
||||
commandQueryResult.args(), input, false, true, syntax -> true, argument -> true);
|
||||
commandQueryResult.args(), input, false, true, syntax -> true, argument -> true, null);
|
||||
if (queryResult == null) {
|
||||
// Invalid argument, return command node (default to root)
|
||||
final int commandNode = commandIdentityMap.getOrDefault(commandQueryResult.command(), 0);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.minestom.server.command.builder;
|
||||
|
||||
import net.minestom.server.command.ArgumentsSignature;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -25,10 +26,16 @@ public class CommandContext {
|
|||
protected Map<String, Object> args = new HashMap<>();
|
||||
protected Map<String, String> rawArgs = new HashMap<>();
|
||||
private CommandData returnData;
|
||||
private final @Nullable ArgumentsSignature signature;
|
||||
|
||||
public CommandContext(@NotNull String input) {
|
||||
public CommandContext(@NotNull String input, @Nullable ArgumentsSignature signature) {
|
||||
this.input = input;
|
||||
this.commandName = input.split(StringUtils.SPACE)[0];
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public @Nullable ArgumentsSignature getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public @NotNull String getInput() {
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.minestom.server.command.builder;
|
|||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
||||
import net.minestom.server.command.ArgumentsSignature;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
|
@ -87,11 +88,11 @@ public class CommandDispatcher {
|
|||
* @param commandString the command with the argument(s)
|
||||
* @return the command result
|
||||
*/
|
||||
public @NotNull CommandResult execute(@NotNull CommandSender source, @NotNull String commandString) {
|
||||
CommandResult commandResult = parse(commandString);
|
||||
public @NotNull CommandResult execute(@NotNull CommandSender source, @NotNull String commandString, @Nullable ArgumentsSignature signature) {
|
||||
CommandResult commandResult = parse(commandString, signature);
|
||||
ParsedCommand parsedCommand = commandResult.parsedCommand;
|
||||
if (parsedCommand != null) {
|
||||
commandResult.commandData = parsedCommand.execute(source);
|
||||
commandResult.commandData = parsedCommand.execute(source, signature);
|
||||
}
|
||||
return commandResult;
|
||||
}
|
||||
|
@ -102,7 +103,7 @@ public class CommandDispatcher {
|
|||
* @param commandString the command (containing the command name and the args if any)
|
||||
* @return the parsing result
|
||||
*/
|
||||
public @NotNull CommandResult parse(@NotNull String commandString) {
|
||||
public @NotNull CommandResult parse(@NotNull String commandString, @Nullable ArgumentsSignature signature) {
|
||||
commandString = commandString.trim();
|
||||
// Verify if the result is cached
|
||||
{
|
||||
|
@ -124,7 +125,7 @@ public class CommandDispatcher {
|
|||
CommandResult result = new CommandResult();
|
||||
result.input = commandString;
|
||||
// Find the used syntax and fill CommandResult#type and CommandResult#parsedCommand
|
||||
findParsedCommand( commandQueryResult, commandName, commandString, result);
|
||||
findParsedCommand( commandQueryResult, commandName, commandString, result, signature);
|
||||
|
||||
// Cache result
|
||||
this.cache.put(commandString, result);
|
||||
|
@ -135,7 +136,8 @@ public class CommandDispatcher {
|
|||
private @NotNull ParsedCommand findParsedCommand(@NotNull CommandQueryResult commandQueryResult,
|
||||
@NotNull String commandName,
|
||||
@NotNull String commandString,
|
||||
@NotNull CommandResult result) {
|
||||
@NotNull CommandResult result,
|
||||
@Nullable ArgumentsSignature signature) {
|
||||
final Command command = commandQueryResult.command();
|
||||
String[] args = commandQueryResult.args();
|
||||
final boolean hasArgument = args.length > 0;
|
||||
|
@ -159,7 +161,7 @@ public class CommandDispatcher {
|
|||
final CommandSyntax syntax = optionalSyntax.get();
|
||||
parsedCommand.syntax = syntax;
|
||||
parsedCommand.executor = syntax.getExecutor();
|
||||
parsedCommand.context = new CommandContext(input);
|
||||
parsedCommand.context = new CommandContext(input, signature);
|
||||
|
||||
result.type = CommandResult.Type.SUCCESS;
|
||||
result.parsedCommand = parsedCommand;
|
||||
|
@ -169,7 +171,7 @@ public class CommandDispatcher {
|
|||
final CommandExecutor defaultExecutor = command.getDefaultExecutor();
|
||||
if (defaultExecutor != null) {
|
||||
parsedCommand.executor = defaultExecutor;
|
||||
parsedCommand.context = new CommandContext(input);
|
||||
parsedCommand.context = new CommandContext(input, signature);
|
||||
|
||||
result.type = CommandResult.Type.SUCCESS;
|
||||
result.parsedCommand = parsedCommand;
|
||||
|
@ -194,7 +196,7 @@ public class CommandDispatcher {
|
|||
|
||||
// Check if there is at least one correct syntax
|
||||
if (!validSyntaxes.isEmpty()) {
|
||||
CommandContext context = new CommandContext(input);
|
||||
CommandContext context = new CommandContext(input, signature);
|
||||
// Search the syntax with all perfect args
|
||||
final ValidSyntaxHolder finalValidSyntax = CommandParser.findMostCorrectSyntax(validSyntaxes, context);
|
||||
if (finalValidSyntax != null) {
|
||||
|
@ -233,7 +235,7 @@ public class CommandDispatcher {
|
|||
|
||||
// No syntax found
|
||||
result.type = CommandResult.Type.INVALID_SYNTAX;
|
||||
result.parsedCommand = ParsedCommand.withDefaultExecutor(command, input);
|
||||
result.parsedCommand = ParsedCommand.withDefaultExecutor(command, input, signature);
|
||||
return result.parsedCommand;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.minestom.server.command.builder;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.ArgumentsSignature;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.condition.CommandCondition;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
|
@ -39,9 +40,9 @@ public class ParsedCommand {
|
|||
* @param source the command source
|
||||
* @return the command data, null if none
|
||||
*/
|
||||
public @Nullable CommandData execute(@NotNull CommandSender source) {
|
||||
public @Nullable CommandData execute(@NotNull CommandSender source, @Nullable ArgumentsSignature signature) {
|
||||
// Global listener
|
||||
command.globalListener(source, Objects.requireNonNullElseGet(context, () -> new CommandContext(commandString)), commandString);
|
||||
command.globalListener(source, Objects.requireNonNullElseGet(context, () -> new CommandContext(commandString, signature)), commandString);
|
||||
// Command condition check
|
||||
{
|
||||
// Parents
|
||||
|
@ -98,12 +99,12 @@ public class ParsedCommand {
|
|||
return context.getReturnData();
|
||||
}
|
||||
|
||||
public static @NotNull ParsedCommand withDefaultExecutor(@NotNull Command command, @NotNull String input) {
|
||||
public static @NotNull ParsedCommand withDefaultExecutor(@NotNull Command command, @NotNull String input, @Nullable ArgumentsSignature signature) {
|
||||
ParsedCommand parsedCommand = new ParsedCommand();
|
||||
parsedCommand.command = command;
|
||||
parsedCommand.commandString = input;
|
||||
parsedCommand.executor = command.getDefaultExecutor();
|
||||
parsedCommand.context = new CommandContext(input);
|
||||
parsedCommand.context = new CommandContext(input, signature);
|
||||
return parsedCommand;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public class ArgumentCommand extends Argument<CommandResult> {
|
|||
shortcut + StringUtils.SPACE + input
|
||||
: input;
|
||||
CommandDispatcher dispatcher = MinecraftServer.getCommandManager().getDispatcher();
|
||||
CommandResult result = dispatcher.parse(commandString);
|
||||
CommandResult result = dispatcher.parse(commandString, null);
|
||||
|
||||
if (onlyCorrect && result.getType() != CommandResult.Type.SUCCESS)
|
||||
throw new ArgumentSyntaxException("Invalid command", input, INVALID_COMMAND_ERROR);
|
||||
|
|
|
@ -28,7 +28,7 @@ public class ArgumentGroup extends Argument<CommandContext> {
|
|||
List<ValidSyntaxHolder> validSyntaxes = new ArrayList<>();
|
||||
CommandParser.parse(null, group, input.split(StringUtils.SPACE), input, validSyntaxes, null);
|
||||
|
||||
CommandContext context = new CommandContext(input);
|
||||
CommandContext context = new CommandContext(input, null);
|
||||
CommandParser.findMostCorrectSyntax(validSyntaxes, context);
|
||||
if (validSyntaxes.isEmpty()) {
|
||||
throw new ArgumentSyntaxException("Invalid arguments", input, INVALID_ARGUMENTS_ERROR);
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package net.minestom.server.command.builder.arguments;
|
||||
|
||||
import net.minestom.server.command.builder.arguments.minecraft.*;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.*;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentEnchantment;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentEntityType;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentParticle;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentPotionEffect;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentDouble;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentFloat;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentInteger;
|
||||
|
@ -268,4 +271,11 @@ public class ArgumentType {
|
|||
public static ArgumentEntity Entities(@NotNull String id) {
|
||||
return new ArgumentEntity(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ArgumentMessage
|
||||
*/
|
||||
public static ArgumentMessage Message(@NotNull String id) {
|
||||
return new ArgumentMessage(id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package net.minestom.server.command.builder.arguments.minecraft;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.command.builder.NodeMaker;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.crypto.MessageSignature;
|
||||
import net.minestom.server.crypto.SignatureValidator;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This argument type enables chat preview of the entire command while editing
|
||||
* the node with this type. Although the protocol allows multiple signed arguments this is the only
|
||||
* type that supports it and the clientside parser takes the remaining string for this type, so
|
||||
* it is impossible to have any more arguments after this one.<p>
|
||||
* The signature verification happens by first acquiring a {@link net.minestom.server.crypto.SignatureValidator
|
||||
* SignatureValidator} for the sender by using {@link net.minestom.server.crypto.SignatureValidator#from(Player)},
|
||||
* after that the verification happens with {@link net.minestom.server.crypto.SignatureValidator#validate(SignatureValidator, MessageSignature, Component)}
|
||||
* where the component is either the string value of this argument wrapped in {@link Component#text(String)} or
|
||||
* {@link Player#getLastPreviewedMessage()} depending on {@link net.minestom.server.command.ArgumentsSignature#signedPreview()}
|
||||
*/
|
||||
public final class ArgumentMessage extends Argument<String> implements SignableArgument {
|
||||
public ArgumentMessage(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String parse(@NotNull String input) throws ArgumentSyntaxException {
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processNodes(@NotNull NodeMaker nodeMaker, boolean executable) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(this, executable, false, false);
|
||||
argumentNode.parser = "minecraft:message";
|
||||
nodeMaker.addNodes(new DeclareCommandsPacket.Node[]{argumentNode});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package net.minestom.server.command.builder.arguments.minecraft;
|
||||
|
||||
/**
|
||||
* Sealed because argument signing is entirely dependent on the argument type, and it's decided by the client
|
||||
*/
|
||||
public sealed interface SignableArgument permits ArgumentMessage {
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package net.minestom.server.command.builder.parser;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
||||
import net.minestom.server.command.ArgumentsSignature;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.command.builder.CommandContext;
|
||||
import net.minestom.server.command.builder.CommandDispatcher;
|
||||
|
@ -127,7 +128,7 @@ public final class CommandParser {
|
|||
maxArguments = argsSize;
|
||||
|
||||
// Fill arguments map
|
||||
finalContext = new CommandContext(validSyntaxHolder.commandString());
|
||||
finalContext = new CommandContext(validSyntaxHolder.commandString(), context.getSignature());
|
||||
for (var entry : argsValues.entrySet()) {
|
||||
final Argument<?> argument = entry.getKey();
|
||||
final ArgumentParser.ArgumentResult argumentResult = entry.getValue();
|
||||
|
@ -148,7 +149,8 @@ public final class CommandParser {
|
|||
public static ArgumentQueryResult findEligibleArgument(@NotNull Command command, String[] args, String commandString,
|
||||
boolean trailingSpace, boolean forceCorrect,
|
||||
Predicate<CommandSyntax> syntaxPredicate,
|
||||
Predicate<Argument<?>> argumentPredicate) {
|
||||
Predicate<Argument<?>> argumentPredicate,
|
||||
@Nullable ArgumentsSignature signature) {
|
||||
final Collection<CommandSyntax> syntaxes = command.getSyntaxes();
|
||||
|
||||
Int2ObjectRBTreeMap<ArgumentQueryResult> suggestions = new Int2ObjectRBTreeMap<>(Collections.reverseOrder());
|
||||
|
@ -158,7 +160,7 @@ public final class CommandParser {
|
|||
continue;
|
||||
}
|
||||
|
||||
final CommandContext context = new CommandContext(commandString);
|
||||
final CommandContext context = new CommandContext(commandString, signature);
|
||||
|
||||
final Argument<?>[] commandArguments = syntax.getArguments();
|
||||
int inputIndex = 0;
|
||||
|
|
|
@ -3,7 +3,6 @@ package net.minestom.server.crypto;
|
|||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.packet.client.play.ClientCommandChatPacket;
|
||||
import net.minestom.server.utils.crypto.KeyUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -55,11 +54,7 @@ public interface SignatureValidator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Can be used to verify signatures of {@link net.minestom.server.network.packet.client.play.ClientChatMessagePacket}
|
||||
* and {@link ClientCommandChatPacket#signatures()}. For command args the signature is generated for the given
|
||||
* value wrapped in {@link Component#text(String)} or for the preview if it's present regardless of the arg node
|
||||
* name. Vanilla implementation of argument signing can be found at (Mojang mappings):
|
||||
* <i>net.minecraft.client.player.LocalPlayer#signCommandArguments</i><br>
|
||||
* Can be used to verify signatures of chat messages and command arguments.
|
||||
*
|
||||
* @param validator validator acquired from {@link SignatureValidator#from(Player)}
|
||||
* @param signature signature data
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package net.minestom.server.event.player;
|
||||
|
||||
import net.minestom.server.command.ArgumentsSignature;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.trait.CancellableEvent;
|
||||
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Called every time a player send a message starting by '/'.
|
||||
|
@ -12,10 +14,11 @@ public class PlayerCommandEvent implements PlayerInstanceEvent, CancellableEvent
|
|||
|
||||
private final Player player;
|
||||
private String command;
|
||||
private @Nullable ArgumentsSignature signature;
|
||||
|
||||
private boolean cancelled;
|
||||
|
||||
public PlayerCommandEvent(@NotNull Player player, @NotNull String command) {
|
||||
public PlayerCommandEvent(@NotNull Player player, @NotNull String command, @Nullable ArgumentsSignature signature) {
|
||||
this.player = player;
|
||||
this.command = command;
|
||||
}
|
||||
|
@ -53,4 +56,12 @@ public class PlayerCommandEvent implements PlayerInstanceEvent, CancellableEvent
|
|||
public @NotNull Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public @Nullable ArgumentsSignature getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(@Nullable ArgumentsSignature signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class ChatMessageListener {
|
|||
public static void commandChatListener(ClientCommandChatPacket packet, Player player) {
|
||||
final String command = packet.message();
|
||||
if (Messenger.canReceiveCommand(player)) {
|
||||
COMMAND_MANAGER.execute(player, command);
|
||||
COMMAND_MANAGER.execute(player, command, packet.argumentsSignature().signatures().size() > 0 ? packet.argumentsSignature() : null);
|
||||
} else {
|
||||
Messenger.sendRejectionMessage(player);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class TabCompleteListener {
|
|||
|
||||
final ArgumentQueryResult queryResult = CommandParser.findEligibleArgument(commandQueryResult.command(),
|
||||
commandQueryResult.args(), commandString, text.endsWith(StringUtils.SPACE), false,
|
||||
CommandSyntax::hasSuggestion, Argument::hasSuggestion);
|
||||
CommandSyntax::hasSuggestion, Argument::hasSuggestion, null);
|
||||
if (queryResult == null) {
|
||||
// Suggestible argument not found
|
||||
return null;
|
||||
|
|
|
@ -6,13 +6,7 @@ import net.minestom.server.command.builder.suggestion.Suggestion;
|
|||
import net.minestom.server.command.builder.suggestion.SuggestionEntry;
|
||||
import net.minestom.server.listener.TabCompleteListener;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.Completer;
|
||||
import org.jline.reader.EndOfFileException;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
import org.jline.reader.ParsedLine;
|
||||
import org.jline.reader.UserInterruptException;
|
||||
import org.jline.reader.*;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
|
||||
|
@ -44,7 +38,7 @@ public class MinestomTerminal {
|
|||
try {
|
||||
command = reader.readLine(PROMPT);
|
||||
var commandManager = MinecraftServer.getCommandManager();
|
||||
commandManager.execute(commandManager.getConsoleSender(), command);
|
||||
commandManager.execute(commandManager.getConsoleSender(), command, null);
|
||||
} catch (UserInterruptException e) {
|
||||
// Handle Ctrl + C
|
||||
System.exit(0);
|
||||
|
|
Loading…
Reference in New Issue