Skip to content

Commit aaa1fac

Browse files
protect acl actions (#2072)
1 parent 1549bc1 commit aaa1fac

12 files changed

Lines changed: 152 additions & 55 deletions

File tree

web/src/pages/AliasesPage/AliasTable.tsx

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { tableEditColumnSize } from '../../shared/defguard-ui/components/table/c
1717
import { TableBody } from '../../shared/defguard-ui/components/table/TableBody/TableBody';
1818
import { TableCell } from '../../shared/defguard-ui/components/table/TableCell/TableCell';
1919
import { isPresent } from '../../shared/defguard-ui/utils/isPresent';
20+
import { getLicenseInfoQueryOptions } from '../../shared/query';
21+
import { canUseBusinessFeature, licenseActionCheck } from '../../shared/utils/license';
2022

2123
type RowData = AclAlias;
2224

@@ -29,6 +31,10 @@ type Props = {
2931
export const AliasTable = ({ data: rowData }: Props) => {
3032
const navigate = useNavigate();
3133

34+
const { data: licenseInfo, isFetching: isLicenseFetching } = useQuery(
35+
getLicenseInfoQueryOptions,
36+
);
37+
3238
const { data: rules } = useQuery({
3339
queryFn: api.acl.rule.getRules,
3440
queryKey: ['acl', 'rule'],
@@ -124,11 +130,14 @@ export const AliasTable = ({ data: rowData }: Props) => {
124130
text: m.controls_edit(),
125131
icon: 'edit',
126132
onClick: () => {
127-
navigate({
128-
to: '/acl/edit-alias',
129-
search: {
130-
alias: row.id,
131-
},
133+
if (licenseInfo === undefined) return;
134+
licenseActionCheck(canUseBusinessFeature(licenseInfo), () => {
135+
navigate({
136+
to: '/acl/edit-alias',
137+
search: {
138+
alias: row.id,
139+
},
140+
});
132141
});
133142
},
134143
},
@@ -137,7 +146,10 @@ export const AliasTable = ({ data: rowData }: Props) => {
137146
icon: 'delete',
138147
variant: 'danger',
139148
onClick: () => {
140-
deleteAlias(row.id);
149+
if (licenseInfo === undefined) return;
150+
licenseActionCheck(canUseBusinessFeature(licenseInfo), () => {
151+
deleteAlias(row.id);
152+
});
141153
},
142154
},
143155
],
@@ -148,19 +160,26 @@ export const AliasTable = ({ data: rowData }: Props) => {
148160
text: 'Deploy',
149161
icon: 'deploy',
150162
onClick: () => {
151-
applyAliases([row.id]);
163+
if (licenseInfo === undefined) return;
164+
licenseActionCheck(canUseBusinessFeature(licenseInfo), () => {
165+
applyAliases([row.id]);
166+
});
152167
},
153168
});
154169
}
155170
return (
156171
<TableCell>
157-
<IconButtonMenu icon="menu" menuItems={menuItems} />
172+
<IconButtonMenu
173+
icon="menu"
174+
menuItems={menuItems}
175+
disabled={isLicenseFetching}
176+
/>
158177
</TableCell>
159178
);
160179
},
161180
}),
162181
],
163-
[rules, applyAliases, deleteAlias, navigate],
182+
[rules, applyAliases, deleteAlias, navigate, isLicenseFetching, licenseInfo],
164183
);
165184

