From 41b50c7e59505ded80f3d48c35957aa6a496881a Mon Sep 17 00:00:00 2001 From: rhel Date: Thu, 4 Dec 2025 12:53:42 -0600 Subject: [PATCH 1/2] =?UTF-8?q?Added=20reply=20for=20log=20request=20Added?= =?UTF-8?q?=20GnomeBot=20redirector=20Fixed=20cd=5Flauncherlog=20not=20bei?= =?UTF-8?q?ng=20detected=20as=20an=20ok=20file=20Fixed=20=C2=BA=20prefix?= =?UTF-8?q?=20not=20working?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nl/finnt730/Main.java | 14 ++- .../nl/finnt730/commands/CommandCache.java | 2 +- .../builtin/reserved/AliasCommand.java | 1 + .../builtin/reserved/ReservedCommand.java | 2 +- .../listeners/GnomeBotDevListener.java | 96 +++++++++++++++++++ .../nl/finnt730/listeners/PasteListener.java | 7 +- 6 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 src/main/java/nl/finnt730/listeners/GnomeBotDevListener.java diff --git a/src/main/java/nl/finnt730/Main.java b/src/main/java/nl/finnt730/Main.java index cad6c8a..190723f 100644 --- a/src/main/java/nl/finnt730/Main.java +++ b/src/main/java/nl/finnt730/Main.java @@ -1,6 +1,13 @@ package nl.finnt730; +import java.io.File; +import java.util.EnumSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.jsonstructure.DynamicJson; + import haxe.root.JsonStructureLib; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.requests.GatewayIntent; @@ -8,12 +15,8 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag; import nl.finnt730.commands.CommandMigrator; import nl.finnt730.listeners.CommandListener; +import nl.finnt730.listeners.GnomeBotDevListener; import nl.finnt730.listeners.PasteListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.EnumSet; public final class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); @@ -59,6 +62,7 @@ public static void main(String[] args) { discordLogger.info("Starting Discord bot..."); JDABuilder.createLight(botToken, EnumSet.of(GatewayIntent.GUILD_MESSAGES, GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_MESSAGE_POLLS, GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS)) .addEventListeners(new CommandListener()) + .addEventListeners(new GnomeBotDevListener()) .addEventListeners(new PasteListener()) .enableCache(CacheFlag.ROLE_TAGS) .setMemberCachePolicy(MemberCachePolicy.ALL) // Would do ONLINE but I don't think that will work if you aren't literally set to Online status. diff --git a/src/main/java/nl/finnt730/commands/CommandCache.java b/src/main/java/nl/finnt730/commands/CommandCache.java index 84b2726..1bcf1c8 100644 --- a/src/main/java/nl/finnt730/commands/CommandCache.java +++ b/src/main/java/nl/finnt730/commands/CommandCache.java @@ -18,7 +18,7 @@ public class CommandCache { private static final Map cache = new HashMap<>(); public static final String DEFAULT_PREFIX = "!"; - public static final String HOI4_ESP = "º";//In HOI4 they always use the key next to 1 no matter the layout. + public static final String HOI4_ESP = "\u00BA";//In HOI4 they always use the key next to 1 no matter the layout. private static final DatabaseManager dbManager = DatabaseManager.getInstance(); // Init builtin commands diff --git a/src/main/java/nl/finnt730/commands/builtin/reserved/AliasCommand.java b/src/main/java/nl/finnt730/commands/builtin/reserved/AliasCommand.java index b00e3c9..daebf2a 100644 --- a/src/main/java/nl/finnt730/commands/builtin/reserved/AliasCommand.java +++ b/src/main/java/nl/finnt730/commands/builtin/reserved/AliasCommand.java @@ -49,6 +49,7 @@ public void handle(MessageReceivedEvent event, Member invoker, String commandCon } } catch (Exception ex) { event.getChannel().sendMessage("Something went wrong while trying to add aliases. Try again.").queue(); + ex.printStackTrace(); } } } diff --git a/src/main/java/nl/finnt730/commands/builtin/reserved/ReservedCommand.java b/src/main/java/nl/finnt730/commands/builtin/reserved/ReservedCommand.java index 45fac93..072d304 100644 --- a/src/main/java/nl/finnt730/commands/builtin/reserved/ReservedCommand.java +++ b/src/main/java/nl/finnt730/commands/builtin/reserved/ReservedCommand.java @@ -11,6 +11,6 @@ public ReservedCommand() { @Override public final boolean canInvoke(Guild guild, Member invoker) { - return invoker.getRoles().stream().anyMatch((role) -> role.isHoisted() || Global.isManager(role)); + return invoker.getRoles().stream().anyMatch((role) -> role.isHoisted() || Global.isManager(role) || invoker.isOwner()); } } diff --git a/src/main/java/nl/finnt730/listeners/GnomeBotDevListener.java b/src/main/java/nl/finnt730/listeners/GnomeBotDevListener.java new file mode 100644 index 0000000..d444784 --- /dev/null +++ b/src/main/java/nl/finnt730/listeners/GnomeBotDevListener.java @@ -0,0 +1,96 @@ +package nl.finnt730.listeners; + +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.entities.emoji.Emoji; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GnomeBotDevListener extends ListenerAdapter { + private static final Logger logger = LoggerFactory.getLogger("nl.finnt730.linkconverter"); + private static final String GNOMEBOT_DOMAIN = "gnomebot.dev"; + private static final String MCLOGS_PATH = "/paste/mclogs/"; + private static final String SHIELD_EMOJI = "🛡️"; + private static final Emoji SHIELD_EMOJI_OBJ = Emoji.fromUnicode(SHIELD_EMOJI); + + private static final Pattern GNOMEBOT_PATTERN = Pattern.compile( + "https?://" + Pattern.quote(GNOMEBOT_DOMAIN) + Pattern.quote(MCLOGS_PATH) + "([a-zA-Z0-9]+)", + Pattern.CASE_INSENSITIVE); + private static final Pattern LOGS_UPLOADED_PATTERN = Pattern + .compile("The logs have been uploaded to `" + Pattern.quote(GNOMEBOT_DOMAIN) + "`"); + + @Override + public void onMessageReceived(MessageReceivedEvent event) { + try { + if (event.getAuthor().isBot()) { + return; + } + + Message message = event.getMessage(); + String content = message.getContentRaw(); + + if (content.contains(GNOMEBOT_DOMAIN)) { + logger.debug("Found gnomebot.dev link in message from user {}", event.getAuthor().getName()); + message.addReaction(SHIELD_EMOJI_OBJ).queue(); + } + } catch (Exception e) { + logger.error("Error processing message for link conversion setup", e); + } + } + + @Override + public void onMessageReactionAdd(MessageReactionAddEvent event) { + try { + if (event.getUser().isBot()) { + return; + } + + if (SHIELD_EMOJI.equals(event.getReaction().getEmoji().getName())) { + logger.info("Link conversion reaction triggered by user {} on message {}", event.getUser().getName(), + event.getMessageId()); + + event.getChannel().retrieveMessageById(event.getMessageId()).queue(message -> { + // Clear all reactions first to prevent duplicate processing + message.clearReactions().queue(v -> { + try { + String content = message.getContentRaw(); + final String convertedContent = LOGS_UPLOADED_PATTERN.matcher(convertGnomebotLinks(content)) + .replaceAll("The logs have been uploaded to `mclo.gs`"); + + if (!convertedContent.equals(content)) { + message.reply(convertedContent).mentionRepliedUser(false).queue(); + } + } catch (Exception e) { + logger.error("Error processing link conversion reaction", e); + } + }); + }); + } + } catch (Exception e) { + logger.error("Error handling link conversion reaction", e); + } + } + + private String convertGnomebotLinks(String content) { + Matcher matcher = GNOMEBOT_PATTERN.matcher(content); + StringBuffer result = new StringBuffer(); + + while (matcher.find()) { + String originalLink = matcher.group(0); + String linkId = matcher.group(1); + String mcloLink = "https://mclo.gs/" + linkId; + + logger.debug("Converting link: {} -> {}", originalLink, mcloLink); + matcher.appendReplacement(result, mcloLink); + } + matcher.appendTail(result); + + return result.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/nl/finnt730/listeners/PasteListener.java b/src/main/java/nl/finnt730/listeners/PasteListener.java index 0b56c41..e6987bc 100644 --- a/src/main/java/nl/finnt730/listeners/PasteListener.java +++ b/src/main/java/nl/finnt730/listeners/PasteListener.java @@ -106,7 +106,7 @@ public void onMessageReactionAdd(MessageReactionAddEvent event) { } } } - createPaste(attachmentContent, event.getChannel(), fileNames, event.getUserId()); + createPaste(attachmentContent, event.getChannel(), fileNames, event.getUserId(),message); } } catch (Exception e) { logger.error("Error processing paste reaction", e); @@ -119,7 +119,7 @@ public void onMessageReactionAdd(MessageReactionAddEvent event) { } private static void createPaste(List contentList, MessageChannel channel, - List fileNames, String userId) { + List fileNames, String userId, Message message) { CompletableFuture.runAsync(() -> { try { logger.info("Creating paste for user {} with {} files", userId, contentList.size()); @@ -164,7 +164,7 @@ private static void createPaste(List contentList, MessageChannel channel } } - channel.sendMessage(pasteResponse.toString()).queue(); + message.reply(pasteResponse.toString()).mentionRepliedUser(false).queue(); logger.info("Paste creation completed for user {}", userId); } catch (Exception e) { logger.error("Error in paste creation process", e); @@ -174,6 +174,7 @@ private static void createPaste(List contentList, MessageChannel channel private static boolean isPasteable(Message.Attachment attachment) { if (attachment.isVideo() || attachment.isImage()) return false; + if(attachment.getFileName().equals("cd_launcherlog")) return true; return !DENYLISTED_EXTENSIONS.contains(attachment.getFileExtension()); } } \ No newline at end of file From 8c93c8182735bc2dc3f35ac9e5b8c96a0a0ec37b Mon Sep 17 00:00:00 2001 From: rhel Date: Thu, 4 Dec 2025 22:43:43 -0600 Subject: [PATCH 2/2] Added ability for BotManagers to delete bot messages. --- .gitignore | 4 ++ src/main/java/nl/finnt730/Main.java | 2 + .../listeners/SelfDestructListener.java | 70 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/main/java/nl/finnt730/listeners/SelfDestructListener.java diff --git a/.gitignore b/.gitignore index 6d350e3..701e590 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ bin/ /env.json userdb.json /commands +prod.db +logs/forgebot-errors.log +logs/forgebot-io.log +logs/forgebot.log diff --git a/src/main/java/nl/finnt730/Main.java b/src/main/java/nl/finnt730/Main.java index 190723f..54d240a 100644 --- a/src/main/java/nl/finnt730/Main.java +++ b/src/main/java/nl/finnt730/Main.java @@ -17,6 +17,7 @@ import nl.finnt730.listeners.CommandListener; import nl.finnt730.listeners.GnomeBotDevListener; import nl.finnt730.listeners.PasteListener; +import nl.finnt730.listeners.SelfDestructListener; public final class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); @@ -63,6 +64,7 @@ public static void main(String[] args) { JDABuilder.createLight(botToken, EnumSet.of(GatewayIntent.GUILD_MESSAGES, GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_MESSAGE_POLLS, GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS)) .addEventListeners(new CommandListener()) .addEventListeners(new GnomeBotDevListener()) + .addEventListeners(new SelfDestructListener()) .addEventListeners(new PasteListener()) .enableCache(CacheFlag.ROLE_TAGS) .setMemberCachePolicy(MemberCachePolicy.ALL) // Would do ONLINE but I don't think that will work if you aren't literally set to Online status. diff --git a/src/main/java/nl/finnt730/listeners/SelfDestructListener.java b/src/main/java/nl/finnt730/listeners/SelfDestructListener.java new file mode 100644 index 0000000..5ffc960 --- /dev/null +++ b/src/main/java/nl/finnt730/listeners/SelfDestructListener.java @@ -0,0 +1,70 @@ +package nl.finnt730.listeners; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.emoji.Emoji; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import nl.finnt730.Global; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SelfDestructListener extends ListenerAdapter { + private static final Logger logger = LoggerFactory.getLogger(SelfDestructListener.class); + private static final String TRASH_EMOJI = "🗑️"; + private static final Emoji TRASH_EMOJI_OBJ = Emoji.fromUnicode(TRASH_EMOJI); + + @Override + public void onMessageReceived(MessageReceivedEvent event) { + try { + // Only process messages from the bot itself + if (!event.getAuthor().isBot() || !event.getJDA().getSelfUser().equals(event.getAuthor())) { + return; + } + + Message message = event.getMessage(); + logger.debug("Adding self-destruct reaction to message {}", message.getId()); + message.addReaction(TRASH_EMOJI_OBJ).queue(); + } catch (Exception e) { + logger.error("Error adding self-destruct reaction", e); + } + } + + @Override + public void onMessageReactionAdd(MessageReactionAddEvent event) { + try { + // Ignore reactions from bots + if (event.getUser().isBot()) { + return; + } + + // Only process trash bin reactions + if (!TRASH_EMOJI.equals(event.getReaction().getEmoji().getName())) { + return; + } + + // Check if the reacted message is from our bot + Message message = event.getChannel().retrieveMessageById(event.getMessageId()).complete(); + if (!event.getJDA().getSelfUser().equals(message.getAuthor())) { + return; + } + + // Check if the reactor has permission to delete + Member reactor = event.getMember(); + if (reactor == null) + return; + + boolean hasPermission = reactor.getRoles().stream() + .anyMatch(role -> role.isHoisted() || Global.isManager(role) || reactor.isOwner()); + + if (hasPermission) { + logger.info("Deleting message {} by request of privileged user {}", message.getId(), + event.getUser().getName()); + message.delete().queue(); + } + } catch (Exception e) { + logger.error("Error processing self-destruct reaction", e); + } + } +} \ No newline at end of file