@samitouri / QOSami-HFS / commits / dfd7eb38

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