From 655840dc8220ed46ba18d7d16594586b808e1648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beatrice=20Dellac=C3=A0?= Date: Tue, 22 Nov 2022 17:08:31 +0100 Subject: [PATCH] Implement basic permission check for message commands --- .../commands/message/CommandsCommand.java | 5 ++ .../commands/message/HelloCommand.java | 5 ++ .../hidekobot/datasource/DatabaseSource.java | 4 +- .../listeners/MessageCommandListener.java | 72 +++++++++++++------ .../objects/commands/MessageCommand.java | 15 +++- .../runnables/ExpiredMessageTask.java | 2 +- 6 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/message/CommandsCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/message/CommandsCommand.java index 489db7f..3c12ec4 100644 --- a/src/main/java/wtf/beatrice/hidekobot/commands/message/CommandsCommand.java +++ b/src/main/java/wtf/beatrice/hidekobot/commands/message/CommandsCommand.java @@ -1,11 +1,13 @@ package wtf.beatrice.hidekobot.commands.message; +import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import java.util.Collections; import java.util.LinkedList; +import java.util.List; public class CommandsCommand implements MessageCommand { @@ -15,6 +17,9 @@ public class CommandsCommand implements MessageCommand return new LinkedList<>(Collections.singletonList("commands")); } + @Override + public List getPermissions() { return null; } + @Override public boolean passRawArgs() { return false; diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/message/HelloCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/message/HelloCommand.java index 69ab1b0..1e6d689 100644 --- a/src/main/java/wtf/beatrice/hidekobot/commands/message/HelloCommand.java +++ b/src/main/java/wtf/beatrice/hidekobot/commands/message/HelloCommand.java @@ -1,10 +1,12 @@ package wtf.beatrice.hidekobot.commands.message; +import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import java.util.Arrays; import java.util.LinkedList; +import java.util.List; public class HelloCommand implements MessageCommand { @@ -14,6 +16,9 @@ public class HelloCommand implements MessageCommand return new LinkedList<>(Arrays.asList("hi", "hello", "heya")); } + @Override + public List getPermissions() { return null; } + @Override public boolean passRawArgs() { return false; diff --git a/src/main/java/wtf/beatrice/hidekobot/datasource/DatabaseSource.java b/src/main/java/wtf/beatrice/hidekobot/datasource/DatabaseSource.java index a7783f4..b9da4bc 100644 --- a/src/main/java/wtf/beatrice/hidekobot/datasource/DatabaseSource.java +++ b/src/main/java/wtf/beatrice/hidekobot/datasource/DatabaseSource.java @@ -124,7 +124,7 @@ public class DatabaseSource String guildId; ChannelType channelType = message.getChannelType(); - if(channelType == ChannelType.PRIVATE) + if(!(channelType.isGuild())) { guildId = userId; } else { @@ -220,7 +220,7 @@ public class DatabaseSource String guildId; ChannelType channelType = message.getChannelType(); - if(channelType == ChannelType.PRIVATE) + if(!(channelType.isGuild())) { guildId = "PRIVATE"; } else { diff --git a/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java b/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java index 595f2ab..f10df49 100644 --- a/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java +++ b/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java @@ -1,6 +1,9 @@ package wtf.beatrice.hidekobot.listeners; -import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; @@ -8,7 +11,10 @@ import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.comparators.MessageCommandAliasesComparator; import wtf.beatrice.hidekobot.util.Logger; -import java.util.*; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.TreeMap; public class MessageCommandListener extends ListenerAdapter { @@ -21,7 +27,6 @@ public class MessageCommandListener extends ListenerAdapter // (?i) -> case insensitive flag // ^ -> start of string (not in middle of a sentence) // \b -> the word has to end here - // .* -> there can be anything else after this word public void registerCommand(MessageCommand command) @@ -43,7 +48,6 @@ public class MessageCommandListener extends ListenerAdapter return null; } - public LinkedList getRegisteredCommands() { return new LinkedList<>(registeredCommands.values()); } @@ -55,10 +59,10 @@ public class MessageCommandListener extends ListenerAdapter { String eventMessage = event.getMessage().getContentDisplay(); + // check if the sent message matches the bot activation regex (prefix, name, ...) if(!eventMessage.toLowerCase().matches(commandRegex + ".*")) return; - MessageChannel channel = event.getChannel(); // generate args from the string String argsString = eventMessage.replaceAll(commandRegex + "\\s*", ""); @@ -81,24 +85,50 @@ public class MessageCommandListener extends ListenerAdapter String commandLabel = argsRaw[0]; MessageCommand commandObject = getRegisteredCommand(commandLabel); - if(commandObject != null) + if(commandObject == null) { - String[] commandArgs; - if(commandObject.passRawArgs()) - { - // remove first argument, which is the command label - argsString = argsString.replaceAll("^[\\S]+\\s+", ""); - // pass all other arguments as a single argument as the first array element - commandArgs = new String[]{argsString}; - } - else - { - // copy all split arguments to the array, except from the command label - commandArgs = Arrays.copyOfRange(argsRaw, 1, argsRaw.length); - } - commandObject.runCommand(event, commandLabel, commandArgs); - } else { event.getMessage().reply("Unrecognized command: `" + commandLabel + "`!").queue(); // todo prettier + return; } + + ChannelType channelType = event.getChannelType(); + + + // permissions check + List requiredPermissions = commandObject.getPermissions(); + if(requiredPermissions != null && !requiredPermissions.isEmpty()) + { + if(channelType.isGuild()) //todo: what about forum post + { + Member member = event.getMember(); + GuildChannel channel = event.getGuildChannel(); //todo: what about forum post + if(member != null) + { + if(!member.hasPermission(channel, requiredPermissions)) + { + event.getMessage() + .reply("You do not have permissions to run this command!") + .queue(); // todo prettier + return; + } + + } + } + } + + String[] commandArgs; + if(commandObject.passRawArgs()) + { + // remove first argument, which is the command label + argsString = argsString.replaceAll("^[\\S]+\\s+", ""); + // pass all other arguments as a single argument as the first array element + commandArgs = new String[]{argsString}; + } + else + { + // copy all split arguments to the array, except from the command label + commandArgs = Arrays.copyOfRange(argsRaw, 1, argsRaw.length); + } + commandObject.runCommand(event, commandLabel, commandArgs); } } diff --git a/src/main/java/wtf/beatrice/hidekobot/objects/commands/MessageCommand.java b/src/main/java/wtf/beatrice/hidekobot/objects/commands/MessageCommand.java index ffec1d7..fb6a462 100644 --- a/src/main/java/wtf/beatrice/hidekobot/objects/commands/MessageCommand.java +++ b/src/main/java/wtf/beatrice/hidekobot/objects/commands/MessageCommand.java @@ -1,8 +1,11 @@ package wtf.beatrice.hidekobot.objects.commands; +import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.jetbrains.annotations.Nullable; import java.util.LinkedList; +import java.util.List; public interface MessageCommand { @@ -16,10 +19,19 @@ public interface MessageCommand */ LinkedList getCommandLabels(); + /** + * A list of permissions required to run the command. This is preferred to checking them on your own + * as the message listener handles it more homogeneously. + * + * @return the list of required permissions. + */ + @Nullable + List getPermissions(); + /** * Say if this command does its own text parsing, and tell the message listener if it should automatically * split all arguments in separate entries of an array, or pass everything as the first entry of that array. - * + *

* This is better instead of getting the message contents from the event, because the message listener will * still strip the bot prefix and command name from the args, but leave the rest untouched. * @@ -30,7 +42,6 @@ public interface MessageCommand /** * Run the command logic by parsing the event and replying accordingly. * - * * @param event the received message event. It should not be used for parsing message contents data as * the arguments already account for it in a better way. * diff --git a/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java b/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java index 946ff62..f47157d 100644 --- a/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java +++ b/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java @@ -88,7 +88,7 @@ public class ExpiredMessageTask implements Runnable { } // if this is a DM - if(msgChannelType == ChannelType.PRIVATE) + if(!(msgChannelType.isGuild())) { String userId = databaseSource.getTrackedReplyUserId(messageId); User user = HidekoBot.getAPI().retrieveUserById(userId).complete();