diff --git a/build-number.txt b/build-number.txt index 350756b9..e4da9ac1 100644 --- a/build-number.txt +++ b/build-number.txt @@ -1 +1 @@ -3268 \ No newline at end of file +3278 \ No newline at end of file diff --git a/src/main/java/me/chayapak1/chomens_bot/command/CommandContext.java b/src/main/java/me/chayapak1/chomens_bot/command/CommandContext.java index 8f227464..72f1d452 100644 --- a/src/main/java/me/chayapak1/chomens_bot/command/CommandContext.java +++ b/src/main/java/me/chayapak1/chomens_bot/command/CommandContext.java @@ -279,8 +279,10 @@ public class CommandContext { }; } - public > T getEnum (final Class enumClass) throws CommandException { - final String string = getString(false, true, enumClass.getSimpleName()); + public > T getEnum (final boolean required, final Class enumClass) throws CommandException { + final String string = getString(false, required, enumClass.getSimpleName()); + + if (string.isEmpty()) return null; try { return Enum.valueOf(enumClass, string.toUpperCase()); diff --git a/src/main/java/me/chayapak1/chomens_bot/command/TrustLevel.java b/src/main/java/me/chayapak1/chomens_bot/command/TrustLevel.java index fe2adf06..a0546a4d 100644 --- a/src/main/java/me/chayapak1/chomens_bot/command/TrustLevel.java +++ b/src/main/java/me/chayapak1/chomens_bot/command/TrustLevel.java @@ -15,6 +15,8 @@ public enum TrustLevel { ADMIN(2, Component.text(I18nUtilities.get("trust_level.admin")).color(NamedTextColor.DARK_RED)), OWNER(3, Component.text(I18nUtilities.get("trust_level.owner")).color(NamedTextColor.LIGHT_PURPLE)); + public static final TrustLevel MAX = values()[values().length - 1]; + public final int level; public final Component component; diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/AuthCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/AuthCommand.java new file mode 100644 index 00000000..2cc4cdf0 --- /dev/null +++ b/src/main/java/me/chayapak1/chomens_bot/commands/AuthCommand.java @@ -0,0 +1,55 @@ +package me.chayapak1.chomens_bot.commands; + +import me.chayapak1.chomens_bot.Bot; +import me.chayapak1.chomens_bot.command.Command; +import me.chayapak1.chomens_bot.command.CommandContext; +import me.chayapak1.chomens_bot.command.CommandException; +import me.chayapak1.chomens_bot.command.TrustLevel; +import me.chayapak1.chomens_bot.data.player.PlayerEntry; +import net.kyori.adventure.text.Component; + +import java.util.Arrays; + +public class AuthCommand extends Command { + public AuthCommand () { + super( + "auth", + new String[] {}, + new String[] {}, + TrustLevel.TRUSTED + ); + + final String trustLevels = String.join(" | ", Arrays.stream(TrustLevel.values()).map(Enum::name).toList()); + + this.usages = new String[] { "[player] [" + trustLevels + "]" }; + } + + @Override + public Component execute (final CommandContext context) throws CommandException { + final Bot bot = context.bot; + + final String playerString = context.getString(false, false); + + PlayerEntry player = null; + if (!playerString.isEmpty()) player = bot.players.getEntry(playerString); + if (player == null) player = context.sender; + + TrustLevel trustLevel = context.getEnum(false, TrustLevel.class); + if (trustLevel == null) trustLevel = context.trustLevel; + + if (trustLevel.level > context.trustLevel.level) throw new CommandException( + Component.translatable( + "commands.auth.error.privilege_escalate" + ) + ); + + player.authenticatedTrustLevel = trustLevel; + + return Component.translatable( + "commands.auth.output", + bot.colorPalette.defaultColor, + Component.text(player.profile.getName(), bot.colorPalette.username), + player.authenticatedTrustLevel.component + ); + } +} diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/CloopCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/CloopCommand.java index 986d0c83..e79f4c74 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/CloopCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/CloopCommand.java @@ -35,7 +35,7 @@ public class CloopCommand extends Command { long interval = context.getLong(true); if (interval < 1) interval = 1; - final ChronoUnit unit = context.getEnum(ChronoUnit.class); + final ChronoUnit unit = context.getEnum(true, ChronoUnit.class); if (unit == ChronoUnit.NANOS && interval < 1000) throw new CommandException(Component.translatable("commands.cloop.add.error.too_low_nanoseconds")); diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/KickCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/KickCommand.java index 7d191d84..bbe8a3a4 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/KickCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/KickCommand.java @@ -30,7 +30,7 @@ public class KickCommand extends Command { public Component execute (final CommandContext context) throws CommandException { final Bot bot = context.bot; - final Kick method = context.getEnum(Kick.class); + final Kick method = context.getEnum(true, Kick.class); final PlayerEntry entry = bot.players.getEntry(context.getString(true, true)); diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java index dcfa9d25..b433e905 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java @@ -251,7 +251,7 @@ public class MusicCommand extends Command implements Listener { final Bot bot = context.bot; - final Loop loop = context.getEnum(Loop.class); + final Loop loop = context.getEnum(true, Loop.class); bot.music.loop = loop; diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/ValidateCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/ValidateCommand.java index c3f0afd2..a9e2f399 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/ValidateCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/ValidateCommand.java @@ -36,7 +36,9 @@ public class ValidateCommand extends Command { else if (context instanceof ConsoleCommandContext) return Component .translatable("commands.validate.console", NamedTextColor.GREEN); else return Component.translatable( - "commands.validate.player", + context.sender.authenticatedTrustLevel != TrustLevel.PUBLIC + ? "commands.validate.player_authenticated" + : "commands.validate.player", NamedTextColor.GREEN, trustLevelComponent ); diff --git a/src/main/java/me/chayapak1/chomens_bot/data/player/PlayerEntry.java b/src/main/java/me/chayapak1/chomens_bot/data/player/PlayerEntry.java index 406bae69..2fcff448 100644 --- a/src/main/java/me/chayapak1/chomens_bot/data/player/PlayerEntry.java +++ b/src/main/java/me/chayapak1/chomens_bot/data/player/PlayerEntry.java @@ -1,5 +1,6 @@ package me.chayapak1.chomens_bot.data.player; +import me.chayapak1.chomens_bot.command.TrustLevel; import net.kyori.adventure.text.Component; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; @@ -20,6 +21,7 @@ public class PlayerEntry { public final byte[] keySignature; public boolean listed; public String ip; + public TrustLevel authenticatedTrustLevel = TrustLevel.PUBLIC; public PlayerEntry ( final GameProfile profile, diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/AuthPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/AuthPlugin.java index f37f47d3..a639df36 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/AuthPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/AuthPlugin.java @@ -1,6 +1,7 @@ package me.chayapak1.chomens_bot.plugins; import me.chayapak1.chomens_bot.Bot; +import me.chayapak1.chomens_bot.command.TrustLevel; import me.chayapak1.chomens_bot.data.listener.Listener; import me.chayapak1.chomens_bot.data.logging.LogType; import me.chayapak1.chomens_bot.data.player.PlayerEntry; @@ -42,6 +43,8 @@ public class AuthPlugin implements Listener { cleanup(); + target.authenticatedTrustLevel = TrustLevel.MAX; + bot.logger.log( LogType.AUTH, Component diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/CommandHandlerPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/CommandHandlerPlugin.java index baafded7..e49cfc42 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/CommandHandlerPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/CommandHandlerPlugin.java @@ -8,6 +8,7 @@ import me.chayapak1.chomens_bot.command.CommandException; import me.chayapak1.chomens_bot.command.TrustLevel; import me.chayapak1.chomens_bot.command.contexts.*; import me.chayapak1.chomens_bot.commands.*; +import me.chayapak1.chomens_bot.data.chat.ChatPacketType; import me.chayapak1.chomens_bot.data.listener.Listener; import me.chayapak1.chomens_bot.util.ExceptionUtilities; import net.dv8tion.jda.api.entities.Member; @@ -62,7 +63,8 @@ public class CommandHandlerPlugin implements Listener { new GrepLogCommand(), new FindAltsCommand(), new RestartCommand(), - new NetCommandCommand() + new NetCommandCommand(), + new AuthCommand() ); public static Command findCommand (final String searchTerm) { @@ -160,19 +162,27 @@ public class CommandHandlerPlugin implements Listener { } } + final TrustLevel authenticatedTrustLevel = context.sender.authenticatedTrustLevel; + + final boolean authenticated = context instanceof final PlayerCommandContext playerContext + && playerContext.packetType == ChatPacketType.PLAYER + && authenticatedTrustLevel != TrustLevel.PUBLIC; + final TrustLevel trustLevel = command.trustLevel; - if (trustLevel != TrustLevel.PUBLIC && splitInput.length < 2 && inGame) { + if (trustLevel != TrustLevel.PUBLIC && splitInput.length < 2 && inGame && !authenticated) { context.sendOutput(Component.translatable("command_handler.no_hash_provided", NamedTextColor.RED)); return; } - String userHash = ""; - if (trustLevel != TrustLevel.PUBLIC && inGame) userHash = splitInput[1]; + final boolean needsHash = trustLevel != TrustLevel.PUBLIC && inGame && !authenticated; + + final String userHash = needsHash ? splitInput[1] : ""; final String[] fullArgs = Arrays.copyOfRange(splitInput, 1, splitInput.length); - - final String[] args = Arrays.copyOfRange(splitInput, (trustLevel != TrustLevel.PUBLIC && inGame) ? 2 : 1, splitInput.length); + final String[] args = needsHash + ? Arrays.copyOfRange(splitInput, 2, splitInput.length) + : fullArgs; // LoL ohio spaghetti code if (command.trustLevel != TrustLevel.PUBLIC && !bypass) { @@ -207,6 +217,15 @@ public class CommandHandlerPlugin implements Listener { } context.trustLevel = userTrustLevel; + } else if (authenticated) { + if (trustLevel.level > authenticatedTrustLevel.level) { + context.sendOutput( + Component.translatable("command_handler.not_enough_roles", NamedTextColor.RED) + ); + return; + } + + context.trustLevel = authenticatedTrustLevel; } else { final TrustLevel userTrustLevel = bot.hashing.getTrustLevel(userHash, splitInput[0], context.sender); @@ -225,8 +244,7 @@ public class CommandHandlerPlugin implements Listener { context.trustLevel = userTrustLevel; } } else if (bypass) { - final TrustLevel[] values = TrustLevel.values(); - context.trustLevel = values[values.length - 1]; // highest level + context.trustLevel = TrustLevel.MAX; } // should i give access to all bypass contexts instead of only console? diff --git a/src/main/resources/language-en_us.json b/src/main/resources/language-en_us.json index c848c5e7..777ac73d 100644 --- a/src/main/resources/language-en_us.json +++ b/src/main/resources/language-en_us.json @@ -34,6 +34,10 @@ "commands.generic.error.database_disabled": "Database is not enabled in the bot's configuration", "commands.generic.error.discord_disabled": "The bot's Discord integration has to be enabled to use this command", + "commands.auth.description": "Authenticates yourself or a player so you don't have to input the hash every time you use the bot", + "commands.auth.output": "Player %s has been authenticated with trust level %s", + "commands.auth.error.privilege_escalate": "You cannot escalate privileges!", + "commands.botvisibility.description": "Changes the bot's visibility", "commands.botvisibility.message": "The bot's visibility is now %s", "commands.botvisibility.visible": "visible", @@ -265,6 +269,7 @@ "commands.validate.discord": "You are trusted! (%s)", "commands.validate.console": "You are the console! You have no trust level", "commands.validate.player": "Valid hash (%s)", + "commands.validate.player_authenticated": "You are authenticated! (%s)", "commands.weather.description": "Shows the weather information in a place", "commands.weather.info": "Current weather for %s, %s:\n%s (%s), feels like %s (%s)\nCondition: %s\nCloud cover: %s\nHumidity: %s\nTime: %s",