admin: don't ask for login if no login is possible

Massimo Melina committed Jan 26, 2023 at 16:41 UTC 52dfb6a124ac8c743f73905afeafd55d4daef886
8 files changed +22 -9
admin/src/LoginRequired.ts
+6 -1
@@ -6,10 +6,15 @@ import { Center } from './misc'
6 import { Form } from '@hfs/mui-grid-form'
7 import { apiCall } from './api'
8 import { srpSequence } from '@hfs/shared'
9 -import { Alert } from '@mui/material'
9 +import { Alert, Box } from '@mui/material'
10
11 export function LoginRequired({ children }: any) {
12 const { loginRequired } = useSnapState()
13 + if (loginRequired === 403)
14 + return h(Center, {},
15 + h(Alert, { severity: 'error' }, "Admin-panel only for localhost"),
16 + h(Box, { mt: 2, fontSize: 'small' }, "because no admin account was configured")
17 + )
18 if (loginRequired)
19 return h(LoginForm)
20 return h(Fragment, {}, children)
admin/src/api.ts
+2 -1
@@ -7,6 +7,7 @@ import _ from 'lodash'
7 import { state } from './state'
8 import { Refresh } from '@mui/icons-material'
9 import produce, { Draft } from 'immer'
10 +import { try_ } from './misc'
11
12 export function useApiEx<T=any>(...args: Parameters<typeof useApi>) {
13 const [data, error, reload] = useApi<T>(...args)
@@ -48,7 +49,7 @@ export function apiCall(cmd: string, params?: Dict, { timeout=undefined }={}) :
49 const msg = await res.text() || 'Failed API ' + cmd
50 console.warn(msg + (params ? ' ' + JSON.stringify(params) : ''))
51 if (res.status === 401)
51 - state.loginRequired = true
52 + state.loginRequired = Boolean(try_(() => JSON.parse(msg)?.any)) || 403
53 throw new ApiError(res.status, msg)
54 }, err => {
55 if (err?.message?.includes('fetch'))
admin/src/misc.ts
+1 -1
@@ -78,7 +78,7 @@ export function InLink(props:any) {
78 }
79
80 export function Center(props: any) {
81 - return h(Box, { display:'flex', height:'100%', width:'100%', justifyContent:'center', alignItems:'center', ...props })
81 + return h(Box, { display:'flex', height:'100%', width:'100%', justifyContent:'center', alignItems:'center', flexDirection: 'column', ...props })
82 }
83
84 export async function manipulateConfig(k: string, work:(data:any) => any) {
admin/src/state.ts
+1 -1
@@ -12,7 +12,7 @@ export const state = proxy<{
12 config: Dict
13 vfs: VfsNode | undefined
14 selectedFiles: VfsNode[]
15 - loginRequired: boolean
15 + loginRequired: boolean | number
16 username: string
17 onlinePluginsColumns: Dict<boolean>
18 }>(Object.assign({
shared/index.ts
+8
@@ -72,3 +72,11 @@ export function setHidden(dest: object, src:object) {
72 })))
73 }
74
75 +export function try_(cb: () => any, onException?: (e:any) => any) {
76 + try {
77 + return cb()
78 + }
79 + catch(e) {
80 + return onException?.(e)
81 + }
82 +}
\ No newline at end of file
src/adminApis.ts
+2 -2
@@ -23,7 +23,7 @@ import { getConnections } from './connections'
23 import { debounceAsync, isLocalHost, onOff, wait } from './misc'
24 import _ from 'lodash'
25 import events from './events'
26 -import { getFromAccount } from './perm'
26 +import { anyAccountCanLoginAdmin, getFromAccount } from './perm'
27 import Koa from 'koa'
28 import { getProxyDetected } from './middlewares'
29 import { writeFile } from 'fs/promises'
@@ -144,7 +144,7 @@ export const adminApis: ApiHandlers = {
144 for (const [k, was] of Object.entries(adminApis))
145 adminApis[k] = (params, ctx) =>
146 ctxAdminAccess(ctx) ? was(params, ctx)
147 - : new ApiError(HTTP_UNAUTHORIZED)
147 + : new ApiError(HTTP_UNAUTHORIZED, { any: anyAccountCanLoginAdmin() })
148
149 export const localhostAdmin = defineConfig('localhost_admin', true)
150
src/apiMiddleware.ts
+2 -2
@@ -9,8 +9,8 @@ import { HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_UNAUTHORIZED } from './const'
9 import _, { DebouncedFunc } from 'lodash'
10
11 export class ApiError extends Error {
12 - constructor(public status:number, message?:string | Error) {
13 - super(typeof message === 'string' ? message : message?.message)
12 + constructor(public status:number, message?:string | Error | object) {
13 + super(typeof message === 'string' ? message : message && message instanceof Error ? message.message : JSON.stringify(message))
14 }
15 }
16 type ApiHandlerResult = Record<string,any> | ApiError | Readable | AsyncGenerator<any>
src/const.ts
-1
@@ -5,7 +5,6 @@ import * as fs from 'fs'
5 import { homedir } from 'os'
6 import { mkdirSync } from 'fs'
7 import { basename, dirname, join } from 'path'
8 -import http2 from 'http2'
8
9 export const argv = minimist(process.argv.slice(2))
10 export const DEV = process.env.DEV || argv.dev ? 'DEV' : ''