better code: use constants
Massimo Melina committed
Nov 15, 2023 at 20:32 UTC
5c5b0288302b04a476f1d492915b3e047e8548dd
10 files changed
+36
-32
admin/src/AccountForm.ts
+4
-4
@@ -2,11 +2,11 @@
2
3
import { createElement as h, ReactNode, useEffect, useRef, useState } from 'react'
4
import { BoolField, Form, MultiSelectField } from '@hfs/mui-grid-form'
5
-import { Alert, Box } from '@mui/material'
5
+import { Alert } from '@mui/material'
6
import { apiCall } from './api'
7
import { alertDialog, toast, useDialogBarColors } from './dialog'
8
-import { IconBtn, isEqualLax, modifiedSx, wantArray } from './misc'
9
-import { Account, account2icon } from './AccountsPage'
8
+import { HTTP_NOT_ACCEPTABLE, IconBtn, isEqualLax, modifiedSx, wantArray } from './misc'
9
+import { Account } from './AccountsPage'
10
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
11
import { AutoDelete, Delete } from '@mui/icons-material'
12
import { isMobile } from './misc'
@@ -110,7 +110,7 @@ export async function apiNewPassword(username: string, password: string) {
110
const srp6aNimbusRoutines = new SRPRoutines(new SRPParameters())
111
const res = await createVerifierAndSalt(srp6aNimbusRoutines, username, password)
112
return apiCall('change_srp_others', { username, salt: String(res.s), verifier: String(res.v) }).catch(e => {
113
- if (e.code !== 406) // 406 = server was configured to support clear text authentication
113
+ if (e.code !== HTTP_NOT_ACCEPTABLE) // server doesn't support clear text authentication
114
throw e
115
return apiCall('change_password_others', { username, newPassword: password }) // unencrypted version
116
})
admin/src/InstalledPlugins.ts
+2
-2
@@ -5,7 +5,7 @@ import { createElement as h, Fragment, ReactNode } from 'react'
5
import { Box, Link, Tooltip } from '@mui/material'
6
import { DataTable } from './DataTable'
7
import { Delete, Error as ErrorIcon, PlayCircle, Settings, StopCircle, Upgrade } from '@mui/icons-material'
8
-import { Btn, IconBtn, prefix, with_ } from './misc'
8
+import { Btn, HTTP_FAILED_DEPENDENCY, IconBtn, prefix, with_ } from './misc'
9
import { alertDialog, formDialog, toast } from './dialog'
10
import _ from 'lodash'
11
import { BoolField, Field, MultiSelectField, NumberField, SelectField, StringField } from '@hfs/mui-grid-form'
@@ -51,7 +51,7 @@ export default function InstalledPlugins({ updates }: { updates?: true }) {
51
size,
52
async onClick() {
53
await apiCall('update_plugin', { id }, { timeout: false }).catch(e => {
54
- throw e.code !== 424 ? e
54
+ throw e.code !== HTTP_FAILED_DEPENDENCY ? e
55
: Error("Failed dependencies: " + e.cause?.map((x: any) => prefix(`plugin "`, x.id || x.repo, `" `) + x.error).join('; '))
56
})
57
updateEntry({ id }, { updated: true })
admin/src/LoginRequired.ts
+3
-3
@@ -2,7 +2,7 @@
2
3
import { state, useSnapState } from './state'
4
import { createElement as h, Fragment, useEffect, useRef, useState } from 'react'
5
-import { Center, getHFS, makeSessionRefresher } from './misc'
5
+import { Center, getHFS, HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, makeSessionRefresher } from './misc'
6
import { Form } from '@hfs/mui-grid-form'
7
import { apiCall } from './api'
8
import { srpClientSequence } from '@hfs/shared'
@@ -10,7 +10,7 @@ import { Alert, Box } from '@mui/material'
10
11
export function LoginRequired({ children }: any) {
12
const { loginRequired } = useSnapState()
13
- if (loginRequired === 403)
13
+ if (loginRequired === HTTP_FORBIDDEN)
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")
@@ -58,7 +58,7 @@ function LoginForm() {
58
59
async function login(username: string, password: string) {
60
const res = await srpClientSequence(username, password, apiCall).catch(err => {
61
- throw err?.code === 401 ? "Wrong username or password"
61
+ throw err?.code === HTTP_UNAUTHORIZED ? "Wrong username or password"
62
: err === 'trust' ? "Login aborted: server identity cannot be trusted"
63
: err?.name === 'AbortError' ? "Server didn't respond"
64
: (err?.message || "Unknown error")
admin/src/LogoutPage.ts
+2
-2
@@ -5,7 +5,7 @@ import { Alert, Box } from '@mui/material'
5
import { apiCall, useApiEx } from './api'
6
import { alertDialog } from "./dialog"
7
import { useSnapState } from './state'
8
-import { Btn } from './misc'
8
+import { Btn, HTTP_UNAUTHORIZED } from './misc'
9
import { Logout, PowerSettingsNew } from '@mui/icons-material'
10
11
export default function LogoutPage() {
@@ -22,7 +22,7 @@ export default function LogoutPage() {
22
size: 'large',
23
variant: 'contained',
24
onClick: () => apiCall('logout').catch(err => // we expect 401
25
- err.code !== 401 && alertDialog(err))
25
+ err.code !== HTTP_UNAUTHORIZED && alertDialog(err))
26
}, "I want to logout")
27
),
28
h(Btn, {
admin/src/api.ts
+6
-5
@@ -1,7 +1,8 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import { createElement as h, useEffect, useMemo, useRef, useState } from 'react'
4
-import { Dict, err2msg, Falsy, IconBtn, LIST, spinner, useStateMounted, wantArray, xlate } from './misc'
4
+import { Dict, err2msg, Falsy, IconBtn, LIST, spinner, useStateMounted, wantArray, xlate,
5
+ HTTP_FORBIDDEN, HTTP_UNAUTHORIZED,} from './misc'
6
import { Alert } from '@mui/material'
7
import _ from 'lodash'
8
import { state } from './state'
@@ -12,8 +13,8 @@ export * from '@hfs/shared/api'
13
14
setDefaultApiCallOptions({
15
async onResponse(res: Response, body: any) {
15
- if (res.status === 401) {
16
- state.loginRequired = body?.possible !== false || 403
16
+ if (res.status === HTTP_UNAUTHORIZED) {
17
+ state.loginRequired = body?.possible !== false || HTTP_FORBIDDEN
18
throw new ApiError(res.status, "Unauthorized")
19
}
20
}
@@ -84,8 +85,8 @@ export function useApiList<T=any, S=T>(cmd:string|Falsy, params: Dict={}, { map,
85
return
86
}
87
if (op === LIST.error) {
87
- if (par === 401)
88
- state.loginRequired = msg[2].possible !== false || 403
88
+ if (par === HTTP_UNAUTHORIZED)
89
+ state.loginRequired = msg[2].possible !== false || HTTP_FORBIDDEN
90
else
91
setError(err2msg(par))
92
return
admin/src/importAccountsCsv.ts
+2
-2
@@ -4,7 +4,7 @@ import { Group, Upload } from '@mui/icons-material'
4
import { Box } from '@mui/material'
5
import { apiCall } from './api'
6
import { apiNewPassword } from './AccountForm'
7
-import { IconProgress, prefix, readFile, selectFiles } from './misc'
7
+import { HTTP_CONFLICT, IconProgress, prefix, readFile, selectFiles } from './misc'
8
import { NumberField, BoolField } from '@hfs/mui-grid-form'
9
import Parser from '@gregoranders/csv';
10
@@ -90,7 +90,7 @@ export async function importAccountsCsv(cb?: () => void) {
90
if (rec.p)
91
return apiNewPassword(rec.u, rec.p)
92
}, e => {
93
- if (e.code === 409)
93
+ if (e.code === HTTP_CONFLICT)
94
return already++
95
bad++
96
})
frontend/src/UserPanel.ts
+2
-2
@@ -7,7 +7,7 @@ import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
7
import { apiCall } from '@hfs/shared/api'
8
import { logout } from './login'
9
import { MenuButton } from './menu'
10
-import { hIcon, working } from './misc'
10
+import { hIcon, HTTP_NOT_ACCEPTABLE, working } from './misc'
11
import { t } from './i18n'
12
13
export default function showUserPanel() {
@@ -35,7 +35,7 @@ export default function showUserPanel() {
35
const res = await createVerifierAndSalt(srp6aNimbusRoutines, snap.username, pwd)
36
try {
37
await apiCall('change_srp', { salt: String(res.s), verifier: String(res.v) }, { modal: working }).catch(e => {
38
- if (e.code !== 406) // 406 = server was configured to support clear text authentication
38
+ if (e.code !== HTTP_NOT_ACCEPTABLE) // server doesn't support clear text authentication
39
throw e
40
return apiCall('change_password', { newPassword: pwd }, { modal: working }) // unencrypted version
41
})
frontend/src/login.ts
+5
-4
@@ -3,7 +3,8 @@
3
import { apiCall } from '@hfs/shared/api'
4
import { state, useSnapState } from './state'
5
import { alertDialog, newDialog } from './dialog'
6
-import { getHFS, getPrefixUrl, hIcon, makeSessionRefresher, srpClientSequence, working } from './misc'
6
+import { getHFS, getPrefixUrl, hIcon, makeSessionRefresher, srpClientSequence, working,
7
+ HTTP_CONFLICT, HTTP_UNAUTHORIZED,} from './misc'
8
import { useNavigate } from 'react-router-dom'
9
import { createElement as h, Fragment, useEffect, useRef } from 'react'
10
import { t, useI18N } from './i18n'
@@ -21,8 +22,8 @@ async function login(username:string, password:string) {
22
}, (err: any) => {
23
stopWorking()
24
throw Error(err.message === 'trust' ? t('login_untrusted', "Login aborted: server identity cannot be trusted")
24
- : err.code === 401 ? t('login_bad_credentials', "Invalid credentials")
25
- : err.code === 409 ? t('login_bad_cookies', "Cookies not working - login failed")
25
+ : err.code === HTTP_UNAUTHORIZED ? t('login_bad_credentials', "Invalid credentials")
26
+ : err.code === HTTP_CONFLICT ? t('login_bad_cookies', "Cookies not working - login failed")
27
: t(err.message))
28
})
29
}
@@ -32,7 +33,7 @@ sessionRefresher(getHFS().session)
33
34
export function logout(){
35
return apiCall('logout', {}, { modal: working }).catch(res => {
35
- if (res.code !== 401) // we expect 401
36
+ if (res.code !== HTTP_UNAUTHORIZED) // we expect this error code
37
throw res
38
state.username = ''
39
reloadList()
frontend/src/upload.ts
+6
-4
@@ -2,7 +2,9 @@
2
3
import { createElement as h, DragEvent, Fragment, useMemo, CSSProperties } from 'react'
4
import { Checkbox, Flex, FlexV, iconBtn } from './components'
5
-import { basename, closeDialog, formatBytes, formatPerc, hIcon, isMobile, newDialog, prefix, selectFiles, working } from './misc'
5
+import { basename, closeDialog, formatBytes, formatPerc, hIcon, isMobile, newDialog, prefix, selectFiles, working,
6
+ HTTP_CONFLICT, HTTP_PAYLOAD_TOO_LARGE
7
+} from './misc'
8
import _ from 'lodash'
9
import { proxy, ref, subscribe, useSnapshot } from 'valtio'
10
import { alertDialog, confirmDialog, promptDialog } from './dialog'
@@ -280,7 +282,7 @@ async function startUpload(toUpload: ToUpload, to: string, resume=0) {
282
if (req?.readyState !== 4) return
283
const status = overrideStatus || req.status
284
closeLast?.()
283
- if (status && status !== 409) // 0 = user-aborted, 409 = skipped because existing
285
+ if (status && status !== HTTP_CONFLICT) // 0 = user-aborted, HTTP_CONFLICT = skipped because existing
286
if (status >= 400)
287
error(status)
288
else
@@ -344,7 +346,7 @@ async function startUpload(toUpload: ToUpload, to: string, resume=0) {
346
function error(status: number) {
347
if (uploadState.errors++) return
348
const ERRORS = {
347
- 413: t`file too large`,
349
+ [HTTP_PAYLOAD_TOO_LARGE]: t`file too large`,
350
}
351
const specifier = (ERRORS as any)[status]
352
const msg = t('failed_upload', toUpload, "Couldn't upload {name}") + prefix(': ', specifier)
@@ -423,7 +425,7 @@ async function createFolder() {
425
)))
426
}
427
catch(e: any) {
426
- await alertDialog(e.code === 409 ? t('folder_exists', "Folder with same name already exists") : e)
428
+ await alertDialog(e.code === HTTP_CONFLICT ? t('folder_exists', "Folder with same name already exists") : e)
429
}
430
}
431
frontend/src/useFetchList.ts
+4
-4
@@ -7,7 +7,7 @@ import _ from 'lodash'
7
import { subscribeKey } from 'valtio/utils'
8
import { useIsMounted } from 'usehooks-ts'
9
import { alertDialog } from './dialog'
10
-import { HTTP_MESSAGES, LIST, xlate } from './misc'
10
+import { HTTP_MESSAGES, HTTP_METHOD_NOT_ALLOWED, HTTP_UNAUTHORIZED, LIST, xlate } from './misc'
11
import { t } from './i18n'
12
import { useLocation, useNavigate } from 'react-router-dom'
13
@@ -77,7 +77,7 @@ export default function useFetchList() {
77
if (!Array.isArray(entry)) continue // unexpected
78
const [op, par] = entry
79
const error = op === LIST.error && par
80
- if (error === 405) { // "method not allowed" happens when we try to directly access an unauthorized file, and we get a login prompt, and then get_file_list the file (because we didn't know it was file or folder)
80
+ if (error === HTTP_METHOD_NOT_ALLOWED) { // "method not allowed" happens when we try to directly access an unauthorized file, and we get a login prompt, and then get_file_list the file (because we didn't know it was file or folder)
81
state.messageOnly = t('upload_starting', "Your download should now start")
82
window.location.reload() // reload will start the download, because now we got authenticated
83
continue
@@ -85,9 +85,9 @@ export default function useFetchList() {
85
if (error) {
86
state.stopSearch?.()
87
state.error = xlate(error, HTTP_MESSAGES)
88
- if (error === 401 && snap.username)
88
+ if (error === HTTP_UNAUTHORIZED && snap.username)
89
alertDialog(t('wrong_account', { u: snap.username }, "Account {u} has no access, try another"), 'warning').then()
90
- state.loginRequired = error === 401
90
+ state.loginRequired = error === HTTP_UNAUTHORIZED
91
lastReq.current = null
92
continue
93
}