diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 9d1e9dfb4..76ce55140 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -218,7 +218,8 @@ private void initialize() { settings = injector.getSingleton(Settings.class); ConsoleLoggerFactory.reloadSettings(settings); logger = ConsoleLoggerFactory.get(AuthMe.class); - OnStartupTasks.setupConsoleFilter(getLogger()); + OnStartupTasks onStartupTasks = injector.newInstance(OnStartupTasks.class); + onStartupTasks.setupConsoleFilter(getLogger()); // Set all service fields on the AuthMe class instantiateServices(injector); @@ -236,7 +237,6 @@ private void initialize() { registerEventListeners(injector); // Start Email recall task if needed - OnStartupTasks onStartupTasks = injector.newInstance(OnStartupTasks.class); onStartupTasks.scheduleRecallEmailTask(); } diff --git a/src/main/java/fr/xephi/authme/command/CommandDescription.java b/src/main/java/fr/xephi/authme/command/CommandDescription.java index e195c4752..8177f33bb 100644 --- a/src/main/java/fr/xephi/authme/command/CommandDescription.java +++ b/src/main/java/fr/xephi/authme/command/CommandDescription.java @@ -55,6 +55,10 @@ public class CommandDescription { * Permission node required to execute this command. */ private PermissionNode permission; + /** + * Defines if the command contains sensitive data + */ + private boolean sensitive; /** * Private constructor. @@ -72,7 +76,8 @@ public class CommandDescription { */ private CommandDescription(List labels, String description, String detailedDescription, Class executableCommand, CommandDescription parent, - List arguments, PermissionNode permission) { + List arguments, PermissionNode permission, + boolean sensitive) { this.labels = labels; this.description = description; this.detailedDescription = detailedDescription; @@ -80,6 +85,7 @@ private CommandDescription(List labels, String description, String detai this.parent = parent; this.arguments = arguments; this.permission = permission; + this.sensitive = sensitive; } /** @@ -184,6 +190,10 @@ public PermissionNode getPermission() { return permission; } + public boolean isSensitive() { + return sensitive; + } + /** * Return a builder instance to create a new command description. * @@ -204,6 +214,7 @@ public static final class CommandBuilder { private CommandDescription parent; private List arguments = new ArrayList<>(); private PermissionNode permission; + private Boolean sensitive; /** * Build a CommandDescription and register it onto the parent if available. @@ -232,7 +243,7 @@ public CommandDescription build() { // parents and permissions may be null; arguments may be empty return new CommandDescription(labels, description, detailedDescription, executableCommand, - parent, arguments, permission); + parent, arguments, permission, sensitive == null ? false : sensitive); } public CommandBuilder labels(List labels) { @@ -289,6 +300,16 @@ public CommandBuilder permission(PermissionNode permission) { this.permission = permission; return this; } + + /** + * Defines that the command contains sensitive data + * + * @return The builder + */ + public CommandBuilder sensitive() { + this.sensitive = true; + return this; + } } } diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index fcc3ce611..78c4d2cc0 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -96,6 +96,7 @@ private void buildCommands() { .detailedDescription("Command to log in using AuthMeReloaded.") .withArgument("password", "Login password", MANDATORY) .permission(PlayerPermission.LOGIN) + .sensitive() .executableCommand(LoginCommand.class) .register(); @@ -118,6 +119,7 @@ private void buildCommands() { .withArgument("password", "Password", OPTIONAL) .withArgument("verifyPassword", "Verify password", OPTIONAL) .permission(PlayerPermission.REGISTER) + .sensitive() .executableCommand(RegisterCommand.class) .register(); @@ -141,6 +143,7 @@ private void buildCommands() { .withArgument("oldPassword", "Old password", MANDATORY) .withArgument("newPassword", "New password", MANDATORY) .permission(PlayerPermission.CHANGE_PASSWORD) + .sensitive() .executableCommand(ChangePasswordCommand.class) .register(); @@ -199,6 +202,7 @@ private CommandDescription buildAuthMeBaseCommand() { .withArgument("player", "Player name", MANDATORY) .withArgument("password", "Password", MANDATORY) .permission(AdminPermission.REGISTER) + .sensitive() .executableCommand(RegisterAdminCommand.class) .register(); @@ -233,6 +237,7 @@ private CommandDescription buildAuthMeBaseCommand() { .withArgument("player", "Player name", MANDATORY) .withArgument("pwd", "New password", MANDATORY) .permission(AdminPermission.CHANGE_PASSWORD) + .sensitive() .executableCommand(ChangePasswordAdminCommand.class) .register(); @@ -564,6 +569,7 @@ private CommandDescription buildEmailBaseCommand() { .detailedDescription("Set a new password after successfully recovering your account.") .withArgument("password", "New password", MANDATORY) .permission(PlayerPermission.RECOVER_EMAIL) + .sensitive() .executableCommand(EmailSetPasswordCommand.class) .register(); @@ -592,6 +598,7 @@ private CommandDescription buildTotpBaseCommand() { .description("Command for logging in") .detailedDescription("Processes the two-factor authentication code during login.") .withArgument("code", "The TOTP code to use to log in", MANDATORY) + .sensitive() .executableCommand(TotpCodeCommand.class) .register(); @@ -613,6 +620,7 @@ private CommandDescription buildTotpBaseCommand() { .detailedDescription("Saves the generated TOTP secret after confirmation.") .withArgument("code", "Code from the given secret from /totp add", MANDATORY) .permission(PlayerPermission.ENABLE_TWO_FACTOR_AUTH) + .sensitive() .executableCommand(ConfirmTotpCommand.class) .register(); @@ -624,6 +632,7 @@ private CommandDescription buildTotpBaseCommand() { .detailedDescription("Disables two-factor authentication for your account.") .withArgument("code", "Current 2FA code", MANDATORY) .permission(PlayerPermission.DISABLE_TWO_FACTOR_AUTH) + .sensitive() .executableCommand(RemoveTotpCommand.class) .register(); diff --git a/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java b/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java index 1645ae651..0ffdba58f 100644 --- a/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java +++ b/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java @@ -8,6 +8,7 @@ import fr.xephi.authme.message.Messages; import fr.xephi.authme.output.ConsoleFilter; import fr.xephi.authme.output.Log4JFilter; +import fr.xephi.authme.service.LogFilterService; import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; @@ -39,6 +40,8 @@ public class OnStartupTasks { private BukkitService bukkitService; @Inject private Messages messages; + @Inject + private LogFilterService logFilterService; OnStartupTasks() { } @@ -63,7 +66,7 @@ public static void sendMetrics(AuthMe plugin, Settings settings) { * * @param logger the plugin logger */ - public static void setupConsoleFilter(Logger logger) { + public void setupConsoleFilter(Logger logger) { // Try to set the log4j filter try { Class.forName("org.apache.logging.log4j.core.filter.AbstractFilter"); @@ -71,7 +74,7 @@ public static void setupConsoleFilter(Logger logger) { } catch (ClassNotFoundException | NoClassDefFoundError e) { // log4j is not available consoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled"); - ConsoleFilter filter = new ConsoleFilter(); + ConsoleFilter filter = new ConsoleFilter(logFilterService); logger.setFilter(filter); Bukkit.getLogger().setFilter(filter); Logger.getLogger("Minecraft").setFilter(filter); @@ -79,10 +82,10 @@ public static void setupConsoleFilter(Logger logger) { } // Set the console filter to remove the passwords - private static void setLog4JFilter() { + private void setLog4JFilter() { org.apache.logging.log4j.core.Logger logger; logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger(); - logger.addFilter(new Log4JFilter()); + logger.addFilter(new Log4JFilter(logFilterService)); } /** diff --git a/src/main/java/fr/xephi/authme/output/ConsoleFilter.java b/src/main/java/fr/xephi/authme/output/ConsoleFilter.java index 975cc4cc3..8d50e701e 100644 --- a/src/main/java/fr/xephi/authme/output/ConsoleFilter.java +++ b/src/main/java/fr/xephi/authme/output/ConsoleFilter.java @@ -1,5 +1,7 @@ package fr.xephi.authme.output; +import fr.xephi.authme.service.LogFilterService; + import java.util.logging.Filter; import java.util.logging.LogRecord; @@ -10,13 +12,19 @@ */ public class ConsoleFilter implements Filter { + private LogFilterService filterService; + + public ConsoleFilter(LogFilterService filterService) { + this.filterService = filterService; + } + @Override public boolean isLoggable(LogRecord record) { if (record == null || record.getMessage() == null) { return true; } - if (LogFilterHelper.isSensitiveAuthMeCommand(record.getMessage())) { + if (filterService.isSensitiveAuthMeCommand(record.getMessage())) { String playerName = record.getMessage().split(" ")[0]; record.setMessage(playerName + " issued an AuthMe command"); } diff --git a/src/main/java/fr/xephi/authme/output/Log4JFilter.java b/src/main/java/fr/xephi/authme/output/Log4JFilter.java index 1ebf5141f..b7627510e 100644 --- a/src/main/java/fr/xephi/authme/output/Log4JFilter.java +++ b/src/main/java/fr/xephi/authme/output/Log4JFilter.java @@ -1,5 +1,6 @@ package fr.xephi.authme.output; +import fr.xephi.authme.service.LogFilterService; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.core.LogEvent; @@ -16,6 +17,12 @@ public class Log4JFilter extends AbstractFilter { private static final long serialVersionUID = -5594073755007974254L; + private LogFilterService filterService; + + public Log4JFilter(LogFilterService filterService) { + this.filterService = filterService; + } + /** * Validates a Message instance and returns the {@link Result} value * depending on whether the message contains sensitive AuthMe data. @@ -24,7 +31,7 @@ public class Log4JFilter extends AbstractFilter { * * @return The Result value */ - private static Result validateMessage(Message message) { + private Result validateMessage(Message message) { if (message == null) { return Result.NEUTRAL; } @@ -39,8 +46,8 @@ private static Result validateMessage(Message message) { * * @return The Result value */ - private static Result validateMessage(String message) { - return LogFilterHelper.isSensitiveAuthMeCommand(message) + private Result validateMessage(String message) { + return filterService.isSensitiveAuthMeCommand(message) ? Result.DENY : Result.NEUTRAL; } diff --git a/src/main/java/fr/xephi/authme/output/LogFilterHelper.java b/src/main/java/fr/xephi/authme/output/LogFilterHelper.java deleted file mode 100644 index fa43a01c8..000000000 --- a/src/main/java/fr/xephi/authme/output/LogFilterHelper.java +++ /dev/null @@ -1,50 +0,0 @@ -package fr.xephi.authme.output; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.util.StringUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Service class for the log filters. - */ -final class LogFilterHelper { - - @VisibleForTesting - static final List COMMANDS_TO_SKIP = withAndWithoutAuthMePrefix( - "/login ", "/l ", "/log ", "/register ", "/reg ", "/unregister ", "/unreg ", - "/changepassword ", "/cp ", "/changepass ", "/authme register ", "/authme reg ", "/authme r ", - "/authme changepassword ", "/authme password ", "/authme changepass ", "/authme cp ", "/email setpassword "); - - private static final String ISSUED_COMMAND_TEXT = "issued server command:"; - - private LogFilterHelper() { - // Util class - } - - /** - * Validate a message and return whether the message contains a sensitive AuthMe command. - * - * @param message The message to verify - * - * @return True if it is a sensitive AuthMe command, false otherwise - */ - static boolean isSensitiveAuthMeCommand(String message) { - if (message == null) { - return false; - } - String lowerMessage = message.toLowerCase(); - return lowerMessage.contains(ISSUED_COMMAND_TEXT) && StringUtils.containsAny(lowerMessage, COMMANDS_TO_SKIP); - } - - private static List withAndWithoutAuthMePrefix(String... commands) { - List commandList = new ArrayList<>(commands.length * 2); - for (String command : commands) { - commandList.add(command); - commandList.add(command.substring(0, 1) + "authme:" + command.substring(1)); - } - return Collections.unmodifiableList(commandList); - } -} diff --git a/src/main/java/fr/xephi/authme/service/LogFilterService.java b/src/main/java/fr/xephi/authme/service/LogFilterService.java new file mode 100644 index 000000000..b44a9c5f1 --- /dev/null +++ b/src/main/java/fr/xephi/authme/service/LogFilterService.java @@ -0,0 +1,42 @@ +package fr.xephi.authme.service; + +import fr.xephi.authme.command.CommandMapper; +import fr.xephi.authme.command.FoundCommandResult; + +import javax.inject.Inject; +import java.util.Arrays; +import java.util.List; + +/** + * Service class for the log filters. + */ +public class LogFilterService { + + private static final String ISSUED_COMMAND_PREFIX_TEXT = "issued server command: /"; + + @Inject + private CommandMapper commandMapper; + + /** + * Validate a message and return whether the message contains a sensitive AuthMe command. + * + * @param message The message to verify + * + * @return True if it is a sensitive AuthMe command, false otherwise + */ + public boolean isSensitiveAuthMeCommand(String message) { + if (message == null || !message.contains(ISSUED_COMMAND_PREFIX_TEXT)) { + return false; + } + String rawCommand = message.substring(message.indexOf("/")); + List components = Arrays.asList(rawCommand.split(" ")); + FoundCommandResult command = commandMapper.mapPartsToCommand(null, components); + switch (command.getResultStatus()) { + case UNKNOWN_LABEL: + case MISSING_BASE_COMMAND: + return false; + default: + return command.getCommandDescription().isSensitive(); + } + } +} diff --git a/src/test/java/fr/xephi/authme/output/ConsoleFilterTest.java b/src/test/java/fr/xephi/authme/output/ConsoleFilterTest.java deleted file mode 100644 index 8975068f6..000000000 --- a/src/test/java/fr/xephi/authme/output/ConsoleFilterTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package fr.xephi.authme.output; - -import org.junit.Test; -import org.mockito.Mockito; - -import java.util.logging.LogRecord; - -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Test for {@link ConsoleFilter}. - */ -public class ConsoleFilterTest { - - private final ConsoleFilter filter = new ConsoleFilter(); - - private static final String SENSITIVE_COMMAND = "User issued server command: /login test test"; - private static final String NORMAL_COMMAND = "User issued server command: /motd 2"; - - - @Test - public void shouldReplaceSensitiveRecord() { - // given - LogRecord record = createRecord(SENSITIVE_COMMAND); - - // when - boolean result = filter.isLoggable(record); - - // then - assertThat(result, equalTo(true)); - verify(record).setMessage("User issued an AuthMe command"); - } - - @Test - public void shouldNotFilterRegularCommand() { - // given - LogRecord record = createRecord(NORMAL_COMMAND); - - // when - boolean result = filter.isLoggable(record); - - // then - assertThat(result, equalTo(true)); - verify(record, never()).setMessage("User issued an AuthMe command"); - } - - @Test - public void shouldManageRecordWithNullMessage() { - // given - LogRecord record = createRecord(null); - - // when - boolean result = filter.isLoggable(record); - - // then - assertThat(result, equalTo(true)); - verify(record, never()).setMessage("User issued an AuthMe command"); - } - - - /** - * Creates a mock of {@link LogRecord} and sets it to return the given message. - * - * @param message The message to set. - * - * @return Mock of LogRecord - */ - private static LogRecord createRecord(String message) { - LogRecord record = Mockito.mock(LogRecord.class); - when(record.getMessage()).thenReturn(message); - return record; - } -} diff --git a/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java b/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java deleted file mode 100644 index b9977de8e..000000000 --- a/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java +++ /dev/null @@ -1,230 +0,0 @@ -package fr.xephi.authme.output; - -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; - -import org.apache.logging.log4j.core.Filter.Result; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.message.Message; -import org.junit.Test; -import org.mockito.Mockito; - -/** - * Test for {@link Log4JFilter}. - */ -public class Log4JFilterTest { - - private final Log4JFilter log4JFilter = new Log4JFilter(); - - private static final String SENSITIVE_COMMAND = "User issued server command: /login pass pass"; - private static final String NORMAL_COMMAND = "User issued server command: /help"; - private static final String OTHER_COMMAND = "Starting the server... Write /l for logs"; - - // --------- - // Test the filter(LogEvent) method - // --------- - @Test - public void shouldFilterSensitiveLogEvent() { - // given - Message message = mockMessage(SENSITIVE_COMMAND); - LogEvent event = Mockito.mock(LogEvent.class); - when(event.getMessage()).thenReturn(message); - - // when - Result result = log4JFilter.filter(event); - - // then - assertThat(result, equalTo(Result.DENY)); - } - - @Test - public void shouldNotFilterIrrelevantLogEvent() { - // given - Message message = mockMessage(NORMAL_COMMAND); - LogEvent event = Mockito.mock(LogEvent.class); - when(event.getMessage()).thenReturn(message); - - // when - Result result = log4JFilter.filter(event); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterNonCommandLogEvent() { - // given - Message message = mockMessage(OTHER_COMMAND); - LogEvent event = Mockito.mock(LogEvent.class); - when(event.getMessage()).thenReturn(message); - - // when - Result result = log4JFilter.filter(event); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterLogEventWithNullMessage() { - // given - Message message = mockMessage(null); - LogEvent event = Mockito.mock(LogEvent.class); - when(event.getMessage()).thenReturn(message); - - // when - Result result = log4JFilter.filter(event); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterWhenLogEventIsNull() { - // given / when - Result result = log4JFilter.filter(null); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - // ---------- - // Test filter(Logger, Level, Marker, String, Object...) - // ---------- - @Test - public void shouldFilterSensitiveStringMessage() { - // given / when - Result result = log4JFilter.filter(null, null, null, SENSITIVE_COMMAND); - - // then - assertThat(result, equalTo(Result.DENY)); - } - - @Test - public void shouldNotFilterNormalStringMessage() { - // given / when - Result result = log4JFilter.filter(null, null, null, NORMAL_COMMAND); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterNonCommandStringMessage() { - // given / when - Result result = log4JFilter.filter(null, null, null, OTHER_COMMAND); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldReturnNeutralForNullMessage() { - // given / when - Result result = log4JFilter.filter(null, null, null, null); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - // -------- - // Test filter(Logger, Level, Marker, Object, Throwable) - // -------- - @Test - public void shouldFilterSensitiveObjectMessage() { - // given / when - Result result = log4JFilter.filter(null, null, null, SENSITIVE_COMMAND, new Exception()); - - // then - assertThat(result, equalTo(Result.DENY)); - } - - @Test - public void shouldNotFilterNullObjectParam() { - // given / when - Result result = log4JFilter.filter(null, null, null, (Object) null, new Exception()); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterIrrelevantMessage() { - // given / when - Result result = log4JFilter.filter(null, null, null, OTHER_COMMAND, new Exception()); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterNonSensitiveCommand() { - // given / when - Result result = log4JFilter.filter(null, null, null, NORMAL_COMMAND, new Exception()); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - // -------- - // Test filter(Logger, Level, Marker, Message, Throwable) - // -------- - @Test - public void shouldFilterSensitiveMessage() { - // given - Message message = mockMessage(SENSITIVE_COMMAND); - - // when - Result result = log4JFilter.filter(null, null, null, message, new Exception()); - - // then - assertThat(result, equalTo(Result.DENY)); - } - - @Test - public void shouldNotFilterNonSensitiveMessage() { - // given - Message message = mockMessage(NORMAL_COMMAND); - - // when - Result result = log4JFilter.filter(null, null, null, message, new Exception()); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterNonCommandMessage() { - // given - Message message = mockMessage(OTHER_COMMAND); - - // when - Result result = log4JFilter.filter(null, null, null, message, new Exception()); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - @Test - public void shouldNotFilterNullMessage() { - // given / when - Result result = log4JFilter.filter(null, null, null, null, new Exception()); - - // then - assertThat(result, equalTo(Result.NEUTRAL)); - } - - /** - * Mocks a {@link Message} object and makes it return the given formatted message. - * - * @param formattedMessage the formatted message the mock should return - * @return Message mock - */ - private static Message mockMessage(String formattedMessage) { - Message message = Mockito.mock(Message.class); - when(message.getFormattedMessage()).thenReturn(formattedMessage); - return message; - } - -} diff --git a/src/test/java/fr/xephi/authme/output/LogFilterHelperTest.java b/src/test/java/fr/xephi/authme/output/LogFilterHelperTest.java deleted file mode 100644 index 302345fb9..000000000 --- a/src/test/java/fr/xephi/authme/output/LogFilterHelperTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package fr.xephi.authme.output; - -import com.google.common.collect.Lists; -import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.command.CommandInitializer; -import org.junit.Test; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.junit.Assert.assertThat; - -/** - * Test for {@link LogFilterHelper}. - */ -public class LogFilterHelperTest { - - private static final List ALL_COMMANDS = new CommandInitializer().getCommands(); - - /** - * Checks that {@link LogFilterHelper#COMMANDS_TO_SKIP} contains the entries we expect - * (commands with password argument). - */ - @Test - public void shouldBlacklistAllSensitiveCommands() { - // given - List sensitiveCommands = Arrays.asList( - getCommand("register"), getCommand("login"), getCommand("changepassword"), getCommand("unregister"), - getCommand("authme", "register"), getCommand("authme", "changepassword"), - getCommand("email", "setpassword") - ); - // Build array with entries like "/register ", "/authme cp ", "/authme changepass " - String[] expectedEntries = sensitiveCommands.stream() - .map(cmd -> buildCommandSyntaxes(cmd)) - .flatMap(List::stream) - .map(syntax -> syntax + " ") - .toArray(String[]::new); - - // when / then - assertThat(LogFilterHelper.COMMANDS_TO_SKIP, containsInAnyOrder(expectedEntries)); - - } - - private static CommandDescription getCommand(String label) { - return findCommandWithLabel(label, ALL_COMMANDS); - } - - private static CommandDescription getCommand(String parentLabel, String childLabel) { - CommandDescription parent = getCommand(parentLabel); - return findCommandWithLabel(childLabel, parent.getChildren()); - } - - private static CommandDescription findCommandWithLabel(String label, List commands) { - return commands.stream() - .filter(cmd -> cmd.getLabels().contains(label)) - .findFirst().orElseThrow(() -> new IllegalArgumentException(label)); - } - - /** - * Returns all "command syntaxes" from which the given command can be reached. - * For example, the result might be a List containing "/authme changepassword", "/authme changepass", - * "/authme cp", "/authme:authme changepassword" etc. - * - * @param command the command to build syntaxes for - * @return command syntaxes - */ - private static List buildCommandSyntaxes(CommandDescription command) { - List prefixes = getCommandPrefixes(command); - - return command.getLabels() - .stream() - .map(label -> Lists.transform(prefixes, p -> p + label)) - .flatMap(List::stream) - .collect(Collectors.toList()); - } - - private static List getCommandPrefixes(CommandDescription command) { - if (command.getParent() == null) { - return Arrays.asList("/", "/authme:"); - } - return command.getParent().getLabels() - .stream() - .map(label -> new String[]{"/" + label + " ", "/authme:" + label + " "}) - .flatMap(Arrays::stream) - .collect(Collectors.toList()); - } -}