Expose usedns, date_pattern, and prefregex in jail config UI

- Add use_dns and prefregex fields to JailConfig model (backend + frontend types)
- Add prefregex to JailConfigUpdate; validate as regex before writing
- Fetch usedns and prefregex in get_jail_config via asyncio.gather
- Write usedns and prefregex in update_jail_config
- ConfigPage JailAccordionPanel: editable date_pattern input, dns_mode
  Select dropdown (yes/warn/no/raw), and prefregex input
- 8 new service unit tests + 3 new router integration tests
- 628 tests pass; 85% line coverage; ruff/mypy/tsc/eslint clean
This commit is contained in:
2026-03-12 21:00:51 +01:00
parent e3375fd187
commit d0b8b78d12
8 changed files with 298 additions and 1 deletions

View File

@@ -116,6 +116,8 @@ const MOCK_JAIL: JailConfig = {
date_pattern: null,
log_encoding: "UTF-8",
backend: "auto",
use_dns: "warn",
prefregex: "",
actions: [],
bantime_escalation: null,
};

View File

@@ -254,6 +254,9 @@ function JailAccordionPanel({
const [failRegex, setFailRegex] = useState<string[]>(jail.fail_regex);
const [ignoreRegex, setIgnoreRegex] = useState<string[]>(jail.ignore_regex);
const [logPaths, setLogPaths] = useState<string[]>(jail.log_paths);
const [datePattern, setDatePattern] = useState(jail.date_pattern ?? "");
const [dnsMode, setDnsMode] = useState(jail.use_dns);
const [prefRegex, setPrefRegex] = useState(jail.prefregex);
const [deletingPath, setDeletingPath] = useState<string | null>(null);
const [newLogPath, setNewLogPath] = useState("");
const [newLogPathTail, setNewLogPathTail] = useState(true);
@@ -331,6 +334,9 @@ function JailAccordionPanel({
max_retry: Number(maxRetry) || jail.max_retry,
fail_regex: failRegex,
ignore_regex: ignoreRegex,
date_pattern: datePattern !== "" ? datePattern : null,
dns_mode: dnsMode,
prefregex: prefRegex !== "" ? prefRegex : null,
bantime_escalation: escalation,
});
setMsg({ text: "Saved.", ok: true });
@@ -346,6 +352,9 @@ function JailAccordionPanel({
maxRetry,
failRegex,
ignoreRegex,
datePattern,
dnsMode,
prefRegex,
escEnabled,
escFactor,
escFormula,
@@ -404,6 +413,41 @@ function JailAccordionPanel({
<Input readOnly value={jail.log_encoding} />
</Field>
</div>
<div className={styles.fieldRow}>
<Field label="Date Pattern" hint="Leave blank for auto-detect.">
<Input
className={styles.codeFont}
placeholder="auto-detect"
value={datePattern}
onChange={(_e, d) => {
setDatePattern(d.value);
}}
/>
</Field>
<Field label="DNS Mode">
<Select
value={dnsMode}
onChange={(_e, d) => {
setDnsMode(d.value);
}}
>
<option value="yes">yes resolve hostnames</option>
<option value="warn">warn resolve and warn</option>
<option value="no">no skip hostname resolution</option>
<option value="raw">raw use value as-is</option>
</Select>
</Field>
</div>
<Field label="Prefix Regex" hint="Prepended to every failregex for pre-filtering. Leave blank to disable.">
<Input
className={styles.codeFont}
placeholder="e.g. ^%(__prefix_line)s"
value={prefRegex}
onChange={(_e, d) => {
setPrefRegex(d.value);
}}
/>
</Field>
<Field label="Log Paths">
{logPaths.length === 0 ? (
<Text className={styles.infoText} size={200}>

View File

@@ -50,6 +50,10 @@ export interface JailConfig {
date_pattern: string | null;
log_encoding: string;
backend: string;
/** DNS look-up mode reported by fail2ban: "yes" | "warn" | "no" | "raw". */
use_dns: string;
/** Prefix regex prepended to every failregex; empty string means disabled. */
prefregex: string;
actions: string[];
bantime_escalation: BantimeEscalation | null;
}
@@ -69,6 +73,8 @@ export interface JailConfigUpdate {
find_time?: number | null;
fail_regex?: string[] | null;
ignore_regex?: string[] | null;
/** Prefix regex; undefined/null = skip, "" = clear, non-empty = set. */
prefregex?: string | null;
date_pattern?: string | null;
dns_mode?: string | null;
enabled?: boolean | null;