166185
const table = useReactTable({

web/src/pages/AliasesPage/tabs/AliasesDeployedTab.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useQuery } from '@tanstack/react-query';
12
import { useNavigate } from '@tanstack/react-router';
23
import { useMemo, useState } from 'react';
34
import { m } from '../../../paraglide/messages';
@@ -7,6 +8,8 @@ import type { ButtonProps } from '../../../shared/defguard-ui/components/Button/
78
import { EmptyStateFlexible } from '../../../shared/defguard-ui/components/EmptyStateFlexible/EmptyStateFlexible';
89
import { Search } from '../../../shared/defguard-ui/components/Search/Search';
910
import { TableTop } from '../../../shared/defguard-ui/components/table/TableTop/TableTop';
11+
import { getLicenseInfoQueryOptions } from '../../../shared/query';
12+
import { canUseBusinessFeature, licenseActionCheck } from '../../../shared/utils/license';
1013
import { AliasTable } from '../AliasTable';
1114

1215
type Props = {
@@ -17,18 +20,25 @@ export const AliasesDeployedTab = ({ aliases }: Props) => {
1720
const isEmpty = aliases.length === 0;
1821
const navigate = useNavigate();
1922
const [search, setSearch] = useState('');
23+
const { data: licenseInfo, isFetching: licenseFetching } = useQuery(
24+
getLicenseInfoQueryOptions,
25+
);
2026

2127
const addButtonProps = useMemo(
2228
(): ButtonProps => ({
2329
text: 'Add new alias',
2430
iconLeft: 'add-alias',
2531
variant: 'primary',
2632
testId: 'add-alias',
33+
disabled: licenseFetching,
2734
onClick: () => {
28-
navigate({ to: '/acl/add-alias' });
35+
if (licenseInfo === undefined) return;
36+
licenseActionCheck(canUseBusinessFeature(licenseInfo), () => {
37+
navigate({ to: '/acl/add-alias' });
38+
});
2939
},
3040
}),
31-
[navigate],
41+
[navigate, licenseFetching, licenseInfo],
3242
);
3343

3444
const distilledAliases = useMemo(() => {

web/src/pages/DestinationsPage/components/DestinationsTable.tsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import { tableEditColumnSize } from '../../../shared/defguard-ui/components/tabl
2020
import { TableBody } from '../../../shared/defguard-ui/components/table/TableBody/TableBody';
2121
import { TableCell } from '../../../shared/defguard-ui/components/table/TableCell/TableCell';
2222
import { TableTop } from '../../../shared/defguard-ui/components/table/TableTop/TableTop';
23-
import { getRulesQueryOptions } from '../../../shared/query';
23+
import { getLicenseInfoQueryOptions, getRulesQueryOptions } from '../../../shared/query';
24+
import { canUseBusinessFeature, licenseActionCheck } from '../../../shared/utils/license';
2425
import { resourceById } from '../../../shared/utils/resourceById';
2526

2627
type Props = {
@@ -45,6 +46,10 @@ export const DestinationsTable = ({
4546
const [searchValue, setSearchValue] = useState<string>('');
4647
const navigate = useNavigate();
4748

49+
const { data: licenseInfo, isFetching: licenseFetching } = useQuery(
50+
getLicenseInfoQueryOptions,
51+
);
52+
4853
const { mutate: deleteDestination } = useMutation({
4954
mutationFn: api.acl.destination.deleteDestination,
5055
meta: {
@@ -137,11 +142,14 @@ export const DestinationsTable = ({
137142
text: m.controls_edit(),
138143
icon: 'edit',
139144
onClick: () => {
140-
navigate({
141-
to: '/acl/edit-destination',
142-
search: {
143-
destination: row.id,
144-
},
145+
if (licenseInfo === undefined) return;
146+
licenseActionCheck(canUseBusinessFeature(licenseInfo), () => {
147+
navigate({
148+
to: '/acl/edit-destination',
149+
search: {
150+
destination: row.id,
151+
},
152+
});
145153
});
146154
},
147155
},
@@ -150,21 +158,28 @@ export const DestinationsTable = ({
150158
icon: 'delete',
151159
variant: 'danger',
152160
onClick: () => {
153-
deleteDestination(row.id);
161+
if (licenseInfo === undefined) return;
162+
licenseActionCheck(canUseBusinessFeature(licenseInfo), () => {
163+
deleteDestination(row.id);
164+
});
154165
},
155166
},
156167
],
157168
},
158169
];
159170
return (
160171
<TableCell>
161-
<IconButtonMenu icon="menu" menuItems={menuItems} />
172+
<IconButtonMenu
173+
icon="menu"
174+
menuItems={menuItems}
175+
disabled={licenseFetching}
176+
/>
162177
</TableCell>
163178
);
164179
},
165180
}),
166181
],
167-
[navigate, deleteDestination, rulesById],
182+
[navigate, deleteDestination, rulesById, licenseFetching, licenseInfo],
168183
);
169184

170185
const transformedData = useMemo(() => {

web/src/pages/DestinationsPage/tabs/DestinationDeployedTab/DestinationDeployedTab.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
import { useQuery } from '@tanstack/react-query';
12
import { useNavigate } from '@tanstack/react-router';
23
import { useMemo } from 'react';
34
import type { AclDestination } from '../../../../shared/api/types';
45
import type { ButtonProps } from '../../../../shared/defguard-ui/components/Button/types';
56
import { EmptyStateFlexible } from '../../../../shared/defguard-ui/components/EmptyStateFlexible/EmptyStateFlexible';
7+
import { getLicenseInfoQueryOptions } from '../../../../shared/query';
8+
import {
9+
canUseBusinessFeature,
10+
licenseActionCheck,
11+
} from '../../../../shared/utils/license';
612
import { DestinationsTable } from '../../components/DestinationsTable';
713

814
type Props = {
@@ -12,18 +18,24 @@ type Props = {
1218
export const DestinationDeployedTab = ({ destinations }: Props) => {
1319
const navigate = useNavigate();
1420

21+
const { data: licenseInfo, isFetching } = useQuery(getLicenseInfoQueryOptions);
22+
1523
const addButtonProps = useMemo(
1624
(): ButtonProps => ({
1725
text: 'Add new destination',
1826
variant: 'primary',
1927
iconLeft: 'add-location',
28+
disabled: isFetching,
2029
onClick: () => {
21-
navigate({
22-
to: '/acl/add-destination',
30+
if (licenseInfo === undefined) return;
31+
licenseActionCheck(canUseBusinessFeature(licenseInfo), () => {
32+
navigate({
33+
to: '/acl/add-destination',
34+
});
2335
});
2436
},
2537
}),
26-
[navigate],
38+
[navigate, isFetching, licenseInfo],
2739
);
2840

2941
return (

web/src/pages/RulesPage/RulesTable.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
AclStatus,
1616
type AclStatusValue,
1717
type GroupInfo,
18+
type LicenseInfo,
1819
type NetworkDevice,
1920
type NetworkLocation,
2021
type ResourceById,
@@ -34,6 +35,7 @@ import { TableBody } from '../../shared/defguard-ui/components/table/TableBody/T
3435
import { TableCell } from '../../shared/defguard-ui/components/table/TableCell/TableCell';
3536
import { TableTop } from '../../shared/defguard-ui/components/table/TableTop/TableTop';
3637
import { isPresent } from '../../shared/defguard-ui/utils/isPresent';
38+
import { canUseBusinessFeature, licenseActionCheck } from '../../shared/utils/license';
3739

3840
const displayUser = (user?: User): string => {
3941
if (!isPresent(user)) return '~';
@@ -49,6 +51,7 @@ type RowData = AclRule;
4951
const columnHelper = createColumnHelper<RowData>();
5052

5153
type Props = {
54+
license: LicenseInfo | null;
5255
aliases: ResourceById<AclAlias>;
5356
groups: ResourceById<GroupInfo>;
5457
users: ResourceById<User>;
@@ -70,8 +73,10 @@ export const RulesTable = ({
7073
users,
7174
locations,
7275
data,
76+
license,
7377
}: Props) => {
7478
const navigate = useNavigate();
79+
7580
const { mutate: deleteRule } = useMutation({
7681
mutationFn: api.acl.rule.deleteRule,
7782
meta: {
@@ -270,11 +275,13 @@ export const RulesTable = ({
270275
icon: 'edit',
271276
text: m.controls_edit(),
272277
onClick: () => {
273-
navigate({
274-
to: '/acl/edit-rule',
275-
search: {
276-
rule: row.id,
277-
},
278+
licenseActionCheck(canUseBusinessFeature(license), () => {
279+
navigate({
280+
to: '/acl/edit-rule',
281+
search: {
282+
rule: row.id,
283+
},
284+
});
278285
});
279286
},
280287
},
@@ -287,7 +294,9 @@ export const RulesTable = ({
287294
variant: 'danger',
288295
text: m.controls_delete(),
289296
onClick: () => {
290-
deleteRule(row.id);
297+
licenseActionCheck(canUseBusinessFeature(license), () => {
298+
deleteRule(row.id);
299+
});
291300
},
292301
},
293302
],
@@ -301,7 +310,15 @@ export const RulesTable = ({
301310
},
302311
}),
303312
],
304-
[aliases, renderPermissionCell, deleteRule, locations, navigate, renderStatusCell],
313+
[
314+
aliases,
315+
renderPermissionCell,
316+
deleteRule,
317+
locations,
318+
navigate,
319+
renderStatusCell,
320+
license,
321+
],
305322
);
306323

307324
const visibleRules = useMemo(() => {

web/src/pages/RulesPage/tabs/RulesDeployedTab.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const RulesDeployedTab = ({ rules }: Props) => {
4141
[navigate, licenseFetching, licenseInfo],
4242
);
4343

44-
const { aliases, groups, locations, users, devices, loading } = useRuleDeps();
44+
const { aliases, groups, locations, users, devices, license, loading } = useRuleDeps();
4545

4646
return (
4747
<>
@@ -59,7 +59,8 @@ export const RulesDeployedTab = ({ rules }: Props) => {
5959
isPresent(groups) &&
6060
isPresent(locations) &&
6161
isPresent(users) &&
62-
isPresent(devices) && (
62+
isPresent(devices) &&
63+
isPresent(license) && (
6364
<RulesTable
6465
title="Deployed rules"
6566
buttonProps={buttonProps}
@@ -69,6 +70,7 @@ export const RulesDeployedTab = ({ rules }: Props) => {
6970
devices={devices}
7071
users={users}
7172
locations={locations}
73+
license={license}
7274
enableSearch
7375
/>
7476
)}

0 commit comments

Comments
 (0)