diff --git a/pom.xml b/pom.xml
index 3c8cee5..26d7494 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
net.pcsx2
HifumiBot
- 4.10.0
+ 4.10.1
21
21
diff --git a/src/main/java/net/pcsx2/hifumi/async/AntiBotRunnable.java b/src/main/java/net/pcsx2/hifumi/async/AntiBotRunnable.java
index f18458f..4888019 100644
--- a/src/main/java/net/pcsx2/hifumi/async/AntiBotRunnable.java
+++ b/src/main/java/net/pcsx2/hifumi/async/AntiBotRunnable.java
@@ -1,9 +1,20 @@
package net.pcsx2.hifumi.async;
import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.net.URI;
+import java.net.URL;
import java.time.OffsetDateTime;
import java.util.ArrayList;
+import javax.imageio.ImageIO;
+
+import org.apache.commons.lang3.StringUtils;
+
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.buttons.Button;
@@ -12,6 +23,7 @@
import net.dv8tion.jda.api.entities.Message.Attachment;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.utils.FileUpload;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.pcsx2.hifumi.HifumiBot;
import net.pcsx2.hifumi.database.Database;
@@ -57,8 +69,40 @@ private boolean isImageScam() {
User user = this.message.getAuthor();
if (timeoutRes) {
- // Since our timeout succeeded, now sweep up any other messages the bot might have
- // blasted out while this runnable was going.
+ // Since our timeout succeeded, grab some thumbnails of the images so we have something to present for review before deleting stuff.
+ // If we delete the message first then attachments go too.
+ ArrayList files = new ArrayList();
+
+ for (Attachment attachment : this.message.getAttachments()) {
+ // For now, just do one image... If we have problems later and need them all, yank out this if.
+ if (!files.isEmpty()) {
+ break;
+ }
+
+ try {
+ URL url = URL.of(URI.create(attachment.getProxyUrl()), null);
+ BufferedImage img = ImageIO.read(url);
+ int width = img.getWidth() / 2, height = img.getHeight() / 2;
+ Image scaled = img.getScaledInstance(width, height, Image.SCALE_FAST);
+ BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D graph = bufImg.createGraphics();
+ graph.drawImage(scaled, 0, 0, null);
+ graph.dispose();
+
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ ImageIO.write(bufImg, "png", os);
+
+ try (ByteArrayInputStream imgStream = new ByteArrayInputStream(os.toByteArray())) {
+ FileUpload file = FileUpload.fromData(imgStream, attachment.getFileName()).asSpoiler();
+ files.add(file);
+ }
+ }
+ } catch (Exception e) {
+ // Squelch
+ }
+ }
+
+ // Sweep up any other messages the bot might have blasted out while this runnable was going.
OffsetDateTime timeToRemoveMessagesSince = OffsetDateTime.now().minusMinutes(AGE_MINUTES_TO_REMOVE_MESSAGES);
ArrayList otherMessages = Database.getAllMessagesSinceTime(this.message.getAuthor().getIdLong(), timeToRemoveMessagesSince.toEpochSecond());
@@ -75,24 +119,36 @@ private boolean isImageScam() {
eb.addField("Username", user.getName(), true);
eb.addField("Display Name (as mention)", user.getAsMention(), true);
eb.setColor(Color.YELLOW);
- eb.appendDescription("Links in body:\n");
+
+ // Body content preview
+ eb.addField("Body Content (raw, first 100 chars)", StringUtils.abbreviate(this.message.getContentRaw(), 100), false);
+
+ // Links
+ StringBuilder sb = new StringBuilder();
for (String link : links) {
- eb.appendDescription(link + "\n");
+ sb.append(link + "\n");
}
-
- eb.appendDescription("Attachments:\n");
+
+ eb.addField("Links in Body", sb.toString(), false);
+
+ // Attachments
+ sb = new StringBuilder();
for (Attachment attachment : this.message.getAttachments()) {
- eb.appendDescription(attachment.getProxyUrl() + "\n");
+ sb.append(attachment.getProxyUrl() + "\n");
}
+
+ eb.addField("Attachments", sb.toString(), false);
MessageCreateBuilder mb = new MessageCreateBuilder();
mb.addEmbeds(eb.build());
+ mb.addFiles(files);
mb.addComponents(ActionRow.of(
Button.of(ButtonStyle.DANGER, "imagescam:dospamkick:" + authorIdLong, "Looks like a bot scam, kick user"),
Button.of(ButtonStyle.SUCCESS, "imagescam:clear:" + authorIdLong, "Looks innocent, remove timeout")
));
+
Messaging.sendMessage(HifumiBot.getSelf().getConfig().channels.systemOutputChannelId, mb.build());
return true;
} else {
diff --git a/src/main/java/net/pcsx2/hifumi/event/ButtonEventListener.java b/src/main/java/net/pcsx2/hifumi/event/ButtonEventListener.java
index 68dce6c..1596d2b 100644
--- a/src/main/java/net/pcsx2/hifumi/event/ButtonEventListener.java
+++ b/src/main/java/net/pcsx2/hifumi/event/ButtonEventListener.java
@@ -3,19 +3,10 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
-import net.pcsx2.hifumi.HifumiBot;
-import net.pcsx2.hifumi.command.AbstractSlashCommand;
-import net.pcsx2.hifumi.command.slash.CommandEmulog;
-import net.pcsx2.hifumi.command.slash.CommandServerMetadata;
-import net.pcsx2.hifumi.command.slash.CommandWhois;
-import net.pcsx2.hifumi.moderation.ModActions;
-import net.pcsx2.hifumi.util.MemberUtils;
-import net.pcsx2.hifumi.util.Messaging;
-import net.pcsx2.hifumi.util.UserUtils;
-
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.components.MessageTopLevelComponent;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
@@ -25,6 +16,15 @@
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import net.pcsx2.hifumi.HifumiBot;
+import net.pcsx2.hifumi.command.AbstractSlashCommand;
+import net.pcsx2.hifumi.command.slash.CommandEmulog;
+import net.pcsx2.hifumi.command.slash.CommandServerMetadata;
+import net.pcsx2.hifumi.command.slash.CommandWhois;
+import net.pcsx2.hifumi.moderation.ModActions;
+import net.pcsx2.hifumi.util.MemberUtils;
+import net.pcsx2.hifumi.util.Messaging;
+import net.pcsx2.hifumi.util.UserUtils;
public class ButtonEventListener extends ListenerAdapter {
@@ -132,6 +132,7 @@ public void onButtonInteraction(ButtonInteractionEvent event) {
Button button = Button.of(ButtonStyle.PRIMARY, "imagescam:resolved:" + userIdLong, "Resolved by " + event.getUser().getEffectiveName() + " (kicked user)");
ActionRow actionRow = ActionRow.of(button);
event.getHook().editMessageComponentsById(event.getMessageId(), actionRow).queue();
+ event.getMessage().editMessageAttachments(List.of()).queue();
}
case "clear" -> {
Optional memberOpt = MemberUtils.getOrRetrieveMember(event.getGuild(), userIdLong);
@@ -140,10 +141,14 @@ public void onButtonInteraction(ButtonInteractionEvent event) {
Member member = memberOpt.get();
member.removeTimeout().queue();
event.reply("Timeout removed from user").setEphemeral(true).queue();
- Button button = Button.of(ButtonStyle.PRIMARY, "imagescam:resolved:" + userIdLong, "Resolved by " + event.getUser().getEffectiveName() + " (removed timeout)");
- ActionRow actionRow = ActionRow.of(button);
- event.getHook().editMessageComponentsById(event.getMessageId(), actionRow).queue();
+ } else {
+ event.reply("User could not be retrieved, did they already leave?").setEphemeral(true).queue();
}
+
+ Button button = Button.of(ButtonStyle.PRIMARY, "imagescam:resolved:" + userIdLong, "Resolved by " + event.getUser().getEffectiveName() + " (removed timeout)");
+ ActionRow actionRow = ActionRow.of(button);
+ event.getHook().editMessageComponentsById(event.getMessageId(), actionRow).queue();
+ event.getMessage().editMessageAttachments(List.of()).queue();
}
case "resolved" -> {
event.reply("This event has already been resolved.").setEphemeral(true).queue();