plugins: newSocket lets you now specify a log message for disconnection
Massimo Melina committed
Feb 21, 2025 at 12:34 UTC
d507db8b0861365005a688e3f6c6dcc990b7d599
4 files changed
+32
-25
admin/src/LogsPage.ts
+24
-21
@@ -4,7 +4,7 @@ import { createElement as h, Fragment, ReactNode, useEffect, useMemo, useState }
4
import httpCodes from './httpCodes'
5
import { Box, Tab, Tabs } from '@mui/material'
6
import { API_URL, apiCall, useApi, useApiList } from './api'
7
-import { DataTable, DataTableProps } from './DataTable'
7
+import { DataTable, DataTableColumn, DataTableProps } from './DataTable'
8
import {
9
CFG, Dict, formatBytes, HTTP_UNAUTHORIZED, newDialog, prefix, shortenAgent, splitAt, tryJson, md,
10
typedKeys, _dbg, mapFilter, safeDecodeURIComponent, stringAfter, onlyTruthy, formatTimestamp, formatSpeed
@@ -13,7 +13,6 @@ import {
13
NetmaskField, Flex, IconBtn, useBreakpoint, usePauseButton, useToggleButton, WildcardsSupported, Country,
14
hTooltip, Btn, wikiLink
15
} from './mui';
16
-import { GridColDef } from '@mui/x-data-grid'
16
import _ from 'lodash'
17
import { AutoDelete, LinkOff, ClearAll, Delete, Download, Settings, SmartToy, Terminal } from '@mui/icons-material'
18
import { ConfigForm } from './ConfigForm'
@@ -143,7 +142,7 @@ export function LogFile({ file, footerSide, hidden, limit, filter, ...rest }: Lo
142
const isIps = file === 'ips'
143
if (isIps)
144
reloadIps = reload
146
- const tsColumn: GridColDef = {
145
+ const tsColumn: DataTableColumn = {
146
field: 'ts',
147
headerName: "Timestamp",
148
type: 'dateTime',
@@ -151,6 +150,18 @@ export function LogFile({ file, footerSide, hidden, limit, filter, ...rest }: Lo
150
valueGetter: ({ value }) => new Date(value as string),
151
renderCell: ({ value }) => h(Fragment, {}, value.toLocaleDateString(), h('br'), value.toLocaleTimeString())
152
}
153
+ const ipColumn: DataTableColumn = {
154
+ field: 'ip',
155
+ headerName: "Address",
156
+ flex: .6,
157
+ minWidth: 130,
158
+ maxWidth: 230,
159
+ mergeRender: {
160
+ user: { display: 'flex', justifyContent: 'space-between', gap: '.5em', },
161
+ country: showCountry && {},
162
+ ua: {},
163
+ },
164
+ }
165
const rows = useMemo(() =>
166
filter ? list.filter(filter)
167
: showApi || list?.[0]?.uri === undefined ? list
@@ -209,34 +220,26 @@ export function LogFile({ file, footerSide, hidden, limit, filter, ...rest }: Lo
220
flex: 1,
221
mergeRender: { k: { override: { valueFormatter: ({ value }) => value !== 'log' && value } } }
222
}
212
- ] : file === 'ips' || file === 'disconnections' ? [
223
+ ] : isIps || file === 'disconnections' ? [
224
tsColumn,
214
- {
215
- field: 'ip',
216
- headerName: "Address",
217
- flex: 1,
218
- },
225
+ ipColumn,
226
{
227
headerName: "Country",
228
field: 'country',
229
flex: 1,
230
hidden: !showCountry,
231
+ hideUnder: 'md',
232
valueGetter: ({ value }) => _.find(COUNTRIES, { code: value })?.name || value,
233
renderCell: ({ row }) => h(Country, { code: row.country, long: true, def: '-' }),
234
+ },
235
+ {
236
+ hidden: isIps,
237
+ field: 'msg',
238
+ headerName: "Message",
239
+ flex: 4,
240
}
241
] : [
228
- {
229
- field: 'ip',
230
- headerName: "Address",
231
- flex: .6,
232
- minWidth: 130,
233
- maxWidth: 230,
234
- mergeRender: {
235
- user: { display: 'flex', justifyContent: 'space-between', gap: '.5em', },
236
- country: showCountry && {},
237
- ua: {},
238
- },
239
- },
242
+ ipColumn,
243
{
244
headerName: "Country",
245
field: 'country',
dev-plugins.md
+1
@@ -590,6 +590,7 @@ This section is still partially documented, and you may need to have a look at t
590
- `newSocket`
591
- parameters: { socket,ip }
592
- preventable
593
+ - return: you can return a string with a message that will be logged, and it will also cause disconnection
594
- `getList` called when get=list on legit requests to ?get=list
595
- parameters: { node, ctx }
596
- async supported
src/api.monitor.ts
+2
-2
@@ -1,7 +1,7 @@
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 _ from 'lodash'
4
-import { Connection, getConnections } from './connections'
4
+import { Connection, disconnect, getConnections } from './connections'
5
import { apiAssertTypes, isLocalHost, shortenAgent, try_, wait, wantArray } from './misc'
6
import { ApiHandlers } from './apiMiddleware'
7
import Koa from 'koa'
@@ -17,7 +17,7 @@ export default {
17
: _.matches({ ip, port })
18
const found = getConnections().filter(c => match(getConnAddress(c)))
19
for (const c of found)
20
- c.socket.destroy()
20
+ disconnect(c.socket, "manual disconnection")
21
return { result: found.length }
22
},
23
src/connections.ts
+5
-2
@@ -4,6 +4,7 @@ import { Socket } from 'net'
4
import events from './events'
5
import { Context } from 'koa'
6
import { ip2country } from './geo'
7
+import _ from 'lodash'
8
9
export class Connection {
10
readonly started = new Date()
@@ -42,8 +43,10 @@ const all: Connection[] = []
43
44
export function newConnection(socket: Socket) {
45
const ip = normalizeIp(socket.remoteAddress || '')
45
- if (events.emit('newSocket', { socket, ip })?.isDefaultPrevented())
46
- return socket.destroy()
46
+ const res = events.emit('newSocket', { socket, ip })
47
+ const msg = res?.isDefaultPrevented() ? 'plugin (newSocket)' : res?.find(_.isString)
48
+ if (msg)
49
+ return disconnect(socket, msg)
50
new Connection(socket)
51
}
52