admin/options: block-ip rules can now disabled
Massimo Melina committed
Jan 3, 2024 at 16:46 UTC
8a4a6aa0fbf3e64b21150d578338011529b4005e
3 files changed
+20
-5
admin/src/ArrayField.ts
+9
-2
@@ -2,10 +2,10 @@
2
3
import { createElement as h, Fragment, useMemo, useState } from 'react'
4
import { Dict, isOrderedEqual, setHidden, swap } from './misc'
5
-import { Add, Edit, Delete, ArrowUpward, ArrowDownward, Undo } from '@mui/icons-material'
5
+import { Add, Edit, Delete, ArrowUpward, ArrowDownward, Undo, Check } from '@mui/icons-material'
6
import { formDialog } from './dialog'
7
import { DataGrid, GridActionsCellItem, GridAlignment, GridColDef } from '@mui/x-data-grid'
8
-import { FieldDescriptor, FieldProps, labelFromKey } from '@hfs/mui-grid-form'
8
+import { BoolField, FieldDescriptor, FieldProps, labelFromKey } from '@hfs/mui-grid-form'
9
import { Box, FormHelperText, FormLabel } from '@mui/material'
10
import { DateTimeField } from './DateTimeField'
11
import _ from 'lodash'
@@ -43,6 +43,9 @@ export function ArrayField<T extends object>({ label, helperText, fields, value,
43
field: f.k,
44
headerName: f.headerName ?? (typeof f.label === 'string' ? f.label : labelFromKey(f.k)),
45
disableColumnMenu: true,
46
+ valueGetter({ value }: any) {
47
+ return (f.toField || _.identity)(value)
48
+ },
49
...def,
50
...f.$width ? { [f.$width >= 8 ? 'width' : 'flex']: f.$width } : (!def?.width && !def?.flex && { flex: 1 }),
51
...f.$column,
@@ -126,6 +129,10 @@ export function ArrayField<T extends object>({ label, helperText, fields, value,
129
}
130
131
const byType: Dict<{ field?: Partial<FieldDescriptor>, column?: Partial<GridColDef> }> = {
132
+ boolean: {
133
+ field: { comp: BoolField },
134
+ column: { renderCell: ({ value }) => value && h(Check) },
135
+ },
136
dateTime: {
137
field: { comp: DateTimeField },
138
column: {
admin/src/OptionsPage.ts
+9
-1
@@ -5,7 +5,7 @@ import { createElement as h, Fragment, useEffect, useRef } from 'react';
5
import { apiCall, useApiEx } from './api'
6
import { state, useSnapState } from './state'
7
import { Link as RouterLink } from 'react-router-dom'
8
-import { CardMembership, EditNote, Refresh, Warning } from '@mui/icons-material'
8
+import { CardMembership, Check, EditNote, Refresh, Warning } from '@mui/icons-material'
9
import { Dict, MAX_TILE_SIZE, REPO_URL, isIpLocalHost, wait, with_, try_, ipForUrl, SORT_BY_OPTIONS, THEME_OPTIONS,
10
CFG } from './misc'
11
import { iconTooltip, InLink, LinkBtn, modifiedSx, wikiLink, useBreakpoint, NetmaskField, WildcardsSupported } from './mui'
@@ -179,6 +179,14 @@ export default function OptionsPage() {
179
fields: [
180
{ k: 'ip', label: "Blocked IP", sm: 6, required: true, helperText: h(WildcardsSupported) },
181
{ k: 'expire', $type: 'dateTime', minDate: new Date(), sm: 6, helperText: "Leave empty for no expiration" },
182
+ {
183
+ k: 'disabled',
184
+ $type: 'boolean',
185
+ label: "Enabled",
186
+ toField: (x: any) => !x,
187
+ fromField: (x: any) => x ? undefined : true,
188
+ sm: 6,
189
+ },
190
{ k: 'comment' },
191
],
192
},
src/block.ts
+2
-2
@@ -5,14 +5,14 @@ import { disconnect, getConnections, normalizeIp } from './connections'
5
import { makeNetMatcher, MINUTE, onlyTruthy } from './misc'
6
import { Socket } from 'net'
7
8
-interface BlockingRule { ip: string, comment?: string, expire?: Date }
8
+interface BlockingRule { ip: string, comment?: string, expire?: Date, disabled?: boolean }
9
10
const block = defineConfig('block', [] as BlockingRule[], rules => {
11
const now = new Date()
12
const ret = !Array.isArray(rules) ? []
13
: onlyTruthy(rules.map(rule => {
14
rule.expire &&= new Date(rule.expire)
15
- return !(rule.expire! > now) && makeNetMatcher(rule.ip)
15
+ return !rule.disabled && (rule.expire || now) <= now && makeNetMatcher(rule.ip)
16
}))
17
// reapply new block to existing connections
18
for (const { socket, ip } of getConnections())