admin/config: prevent disabling admin_localhost if you didn't create an admin account
Massimo Melina committed
Apr 13, 2022 at 18:30 UTC
582dee65206ca194f061beccc83bc61ec91a768c
3 files changed
+16
-7
admin/src/ConfigPage.ts
+9
-4
@@ -2,7 +2,7 @@
2
3
import { Box, Button, FormHelperText, Link } from '@mui/material';
4
import { createElement as h, isValidElement, useEffect, useRef } from 'react';
5
-import { apiCall, useApiComp } from './api'
5
+import { apiCall, useApi, useApiComp } from './api'
6
import { state, useSnapState } from './state'
7
import { Info, Refresh } from '@mui/icons-material'
8
import { Dict, modifiedSx } from './misc'
@@ -32,6 +32,8 @@ export default function ConfigPage() {
32
exposedReloadStatus = reloadStatus
33
useEffect(() => () => exposedReloadStatus = undefined, []) // clear on unmount
34
35
+ const admins = useApi('get_admins')[0]?.list
36
+
37
if (isValidElement(res))
38
return res
39
if (isValidElement(status))
@@ -88,8 +90,11 @@ export default function ConfigPage() {
90
helperText: "To avoid an endlessly-growing single log file, you can opt for rotation"
91
},
92
{ k: 'open_browser_at_start', comp: BoolField },
91
- { k: 'localhost_admin', comp: BoolField, label: "Admin access for localhost connections", helperText: "To access Admin without entering credentials" },
92
- { k: 'proxies', comp: NumberField, min: 0, max: 9, sm: 6, lg: 6, label: "How many proxies between this server and users?",
93
+ { k: 'localhost_admin', comp: BoolField, label: "Admin access for localhost connections",
94
+ validate: x => x || admins?.length>0 || "First create at least one admin account",
95
+ helperText: "To access Admin without entering credentials"
96
+ },
97
+ { k: 'proxies', comp: NumberField, min: 0, max: 9, sm: 6, lg: 6, label: "How many HTTP proxies between this server and users?",
98
error: proxyWarning(values, status),
99
helperText: "Wrong number will prevent detection of users' IP address"
100
},
@@ -167,7 +172,7 @@ function ServerPort({ label, value, onChange, status, suggestedPort=1 }: FieldPr
172
],
173
onChange,
174
}),
170
- value! > 0 && h(NumberField, { label: 'Number', fullWidth: false, value, onChange }),
175
+ value! > 0 && h(NumberField, { label: 'Number', fullWidth: false, value, onChange, min: 1, max: 65535 }),
176
),
177
status && h(FormHelperText, { error: Boolean(error) },
178
status === true ? '...'
admin/src/Form.ts
+3
-3
@@ -315,7 +315,7 @@ export function NumberField({ value, onChange, min, max, step, ...props }: Field
315
})
316
}
317
318
-export function BoolField({ label='', value, onChange, helperText, fromField=_.identity, toField=_.identity, ...props }: FieldProps<boolean>) {
318
+export function BoolField({ label='', value, onChange, helperText, error, fromField=_.identity, toField=_.identity, ...props }: FieldProps<boolean>) {
319
const setter = () => toField(value) ?? false
320
const [state, setState] = useState(setter)
321
useEffect(() => setState(setter),
@@ -327,9 +327,9 @@ export function BoolField({ label='', value, onChange, helperText, fromField=_.i
327
onChange(fromField(event.target.checked), { event, was: value })
328
}
329
})
330
- return h(Box, { ml: 1, mt: 1 },
330
+ return h(Box, { ml: 1, mt: 1, sx: error && { color: 'error.main', outlineOffset: 6, outline: '1px solid' } },
331
h(FormControlLabel, { label, control, labelPlacement: 'end' }),
332
- helperText && h(FormHelperText,{},helperText)
332
+ helperText && h(FormHelperText, { error }, helperText)
333
)
334
}
335
server/src/api.accounts.ts
+4
@@ -40,6 +40,10 @@ const apis: ApiHandlers = {
40
return { list: Object.values(getAccounts()).map(prepareAccount) }
41
},
42
43
+ get_admins() {
44
+ return { list: Object.values(getAccounts()).map(prepareAccount).filter(ac => ac?.adminActualAccess).map(ac => ac!.username) }
45
+ },
46
+
47
set_account({ username, changes }) {
48
const { admin } = changes
49
if (admin === null)