Class CommandExecutionManager
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic 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.(package private) static final StringThecommand_resulttext for a command the server console accepted.private final com.google.gson.Gson(package private) static final StringThecommand_resulttext for a command the server console did not accept (Bukkit.dispatchCommandreturnedfalse: an unknown command, or a command whose executor reported a usage error).private UltiPanelWebSocketClient -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate static StringDescribes why a raw blocklist value is not a list of strings, naming only its shape.private static StringdescribeShape(Object value) Names a raw configuration value's type for a diagnostic, without its content.voidexecuteCommand(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:
-
DISPATCHED_OUTPUT
Thecommand_resulttext 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
Thecommand_resulttext for a command the server console did not accept (Bukkit.dispatchCommandreturnedfalse: an unknown command, or a command whose executor reported a usage error).- See Also:
-
blockedCommands
Blocklist of dangerous commands that should not be executed remotely. This is the shipped default, kept whenultipanel.commands.blocklistis absent from config.yml or when its present value is rejected as not a list of strings — 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.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 withLocale.ROOTinto one new set, installed through a singlesetBlockedCommands(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
Describes why a raw blocklist value is not a list of strings, naming only its shape.- Parameters:
raw- the raw value atultipanel.commands.blocklist- Returns:
nullfor 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
Names a raw configuration value's type for a diagnostic, without its content. -
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.
-