admin/internet: shortcut to enable https
Massimo Melina committed
Nov 2, 2023 at 23:35 UTC
dfd7eb38fce58dbf669a15a17b55c9774b2dfd70
4 files changed
+39
-29
admin/src/InternetPage.ts
+23
-13
@@ -2,9 +2,9 @@ import { createElement as h, useEffect, useState } from 'react'
2
import { Alert, Box, Button, Card, CardContent, CircularProgress, Divider, LinearProgress, Link } from '@mui/material'
3
import { CardMembership, HomeWorkTwoTone, Lock, PublicTwoTone, RouterTwoTone, Send } from '@mui/icons-material'
4
import { apiCall, useApiEx } from './api'
5
-import { closeDialog, DAY, formatTimestamp, wantArray, with_ } from '@hfs/shared'
6
-import { Flex, LinkBtn, manipulateConfig, isIP, Btn } from './misc'
7
-import { alertDialog, confirmDialog, promptDialog, toast } from './dialog'
5
+import { closeDialog, DAY, formatTimestamp, wait, wantArray, with_ } from '@hfs/shared'
6
+import { Flex, LinkBtn, isIP, Btn } from './misc'
7
+import { alertDialog, confirmDialog, promptDialog, toast, waitDialog } from './dialog'
8
import { BoolField, Form, NumberField } from '@hfs/mui-grid-form'
9
import md from './md'
10
import { isCertError } from './OptionsPage'
@@ -48,17 +48,18 @@ export default function InternetPage() {
48
useEffect(() => { apiCall('get_config', { only: ['acme_domain', 'acme_email', 'acme_renew'] }).then(setValues) } , [])
49
if (!status || !values) return h(CircularProgress)
50
return element || status.element || h(Card, {}, h(CardContent, {},
51
- h(Flex, { gap: '.5em', fontSize: 'x-large', mb: 1, alignItems: 'center' }, "HTTPS",
52
- h(Lock, { color: listening && !error ? 'success' : 'warning' }) ),
53
- h(Box, { mt: 1 },
54
- isCertError(error) && h(Alert, { severity: 'warning', sx: { mb: 1 } }, error),
51
+ h(Flex, { vert: true },
52
+ h(Box, { fontSize: 'x-large' }, "HTTPS",
53
+ h(Lock, { color: listening && !error ? 'success' : 'warning', sx: { ml: 1, verticalAlign: 'text-top' } }) ),
54
+ isCertError(error) && h(Alert, { severity: 'warning' }, error),
55
+ !listening && h(LinkBtn, { onClick: notEnabled }, "Not enabled")
56
+ || error && "For HTTPS to work, you need a valid certificate",
57
cert.element || with_(cert.data, c => h(Box, {}, h(CardMembership, { fontSize: 'small', sx: { mr: 1, verticalAlign: 'middle' } }), "Current certificate", h('ul', {},
58
h('li', {}, "Domain: ", c.subject?.CN || '-'),
59
h('li', {}, "Issuer: ", c.issuer?.O || h('i', {}, 'self-signed')),
60
h('li', {}, "Validity: ", ['validFrom', 'validTo'].map(k => formatTimestamp(c[k])).join(' – ')),
61
))),
60
- !listening && "Not enabled. " || error && "For HTTPS to work, you need a valid certificate.",
61
- h(Divider, { sx: { my: 2 } }),
62
+ h(Divider),
63
h(Form, {
64
gap: 1,
65
gridProps: {rowSpacing:1},
@@ -91,10 +92,8 @@ export default function InternetPage() {
92
await apiCall('make_cert', { domain, email: values.acme_email }, { timeout: 20_000 })
93
.then(async () => {
94
await alertDialog("Certificate created", 'success')
94
- await manipulateConfig('https_port', async v => {
95
- return v < 0 && await confirmDialog("HTTPS is currently off", { confirmText: "Switch on" }) ? 443 : v
96
- })
97
- status.reload()
95
+ if (!listening)
96
+ await notEnabled()
97
cert.reload()
98
}, alertDialog)
99
}
@@ -104,6 +103,17 @@ export default function InternetPage() {
103
))
104
}
105
106
+ async function notEnabled() {
107
+ if (!await confirmDialog("HTTPS is currently disabled.\nFull configuration is available in the Options page.", { confirmText: "Enable it"})) return
108
+ const stop = waitDialog()
109
+ try {
110
+ await apiCall('set_config', { values: { https_port: 443 } })
111
+ await wait(1000)
112
+ status.reload()
113
+ }
114
+ finally { stop() }
115
+ }
116
+
117
function baseUrlBox() {
118
const url = config?.base_url
119
const hostname = url && new URL(url).hostname
admin/src/dialog.ts
+2
-1
@@ -19,6 +19,7 @@ import { Form, FormProps } from '@hfs/mui-grid-form'
19
import { IconBtn, Flex, Center } from './misc'
20
import { useDark } from './theme'
21
import { useWindowSize } from 'usehooks-ts'
22
+import md from './md'
23
export * from '@hfs/shared/dialogs'
24
25
dialogsDefaults.Container = function Container(d:DialogOptions) {
@@ -128,7 +129,7 @@ export function confirmDialog(msg: ReactNode, { href, confirmText="Go", dontText
129
130
function Content() {
131
return h(Fragment, {},
131
- h(Box, { mb: 2 }, msg),
132
+ h(Box, { mb: 2 }, typeof msg === 'string' ? md(msg) : msg),
133
h(Flex, {},
134
h('a', {
135
href,
admin/src/index.css
+1
-1
@@ -27,7 +27,7 @@ code {
27
28
.wrap .MuiDataGrid-cellContent { white-space: normal }
29
30
-ol, ul { margin-top: .2em; padding-left: 1.5em; }
30
+ol, ul { margin-top: .2em; margin-bottom: .2em; padding-left: 1.5em; }
31
32
.dialog-alert .MuiDialogContent-root {
33
max-width: 45em;
src/adminApis.ts
+13
-14
@@ -19,7 +19,7 @@ import monitorApis from './api.monitor'
19
import langApis from './api.lang'
20
import netApis from './api.net'
21
import { getConnections } from './connections'
22
-import { debounceAsync, isLocalHost, makeNetMatcher, onOff, tryJson, wait, waitFor } from './misc'
22
+import { apiAssertTypes, debounceAsync, isLocalHost, makeNetMatcher, onOff, tryJson, wait, waitFor } from './misc'
23
import events from './events'
24
import { accountCanLoginAdmin, accountsConfig, getFromAccount } from './perm'
25
import Koa from 'koa'
@@ -46,19 +46,18 @@ export const adminApis: ApiHandlers = {
46
...langApis,
47
...netApis,
48
49
- async set_config({ values: v }) {
50
- if (v) {
51
- await setConfig(v)
52
- if (v.port === 0 || v.https_port === 0)
53
- return await waitFor(async () => {
54
- const st = await getServerStatus()
55
- // wait for all random ports to be done, so we communicate new numbers
56
- if ((v.port !== 0 || st.http.listening)
57
- && (v.https_port !== 0 || st.https.listening))
58
- return st
59
- }, { timeout: 1000 })
60
- ?? new ApiError(HTTP_SERVER_ERROR, "something went wrong changing ports")
61
- }
49
+ async set_config({ values }) {
50
+ apiAssertTypes({ object: { values } })
51
+ setConfig(values)
52
+ if (values.port === 0 || values.https_port === 0)
53
+ return await waitFor(async () => {
54
+ const st = await getServerStatus()
55
+ // wait for all random ports to be done, so we communicate new numbers
56
+ if ((values.port !== 0 || st.http.listening)
57
+ && (values.https_port !== 0 || st.https.listening))
58
+ return st
59
+ }, { timeout: 1000 })
60
+ ?? new ApiError(HTTP_SERVER_ERROR, "something went wrong changing ports")
61
return {}
62
},
63