Add permissions handling to the console; remove kill permission (wrapped in with stop)

This commit is contained in:
Dane Everitt 2020-03-29 22:12:50 -07:00
parent 79095b526c
commit 171b21e7ee
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
5 changed files with 42 additions and 28 deletions

View file

@ -18,11 +18,10 @@ class SendPowerRequest extends ClientApiRequest
case 'start': case 'start':
return Permission::ACTION_CONTROL_START; return Permission::ACTION_CONTROL_START;
case 'stop': case 'stop':
case 'kill':
return Permission::ACTION_CONTROL_STOP; return Permission::ACTION_CONTROL_STOP;
case 'restart': case 'restart':
return Permission::ACTION_CONTROL_RESTART; return Permission::ACTION_CONTROL_RESTART;
case 'kill':
return Permission::ACTION_CONTROL_KILL;
} }
return '__invalid'; return '__invalid';

View file

@ -20,7 +20,6 @@ class Permission extends Validable
const ACTION_CONTROL_START = 'control.start'; const ACTION_CONTROL_START = 'control.start';
const ACTION_CONTROL_STOP = 'control.stop'; const ACTION_CONTROL_STOP = 'control.stop';
const ACTION_CONTROL_RESTART = 'control.restart'; const ACTION_CONTROL_RESTART = 'control.restart';
const ACTION_CONTROL_KILL = 'control.kill';
const ACTION_DATABASE_READ = 'database.read'; const ACTION_DATABASE_READ = 'database.read';
const ACTION_DATABASE_CREATE = 'database.create'; const ACTION_DATABASE_CREATE = 'database.create';
@ -111,7 +110,6 @@ class Permission extends Validable
'start' => 'Allows a user to start the server if it is stopped.', 'start' => 'Allows a user to start the server if it is stopped.',
'stop' => 'Allows a user to stop a server if it is running.', 'stop' => 'Allows a user to stop a server if it is running.',
'restart' => 'Allows a user to perform a server restart. This allows them to start the server if it is offline, but not put the server in a completely stopped state.', 'restart' => 'Allows a user to perform a server restart. This allows them to start the server if it is offline, but not put the server in a completely stopped state.',
'kill' => 'Allows a user to terminate a server process.',
], ],
], ],

View file

