Class CommandExecutionManager

java.lang.Object
com.ultikits.ultitools.manager.CommandExecutionManager

@Internal public class CommandExecutionManager extends Object
Command execution manager. Handles command execution requests received over the WebSocket connection.
  • Field Details

    • webSocketClient

      private UltiPanelWebSocketClient webSocketClient
    • pendingCommands

    • gson

      private final com.google.gson.Gson gson
    • BLOCKLIST_CONFIG_KEY

      private static final String BLOCKLIST_CONFIG_KEY
      The literal config path loadConfiguration() reads and every configurable refusal this class produces names — ultipanel.commands.blocklist.
      See Also:
    • ACTION_EXECUTE_COMMAND

      private static final String ACTION_EXECUTE_COMMAND
      The RemoteActionLog.Entry.getAction() literal for every entry this class records.
      See Also:
    • DISPATCHED_OUTPUT

      static final String DISPATCHED_OUTPUT
      The command_result text for a command the server console accepted. A panel command is typed into the server console (maintainer decision, 6.3.0): it runs as the console sender, and Paper sends a console command's replies to the console itself, never to a sender the framework could read, so the result cannot carry them. They reach the panel through the log stream, which mirrors the console (ConsoleMirror).
      See Also:
    • NOT_ACCEPTED_OUTPUT

      static final String NOT_ACCEPTED_OUTPUT
      The command_result text for a command the server console did not accept (Bukkit.dispatchCommand returned false: an unknown command, or a command whose executor reported a usage error).
      See Also:
    • blockedCommands

      private Set<String> blockedCommands
      Blocklist of dangerous commands that should not be executed remotely. This is the shipped default, kept when ultipanel.commands.blocklist is absent from config.yml or when its present value is rejected as not a list of strings — see loadConfiguration().
  • Constructor Details

    • CommandExecutionManager

      public CommandExecutionManager()
  • Method Details

    • loadConfiguration

      public final void loadConfiguration()
      Loads ultipanel.commands.blocklist from config.yml, copying ErrorReportCollector.loadConfiguration()'s exact shape: a null-guard on UltiTools.getInstance(), one try/catch whose failure branch keeps the current blocklist and logs a warning naming the key.

      Distinguishes an absent key from an explicit empty list via isSet(path) — Bukkit's getStringList returns an empty list for both, and collapsing that distinction would make D-03's honest "block nothing" escape value silently impossible (T-06-12). The shipped ten-command default applies only when the key is absent; an explicit empty list is honored as the operator deliberately granting every command.

      A present value is validated as a whole before anything is installed: it must be a list whose every element is a string. The raw value is read, not Bukkit's converting getStringList, because that getter turns a non-list into an empty list, drops mapping, nested-list and null elements, and stringifies numbers and booleans — so its output cannot show what the operator wrote, and installing it would silently replace the policy with an empty or partial one. Any other shape (a scalar, a map, or a list with any non-string element) rejects the whole value: one warning naming the key and the rejected shape (the value's type, or the first offending element's position and type) is logged, never the value itself, and the current in-memory blocklist is kept — the shipped default on a newly constructed manager, the previous valid list on a repeated call. A valid list is trimmed and lower-cased with Locale.ROOT into one new set, installed through a single setBlockedCommands(Set) call.

      This method never writes config.yml or the loaded configuration: it neither saves nor repairs an invalid value, so the operator's file and the in-memory section keep exactly what the operator wrote.

    • describeInvalidBlocklist

      private static String describeInvalidBlocklist(Object raw)
      Describes why a raw blocklist value is not a list of strings, naming only its shape.
      Parameters:
      raw - the raw value at ultipanel.commands.blocklist
      Returns:
      null for a list whose every element is a string; otherwise the value's type, or the first non-string element's 1-based position and type — never the value itself
    • describeShape

      private static String describeShape(Object value)
      Names a raw configuration value's type for a diagnostic, without its content.
    • setBlockedCommands

      public void setBlockedCommands(Set<String> commands)
      Set the blocklist of commands that should not be executed remotely. This is now loadConfiguration()'s config-load target, not just a test-only seam — it has zero production call sites of its own, but every operator-configured blocklist reaches this class through it.
      Parameters:
      commands - Set of command names to block (case-insensitive)
    • isCommandAllowed

      public AccessDecision isCommandAllowed(String command)
      Whether a command is allowed for remote execution.

      Extracts the base command (the first word) and strips any namespace prefix (e.g. bukkit:op -> op, minecraft:stop -> stop) BEFORE checking it against the operator-configured blocklist at ultipanel.commands.blocklist in plugins/UltiTools/config.yml — so both the bare command and its namespaced form are blocked; the stripping order is what makes that true. The blocklist is editable in both directions — an operator may remove any of the ten shipped defaults, add to them, or clear the list entirely — and there is deliberately no unoverridable floor beneath it (D-04): a floor would constrain the operator without constraining an attacker who already holds the operator's identity, since the same outcomes remain reachable through other commands or a third-party plugin's own admin commands.

      Parameters:
      command - The command to check (with or without leading slash)
      Returns:
      an AccessDecision naming why a refused command was refused
    • setWebSocketClient

      public void setWebSocketClient(UltiPanelWebSocketClient client)
      Sets the WebSocket client.
      Parameters:
      client - the WebSocket client
    • executeCommand

      public void executeCommand(com.google.gson.JsonObject commandData)
      Executes a command received from the panel.
    • executeCommandInternal

      private void executeCommandInternal(String command, String executor, String commandId, long startTime)
      Internal command execution logic.
    • resolveActor

      private static String resolveActor(String executor)
      The action-log actor field — the inbound executor field verbatim, or the literal "panel" when absent. Mirrors PluginInitiationUtils.resolveActor(JsonObject) exactly: the framework cannot attribute a remote command to an individual panel operator today (see RemoteActionLog.Entry's javadoc), so this never invents a per-operator identity.
    • sendCommandResult

      private void sendCommandResult(String commandId, boolean success, String output, long executionTime)
      Sends the command execution result.