| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent cf9421d commit 8e0f29f
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -28,6 +28,18 @@ public class ModerationConfig extends GuildConfigItem { | |||
| 28 | 28 | private long adminRoleId = 0; | |
| 29 | 29 | private long expertRoleId = 0; | |
| 30 | 30 | ||
| 31 | + /** | ||
| 32 | + * The time window, in seconds, that the cross-channel spam automod looks back over when | ||
| 33 | + * counting a user's recent messages. If this is {@code 0}, the cross-channel spam automod | ||
| 34 | + * is disabled. | ||
| 35 | + */ | ||
| 36 | + private int crossChannelSpamWindowSeconds = 0; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * The number of distinct channels a user must post in within | ||
| 40 | + * {@link #crossChannelSpamWindowSeconds} seconds before the cross-channel spam automod acts. | ||
| 41 | + */ | ||
| 42 | + private int crossChannelSpamMinChannels = 3; | ||
| 31 | 43 | /** | |
| 32 | 44 | * ID of the share-knowledge channel. | |
| 33 | 45 | */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -39,10 +39,10 @@ public void onMessageUpdate(@NotNull MessageUpdateEvent event) { | |||
| 39 | 39 | CachedMessage before; | |
| 40 | 40 | if (optional.isPresent()) { | |
| 41 | 41 | CachedMessage inCache= optional.get(); | |
| 42 | - before = new CachedMessage(inCache.getMessageId(), inCache.getAuthorId(), inCache.getMessageContent(), inCache.getAttachments()); | ||
| 42 | + before = new CachedMessage(inCache.getMessageId(), inCache.getAuthorId(), inCache.getChannelId(),inCache.getMessageContent(), inCache.getAttachments()); | ||
| 43 | 43 | inCache.init(event.getMessage()); | |
| 44 | 44 | } else { | |
| 45 | - before = new CachedMessage(event.getMessageIdLong(), event.getAuthor().getIdLong(), "[unknown content]", List.of()); | ||
| 45 | + before = new CachedMessage(event.getMessageIdLong(), event.getAuthor().getIdLong(), event.getChannel().getIdLong(),"[unknown content]", List.of()); | ||
| 46 | 46 | messageCache.cache(event.getMessage()); | |
| 47 | 47 | } | |
| 48 | 48 | messageCache.sendUpdatedMessageToLog(event.getMessage(), before); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -88,7 +88,7 @@ public List<CachedMessage> getAll() throws DataAccessException { | |||
| 88 | 88 | messages.merge(msg.getMessageId(), msg, (oldValue, value) -> { | |
| 89 | 89 | ArrayList<String> attachments = new ArrayList<>(oldValue.getAttachments()); | |
| 90 | 90 | attachments.addAll(value.getAttachments()); | |
| 91 | - return new CachedMessage(oldValue.getMessageId(), oldValue.getAuthorId(), oldValue.getMessageContent(), attachments); | ||
| 91 | + return new CachedMessage(oldValue.getMessageId(), oldValue.getAuthorId(), oldValue.getChannelId(),oldValue.getMessageContent(), attachments); | ||
| 92 | 92 | }); | |
| 93 | 93 | } | |
| 94 | 94 | return new ArrayList<>(messages.values()); | |
@@ -119,6 +119,7 @@ private CachedMessage read(ResultSet rs) throws SQLException { | |||
| 119 | 119 | return new CachedMessage( | |
| 120 | 120 | rs.getLong("message_cache.message_id"), | |
| 121 | 121 | rs.getLong("author_id"), | |
| 122 | + rs.getLong("channel_id"), | ||
| 122 | 123 | rs.getString("message_content"), | |
| 123 | 124 | attachments); | |
| 124 | 125 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,7 @@ | |||
| 9 | 9 | import net.discordjug.javabot.util.MessageUtils; | |
| 10 | 10 | import net.dv8tion.jda.api.entities.Message; | |
| 11 | 11 | import net.dv8tion.jda.api.entities.Message.Attachment; | |
| 12 | + import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; | ||
| 12 | 13 | ||
| 13 | 14 | /** | |
| 14 | 15 | * Represents a cached Message. | |
@@ -19,12 +20,14 @@ | |||
| 19 | 20 | public class CachedMessage { | |
| 20 | 21 | private final long messageId; | |
| 21 | 22 | private final long authorId; | |
| 23 | + private final long channelId; | ||
| 22 | 24 | private String messageContent; | |
| 23 | 25 | private List<String> attachments=new ArrayList<>(); | |
| 24 | 26 | ||
| 25 | - private CachedMessage(long messageId, long authorId) { | ||
| 27 | + private CachedMessage(long messageId, long authorId,long channelId) { | ||
| 26 | 28 | this.messageId = messageId; | |
| 27 | 29 | this.authorId = authorId; | |
| 30 | + this.channelId = channelId; | ||
| 28 | 31 | } | |
| 29 | 32 | ||
| 30 | 33 | /** | |
@@ -34,10 +37,11 @@ private CachedMessage(long messageId, long authorId) { | |||
| 34 | 37 | * @param messageContent the textual content of the message | |
| 35 | 38 | * @param attachments The attachment URLs | |
| 36 | 39 | */ | |
| 37 | - public CachedMessage(long messageId, long authorId, String messageContent, List<String> attachments) { | ||
| 40 | + public CachedMessage(long messageId, long authorId, long channelId, String messageContent, List<String> attachments) { | ||
| 38 | 41 | super(); | |
| 39 | 42 | this.messageId = messageId; | |
| 40 | 43 | this.authorId = authorId; | |
| 44 | + this.channelId = channelId; | ||
| 41 | 45 | this.messageContent = messageContent; | |
| 42 | 46 | this.attachments = List.copyOf(attachments); | |
| 43 | 47 | } | |
@@ -49,7 +53,7 @@ public CachedMessage(long messageId, long authorId, String messageContent, List< | |||
| 49 | 53 | * @return The built {@link CachedMessage}. | |
| 50 | 54 | */ | |
| 51 | 55 | public static CachedMessage of(Message message) { | |
| 52 | - CachedMessage cachedMessage = new CachedMessage(message.getIdLong(), message.getAuthor().getIdLong()); | ||
| 56 | + CachedMessage cachedMessage = new CachedMessage(message.getIdLong(), message.getAuthor().getIdLong(),message.getChannelIdLong()); | ||
| 53 | 57 | cachedMessage.init(message); | |
| 54 | 58 | return cachedMessage; | |
| 55 | 59 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,12 +2,15 @@ | |||
| 2 | 2 | ||
| 3 | 3 | import lombok.extern.slf4j.Slf4j; | |
| 4 | 4 | import net.discordjug.javabot.data.config.BotConfig; | |
| 5 | + import net.discordjug.javabot.data.config.guild.ModerationConfig; | ||
| 5 | 6 | import net.discordjug.javabot.data.h2db.message_cache.MessageCache; | |
| 7 | + import net.discordjug.javabot.data.h2db.message_cache.model.CachedMessage; | ||
| 6 | 8 | import net.discordjug.javabot.systems.moderation.warn.model.WarnSeverity; | |
| 7 | 9 | import net.discordjug.javabot.systems.notification.NotificationService; | |
| 8 | 10 | import net.discordjug.javabot.util.ExceptionLogger; | |
| 9 | 11 | import net.discordjug.javabot.util.MessageUtils; | |
| 10 | 12 | import net.dv8tion.jda.api.Permission; | |
| 13 | + import net.dv8tion.jda.api.entities.Guild; | ||
| 11 | 14 | import net.dv8tion.jda.api.entities.Member; | |
| 12 | 15 | import net.dv8tion.jda.api.entities.Message; | |
| 13 | 16 | import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; | |
@@ -24,6 +27,7 @@ | |||
| 24 | 27 | import java.net.URL; | |
| 25 | 28 | import java.time.Duration; | |
| 26 | 29 | import java.time.temporal.ChronoUnit; | |
| 30 | + import java.util.ArrayList; | ||
| 27 | 31 | import java.util.Collections; | |
| 28 | 32 | import java.util.List; | |
| 29 | 33 | import java.util.Scanner; | |
@@ -50,7 +54,7 @@ public class AutoMod extends ListenerAdapter { | |||
| 50 | 54 | private final MessageCache messageCache; | |
| 51 | 55 | ||
| 52 | 56 | /** | |
| 53 | - * Constructor of the class, that creates a list of strings with potential spam/scam urls. | ||
| 57 | + * Constructor of the class, that creates a list of strings with potential spam/scam URLs. | ||
| 54 | 58 | * @param notificationService The {@link QOTWPointsService} | |
| 55 | 59 | * @param botConfig The main configuration of the bot | |
| 56 | 60 | * @param moderationService Service object for moderating members | |
@@ -108,18 +112,33 @@ private void checkNewMessageAutomod(@Nonnull Message message) { | |||
| 108 | 112 | .stream() | |
| 109 | 113 | .filter(cached -> cached.getMessageId() != message.getIdLong()) // exclude new/current message | |
| 110 | 114 | .filter(cached -> cached.getAuthorId() == message.getAuthor().getIdLong()) | |
| 111 | - .filter(cached -> | ||
| 115 | + .filter(cached -> | ||
| 112 | 116 | // only java files -> not spam | |
| 113 | - cached.getAttachments().isEmpty() || | ||
| 117 | + cached.getAttachments().isEmpty() || | ||
| 114 | 118 | cached.getAttachments().stream() | |
| 115 | 119 | .anyMatch(attachment -> !attachment.contains(".java?"))) | |
| 116 | 120 | .count() + 1; // include new message | |
| 117 | - | ||
| 121 | + | ||
| 118 | 122 | if (spamCount >= 5) { | |
| 119 | 123 | handleSpam(message, message.getMember()); | |
| 120 | 124 | } | |
| 121 | 125 | ||
| 122 | 126 | checkContentAutomod(message); | |
| 127 | + checkCrossChannelSpam(message); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + private void checkCrossChannelSpam(@Nonnull Message message) { | ||
| 131 | + List<CachedMessage> spamMessages = new ArrayList<>(); | ||
| 132 | + messageCache.getMessagesAfter(message.getTimeCreated().minusSeconds((botConfig.get(message.getGuild()).getModerationConfig()).getCrossChannelSpamWindowSeconds())).stream() | ||
| 133 | + .filter(cachedMessage -> cachedMessage.getAuthorId() == message.getAuthor().getIdLong()) | ||
| 134 | + .filter(cachedMessage -> spamMessages.stream().noneMatch( | ||
| 135 | + spamMessage -> spamMessage.getChannelId() == cachedMessage.getChannelId())) | ||
| 136 | + .forEach(spamMessages::add); | ||
| 137 | + | ||
| 138 | + if(spamMessages.size() > (botConfig.get(message.getGuild()).getModerationConfig()).getCrossChannelSpamMinChannels()){ | ||
| 139 | + handleSpam(spamMessages,message); | ||
| 140 | + } | ||
| 141 | + | ||
| 123 | 142 | } | |
| 124 | 143 | ||
| 125 | 144 | /** | |
@@ -174,6 +193,22 @@ private void handleSpam(@Nonnull Message msg, Member member) { | |||
| 174 | 193 | msg.delete().queue(); | |
| 175 | 194 | } | |
| 176 | 195 | ||
| 196 | + private void handleSpam(@Nonnull List<CachedMessage> cachedMessages, Message message) { | ||
| 197 | + Guild guild = message.getGuild(); | ||
| 198 | + moderationService | ||
| 199 | + .timeout( | ||
| 200 | + message.getAuthor(), | ||
| 201 | + "Automod: Spam", | ||
| 202 | + message.getGuild().getSelfMember(), | ||
| 203 | + Duration.of(6, ChronoUnit.HOURS), | ||
| 204 | + message.getChannel(), | ||
| 205 | + false | ||
| 206 | + ); | ||
| 207 | + | ||
| 208 | + cachedMessages.forEach(cachedMessage -> guild.getTextChannelById(cachedMessage.getChannelId()) | ||
| 209 | + .deleteMessageById(cachedMessage.getMessageId()).queue()); | ||
| 210 | + } | ||
| 211 | + | ||
| 177 | 212 | /** | |
| 178 | 213 | * returns the original String cleaned up of unused code points and spaces. | |
| 179 | 214 | * | |
@@ -218,7 +253,7 @@ public boolean hasSuspiciousLink(@NotNull Message message) { | |||
| 218 | 253 | * Checks whether the given message contains a discord invite link. | |
| 219 | 254 | * | |
| 220 | 255 | * @param message The Message to check. | |
| 221 | - * @return True if an invite is found and False if not. | ||
| 256 | + * @return True if an invitation is found and False if not. | ||
| 222 | 257 | */ | |
| 223 | 258 | public boolean hasAdvertisingLink(@NotNull Message message) { | |
| 224 | 259 | // Advertising | |
@@ -237,5 +272,5 @@ private boolean isSuggestionsChannel(@NotNull MessageChannelUnion channel) { | |||
| 237 | 272 | return channel.getType().isGuild() && | |
| 238 | 273 | channel.getIdLong() == botConfig.get(channel.asGuildMessageChannel().getGuild()).getModerationConfig().getSuggestionChannel().getIdLong(); | |
| 239 | 274 | } | |
| 240 | - | ||
| 275 | + | ||
| 241 | 276 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments