Skip to content

Commit 8978945

Browse files
authored
Forbid posting blacklisted files (#542)
* added AttachmentListener checks if the message attachment contains blacklisted file extensions * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * added review feedback * fixed typo * added review feedback * added review feedback
1 parent 99a635d commit 8978945

File tree

4 files changed

+175
-2
lines changed

4 files changed

+175
-2
lines changed

application/config.json.template

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,43 @@
4545
],
4646
"categoryRoleSuffix": " - Helper"
4747
},
48-
"mediaOnlyChannelPattern": "memes"
48+
"mediaOnlyChannelPattern": "memes",
49+
"blacklistedFileExtension": [
50+
"application",
51+
"bat",
52+
"cmd",
53+
"com",
54+
"cpl",
55+
"exe",
56+
"gadget",
57+
"hta",
58+
"inf"
59+
"jse",
60+
"lnk",
61+
"msc",
62+
"msh",
63+
"msh1",
64+
"msh1xml",
65+
"msh2",
66+
"msh2xml",
67+
"mshxml",
68+
"msi",
69+
"msp",
70+
"pif",
71+
"ps1",
72+
"ps1xml",
73+
"ps2",
74+
"ps2xml",
75+
"psc1",
76+
"psc2",
77+
"scf",
78+
"scr",
79+
"vb",
80+
"vbe",
81+
"vbs",
82+
"ws",
83+
"wsc",
84+
"wsf",
85+
"wsh"
86+
]
4987
}

application/src/main/java/org/togetherjava/tjbot/commands/Features.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand;
1212
import org.togetherjava.tjbot.commands.mediaonly.MediaOnlyChannelListener;
1313
import org.togetherjava.tjbot.commands.moderation.*;
14+
import org.togetherjava.tjbot.commands.moderation.attachment.BlacklistedAttachmentListener;
1415
import org.togetherjava.tjbot.commands.moderation.scam.ScamBlocker;
1516
import org.togetherjava.tjbot.commands.moderation.scam.ScamHistoryPurgeRoutine;
1617
import org.togetherjava.tjbot.commands.moderation.scam.ScamHistoryStore;
@@ -92,6 +93,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
9293
features.add(new ImplicitAskListener(config, helpSystemHelper));
9394
features.add(new MediaOnlyChannelListener(config));
9495
features.add(new FileSharingMessageListener(config));
96+
features.add(new BlacklistedAttachmentListener(config, modAuditLogWriter));
9597

9698
// Event receivers
9799
features.add(new RejoinModerationRoleListener(actionsStore, config));
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package org.togetherjava.tjbot.commands.moderation.attachment;
2+
3+
import net.dv8tion.jda.api.EmbedBuilder;
4+
import net.dv8tion.jda.api.MessageBuilder;
5+
import net.dv8tion.jda.api.entities.Message;
6+
import net.dv8tion.jda.api.entities.MessageEmbed;
7+
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
8+
import net.dv8tion.jda.api.requests.RestAction;
9+
import org.togetherjava.tjbot.commands.MessageReceiverAdapter;
10+
import org.togetherjava.tjbot.config.Config;
11+
import org.togetherjava.tjbot.moderation.ModAuditLogWriter;
12+
13+
import javax.annotation.Nonnull;
14+
import java.awt.*;
15+
import java.util.List;
16+
import java.util.Locale;
17+
import java.util.regex.Pattern;
18+
19+
/**
20+
* Reacts to blacklisted attachments being posted, upon which they are deleted.
21+
*/
22+
public final class BlacklistedAttachmentListener extends MessageReceiverAdapter {
23+
private final ModAuditLogWriter modAuditLogWriter;
24+
private final List<String> blacklistedFileExtensions;
25+
26+
/**
27+
* Creates a AttachmentListener to receive all message sent in any channel.
28+
*
29+
* @param config to find the blacklisted media attachments
30+
* @param modAuditLogWriter to inform the mods about the suspicious attachment
31+
*/
32+
public BlacklistedAttachmentListener(Config config, ModAuditLogWriter modAuditLogWriter) {
33+
super(Pattern.compile(".*"));
34+
this.modAuditLogWriter = modAuditLogWriter;
35+
this.blacklistedFileExtensions = config.getBlacklistedFileExtensions();
36+
}
37+
38+
@Override
39+
public void onMessageReceived(MessageReceivedEvent event) {
40+
if (event.getAuthor().isBot() || event.isWebhookMessage()) {
41+
return;
42+
}
43+
if (doesMessageContainBlacklistedContent(event.getMessage())) {
44+
handleBadMessage(event.getMessage());
45+
}
46+
}
47+
48+
private void handleBadMessage(Message message) {
49+
message.delete().flatMap(any -> dmUser(message)).queue(any -> warnMods(message));
50+
}
51+
52+
@Nonnull
53+
private RestAction<Message> dmUser(Message message) {
54+
Message dmMessage = createDmMessage(message);
55+
return message.getAuthor()
56+
.openPrivateChannel()
57+
.flatMap(privateChannel -> privateChannel.sendMessage(dmMessage));
58+
}
59+
60+
@Nonnull
61+
private Message createDmMessage(Message originalMessage) {
62+
String contentRaw = originalMessage.getContentRaw();
63+
String blacklistedAttachments =
64+
String.join(", ", getBlacklistedAttachmentsFromMessage(originalMessage));
65+
66+
String dmMessageContent =
67+
"""
68+
Hey there, you posted a message containing a blacklisted file attachment: %s.
69+
We had to delete your message for security reasons.
70+
71+
Feel free to repost your message without, or with a different file instead. Sorry for any inconvenience caused by this 🙇️
72+
"""
73+
.formatted(blacklistedAttachments);
74+
75+
// No embed needed if there was no message from the user
76+
if (contentRaw.isEmpty()) {
77+
return new MessageBuilder(dmMessageContent).build();
78+
}
79+
return createBaseResponse(contentRaw, dmMessageContent);
80+
}
81+
82+
@Nonnull
83+
private Message createBaseResponse(String originalMessageContent, String dmMessageContent) {
84+
MessageEmbed originalMessageEmbed =
85+
new EmbedBuilder().setDescription(originalMessageContent)
86+
.setColor(Color.ORANGE)
87+
.build();
88+
return new MessageBuilder(dmMessageContent).setEmbeds(originalMessageEmbed).build();
89+
}
90+
91+
@Nonnull
92+
private List<String> getBlacklistedAttachmentsFromMessage(Message originalMessage) {
93+
return originalMessage.getAttachments()
94+
.stream()
95+
.filter(attachment -> blacklistedFileExtensions
96+
.contains(attachment.getFileExtension().toLowerCase(Locale.US)))
97+
.map(Message.Attachment::getFileName)
98+
.toList();
99+
}
100+
101+
private boolean doesMessageContainBlacklistedContent(Message message) {
102+
return message.getAttachments()
103+
.stream()
104+
.anyMatch(attachment -> blacklistedFileExtensions
105+
.contains(attachment.getFileExtension().toLowerCase(Locale.US)));
106+
}
107+
108+
private void warnMods(Message sentUserMessage) {
109+
String blacklistedAttachmentsFromMessage =
110+
String.join(", ", getBlacklistedAttachmentsFromMessage(sentUserMessage));
111+
112+
modAuditLogWriter.write(
113+
"Message with blacklisted content detected: %s"
114+
.formatted(blacklistedAttachmentsFromMessage),
115+
"Sent Message: %s".formatted(sentUserMessage), sentUserMessage.getAuthor(),
116+
sentUserMessage.getTimeCreated(), sentUserMessage.getGuild());
117+
}
118+
}

application/src/main/java/org/togetherjava/tjbot/config/Config.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import javax.annotation.Nonnull;
99
import java.io.IOException;
1010
import java.nio.file.Path;
11+
import java.util.Collections;
12+
import java.util.List;
1113

1214
/**
1315
* Configuration of the application. Create instances using {@link #load(Path)}.
@@ -28,6 +30,7 @@ public final class Config {
2830
private final ScamBlockerConfig scamBlocker;
2931
private final String wolframAlphaAppId;
3032
private final HelpSystemConfig helpSystem;
33+
private final List<String> blacklistedFileExtension;
3134

3235
private final String mediaOnlyChannelPattern;
3336

@@ -48,7 +51,8 @@ private Config(@JsonProperty("token") String token,
4851
@JsonProperty("scamBlocker") ScamBlockerConfig scamBlocker,
4952
@JsonProperty("wolframAlphaAppId") String wolframAlphaAppId,
5053
@JsonProperty("helpSystem") HelpSystemConfig helpSystem,
51-
@JsonProperty("mediaOnlyChannelPattern") String mediaOnlyChannelPattern) {
54+
@JsonProperty("mediaOnlyChannelPattern") String mediaOnlyChannelPattern,
55+
@JsonProperty("blacklistedFileExtension") List<String> blacklistedFileExtension) {
5256
this.token = token;
5357
this.gistApiKey = gistApiKey;
5458
this.databasePath = databasePath;
@@ -65,6 +69,7 @@ private Config(@JsonProperty("token") String token,
6569
this.wolframAlphaAppId = wolframAlphaAppId;
6670
this.helpSystem = helpSystem;
6771
this.mediaOnlyChannelPattern = mediaOnlyChannelPattern;
72+
this.blacklistedFileExtension = blacklistedFileExtension;
6873
}
6974

7075
/**
@@ -235,4 +240,14 @@ public HelpSystemConfig getHelpSystem() {
235240
public String getMediaOnlyChannelPattern() {
236241
return mediaOnlyChannelPattern;
237242
}
243+
244+
/**
245+
* Gets a list of all blacklisted file extensions.
246+
*
247+
* @return a list of all blacklisted file extensions
248+
*/
249+
@Nonnull
250+
public List<String> getBlacklistedFileExtensions() {
251+
return Collections.unmodifiableList(blacklistedFileExtension);
252+
}
238253
}

0 commit comments

Comments
 (0)