@ -4,6 +4,9 @@ import * as TerminalFit from 'xterm/lib/addons/fit/fit';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import { ServerContext } from '@/state/server'; import { ServerContext } from '@/state/server';
import styled from 'styled-components'; import styled from 'styled-components';
import Can from '@/components/elements/Can';
import { usePermissions } from '@/plugins/usePermissions';
import classNames from 'classnames';
const theme = { const theme = {
background: 'transparent', background: 'transparent',
@ -52,6 +55,7 @@ export default () => {
const useRef = useCallback(node => setTerminalElement(node), []); const useRef = useCallback(node => setTerminalElement(node), []);
const terminal = useMemo(() => new Terminal({ ...terminalProps }), []); const terminal = useMemo(() => new Terminal({ ...terminalProps }), []);
const { connected, instance } = ServerContext.useStoreState(state => state.socket); const { connected, instance } = ServerContext.useStoreState(state => state.socket);
const [ canSendCommands ] = usePermissions([ 'control.console']);
const handleConsoleOutput = (line: string, prelude = false) => terminal.writeln( const handleConsoleOutput = (line: string, prelude = false) => terminal.writeln(
(prelude ? TERMINAL_PRELUDE : '') + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m', (prelude ? TERMINAL_PRELUDE : '') + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m',
@ -121,7 +125,9 @@ export default () => {
<div className={'text-xs font-mono relative'}> <div className={'text-xs font-mono relative'}>
<SpinnerOverlay visible={!connected} size={'large'}/> <SpinnerOverlay visible={!connected} size={'large'}/>
<div <div
className={'rounded-t p-2 bg-black w-full'} className={classNames('rounded-t p-2 bg-black w-full', {
'rounded-b': !canSendCommands,
})}
style={{ style={{
minHeight: '16rem', minHeight: '16rem',
maxHeight: '32rem', maxHeight: '32rem',
@ -129,6 +135,7 @@ export default () => {
> >
<TerminalDiv id={'terminal'} ref={useRef}/> <TerminalDiv id={'terminal'} ref={useRef}/>
</div> </div>
{canSendCommands &&
<div className={'rounded-b bg-neutral-900 text-neutral-100 flex'}> <div className={'rounded-b bg-neutral-900 text-neutral-100 flex'}>
<div className={'flex-no-shrink p-2 font-bold'}>$</div> <div className={'flex-no-shrink p-2 font-bold'}>$</div>
<div className={'w-full'}> <div className={'w-full'}>
@ -140,6 +147,7 @@ export default () => {
/> />
</div> </div>
</div> </div>
}
</div> </div>
); );
}; };

View file

@ -9,6 +9,7 @@ import { faMicrochip } from '@fortawesome/free-solid-svg-icons/faMicrochip';
import { bytesToHuman } from '@/helpers'; import { bytesToHuman } from '@/helpers';
import SuspenseSpinner from '@/components/elements/SuspenseSpinner'; import SuspenseSpinner from '@/components/elements/SuspenseSpinner';
import TitledGreyBox from '@/components/elements/TitledGreyBox'; import TitledGreyBox from '@/components/elements/TitledGreyBox';
import Can from '@/components/elements/Can';
type PowerAction = 'start' | 'stop' | 'restart' | 'kill'; type PowerAction = 'start' | 'stop' | 'restart' | 'kill';
@ -109,28 +110,36 @@ export default () => {
&nbsp;{cpu.toFixed(2)} % &nbsp;{cpu.toFixed(2)} %
</p> </p>
</TitledGreyBox> </TitledGreyBox>
<div className={'grey-box justify-center'}> <Can action={[ 'control.start', 'control.stop', 'control.restart' ]} matchAny={true}>
<button <div className={'grey-box justify-center'}>
className={'btn btn-secondary btn-xs mr-2'} <Can action={'control.start'}>
disabled={status !== 'offline'} <button
onClick={e => { className={'btn btn-secondary btn-xs mr-2'}
e.preventDefault(); disabled={status !== 'offline'}
sendPowerCommand('start'); onClick={e => {
}} e.preventDefault();
> sendPowerCommand('start');
Start }}
</button> >
<button Start
className={'btn btn-secondary btn-xs mr-2'} </button>
onClick={e => { </Can>
e.preventDefault(); <Can action={'control.restart'}>
sendPowerCommand('restart'); <button
}} className={'btn btn-secondary btn-xs mr-2'}
> onClick={e => {
Restart e.preventDefault();
</button> sendPowerCommand('restart');
<StopOrKillButton onPress={action => sendPowerCommand(action)}/> }}
</div> >
Restart
</button>
</Can>
<Can action={'control.stop'}>
<StopOrKillButton onPress={action => sendPowerCommand(action)}/>
</Can>
</div>
</Can>
</div> </div>
<div className={'flex-1 mx-4 mr-4'}> <div className={'flex-1 mx-4 mr-4'}>
<SuspenseSpinner> <SuspenseSpinner>

View file

@ -2,7 +2,7 @@ import { action, Action } from 'easy-peasy';
export type SubuserPermission = export type SubuserPermission =
'websocket.*' | 'websocket.*' |
'control.console' | 'control.start' | 'control.stop' | 'control.restart' | 'control.kill' | 'control.console' | 'control.start' | 'control.stop' | 'control.restart' |
'user.create' | 'user.read' | 'user.update' | 'user.delete' | 'user.create' | 'user.read' | 'user.update' | 'user.delete' |
'file.create' | 'file.read' | 'file.update' | 'file.delete' | 'file.archive' | 'file.sftp' | 'file.create' | 'file.read' | 'file.update' | 'file.delete' | 'file.archive' | 'file.sftp' |
'allocation.read' | 'allocation.update' | 'allocation.read' | 'allocation.update' |