feat: "hashing" via discord by DM-ing the bot hash

This commit is contained in:
ChomeNS
2025-04-11 17:08:23 +07:00
parent 9557231010
commit a5602d1a01
9 changed files with 214 additions and 18 deletions

View File

@@ -107,6 +107,8 @@ public class Configuration {
public static class Discord {
public boolean enabled = false;
public String prefix = "default!";
public String serverId;
public boolean enableDiscordHashing = true;
public String token;
public Map<String, String> servers = new HashMap<>();
public EmbedColors embedColors = new EmbedColors();

View File

@@ -1,8 +1,13 @@
package me.chayapak1.chomens_bot.command;
import me.chayapak1.chomens_bot.Configuration;
import me.chayapak1.chomens_bot.Main;
import net.dv8tion.jda.api.entities.Role;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import java.util.List;
public enum TrustLevel {
PUBLIC(0, Component.text("Public").color(NamedTextColor.GREEN)),
TRUSTED(1, Component.text("Trusted").color(NamedTextColor.RED)),
@@ -16,4 +21,29 @@ public enum TrustLevel {
this.level = level;
this.component = component;
}
public static TrustLevel fromDiscordRoles (final List<Role> roles) {
if (Main.discord == null) return PUBLIC;
final Configuration.Discord options = Main.discord.options;
if (options == null) return PUBLIC;
TrustLevel userTrustLevel = PUBLIC;
for (final Role role : roles) {
if (role.getName().equalsIgnoreCase(options.ownerRoleName)) {
userTrustLevel = OWNER;
break;
} else if (role.getName().equalsIgnoreCase(options.adminRoleName)) {
userTrustLevel = ADMIN;
break;
} else if (role.getName().equalsIgnoreCase(options.trustedRoleName)) {
userTrustLevel = TRUSTED;
break;
}
}
return userTrustLevel;
}
}

View File

@@ -10,7 +10,8 @@ public enum LogType {
ERROR(Component.text("Error").color(NamedTextColor.RED)),
COMMAND_OUTPUT(Component.text("Command Output").color(NamedTextColor.LIGHT_PURPLE)),
AUTH(Component.text("Auth").color(NamedTextColor.RED)),
SIMPLE_VOICE_CHAT(Component.text("Simple Voice Chat").color(NamedTextColor.AQUA));
SIMPLE_VOICE_CHAT(Component.text("Simple Voice Chat").color(NamedTextColor.AQUA)),
DISCORD(Component.text("Discord").color(NamedTextColor.BLUE));
public final Component component;

View File

@@ -0,0 +1,127 @@
package me.chayapak1.chomens_bot.discord;
import me.chayapak1.chomens_bot.Configuration;
import me.chayapak1.chomens_bot.command.TrustLevel;
import me.chayapak1.chomens_bot.data.logging.LogType;
import me.chayapak1.chomens_bot.plugins.HashingPlugin;
import me.chayapak1.chomens_bot.util.LoggerUtilities;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.requests.ErrorResponse;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
public class DirectMessageEventHandler extends ListenerAdapter {
private static final String HASH_MESSAGE = "hash";
private final JDA jda;
private final Configuration.Discord options;
public DirectMessageEventHandler (
final JDA jda,
final Configuration.Discord options
) {
this.jda = jda;
this.options = options;
jda.addEventListener(this);
}
@Override
public void onMessageReceived (@NotNull final MessageReceivedEvent event) {
if (!options.enableDiscordHashing || event.getChannelType() != ChannelType.PRIVATE) return;
final Message message = event.getMessage();
if (!message.getContentDisplay().equalsIgnoreCase(HASH_MESSAGE)) return;
final Guild guild;
try {
guild = jda.getGuildById(options.serverId);
} catch (final NumberFormatException e) {
// there will be a custom error message
// from JDA when it fails to parse a snowflake,
// the user will read that
LoggerUtilities.error(e);
return;
}
if (guild == null) return;
guild.retrieveMember(message.getAuthor())
.queue(
member -> {
if (member == null) return;
final TrustLevel trustLevel = TrustLevel.fromDiscordRoles(member.getRoles());
if (trustLevel == TrustLevel.PUBLIC) {
LoggerUtilities.log(
LogType.DISCORD,
Component.translatable(
"User %s tried to get hash in Discord without any trusted roles!",
Component.text(member.toString())
)
);
message.reply("You do not have any trusted roles!")
.queue();
return;
}
sendHash(trustLevel, message, member);
},
exception -> {
if (!(exception instanceof final ErrorResponseException error)) return;
final ErrorResponse errorResponse = error.getErrorResponse();
if (errorResponse == ErrorResponse.UNKNOWN_MEMBER) {
message.reply("You are not in " + guild.getName() + "!")
.queue();
} else if (errorResponse == ErrorResponse.UNKNOWN_USER) {
LoggerUtilities.error(
Component.translatable(
"Got ErrorResponse.UNKNOWN_USER while trying to " +
"retrieve member! Weird user. User: %s",
Component.text(message.getAuthor().toString())
)
);
}
// that's all the possible errors, the javadocs said
}
);
}
private void sendHash (final TrustLevel trustLevel, final Message message, final Member member) {
final String result = HashingPlugin.generateDiscordHash(member.getIdLong(), trustLevel);
message
.reply(
String.format(
"Hash for %s trust level: **%s**",
trustLevel,
result
)
)
.queue();
LoggerUtilities.log(
LogType.DISCORD,
Component.translatable(
"Generated hash %s (%s) for user %s",
Component.text(result),
Component.text(trustLevel.toString()),
Component.text(member.getEffectiveName())
)
);
}
}

View File

@@ -174,20 +174,7 @@ public class CommandHandlerPlugin implements TickPlugin.Listener {
final List<Role> roles = member.getRoles();
TrustLevel userTrustLevel = TrustLevel.PUBLIC;
for (final Role role : roles) {
if (role.getName().equalsIgnoreCase(bot.config.discord.ownerRoleName)) {
userTrustLevel = TrustLevel.OWNER;
break;
} else if (role.getName().equalsIgnoreCase(bot.config.discord.adminRoleName)) {
userTrustLevel = TrustLevel.ADMIN;
break;
} else if (role.getName().equalsIgnoreCase(bot.config.discord.trustedRoleName)) {
userTrustLevel = TrustLevel.TRUSTED;
break;
}
}
final TrustLevel userTrustLevel = TrustLevel.fromDiscordRoles(roles);
if (trustLevel.level > userTrustLevel.level) {
context.sendOutput(

View File

@@ -3,6 +3,7 @@ package me.chayapak1.chomens_bot.plugins;
import me.chayapak1.chomens_bot.Bot;
import me.chayapak1.chomens_bot.Configuration;
import me.chayapak1.chomens_bot.Main;
import me.chayapak1.chomens_bot.discord.DirectMessageEventHandler;
import me.chayapak1.chomens_bot.discord.GuildMessageEventHandler;
import me.chayapak1.chomens_bot.util.CodeBlockUtilities;
import me.chayapak1.chomens_bot.util.ComponentUtilities;
@@ -29,6 +30,8 @@ import java.util.regex.Matcher;
public class DiscordPlugin {
public JDA jda;
public Configuration.Discord options;
public final Map<String, String> servers;
public final String prefix;
@@ -38,7 +41,7 @@ public class DiscordPlugin {
public final String discordUrl;
public DiscordPlugin (final Configuration config) {
final Configuration.Discord options = config.discord;
this.options = config.discord;
this.prefix = options.prefix;
this.servers = options.servers;
this.discordUrl = config.discord.inviteLink;
@@ -53,7 +56,11 @@ public class DiscordPlugin {
.clickEvent(ClickEvent.openUrl(discordUrl));
final JDABuilder builder = JDABuilder.createDefault(config.discord.token);
builder.enableIntents(GatewayIntent.MESSAGE_CONTENT);
builder.enableIntents(
GatewayIntent.MESSAGE_CONTENT,
GatewayIntent.DIRECT_MESSAGES,
GatewayIntent.GUILD_MEMBERS
);
builder.setEnableShutdownHook(false);
try {
@@ -66,6 +73,7 @@ public class DiscordPlugin {
jda.getPresence().setPresence(Activity.playing(config.discord.statusMessage), false);
new GuildMessageEventHandler(jda, prefix, messagePrefix);
new DirectMessageEventHandler(jda, options);
Main.EXECUTOR.scheduleAtFixedRate(this::onDiscordTick, 0, 50, TimeUnit.MILLISECONDS);

View File

@@ -4,11 +4,18 @@ import com.google.common.hash.Hashing;
import me.chayapak1.chomens_bot.Bot;
import me.chayapak1.chomens_bot.command.TrustLevel;
import me.chayapak1.chomens_bot.data.player.PlayerEntry;
import me.chayapak1.chomens_bot.util.RandomStringUtilities;
import org.apache.commons.lang3.tuple.Pair;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class HashingPlugin {
public static final Map<Long, Pair<TrustLevel, String>> discordHashes = new ConcurrentHashMap<>();
private final Bot bot;
public HashingPlugin (final Bot bot) {
@@ -64,10 +71,42 @@ public class HashingPlugin {
checkHash(getOwnerHash(prefix, sender, false), input);
}
public boolean isCorrectDiscordHash (final String input) {
for (final Pair<TrustLevel, String> pair : discordHashes.values()) {
if (checkHash(pair.getRight(), input)) return true;
}
return false;
}
public TrustLevel getDiscordHashTrustLevel (final String input) {
for (final Map.Entry<Long, Pair<TrustLevel, String>> entry : new ArrayList<>(discordHashes.entrySet())) {
final Pair<TrustLevel, String> pair = entry.getValue();
if (!pair.getRight().equals(input)) continue;
discordHashes.remove(entry.getKey());
return pair.getLeft();
}
return TrustLevel.PUBLIC;
}
public TrustLevel getTrustLevel (final String input, final String prefix, final PlayerEntry sender) {
if (isCorrectOwnerHash(input, prefix, sender)) return TrustLevel.OWNER;
else if (isCorrectAdminHash(input, prefix, sender)) return TrustLevel.ADMIN;
else if (isCorrectHash(input, prefix, sender)) return TrustLevel.TRUSTED;
else if (isCorrectDiscordHash(input)) return getDiscordHashTrustLevel(input);
else return TrustLevel.PUBLIC;
}
public static String generateDiscordHash (final long userId, final TrustLevel trustLevel) {
// i wouldn't say it's a hash, it's just a random string
final String string = RandomStringUtilities.generate(16);
discordHashes.putIfAbsent(userId, Pair.of(trustLevel, string));
return discordHashes.get(userId).getRight();
}
}