From df6974ad04d63ff50dcb7bab5662103bf8143e18 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Thu, 8 Jul 2021 22:21:53 +0200 Subject: [PATCH] CMDoS because Brigadier --- .../steamwar/command/SWCommandBrigadier.java | 257 +++++++----------- .../de/steamwar/command/SWCommandNormal.java | 131 +-------- .../src/de/steamwar/command/SubCommand.java | 157 +++++++++++ 3 files changed, 255 insertions(+), 290 deletions(-) create mode 100644 SpigotCore_Main/src/de/steamwar/command/SubCommand.java diff --git a/SpigotCore_Main/src/de/steamwar/command/SWCommandBrigadier.java b/SpigotCore_Main/src/de/steamwar/command/SWCommandBrigadier.java index 92e131a..16ba87b 100644 --- a/SpigotCore_Main/src/de/steamwar/command/SWCommandBrigadier.java +++ b/SpigotCore_Main/src/de/steamwar/command/SWCommandBrigadier.java @@ -70,7 +70,7 @@ class SWCommandBrigadier implements SWCommandInterface { Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument"); return; } - commandHelpList.add(new SubCommand(swCommand, method, anno.value(), new HashMap<>())); + commandList.add(createSubCommand(method, anno.value())); }); } for (Method method : methods) { @@ -92,7 +92,7 @@ class SWCommandBrigadier implements SWCommandInterface { return; } } - commandList.add(new SubCommand(swCommand, method, anno.value(), new HashMap<>())); + commandList.add(createSubCommand(method, anno.value())); }); } @@ -110,6 +110,62 @@ class SWCommandBrigadier implements SWCommandInterface { } } + private SubCommand createSubCommand(Method method, String[] strings) { + return new SubCommand(swCommand, method, strings, localTypeMapper, current -> { + ArgumentBuilder argumentBuilder = null; + for (String s : current.subCommand) { + LiteralArgumentBuilder literalArgumentBuilder = LiteralArgumentBuilder.literal(s); + if (argumentBuilder != null) { + argumentBuilder.then(literalArgumentBuilder); + } else { + current.argumentNode = literalArgumentBuilder; + } + argumentBuilder = literalArgumentBuilder; + } + + for (int i = 0; i < current.arguments.length - (current.varArgType != null ? 1 : 0); i++) { + Parameter parameter = current.parameters[i + 1]; + Class parameterType = parameter.getType(); + ArgumentType argumentType = getArgumentType(parameter, parameterType, current); + + RequiredArgumentBuilder requiredArgumentBuilder = RequiredArgumentBuilder.argument(parameter.getName(), argumentType); + if (argumentBuilder != null) { + argumentBuilder.then(requiredArgumentBuilder); + } else { + current.argumentNode = requiredArgumentBuilder; + } + argumentBuilder = requiredArgumentBuilder; + if (i == current.arguments.length - 1) { + argumentBuilder.executes(commandContext -> { + current.invoke((CommandSender) commandContext.getCommand(), commandContext.getInput().split(" ")); + return 0; + }); + } + } + if (current.varArgType != null) { + // TODO: UNSUPORTED + /*Parameter parameter = parameters[parameters.length - 1]; + Class parameterType = parameter.getType(); + TypeMapper typeMapper = arguments[arguments.length - 1]; + ArgumentType argumentType = getArgumentType(parameter, parameterType, typeMapper); + + RequiredArgumentBuilder requiredArgumentBuilder = RequiredArgumentBuilder.argument(parameter.getName(), argumentType); + if (argumentBuilder != null) { + argumentBuilder.then(requiredArgumentBuilder); + } else { + argumentNode = requiredArgumentBuilder; + } + argumentBuilder = requiredArgumentBuilder; + argumentBuilder.executes(commandContext -> { + invoke((CommandSender) commandContext.getCommand(), commandContext.getInput().split(" ")); + return 0; + }); + CommandNode commandNode = argumentBuilder.build(); + argumentBuilder.redirect(commandNode);*/ + } + }); + } + private void register(String name, SubCommand subCommand, String command, String... aliases) { LiteralArgumentBuilder literalArgumentBuilder = LiteralArgumentBuilder.literal(name); if (subCommand.argumentNode == null) { @@ -165,171 +221,42 @@ class SWCommandBrigadier implements SWCommandInterface { swCommandNormal.register(); } - static class SubCommand { - - ArgumentBuilder argumentNode = null; - boolean normalTabCompleteNeeded = false; - - private SWCommand swCommand; - private Method method; - String[] subCommand; - TypeMapper[] arguments; - private Predicate commandSenderPredicate; - private Function commandSenderFunction; - Class varArgType = null; - - SubCommand(SWCommand swCommand, Method method, String[] subCommand, Map> localTypeMapper) { - this.swCommand = swCommand; - this.method = method; - - Parameter[] parameters = method.getParameters(); - commandSenderPredicate = sender -> parameters[0].getType().isAssignableFrom(sender.getClass()); - commandSenderFunction = sender -> parameters[0].getType().cast(sender); - this.subCommand = subCommand; - - arguments = new TypeMapper[parameters.length - 1]; - for (int i = 1; i < parameters.length; i++) { - Parameter parameter = parameters[i]; - Class clazz = parameter.getType(); - if (parameter.isVarArgs()) { - clazz = clazz.getComponentType(); - varArgType = clazz; - } - - SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class); - if (clazz.isEnum() && mapper == null && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) { - Class> enumClass = (Class>) clazz; - List tabCompletes = new ArrayList<>(); - for (Enum enumConstant : enumClass.getEnumConstants()) { - tabCompletes.add(enumConstant.name().toLowerCase()); - } - arguments[i - 1] = SWCommandUtils.createMapper(s -> ENUM_MAPPER.apply(enumClass, s), s -> tabCompletes); - continue; - } - - String name = clazz.getTypeName(); - if (mapper != null) { - name = mapper.value(); - } - arguments[i - 1] = localTypeMapper.containsKey(name) - ? localTypeMapper.get(name) - : MAPPER_FUNCTIONS.getOrDefault(name, ERROR_FUNCTION); - } - - - ArgumentBuilder argumentBuilder = null; - for (String s : subCommand) { - LiteralArgumentBuilder literalArgumentBuilder = LiteralArgumentBuilder.literal(s); - if (argumentBuilder != null) { - argumentBuilder.then(literalArgumentBuilder); - } else { - argumentNode = literalArgumentBuilder; - } - argumentBuilder = literalArgumentBuilder; - } - - for (int i = 0; i < arguments.length - (varArgType != null ? 1 : 0); i++) { - Parameter parameter = parameters[i + 1]; - Class parameterType = parameter.getType(); - ArgumentType argumentType = getArgumentType(parameter, parameterType, arguments[i]); - - RequiredArgumentBuilder requiredArgumentBuilder = RequiredArgumentBuilder.argument(parameter.getName(), argumentType); - if (argumentBuilder != null) { - argumentBuilder.then(requiredArgumentBuilder); - } else { - argumentNode = requiredArgumentBuilder; - } - argumentBuilder = requiredArgumentBuilder; - if (i == arguments.length - 1) { - argumentBuilder.executes(commandContext -> { - invoke((CommandSender) commandContext.getCommand(), commandContext.getInput().split(" ")); - return 0; - }); - } - } - if (varArgType != null) { - // TODO: UNSUPORTED - /*Parameter parameter = parameters[parameters.length - 1]; - Class parameterType = parameter.getType(); - TypeMapper typeMapper = arguments[arguments.length - 1]; - ArgumentType argumentType = getArgumentType(parameter, parameterType, typeMapper); - - RequiredArgumentBuilder requiredArgumentBuilder = RequiredArgumentBuilder.argument(parameter.getName(), argumentType); - if (argumentBuilder != null) { - argumentBuilder.then(requiredArgumentBuilder); - } else { - argumentNode = requiredArgumentBuilder; - } - argumentBuilder = requiredArgumentBuilder; - argumentBuilder.executes(commandContext -> { - invoke((CommandSender) commandContext.getCommand(), commandContext.getInput().split(" ")); - return 0; - }); - CommandNode commandNode = argumentBuilder.build(); - argumentBuilder.redirect(commandNode);*/ - } - } - - boolean invoke(CommandSender commandSender, String[] args) { - if (args.length < arguments.length + subCommand.length - (varArgType != null ? 1 : 0)) { - return false; - } - if (varArgType == null && args.length > arguments.length + subCommand.length) { - return false; - } - try { - if (!commandSenderPredicate.test(commandSender)) { - return false; - } - Object[] objects = SWCommandUtils.generateArgumentArray(commandSender, arguments, args, varArgType, subCommand); - objects[0] = commandSenderFunction.apply(commandSender); - method.setAccessible(true); - method.invoke(swCommand, objects); - } catch (IllegalAccessException | RuntimeException | InvocationTargetException e) { - throw new SecurityException(e.getMessage(), e); - } catch (CommandParseException e) { - return false; - } - return true; - } - - private ArgumentType getArgumentType(Parameter parameter, Class parameterType, TypeMapper typeMapper) { - ArgumentType argumentType; - if (parameterType == boolean.class || parameterType == Boolean.class) { - argumentType = BoolArgumentType.bool(); - } else if (parameterType == int.class || parameterType == Integer.class) { - SWCommand.IntRange intRange = parameter.getAnnotation(SWCommand.IntRange.class); - if (intRange != null) { - argumentType = IntegerArgumentType.integer(intRange.min(), intRange.max()); - } else { - argumentType = IntegerArgumentType.integer(); - } - } else if (parameterType == float.class || parameterType == Float.class) { - SWCommand.FloatRange floatRange = parameter.getAnnotation(SWCommand.FloatRange.class); - if (floatRange != null) { - argumentType = FloatArgumentType.floatArg(floatRange.min(), floatRange.max()); - } else { - argumentType = FloatArgumentType.floatArg(); - } - } else if (parameterType == long.class || parameterType == Long.class) { - SWCommand.LongRange longRange = parameter.getAnnotation(SWCommand.LongRange.class); - if (longRange != null) { - argumentType = LongArgumentType.longArg(longRange.min(), longRange.max()); - } else { - argumentType = LongArgumentType.longArg(); - } - } else if (parameterType == double.class || parameterType == Double.class) { - SWCommand.DoubleRange doubleRange = parameter.getAnnotation(SWCommand.DoubleRange.class); - if (doubleRange != null) { - argumentType = DoubleArgumentType.doubleArg(doubleRange.min(), doubleRange.max()); - } else { - argumentType = DoubleArgumentType.doubleArg(); - } + private ArgumentType getArgumentType(Parameter parameter, Class parameterType, SubCommand subCommand) { + ArgumentType argumentType; + if (parameterType == boolean.class || parameterType == Boolean.class) { + argumentType = BoolArgumentType.bool(); + } else if (parameterType == int.class || parameterType == Integer.class) { + SWCommand.IntRange intRange = parameter.getAnnotation(SWCommand.IntRange.class); + if (intRange != null) { + argumentType = IntegerArgumentType.integer(intRange.min(), intRange.max()); } else { - argumentType = StringArgumentType.string(); - normalTabCompleteNeeded = true; + argumentType = IntegerArgumentType.integer(); } - return argumentType; + } else if (parameterType == float.class || parameterType == Float.class) { + SWCommand.FloatRange floatRange = parameter.getAnnotation(SWCommand.FloatRange.class); + if (floatRange != null) { + argumentType = FloatArgumentType.floatArg(floatRange.min(), floatRange.max()); + } else { + argumentType = FloatArgumentType.floatArg(); + } + } else if (parameterType == long.class || parameterType == Long.class) { + SWCommand.LongRange longRange = parameter.getAnnotation(SWCommand.LongRange.class); + if (longRange != null) { + argumentType = LongArgumentType.longArg(longRange.min(), longRange.max()); + } else { + argumentType = LongArgumentType.longArg(); + } + } else if (parameterType == double.class || parameterType == Double.class) { + SWCommand.DoubleRange doubleRange = parameter.getAnnotation(SWCommand.DoubleRange.class); + if (doubleRange != null) { + argumentType = DoubleArgumentType.doubleArg(doubleRange.min(), doubleRange.max()); + } else { + argumentType = DoubleArgumentType.doubleArg(); + } + } else { + argumentType = StringArgumentType.string(); + subCommand.normalTabCompleteNeeded = true; } + return argumentType; } } diff --git a/SpigotCore_Main/src/de/steamwar/command/SWCommandNormal.java b/SpigotCore_Main/src/de/steamwar/command/SWCommandNormal.java index 144f867..b325a81 100644 --- a/SpigotCore_Main/src/de/steamwar/command/SWCommandNormal.java +++ b/SpigotCore_Main/src/de/steamwar/command/SWCommandNormal.java @@ -24,19 +24,14 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.*; import java.util.function.BiConsumer; -import java.util.function.Function; import java.util.function.IntPredicate; -import java.util.function.Predicate; import java.util.logging.Level; import java.util.stream.Collectors; -import static de.steamwar.command.SWCommandUtils.*; - class SWCommandNormal implements SWCommandInterface { private final SWCommand swCommand; @@ -91,7 +86,7 @@ class SWCommandNormal implements SWCommandInterface { Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument"); return; } - commandHelpList.add(new SubCommand(swCommand, method, anno.value(), new HashMap<>())); + commandHelpList.add(createSubCommand(method, anno.value())); }); } for (Method method : methods) { @@ -113,7 +108,7 @@ class SWCommandNormal implements SWCommandInterface { return; } } - commandList.add(new SubCommand(swCommand, method, anno.value(), localTypeMapper)); + commandList.add(createSubCommand(method, anno.value())); }); this.commandList.sort((o1, o2) -> { @@ -129,6 +124,10 @@ class SWCommandNormal implements SWCommandInterface { } } + private de.steamwar.command.SubCommand createSubCommand(Method method, String[] strings) { + return new de.steamwar.command.SubCommand(swCommand, method, strings, localTypeMapper, current -> {}); + } + private void add(Class annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class returnType, BiConsumer consumer) { T[] anno = SWCommandUtils.getAnnotation(method, annotation); if (anno == null || anno.length == 0) return; @@ -169,122 +168,4 @@ class SWCommandNormal implements SWCommandInterface { public void register() { SWCommandUtils.commandMap.register("steamwar", this.command); } - - static class SubCommand { - - private SWCommand swCommand; - private Method method; - String[] subCommand; - TypeMapper[] arguments; - private Predicate commandSenderPredicate; - private Function commandSenderFunction; - Class varArgType = null; - - SubCommand(SWCommand swCommand, Method method, String[] subCommand, Map> localTypeMapper) { - this.swCommand = swCommand; - this.method = method; - - Parameter[] parameters = method.getParameters(); - commandSenderPredicate = sender -> parameters[0].getType().isAssignableFrom(sender.getClass()); - commandSenderFunction = sender -> parameters[0].getType().cast(sender); - this.subCommand = subCommand; - - arguments = new TypeMapper[parameters.length - 1]; - for (int i = 1; i < parameters.length; i++) { - Parameter parameter = parameters[i]; - Class clazz = parameter.getType(); - if (parameter.isVarArgs()) { - clazz = clazz.getComponentType(); - varArgType = clazz; - } - - SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class); - if (clazz.isEnum() && mapper == null && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) { - Class> enumClass = (Class>) clazz; - List tabCompletes = new ArrayList<>(); - for (Enum enumConstant : enumClass.getEnumConstants()) { - tabCompletes.add(enumConstant.name().toLowerCase()); - } - arguments[i - 1] = SWCommandUtils.createMapper(s -> ENUM_MAPPER.apply(enumClass, s), s -> tabCompletes); - continue; - } - - String name = clazz.getTypeName(); - if (mapper != null) { - name = mapper.value(); - } - arguments[i - 1] = localTypeMapper.containsKey(name) - ? localTypeMapper.get(name) - : MAPPER_FUNCTIONS.getOrDefault(name, ERROR_FUNCTION); - } - } - - boolean invoke(CommandSender commandSender, String[] args) { - if (args.length < arguments.length + subCommand.length - (varArgType != null ? 1 : 0)) { - return false; - } - if (varArgType == null && args.length > arguments.length + subCommand.length) { - return false; - } - try { - if (!commandSenderPredicate.test(commandSender)) { - return false; - } - Object[] objects = SWCommandUtils.generateArgumentArray(commandSender, arguments, args, varArgType, subCommand); - objects[0] = commandSenderFunction.apply(commandSender); - method.setAccessible(true); - method.invoke(swCommand, objects); - } catch (IllegalAccessException | RuntimeException | InvocationTargetException e) { - throw new SecurityException(e.getMessage(), e); - } catch (CommandParseException e) { - return false; - } - return true; - } - - List tabComplete(CommandSender commandSender, String[] args) { - if (varArgType == null && args.length > arguments.length + subCommand.length) { - return null; - } - int index = 0; - List argsList = new LinkedList<>(Arrays.asList(args)); - for (String value : subCommand) { - String s = argsList.remove(0); - if (argsList.isEmpty()) return Collections.singletonList(value); - if (!value.equalsIgnoreCase(s)) return null; - index++; - } - for (TypeMapper argument : arguments) { - String s = argsList.remove(0); - if (argsList.isEmpty()) { - return argument.tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s); - } - try { - if (argument.map(commandSender, Arrays.copyOf(args, index), s) == null) { - return null; - } - } catch (Exception e) { - return null; - } - index++; - } - if (varArgType != null && !argsList.isEmpty()) { - while (!argsList.isEmpty()) { - String s = argsList.remove(0); - if (argsList.isEmpty()) { - return arguments[arguments.length - 1].tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s); - } - try { - if (arguments[arguments.length - 1].map(commandSender, Arrays.copyOf(args, index), s) == null) { - return null; - } - } catch (Exception e) { - return null; - } - index++; - } - } - return null; - } - } } diff --git a/SpigotCore_Main/src/de/steamwar/command/SubCommand.java b/SpigotCore_Main/src/de/steamwar/command/SubCommand.java new file mode 100644 index 0000000..2a2c267 --- /dev/null +++ b/SpigotCore_Main/src/de/steamwar/command/SubCommand.java @@ -0,0 +1,157 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.command; + +import com.mojang.brigadier.builder.ArgumentBuilder; +import org.bukkit.command.CommandSender; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import static de.steamwar.command.SWCommandUtils.*; + +class SubCommand { + + ArgumentBuilder argumentNode = null; + boolean normalTabCompleteNeeded = false; + + SWCommand swCommand; + Parameter[] parameters; + Method method; + String[] subCommand; + TypeMapper[] arguments; + Predicate commandSenderPredicate; + Function commandSenderFunction; + Class varArgType = null; + + public SubCommand(SWCommand swCommand, Method method, String[] subCommand, Map> localTypeMapper, Consumer consumer) { + this.swCommand = swCommand; + this.method = method; + + parameters = method.getParameters(); + commandSenderPredicate = sender -> parameters[0].getType().isAssignableFrom(sender.getClass()); + commandSenderFunction = sender -> parameters[0].getType().cast(sender); + this.subCommand = subCommand; + + arguments = new TypeMapper[parameters.length - 1]; + for (int i = 1; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + Class clazz = parameter.getType(); + if (parameter.isVarArgs()) { + clazz = clazz.getComponentType(); + varArgType = clazz; + } + + SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class); + if (clazz.isEnum() && mapper == null && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) { + Class> enumClass = (Class>) clazz; + List tabCompletes = new ArrayList<>(); + for (Enum enumConstant : enumClass.getEnumConstants()) { + tabCompletes.add(enumConstant.name().toLowerCase()); + } + arguments[i - 1] = SWCommandUtils.createMapper(s -> ENUM_MAPPER.apply(enumClass, s), s -> tabCompletes); + continue; + } + + String name = clazz.getTypeName(); + if (mapper != null) { + name = mapper.value(); + } + arguments[i - 1] = localTypeMapper.containsKey(name) + ? localTypeMapper.get(name) + : MAPPER_FUNCTIONS.getOrDefault(name, ERROR_FUNCTION); + } + + consumer.accept(this); + } + + boolean invoke(CommandSender commandSender, String[] args) { + if (args.length < arguments.length + subCommand.length - (varArgType != null ? 1 : 0)) { + return false; + } + if (varArgType == null && args.length > arguments.length + subCommand.length) { + return false; + } + try { + if (!commandSenderPredicate.test(commandSender)) { + return false; + } + Object[] objects = SWCommandUtils.generateArgumentArray(commandSender, arguments, args, varArgType, subCommand); + objects[0] = commandSenderFunction.apply(commandSender); + method.setAccessible(true); + method.invoke(swCommand, objects); + } catch (IllegalAccessException | RuntimeException | InvocationTargetException e) { + throw new SecurityException(e.getMessage(), e); + } catch (CommandParseException e) { + return false; + } + return true; + } + + List tabComplete(CommandSender commandSender, String[] args) { + if (varArgType == null && args.length > arguments.length + subCommand.length) { + return null; + } + int index = 0; + List argsList = new LinkedList<>(Arrays.asList(args)); + for (String value : subCommand) { + String s = argsList.remove(0); + if (argsList.isEmpty()) return Collections.singletonList(value); + if (!value.equalsIgnoreCase(s)) return null; + index++; + } + for (TypeMapper argument : arguments) { + String s = argsList.remove(0); + if (argsList.isEmpty()) { + return argument.tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s); + } + try { + if (argument.map(commandSender, Arrays.copyOf(args, index), s) == null) { + return null; + } + } catch (Exception e) { + return null; + } + index++; + } + if (varArgType != null && !argsList.isEmpty()) { + while (!argsList.isEmpty()) { + String s = argsList.remove(0); + if (argsList.isEmpty()) { + return arguments[arguments.length - 1].tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s); + } + try { + if (arguments[arguments.length - 1].map(commandSender, Arrays.copyOf(args, index), s) == null) { + return null; + } + } catch (Exception e) { + return null; + } + index++; + } + } + return null; + } +}