Skip to content

Commit

Permalink
BUGFIX: Prevent 403 error for users without command privileges
Browse files Browse the repository at this point in the history
Resolves: #15
  • Loading branch information
Sebobo committed Jan 8, 2024
1 parent c7b7f53 commit d4f2443
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 23 deletions.
5 changes: 5 additions & 0 deletions Classes/Controller/TerminalCommandController.php
Expand Up @@ -79,6 +79,11 @@ class TerminalCommandController extends ActionController

public function getCommandsAction(): void
{
if (!$this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess')) {
$this->view->assign('value', ['success' => false, 'result' => []]);
return;
}

$commandNames = $this->terminalCommandService->getCommandNames();

$availableCommandNames = array_filter($commandNames, function ($commandName) {
Expand Down
11 changes: 11 additions & 0 deletions Configuration/Policy.yaml
Expand Up @@ -3,6 +3,9 @@ privilegeTargets:
'Shel.Neos.Terminal:ExecuteCommands':
matcher: 'method(Shel\Neos\Terminal\Controller\TerminalCommandController->(?!initialize).*Action())'

'Shel.Neos.Terminal:GetCommands':
matcher: 'method(Shel\Neos\Terminal\Controller\TerminalCommandController->getCommandsAction())'

'Shel\Neos\Terminal\Security\TerminalCommandPrivilege':
'Shel.Neos.Terminal:Command.All':
matcher: '*'
Expand All @@ -16,6 +19,13 @@ privilegeTargets:
matcher: 'nodeRepair'

roles:
'Neos.Flow:Everybody':
privileges:
# Allow everybody to load commands to prevent 403 errors for users without access in the UI.
# The command list will still be empty in the response as all commands have their own privileges.
- privilegeTarget: 'Shel.Neos.Terminal:GetCommands'
permission: GRANT

'Shel.Neos.Terminal:TerminalUser':
label: 'Terminal user'
description: 'Grants access to run read-only eel and search terminal commands'
Expand All @@ -26,6 +36,7 @@ roles:
permission: GRANT
- privilegeTarget: 'Shel.Neos.Terminal:Command.Search'
permission: GRANT

'Neos.Neos:Administrator':
privileges:
- privilegeTarget: 'Shel.Neos.Terminal:ExecuteCommands'
Expand Down
3 changes: 2 additions & 1 deletion Resources/Private/JavaScript/Terminal/src/manifest.js
Expand Up @@ -17,14 +17,15 @@ manifest('Shel.Neos.Terminal:Terminal', {}, (globalRegistry, { store, frontendCo
globalRegistry.get('reducers').set('Shel.Neos.Terminal', { reducer });
globalRegistry.get('containers').set('PrimaryToolbar/Middle/Terminal', Terminal);

// TODO: Don't register hotkey if terminal is not accessible for the current user
if (frontendConfiguration.hotkeys !== null && frontendConfiguration.hotkeys.length !== 0) {
globalRegistry.get('hotkeys').set('Shel.Neos.Terminal.toggle', {
description: 'Toggle Neos Terminal',
action: actions.toggleNeosTerminal,
});
}

// Register commands for command bar if installed
// Register commands for command bar if installed and commands are available
const commandBarRegistry = globalRegistry.get('Shel.Neos.CommandBar');
if (commandBarRegistry) {
commandBarRegistry.set('plugins/terminal', terminalCommandRegistry.getCommandsForCommandBar);
Expand Down
Expand Up @@ -26,7 +26,7 @@ class TerminalCommandRegistry {
private commands: CommandList;
private loading = false;

public getCommands = async () => {
public getCommands = async (): Promise<CommandList> => {
// Wait for commands to be loaded if another call already requested them
let i = 0;
while (this.loading) {
Expand Down Expand Up @@ -56,29 +56,31 @@ class TerminalCommandRegistry {
return this.i18nRegistry.translate(id, fallback, params, packageKey, sourceName);
};

public getCommandsForCommandBar = async () => {
public getCommandsForCommandBar = async (): Promise<Record<string, object>> => {
const commands = await this.getCommands();
const invokeCommand = this.invokeCommand;
return {
'shel.neos.terminal': {
name: 'Terminal',
description: 'Execute terminal commands',
icon: 'terminal',
subCommands: Object.values(commands).reduce((acc, { name, description }) => {
acc[name] = {
name,
icon: 'terminal',
description: this.translate(description),
action: async function* (arg) {
yield* invokeCommand(name, arg);
},
canHandleQueries: true,
executeManually: true,
};
return acc;
}, {}),
},
};
return Object.keys(commands).length > 0
? {
'shel.neos.terminal': {
name: 'Terminal',
description: 'Execute terminal commands',
icon: 'terminal',
subCommands: Object.values(commands).reduce((acc, { name, description }) => {
acc[name] = {
name,
icon: 'terminal',
description: this.translate(description),
action: async function* (arg) {
yield* invokeCommand(name, arg);
},
canHandleQueries: true,
executeManually: true,
};
return acc;
}, {}),
},
}
: {};
};

public invokeCommand = async function* (commandName: string, arg = '') {
Expand Down

0 comments on commit d4f2443

Please sign in to comment.