feat: improve admin security on dnshole controls (#1686)
This commit is contained in:
@@ -7,10 +7,10 @@ import { PiHoleClient } from '~/tools/server/sdk/pihole/piHole';
|
|||||||
import { ConfigAppType } from '~/types/app';
|
import { ConfigAppType } from '~/types/app';
|
||||||
import { AdStatistics } from '~/widgets/dnshole/type';
|
import { AdStatistics } from '~/widgets/dnshole/type';
|
||||||
|
|
||||||
import { createTRPCRouter, publicProcedure } from '../../trpc';
|
import { adminProcedure, createTRPCRouter, publicProcedure } from '../../trpc';
|
||||||
|
|
||||||
export const dnsHoleRouter = createTRPCRouter({
|
export const dnsHoleRouter = createTRPCRouter({
|
||||||
control: publicProcedure
|
control: adminProcedure
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
action: z.enum(['enable', 'disable']),
|
action: z.enum(['enable', 'disable']),
|
||||||
|
|||||||
@@ -68,16 +68,17 @@ const dnsLightStatus = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
|
function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
|
||||||
const utils = api.useContext();
|
|
||||||
const { data: sessionData } = useSession();
|
const { data: sessionData } = useSession();
|
||||||
const { isInitialLoading, data, isFetching: fetchingDnsSummary } = useDnsHoleSummeryQuery();
|
const { isInitialLoading, data, isFetching: fetchingDnsSummary } = useDnsHoleSummeryQuery();
|
||||||
const { mutateAsync, isLoading: changingStatus } = useDnsHoleControlMutation();
|
const { mutateAsync, isLoading: changingStatus } = useDnsHoleControlMutation();
|
||||||
const { width, ref } = useElementSize();
|
const { width, ref } = useElementSize();
|
||||||
const { t } = useTranslation(['common', 'modules/dns-hole-controls']);
|
const { t } = useTranslation(['common', 'modules/dns-hole-controls']);
|
||||||
|
|
||||||
|
const enableControls = sessionData?.user.isAdmin ?? false;
|
||||||
|
|
||||||
const { name: configName, config } = useConfigContext();
|
const { name: configName, config } = useConfigContext();
|
||||||
|
|
||||||
const trpcUtils = api.useContext();
|
const trpcUtils = api.useUtils();
|
||||||
|
|
||||||
if (isInitialLoading || !data || !configName) {
|
if (isInitialLoading || !data || !configName) {
|
||||||
return <WidgetLoading />;
|
return <WidgetLoading />;
|
||||||
@@ -123,13 +124,24 @@ function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
|
|||||||
return dnsList;
|
return dnsList;
|
||||||
};
|
};
|
||||||
|
|
||||||
const reFetchSummaryDns = () => {
|
const toggleDns = async (action: 'enable' | 'disable', appsToChange?: string[]) => {
|
||||||
trpcUtils.dnsHole.summary.invalidate();
|
await mutateAsync(
|
||||||
|
{
|
||||||
|
action,
|
||||||
|
configName,
|
||||||
|
appsToChange,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSettled: () => {
|
||||||
|
trpcUtils.dnsHole.summary.invalidate();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack justify="space-between" h={'100%'} spacing="0.25rem">
|
<Stack justify="space-between" h={'100%'} spacing="0.25rem">
|
||||||
{sessionData?.user?.isAdmin && widget.properties.showToggleAllButtons && (
|
{enableControls && widget.properties.showToggleAllButtons && (
|
||||||
<SimpleGrid
|
<SimpleGrid
|
||||||
ref={ref}
|
ref={ref}
|
||||||
cols={width > 275 ? 2 : 1}
|
cols={width > 275 ? 2 : 1}
|
||||||
@@ -137,20 +149,7 @@ function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
|
|||||||
spacing="0.25rem"
|
spacing="0.25rem"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={() => toggleDns('enable', getDnsStatus()?.disabled)}
|
||||||
await mutateAsync(
|
|
||||||
{
|
|
||||||
action: 'enable',
|
|
||||||
configName,
|
|
||||||
appsToChange: getDnsStatus()?.disabled,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onSettled: () => {
|
|
||||||
reFetchSummaryDns();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
disabled={getDnsStatus()?.disabled.length === 0 || fetchingDnsSummary || changingStatus}
|
disabled={getDnsStatus()?.disabled.length === 0 || fetchingDnsSummary || changingStatus}
|
||||||
leftIcon={<IconPlayerPlay size={20} />}
|
leftIcon={<IconPlayerPlay size={20} />}
|
||||||
variant="light"
|
variant="light"
|
||||||
@@ -160,20 +159,7 @@ function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
|
|||||||
{t('enableAll')}
|
{t('enableAll')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={() => toggleDns('disable', getDnsStatus()?.enabled)}
|
||||||
await mutateAsync(
|
|
||||||
{
|
|
||||||
action: 'disable',
|
|
||||||
configName,
|
|
||||||
appsToChange: getDnsStatus()?.enabled,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onSettled: () => {
|
|
||||||
reFetchSummaryDns();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
disabled={getDnsStatus()?.enabled.length === 0 || fetchingDnsSummary || changingStatus}
|
disabled={getDnsStatus()?.enabled.length === 0 || fetchingDnsSummary || changingStatus}
|
||||||
leftIcon={<IconPlayerStop size={20} />}
|
leftIcon={<IconPlayerStop size={20} />}
|
||||||
variant="light"
|
variant="light"
|
||||||
@@ -190,7 +176,8 @@ function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
|
|||||||
display="flex"
|
display="flex"
|
||||||
style={{
|
style={{
|
||||||
flex: '1',
|
flex: '1',
|
||||||
justifyContent: widget.properties.showToggleAllButtons ? 'flex-end' : 'space-evenly',
|
justifyContent:
|
||||||
|
enableControls && widget.properties.showToggleAllButtons ? 'flex-end' : 'space-evenly',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{data.status.map((dnsHole, index) => {
|
{data.status.map((dnsHole, index) => {
|
||||||
@@ -217,21 +204,11 @@ function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
|
|||||||
<Stack spacing="0rem">
|
<Stack spacing="0rem">
|
||||||
<Text>{app.name}</Text>
|
<Text>{app.name}</Text>
|
||||||
<UnstyledButton
|
<UnstyledButton
|
||||||
onClick={async () => {
|
onClick={() =>
|
||||||
await mutateAsync(
|
toggleDns(dnsHole.status === 'enabled' ? 'disable' : 'enable', [app.id])
|
||||||
{
|
}
|
||||||
action: dnsHole.status === 'enabled' ? 'disable' : 'enable',
|
|
||||||
configName,
|
|
||||||
appsToChange: [app.id],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onSettled: () => {
|
|
||||||
reFetchSummaryDns();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
disabled={fetchingDnsSummary || changingStatus}
|
disabled={fetchingDnsSummary || changingStatus}
|
||||||
|
style={{ pointerEvents: enableControls ? 'auto' : 'none' }}
|
||||||
>
|
>
|
||||||
<Badge
|
<Badge
|
||||||
variant="dot"
|
variant="dot"
|
||||||
|
|||||||
Reference in New Issue
Block a user