Class CommandExecutionManager
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static classCommand output capture.static classCommand result data class. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final StringTheRemoteActionLog.Entry.getAction()literal for every entry this class records.Blocklist of dangerous commands that should not be executed remotely.private static final StringThe literal config pathloadConfiguration()reads and every configurable refusal this class produces names —ultipanel.commands.blocklist.private final com.google.gson.Gsonprivate UltiPanelWebSocketClient -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidexecuteCommand(com.google.gson.JsonObject commandData) Executes a command received from the panel.private voidexecuteCommandInternal(String command, String executor, String commandId, long startTime) Internal command execution logic.isCommandAllowed(String command) Whether a command is allowed for remote execution.final voidLoadsultipanel.commands.blocklistfrom config.yml, copyingErrorReportCollector.loadConfiguration()'s exact shape: a null-guard onUltiTools.getInstance(), one try/catch whose failure branch keeps the current blocklist and logs a warning naming the key.private static StringresolveActor(String executor) The action-logactorfield — the inboundexecutorfield verbatim, or the literal"panel"when absent.private voidsendCommandResult(String commandId, boolean success, String output, long executionTime) Sends the command execution result.voidsetBlockedCommands(Set<String> commands) Set the blocklist of commands that should not be executed remotely.voidSets the WebSocket client.
-
Field Details
-
webSocketClient
-
pendingCommands
private final ConcurrentHashMap<String,CompletableFuture<CommandExecutionManager.CommandResult>> pendingCommands -
gson
private final com.google.gson.Gson gson -
BLOCKLIST_CONFIG_KEY
The literal config pathloadConfiguration()reads and every configurable refusal this class produces names —ultipanel.commands.blocklist.- See Also:
-
ACTION_EXECUTE_COMMAND
TheRemoteActionLog.Entry.getAction()literal for every entry this class records.- See Also:
-
blockedCommands
Blocklist of dangerous commands that should not be executed remotely. This is the shipped default, used only whenultipanel.commands.blocklistis absent from config.yml — seeloadConfiguration().
-
-
Constructor Details
-
CommandExecutionManager
public CommandExecutionManager()
-
-
Method Details
-
loadConfiguration
public final void loadConfiguration()Loadsultipanel.commands.blocklistfrom config.yml, copyingErrorReportCollector.loadConfiguration()'s exact shape: a null-guard onUltiTools.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'sgetStringListreturns 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. -
setBlockedCommands
Set the blocklist of commands that should not be executed remotely. This is nowloadConfiguration()'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
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 atultipanel.commands.blocklistinplugins/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
AccessDecisionnaming why a refused command was refused
-
setWebSocketClient
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
The action-logactorfield — the inboundexecutorfield verbatim, or the literal"panel"when absent. MirrorsPluginInitiationUtils.resolveActor(JsonObject)exactly: the framework cannot attribute a remote command to an individual panel operator today (seeRemoteActionLog.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.
-