@samitouri / QOSami-HFS / commits / 5dc36082

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