admin/logs: notes for failed login
Massimo Melina committed
Dec 4, 2023 at 00:16 UTC
5dc36082e1a6ecfa23983784392b1a30d0c23e9e
3 files changed
+14
-7
admin/src/LogsPage.ts
+7
-5
@@ -4,12 +4,13 @@ import { createElement as h, Fragment, useMemo, useState } from 'react';
4
import { Box, Tab, Tabs } from '@mui/material'
5
import { API_URL, useApiList } from './api'
6
import { DataTable } from './DataTable'
7
-import { formatBytes, tryJson } from '@hfs/shared'
7
+import { formatBytes, HTTP_UNAUTHORIZED, prefix, tryJson } from '@hfs/shared'
8
import { logLabels } from './OptionsPage'
9
import { Flex, typedKeys, useBreakpoint, usePauseButton, useToggleButton } from './misc';
10
import { GridColDef } from '@mui/x-data-grid'
11
import _ from 'lodash'
12
import { SmartToy } from '@mui/icons-material'
13
+import md from './md'
14
15
export default function LogsPage() {
16
const [tab, setTab] = useState(0)
@@ -40,10 +41,10 @@ function LogFile({ file, pause, showApi }: { file: string, pause?: boolean, show
41
pause,
42
map(x) {
43
const { extra } = x
43
- if (!extra) return
44
- const notes = extra.dl ? "fully downloaded" : extra.ul ? "uploaded " + formatBytes(extra.size) : ''
45
- if (notes)
46
- x.notes = notes
44
+ x.notes = extra?.dl ? "fully downloaded"
45
+ : extra?.ul ? "uploaded " + formatBytes(extra.size)
46
+ : x.status === HTTP_UNAUTHORIZED && x.uri.startsWith(API_URL + 'loginSrp') ? "login failed" + prefix(':\n', extra?.u)
47
+ : x.notes
48
return x
49
}
50
})
@@ -122,6 +123,7 @@ function LogFile({ file, pause, showApi }: { file: string, pause?: boolean, show
123
width: 105, // https://github.com/rejetto/hfs/discussions/388
124
hideUnder: 'sm',
125
cellClassName: 'wrap',
126
+ renderCell: ({ value }) => value && md(value),
127
},
128
{
129
field: 'uri',
src/api.auth.ts
+6
-1
@@ -42,8 +42,11 @@ export const loginSrp1: ApiHandler = async ({ username }, ctx) => {
42
const account = getAccount(username)
43
if (!ctx.session)
44
return new ApiError(HTTP_SERVER_ERROR)
45
- if (!account || !accountCanLogin(account)) // TODO simulate fake account to prevent knowing valid usernames
45
+ if (!account || !accountCanLogin(account)) { // TODO simulate fake account to prevent knowing valid usernames
46
+ ctx.state.logExtra = { u: username }
47
+ ctx.state.dont_log = false // log even if log_api is false
48
return new ApiError(HTTP_UNAUTHORIZED)
49
+ }
50
try {
51
const { step1, ...rest } = await srpStep1(account)
52
const sid = Math.random()
@@ -77,6 +80,8 @@ export const loginSrp2: ApiHandler = async ({ pubKey, proof }, ctx) => {
80
}
81
}
82
catch(e) {
83
+ ctx.state.dont_log = false // log even if log_api is false
84
+ ctx.state.logExtra = { u: username }
85
return new ApiError(HTTP_UNAUTHORIZED, String(e))
86
}
87
finally {
src/log.ts
+1
-1
@@ -105,7 +105,7 @@ export const logMw: Koa.Middleware = async (ctx, next) => {
105
const uri = ctx.originalUrl
106
const extra = ctx.state.includesLastByte && ctx.vfsNode && ctx.res.finished && { dl: 1 }
107
|| ctx.state.uploadPath && { ul: ctx.state.uploadPath, size: ctx.state.uploadSize }
108
- || undefined
108
+ || ctx.state.logExtra
109
events.emit(logger.name, Object.assign(_.pick(ctx, ['ip', 'method','status']), { length, user, ts: now, uri, extra }))
110
debounce(() => // once in a while we check if the file is still good (not deleted, etc), or we'll reopen it
111
stat(logger.path).catch(() => logger.reopen())) // async = smoother but we may lose some entries