From 19a6a5c6081a849b31759ad235d52315c8362c0f Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Tue, 27 Feb 2024 12:36:44 +0200 Subject: [PATCH] fix(docker): hide write buttons for non authorized [EE-6775] (#11260) --- app/docker/react/components/index.ts | 8 ++- .../ConfigsDatatable/ConfigsDatatable.tsx | 49 +++++++++++----- app/react/docker/secrets/ListView/.keep | 0 .../secrets/ListView/SecretsDatatable.tsx | 57 ++++++++++++------- app/react/hooks/useUser.tsx | 10 +++- 5 files changed, 84 insertions(+), 40 deletions(-) delete mode 100644 app/react/docker/secrets/ListView/.keep diff --git a/app/docker/react/components/index.ts b/app/docker/react/components/index.ts index def6b6761..1f1ab5e2f 100644 --- a/app/docker/react/components/index.ts +++ b/app/docker/react/components/index.ts @@ -79,7 +79,7 @@ const ngModule = angular ) .component( 'dockerConfigsDatatable', - r2a(withUIRouter(ConfigsDatatable), [ + r2a(withUIRouter(withCurrentUser(ConfigsDatatable)), [ 'dataset', 'onRemoveClick', 'onRefresh', @@ -121,7 +121,11 @@ const ngModule = angular .component('dockerEventsDatatable', r2a(EventsDatatable, ['dataset'])) .component( 'dockerSecretsDatatable', - r2a(withUIRouter(SecretsDatatable), ['dataset', 'onRefresh', 'onRemove']) + r2a(withUIRouter(withCurrentUser(SecretsDatatable)), [ + 'dataset', + 'onRefresh', + 'onRemove', + ]) ) .component( 'dockerStacksDatatable', diff --git a/app/react/docker/configs/ListView/ConfigsDatatable/ConfigsDatatable.tsx b/app/react/docker/configs/ListView/ConfigsDatatable/ConfigsDatatable.tsx index 86c13349e..7f87933f3 100644 --- a/app/react/docker/configs/ListView/ConfigsDatatable/ConfigsDatatable.tsx +++ b/app/react/docker/configs/ListView/ConfigsDatatable/ConfigsDatatable.tsx @@ -1,5 +1,7 @@ import { Clipboard, Plus, Trash2 } from 'lucide-react'; +import { Authorized, useAuthorizations } from '@/react/hooks/useUser'; + import { Datatable, TableSettingsMenu } from '@@/datatables'; import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh'; import { useRepeater } from '@@/datatables/useRepeater'; @@ -26,6 +28,11 @@ export function ConfigsDatatable({ dataset, onRefresh, onRemoveClick }: Props) { useRepeater(tableState.autoRefreshRate, onRefresh); + const hasWriteAccessQuery = useAuthorizations([ + 'DockerConfigCreate', + 'DockerConfigDelete', + ]); + return ( )} - renderTableActions={(selectedRows) => ( -
- - -
- )} + disableSelect={!hasWriteAccessQuery.authorized} + renderTableActions={(selectedRows) => + hasWriteAccessQuery.authorized && ( +
+ + + + + + + +
+ ) + } /> ); } diff --git a/app/react/docker/secrets/ListView/.keep b/app/react/docker/secrets/ListView/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/react/docker/secrets/ListView/SecretsDatatable.tsx b/app/react/docker/secrets/ListView/SecretsDatatable.tsx index 36d87b35e..81343a4e1 100644 --- a/app/react/docker/secrets/ListView/SecretsDatatable.tsx +++ b/app/react/docker/secrets/ListView/SecretsDatatable.tsx @@ -3,6 +3,7 @@ import { Lock, Plus, Trash2 } from 'lucide-react'; import { SecretViewModel } from '@/docker/models/secret'; import { isoDate } from '@/portainer/filters/filters'; +import { Authorized, useAuthorizations } from '@/react/hooks/useUser'; import { buildNameColumn } from '@@/datatables/buildNameColumn'; import { Datatable, TableSettingsMenu } from '@@/datatables'; @@ -53,6 +54,11 @@ export function SecretsDatatable({ const tableState = useTableState(store, storageKey); useRepeater(tableState.autoRefreshRate, onRefresh); + const hasWriteAccessQuery = useAuthorizations([ + 'DockerSecretCreate', + 'DockerSecretDelete', + ]); + return ( ( - - )} + renderTableActions={(selectedItems) => + hasWriteAccessQuery.authorized && ( + + ) + } renderTableSettings={() => ( - + + + - + + + ); } diff --git a/app/react/hooks/useUser.tsx b/app/react/hooks/useUser.tsx index 04df8f195..7fdbbb881 100644 --- a/app/react/hooks/useUser.tsx +++ b/app/react/hooks/useUser.tsx @@ -88,6 +88,14 @@ export function useIsEdgeAdmin({ }; } +/** + * Check if the user has some of the authorizations + * + * @param authorizations a list of authorizations to check + * @param forceEnvironmentId to force the environment id, used where the environment id can't be loaded from the router, like sidebar + * @param adminOnlyCE if true, will return false if the user is not an admin in CE + * @returns query result with isLoading and authorized - authorized is true if the user has some of the authorizations + */ export function useAuthorizations( authorizations: string | string[], forceEnvironmentId?: EnvironmentId, @@ -137,7 +145,7 @@ export function useIsEnvironmentAdmin({ } /** - * will return true if the user has the authorizations. assumes the user is authenticated and not an admin + * will return true if the user has some of the authorizations. assumes the user is authenticated and not an admin * * @private Please use `useAuthorizations` instead. Exported only for angular's authentication service app/portainer/services/authentication.js:154 */