From a1c37308611a5f0c249b0a01ebef36bae9904211 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 19 Apr 2020 11:58:26 -0700 Subject: [PATCH] Update frontend to only allow selection of valid permissions for subusers --- .../Api/Client/Servers/SubuserController.php | 3 +- .../server/users/EditSubuserModal.tsx | 51 ++++++++++++++++--- .../components/server/users/UserRow.tsx | 6 ++- resources/styles/components/forms.css | 2 +- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/Api/Client/Servers/SubuserController.php b/app/Http/Controllers/Api/Client/Servers/SubuserController.php index 05e82358a..da6fee428 100644 --- a/app/Http/Controllers/Api/Client/Servers/SubuserController.php +++ b/app/Http/Controllers/Api/Client/Servers/SubuserController.php @@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers; use Illuminate\Http\Request; use Pterodactyl\Models\Server; use Illuminate\Http\JsonResponse; +use Pterodactyl\Models\Permission; use Pterodactyl\Repositories\Eloquent\SubuserRepository; use Pterodactyl\Services\Subusers\SubuserCreationService; use Pterodactyl\Transformers\Api\Client\SubuserTransformer; @@ -123,6 +124,6 @@ class SubuserController extends ClientApiController */ protected function getDefaultPermissions(Request $request): array { - return array_unique(array_merge($request->input('permissions') ?? [], ['websocket.connect'])); + return array_unique(array_merge($request->input('permissions') ?? [], [Permission::ACTION_WEBSOCKET_CONNECT])); } } diff --git a/resources/scripts/components/server/users/EditSubuserModal.tsx b/resources/scripts/components/server/users/EditSubuserModal.tsx index bd6c0dfdb..81fefcc7d 100644 --- a/resources/scripts/components/server/users/EditSubuserModal.tsx +++ b/resources/scripts/components/server/users/EditSubuserModal.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, useRef } from 'react'; +import React, { forwardRef, useEffect, useRef } from 'react'; import { Subuser } from '@/state/server/subusers'; import { Form, Formik, FormikHelpers, useFormikContext } from 'formik'; import { array, object, string } from 'yup'; @@ -16,6 +16,7 @@ import { httpErrorToHuman } from '@/api/http'; import FlashMessageRender from '@/components/FlashMessageRender'; import Can from '@/components/elements/Can'; import { usePermissions } from '@/plugins/usePermissions'; +import { useDeepMemo } from '@/plugins/useDeepMemo'; type Props = { subuser?: Subuser; @@ -37,12 +38,38 @@ const PermissionLabel = styled.label` ${tw`border-neutral-500 bg-neutral-800`}; } } + + &.disabled { + ${tw`opacity-50`}; + + & input[type="checkbox"]:not(:checked) { + ${tw`border-0`}; + } + } `; const EditSubuserModal = forwardRef(({ subuser, ...props }, ref) => { const { values, isSubmitting, setFieldValue } = useFormikContext(); - const [ canEditUser ] = usePermissions([ 'user.update' ]); - const permissions = useStoreState((state: ApplicationStore) => state.permissions.data); + const [ canEditUser ] = usePermissions(subuser ? [ 'user.update' ] : [ 'user.create' ]); + const permissions = useStoreState(state => state.permissions.data); + + // The currently logged in user's permissions. We're going to filter out any permissions + // that they should not need. + const loggedInPermissions = ServerContext.useStoreState(state => state.server.permissions); + + // The permissions that can be modified by this user. + const editablePermissions = useDeepMemo(() => { + const cleaned = Object.keys(permissions) + .map(key => Object.keys(permissions[key].keys).map(pkey => `${key}.${pkey}`)); + + const list: string[] = ([] as string[]).concat.apply([], Object.values(cleaned)); + + if (loggedInPermissions.length === 1 && loggedInPermissions[0] === '*') { + return list; + } + + return list.filter(key => loggedInPermissions.indexOf(key) >= 0); + }, [permissions, loggedInPermissions]); return ( @@ -54,6 +81,12 @@ const EditSubuserModal = forwardRef(({ subuser, ...pr } +
+

+ Only permissions which your account is currently assigned may be selected when creating or + modifying other users. +

+
{!subuser &&
(({ subuser, ...pr title={

{key}

- {canEditUser && + {canEditUser && editablePermissions.indexOf(key) >= 0 && { @@ -106,7 +139,7 @@ const EditSubuserModal = forwardRef(({ subuser, ...pr htmlFor={`permission_${key}_${pkey}`} className={classNames('transition-colors duration-75', { 'mt-2': index !== 0, - disabled: !canEditUser, + disabled: !canEditUser || editablePermissions.indexOf(`${key}.${pkey}`) < 0, })} >
@@ -115,7 +148,7 @@ const EditSubuserModal = forwardRef(({ subuser, ...pr name={'permissions'} value={`${key}.${pkey}`} className={'w-5 h-5 mr-2'} - disabled={!canEditUser} + disabled={!canEditUser || editablePermissions.indexOf(`${key}.${pkey}`) < 0} />
@@ -133,7 +166,7 @@ const EditSubuserModal = forwardRef(({ subuser, ...pr ))}
- +