From 23a2af2464d311e807e78901db78d74c36343769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Sat, 15 Apr 2023 23:48:40 +0200 Subject: [PATCH] Add Orebfuscator command (#286) * feat: add orebfuscator dump command * chore: change issue template --- .github/ISSUE_TEMPLATE/bug-report.yml | 32 +--- .../net/imprex/orebfuscator/Orebfuscator.java | 3 + .../orebfuscator/OrebfuscatorCommand.java | 143 ++++++++++++++++++ .../imprex/orebfuscator/util/OFCLogger.java | 26 ++++ .../orebfuscator/util/PermissionUtil.java | 10 +- .../src/main/resources/plugin.yml | 10 +- pom.xml | 1 - 7 files changed, 190 insertions(+), 35 deletions(-) create mode 100644 orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 6d982200..3cdb3dcc 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -29,38 +29,14 @@ body: placeholder: Describe what you expected to happen here. validations: required: true - - type: input - id: server-info - attributes: - label: Server Details - description: Please provide a description of the server details, including type and specific version number. (use `/version` command for server version) - placeholder: '3219-Spigot-b166a49-8c6d60c (MC: 1.17.1)' - validations: - required: true - - type: input - id: orebfuscator-version - attributes: - label: Orebfuscator Version - description: Please provide the specific, precise version number of Orebfuscator you are using to reproduce this bug. (use `/version Orebfuscator` command for Orebfuscator version) - placeholder: '5.1.5' - validations: - required: true - - type: input - id: protocollib-version - attributes: - label: ProtocolLib Version - description: Please provide the specific, precise version number of ProtocolLib you are using to reproduce this bug. (use `/version ProtocolLib` command for ProtocolLib version) - placeholder: 4.7.1-SNAPSHOT-b531 - validations: - required: true - type: textarea - id: logs + id: dump attributes: - label: Logs and Configs - description: If you think it would be helpful, please also include a pastebin of any relevant config files or log output. You should use https://gist.github.com/ to upload, then include the link below. + label: Orebfuscator Dump + description: Please provide an Orebfuscator dump file (use `/orebfuscator dump`) or if Orebfuscator didn't start provide a ProtocolLib dump (use `/protocol dump`). You should use https://gist.github.com/ to upload, then include the link below. placeholder: https://gist.github.com/HelpfulBugReporter/ThisIsAVeryUsefulLogOutput validations: - required: false + required: true - type: textarea id: extra-info attributes: diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index 2b1e476d..74409f9d 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -89,6 +89,9 @@ public void onEnable() { OrebfuscatorService.class, new DefaultOrebfuscatorService(this), this, ServicePriority.Normal); + + // add commands + getCommand("orebfuscator").setExecutor(new OrebfuscatorCommand(this)); } catch (Exception e) { OFCLogger.error("An error occurred while enabling plugin", e); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java new file mode 100644 index 00000000..6e55459d --- /dev/null +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorCommand.java @@ -0,0 +1,143 @@ +package net.imprex.orebfuscator; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; + +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketListener; +import com.google.gson.JsonObject; +import com.google.gson.internal.Streams; +import com.google.gson.stream.JsonWriter; + +import net.imprex.orebfuscator.util.HeightAccessor; +import net.imprex.orebfuscator.util.JavaVersion; +import net.imprex.orebfuscator.util.MinecraftVersion; +import net.imprex.orebfuscator.util.OFCLogger; +import net.imprex.orebfuscator.util.PermissionUtil; + +public class OrebfuscatorCommand implements CommandExecutor, TabCompleter { + + private static final List TAB_COMPLETE = Arrays.asList("dump"); + + private final DateTimeFormatter fileFormat = DateTimeFormatter.ofPattern("uuuu-MM-dd_HH.mm.ss"); + private final DateTimeFormatter timeFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + + private final Orebfuscator orebfuscator; + + public OrebfuscatorCommand(Orebfuscator orebfuscator) { + this.orebfuscator = orebfuscator; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!command.getName().equalsIgnoreCase("orebfuscator")) { + sender.sendMessage("Incorrect command registered!"); + return false; + } + + if (!PermissionUtil.canAccessAdminTools(sender)) { + sender.sendMessage("You don't have the 'orebfuscator.admin' permission."); + return false; + } + + if (args.length == 0) { + sender.sendMessage("You are using " + this.orebfuscator.toString()); + } else if (args[0].equalsIgnoreCase("dump")) { + TemporalAccessor now = OffsetDateTime.now(ZoneOffset.UTC); + + JsonObject root = new JsonObject(); + root.addProperty("timestamp", timeFormat.format(now)); + + JsonObject versions = new JsonObject(); + versions.addProperty("java", Integer.toString(JavaVersion.get())); + versions.addProperty("nms", MinecraftVersion.nmsVersion()); + versions.addProperty("server", Bukkit.getVersion()); + versions.addProperty("bukkit", Bukkit.getBukkitVersion()); + versions.addProperty("protocolLib", ProtocolLibrary.getPlugin().toString()); + versions.addProperty("orebfuscator", orebfuscator.toString()); + root.add("versions", versions); + + JsonObject plugins = new JsonObject(); + for (Plugin bukkitPlugin : Bukkit.getPluginManager().getPlugins()) { + PluginDescriptionFile description = bukkitPlugin.getDescription(); + JsonObject plugin = new JsonObject(); + plugin.addProperty("version", description.getVersion()); + plugin.addProperty("author", description.getAuthors().toString()); + plugins.add(bukkitPlugin.getName(), plugin); + } + root.add("plugins", plugins); + + JsonObject worlds = new JsonObject(); + for (World bukkitWorld : Bukkit.getWorlds()) { + JsonObject world = new JsonObject(); + world.addProperty("uuid", bukkitWorld.getUID().toString()); + world.addProperty("heightAccessor", HeightAccessor.get(bukkitWorld).toString()); + worlds.add(bukkitWorld.getName(), world); + } + root.add("worlds", worlds); + + JsonObject listeners = new JsonObject(); + for (PacketListener packetListener : ProtocolLibrary.getProtocolManager().getPacketListeners()) { + JsonObject listener = new JsonObject(); + listener.addProperty("plugin", packetListener.getPlugin().toString()); + listener.addProperty("receivingWhitelist", packetListener.getSendingWhitelist().toString()); + listener.addProperty("sendingWhitelist", packetListener.getSendingWhitelist().toString()); + String key = packetListener.getClass().toGenericString() + "@" + System.identityHashCode(packetListener); + listeners.add(key, listener); + } + root.add("listeners", listeners); + + Base64.Encoder encoder = Base64.getUrlEncoder(); + + String latestLog = OFCLogger.getLatestVerboseLog(); + root.addProperty("verbose_log", encoder.encodeToString(latestLog.getBytes(StandardCharsets.UTF_8))); + + try { + Path configPath = orebfuscator.getDataFolder().toPath().resolve("config.yml"); + String config = Files.readAllLines(configPath).stream().collect(Collectors.joining("\n")); + root.addProperty("config", encoder.encodeToString(config.getBytes(StandardCharsets.UTF_8))); + } catch (IOException e) { + e.printStackTrace(); + } + + Path path = orebfuscator.getDataFolder().toPath().resolve("dump-" + fileFormat.format(now) + ".json"); + try (JsonWriter writer = new JsonWriter(Files.newBufferedWriter(path))) { + writer.setIndent(" "); + Streams.write(root, writer); + } catch (IOException e) { + e.printStackTrace(); + } + + sender.sendMessage("Dump file created at: " + path); + } else { + return false; + } + + return true; + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + return args.length == 1 ? TAB_COMPLETE : Collections.emptyList(); + } +} diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/OFCLogger.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/OFCLogger.java index 4801bf9a..0213ea5d 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/OFCLogger.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/OFCLogger.java @@ -1,5 +1,7 @@ package net.imprex.orebfuscator.util; +import java.util.LinkedList; +import java.util.Queue; import java.util.logging.Level; import java.util.logging.Logger; @@ -7,6 +9,7 @@ public final class OFCLogger { public static Logger LOGGER = Logger.getLogger("Orebfuscator"); + private static final Queue VERBOSE_LOG = new LinkedList(); private static boolean verbose = false; public static void setVerboseLogging(boolean verbose) { @@ -20,6 +23,29 @@ public static void debug(String message) { if (OFCLogger.verbose) { OFCLogger.LOGGER.log(Level.INFO, "[Debug] " + message); } + + synchronized (VERBOSE_LOG) { + while (VERBOSE_LOG.size() >= 1000) { + VERBOSE_LOG.poll(); + } + VERBOSE_LOG.offer(message); + } + } + + public static String getLatestVerboseLog() { + synchronized (VERBOSE_LOG) { + int length = 0; + for (String message : VERBOSE_LOG) { + length += message.length() + 1; + } + + StringBuilder builder = new StringBuilder(length); + for (String message : VERBOSE_LOG) { + builder.append(message).append("\n"); + } + builder.deleteCharAt(builder.length() - 1); + return builder.toString(); + } } public static void warn(String message) { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java index 05e7385a..d3c79674 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/PermissionUtil.java @@ -1,19 +1,19 @@ package net.imprex.orebfuscator.util; -import org.bukkit.entity.Player; +import org.bukkit.permissions.Permissible; public class PermissionUtil { - public static boolean canDeobfuscate(Player player) { + public static boolean canDeobfuscate(Permissible permissible) { try { - return player.hasPermission("orebfuscator.bypass"); + return permissible.hasPermission("orebfuscator.bypass"); } catch (UnsupportedOperationException e) { // fix #131: catch TemporaryPlayer not implementing hasPermission return false; } } - public static boolean canAccessAdminTools(Player player) { - return player.isOp() || player.hasPermission("orebfuscator.admin"); + public static boolean canAccessAdminTools(Permissible permissible) { + return permissible.isOp() || permissible.hasPermission("orebfuscator.admin"); } } diff --git a/orebfuscator-plugin/src/main/resources/plugin.yml b/orebfuscator-plugin/src/main/resources/plugin.yml index d1081c01..c6946cc6 100644 --- a/orebfuscator-plugin/src/main/resources/plugin.yml +++ b/orebfuscator-plugin/src/main/resources/plugin.yml @@ -11,6 +11,14 @@ authors: [NgLoader, lishid, SydMontague, ProgrammerDan, Aleksey-Terzi] depend: [ProtocolLib] +commands: + orebfuscator: + aliases: [ofc] + description: Performs administrative tasks regarding Orebfuscator. + usage: / [dump] + permission: orebfuscator.admin + permission-message: You don't have + permissions: orebfuscator.*: default: false @@ -20,7 +28,7 @@ permissions: orebfuscator.bypass: true orebfuscator.admin: default: op - description: Access to update notifications + description: Access to update notifications and commands orebfuscator.bypass: default: false description: Bypass the obfuscation diff --git a/pom.xml b/pom.xml index 1ca3d535..62b3c551 100644 --- a/pom.xml +++ b/pom.xml @@ -95,7 +95,6 @@ *:* - META-INF/*.MF META-INF/*.SF META-INF/*.DSA META-INF/*.RSA