Narrow jail config types with explicit union values
This commit is contained in:
@@ -4,9 +4,14 @@ Request, response, and domain models for the config router and service.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
DNSMode = Literal["yes", "warn", "no", "raw"]
|
||||||
|
LogEncoding = Literal["auto", "ascii", "utf-8", "UTF-8", "latin-1"]
|
||||||
|
BackendType = Literal["auto", "polling", "pyinotify", "systemd", "gamin"]
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Ban-time escalation
|
# Ban-time escalation
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -79,9 +84,9 @@ class JailConfig(BaseModel):
|
|||||||
ignore_regex: list[str] = Field(default_factory=list, description="Regex patterns that bypass the ban logic.")
|
ignore_regex: list[str] = Field(default_factory=list, description="Regex patterns that bypass the ban logic.")
|
||||||
log_paths: list[str] = Field(default_factory=list, description="Monitored log files.")
|
log_paths: list[str] = Field(default_factory=list, description="Monitored log files.")
|
||||||
date_pattern: str | None = Field(default=None, description="Custom date pattern for log parsing.")
|
date_pattern: str | None = Field(default=None, description="Custom date pattern for log parsing.")
|
||||||
log_encoding: str = Field(default="UTF-8", description="Log file encoding.")
|
log_encoding: LogEncoding = Field(default="UTF-8", description="Log file encoding.")
|
||||||
backend: str = Field(default="polling", description="Log monitoring backend.")
|
backend: BackendType = Field(default="polling", description="Log monitoring backend.")
|
||||||
use_dns: str = Field(default="warn", description="DNS lookup mode: yes | warn | no | raw.")
|
use_dns: DNSMode = Field(default="warn", description="DNS lookup mode: yes | warn | no | raw.")
|
||||||
prefregex: str = Field(default="", description="Prefix regex prepended to every failregex; empty means disabled.")
|
prefregex: str = Field(default="", description="Prefix regex prepended to every failregex; empty means disabled.")
|
||||||
actions: list[str] = Field(default_factory=list, description="Names of actions attached to this jail.")
|
actions: list[str] = Field(default_factory=list, description="Names of actions attached to this jail.")
|
||||||
bantime_escalation: BantimeEscalation | None = Field(
|
bantime_escalation: BantimeEscalation | None = Field(
|
||||||
@@ -119,9 +124,9 @@ class JailConfigUpdate(BaseModel):
|
|||||||
ignore_regex: list[str] | None = Field(default=None)
|
ignore_regex: list[str] | None = Field(default=None)
|
||||||
prefregex: str | None = Field(default=None, description="Prefix regex; None = skip, '' = clear, non-empty = set.")
|
prefregex: str | None = Field(default=None, description="Prefix regex; None = skip, '' = clear, non-empty = set.")
|
||||||
date_pattern: str | None = Field(default=None)
|
date_pattern: str | None = Field(default=None)
|
||||||
dns_mode: str | None = Field(default=None, description="DNS lookup mode: yes | warn | no | raw.")
|
dns_mode: DNSMode | None = Field(default=None, description="DNS lookup mode: yes | warn | no | raw.")
|
||||||
backend: str | None = Field(default=None, description="Log monitoring backend.")
|
backend: BackendType | None = Field(default=None, description="Log monitoring backend.")
|
||||||
log_encoding: str | None = Field(default=None, description="Log file encoding.")
|
log_encoding: LogEncoding | None = Field(default=None, description="Log file encoding.")
|
||||||
enabled: bool | None = Field(default=None)
|
enabled: bool | None = Field(default=None)
|
||||||
bantime_escalation: BantimeEscalationUpdate | None = Field(
|
bantime_escalation: BantimeEscalationUpdate | None = Field(
|
||||||
default=None,
|
default=None,
|
||||||
@@ -680,7 +685,7 @@ class JailSectionConfig(BaseModel):
|
|||||||
findtime: int | None = Field(default=None, ge=1, description="Time window in seconds for counting failures.")
|
findtime: int | None = Field(default=None, ge=1, description="Time window in seconds for counting failures.")
|
||||||
bantime: int | None = Field(default=None, description="Ban duration in seconds. -1 for permanent.")
|
bantime: int | None = Field(default=None, description="Ban duration in seconds. -1 for permanent.")
|
||||||
action: list[str] = Field(default_factory=list, description="Action references.")
|
action: list[str] = Field(default_factory=list, description="Action references.")
|
||||||
backend: str | None = Field(default=None, description="Log monitoring backend.")
|
backend: BackendType | None = Field(default=None, description="Log monitoring backend.")
|
||||||
extra: dict[str, str] = Field(default_factory=dict, description="Additional settings not captured by named fields.")
|
extra: dict[str, str] = Field(default_factory=dict, description="Additional settings not captured by named fields.")
|
||||||
|
|
||||||
|
|
||||||
@@ -764,11 +769,11 @@ class InactiveJail(BaseModel):
|
|||||||
default=600,
|
default=600,
|
||||||
description="Failure-counting window in seconds, parsed from findtime string.",
|
description="Failure-counting window in seconds, parsed from findtime string.",
|
||||||
)
|
)
|
||||||
log_encoding: str = Field(
|
log_encoding: LogEncoding = Field(
|
||||||
default="auto",
|
default="auto",
|
||||||
description="Log encoding, e.g. ``utf-8`` or ``auto``.",
|
description="Log encoding, e.g. ``utf-8`` or ``auto``.",
|
||||||
)
|
)
|
||||||
backend: str = Field(
|
backend: BackendType = Field(
|
||||||
default="auto",
|
default="auto",
|
||||||
description="Log-monitoring backend, e.g. ``auto``, ``pyinotify``, ``polling``.",
|
description="Log-monitoring backend, e.g. ``auto``, ``pyinotify``, ``polling``.",
|
||||||
)
|
)
|
||||||
@@ -776,7 +781,7 @@ class InactiveJail(BaseModel):
|
|||||||
default=None,
|
default=None,
|
||||||
description="Date pattern for log parsing, or None for auto-detect.",
|
description="Date pattern for log parsing, or None for auto-detect.",
|
||||||
)
|
)
|
||||||
use_dns: str = Field(
|
use_dns: DNSMode = Field(
|
||||||
default="warn",
|
default="warn",
|
||||||
description="DNS resolution mode: ``yes``, ``warn``, ``no``, or ``raw``.",
|
description="DNS resolution mode: ``yes``, ``warn``, ``no``, or ``raw``.",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import { KVEditor } from "./KVEditor";
|
import { KVEditor } from "./KVEditor";
|
||||||
import { StringListEditor } from "./StringListEditor";
|
import { StringListEditor } from "./StringListEditor";
|
||||||
import { useConfigStyles } from "./configStyles";
|
import { useConfigStyles } from "./configStyles";
|
||||||
import type { JailSectionConfig } from "../../types/config";
|
import type { BackendType, JailSectionConfig } from "../../types/config";
|
||||||
|
|
||||||
const BACKENDS = ["", "auto", "polling", "gamin", "pyinotify", "systemd"] as const;
|
const BACKENDS = ["", "auto", "polling", "gamin", "pyinotify", "systemd"] as const;
|
||||||
|
|
||||||
@@ -64,7 +64,9 @@ export function JailSectionPanel({ jailName, section, onChange }: JailSectionPan
|
|||||||
<Select
|
<Select
|
||||||
size="small"
|
size="small"
|
||||||
value={section.backend ?? ""}
|
value={section.backend ?? ""}
|
||||||
onChange={(_e, d) => { update({ backend: d.value || null }); }}
|
onChange={(_e, d) => {
|
||||||
|
update({ backend: d.value ? (d.value as BackendType) : null });
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{BACKENDS.map((b) => (
|
{BACKENDS.map((b) => (
|
||||||
<option key={b} value={b}>
|
<option key={b} value={b}>
|
||||||
|
|||||||
@@ -34,11 +34,14 @@ import {
|
|||||||
import { ApiError } from "../../api/client";
|
import { ApiError } from "../../api/client";
|
||||||
import type {
|
import type {
|
||||||
AddLogPathRequest,
|
AddLogPathRequest,
|
||||||
|
BackendType,
|
||||||
|
DNSMode,
|
||||||
InactiveJail,
|
InactiveJail,
|
||||||
JailConfig,
|
JailConfig,
|
||||||
JailConfigUpdate,
|
JailConfigUpdate,
|
||||||
JailValidationIssue,
|
JailValidationIssue,
|
||||||
JailValidationResult,
|
JailValidationResult,
|
||||||
|
LogEncoding,
|
||||||
} from "../../types/config";
|
} from "../../types/config";
|
||||||
import { useAutoSave } from "../../hooks/useAutoSave";
|
import { useAutoSave } from "../../hooks/useAutoSave";
|
||||||
import { useConfigActiveStatus } from "../../hooks/useConfigActiveStatus";
|
import { useConfigActiveStatus } from "../../hooks/useConfigActiveStatus";
|
||||||
@@ -127,9 +130,9 @@ function JailConfigDetail({
|
|||||||
const [ignoreRegex, setIgnoreRegex] = useState<string[]>(jail.ignore_regex);
|
const [ignoreRegex, setIgnoreRegex] = useState<string[]>(jail.ignore_regex);
|
||||||
const [logPaths, setLogPaths] = useState<string[]>(jail.log_paths);
|
const [logPaths, setLogPaths] = useState<string[]>(jail.log_paths);
|
||||||
const [datePattern, setDatePattern] = useState(jail.date_pattern ?? "");
|
const [datePattern, setDatePattern] = useState(jail.date_pattern ?? "");
|
||||||
const [dnsMode, setDnsMode] = useState(jail.use_dns);
|
const [dnsMode, setDnsMode] = useState<DNSMode>(jail.use_dns);
|
||||||
const [backend, setBackend] = useState(jail.backend);
|
const [backend, setBackend] = useState<BackendType>(jail.backend);
|
||||||
const [logEncoding, setLogEncoding] = useState(jail.log_encoding);
|
const [logEncoding, setLogEncoding] = useState<LogEncoding>(jail.log_encoding);
|
||||||
const [prefRegex, setPrefRegex] = useState(jail.prefregex);
|
const [prefRegex, setPrefRegex] = useState(jail.prefregex);
|
||||||
const [deletingPath, setDeletingPath] = useState<string | null>(null);
|
const [deletingPath, setDeletingPath] = useState<string | null>(null);
|
||||||
const [newLogPath, setNewLogPath] = useState("");
|
const [newLogPath, setNewLogPath] = useState("");
|
||||||
@@ -302,7 +305,7 @@ function JailConfigDetail({
|
|||||||
value={backend}
|
value={backend}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
onChange={(_e, d) => {
|
onChange={(_e, d) => {
|
||||||
setBackend(d.value);
|
setBackend(d.value as BackendType);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{BACKENDS.map((b) => (
|
{BACKENDS.map((b) => (
|
||||||
@@ -315,7 +318,7 @@ function JailConfigDetail({
|
|||||||
value={logEncoding.toLowerCase()}
|
value={logEncoding.toLowerCase()}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
onChange={(_e, d) => {
|
onChange={(_e, d) => {
|
||||||
setLogEncoding(d.value);
|
setLogEncoding(d.value as LogEncoding);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{LOG_ENCODINGS.map((e) => (
|
{LOG_ENCODINGS.map((e) => (
|
||||||
@@ -350,7 +353,7 @@ function JailConfigDetail({
|
|||||||
value={dnsMode}
|
value={dnsMode}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
onChange={(_e, d) => {
|
onChange={(_e, d) => {
|
||||||
setDnsMode(d.value);
|
setDnsMode(d.value as DNSMode);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<option value="yes">yes — resolve hostnames</option>
|
<option value="yes">yes — resolve hostnames</option>
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ export interface BantimeEscalationUpdate {
|
|||||||
// Jail Configuration
|
// Jail Configuration
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export type DNSMode = "yes" | "warn" | "no" | "raw";
|
||||||
|
export type LogEncoding = "auto" | "ascii" | "utf-8" | "UTF-8" | "latin-1";
|
||||||
|
export type BackendType = "auto" | "polling" | "pyinotify" | "systemd" | "gamin";
|
||||||
|
|
||||||
export interface JailConfig {
|
export interface JailConfig {
|
||||||
name: string;
|
name: string;
|
||||||
ban_time: number;
|
ban_time: number;
|
||||||
@@ -48,10 +52,10 @@ export interface JailConfig {
|
|||||||
ignore_regex: string[];
|
ignore_regex: string[];
|
||||||
log_paths: string[];
|
log_paths: string[];
|
||||||
date_pattern: string | null;
|
date_pattern: string | null;
|
||||||
log_encoding: string;
|
log_encoding: LogEncoding;
|
||||||
backend: string;
|
backend: BackendType;
|
||||||
/** DNS look-up mode reported by fail2ban: "yes" | "warn" | "no" | "raw". */
|
/** DNS look-up mode reported by fail2ban: "yes" | "warn" | "no" | "raw". */
|
||||||
use_dns: string;
|
use_dns: DNSMode;
|
||||||
/** Prefix regex prepended to every failregex; empty string means disabled. */
|
/** Prefix regex prepended to every failregex; empty string means disabled. */
|
||||||
prefregex: string;
|
prefregex: string;
|
||||||
actions: string[];
|
actions: string[];
|
||||||
@@ -76,9 +80,9 @@ export interface JailConfigUpdate {
|
|||||||
/** Prefix regex; undefined/null = skip, "" = clear, non-empty = set. */
|
/** Prefix regex; undefined/null = skip, "" = clear, non-empty = set. */
|
||||||
prefregex?: string | null;
|
prefregex?: string | null;
|
||||||
date_pattern?: string | null;
|
date_pattern?: string | null;
|
||||||
dns_mode?: string | null;
|
dns_mode?: DNSMode | null;
|
||||||
backend?: string | null;
|
backend?: BackendType | null;
|
||||||
log_encoding?: string | null;
|
log_encoding?: LogEncoding | null;
|
||||||
enabled?: boolean | null;
|
enabled?: boolean | null;
|
||||||
bantime_escalation?: BantimeEscalationUpdate | null;
|
bantime_escalation?: BantimeEscalationUpdate | null;
|
||||||
}
|
}
|
||||||
@@ -454,7 +458,7 @@ export interface JailSectionConfig {
|
|||||||
findtime: number | null;
|
findtime: number | null;
|
||||||
bantime: number | null;
|
bantime: number | null;
|
||||||
action: string[];
|
action: string[];
|
||||||
backend: string | null;
|
backend: BackendType | null;
|
||||||
extra: Record<string, string>;
|
extra: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,13 +509,13 @@ export interface InactiveJail {
|
|||||||
/** Failure-counting window in seconds, parsed from findtime. */
|
/** Failure-counting window in seconds, parsed from findtime. */
|
||||||
find_time_seconds: number;
|
find_time_seconds: number;
|
||||||
/** Log encoding, e.g. ``"auto"`` or ``"utf-8"``. */
|
/** Log encoding, e.g. ``"auto"`` or ``"utf-8"``. */
|
||||||
log_encoding: string;
|
log_encoding: LogEncoding;
|
||||||
/** Log-monitoring backend. */
|
/** Log-monitoring backend. */
|
||||||
backend: string;
|
backend: BackendType;
|
||||||
/** Date pattern for log parsing, or null for auto-detect. */
|
/** Date pattern for log parsing, or null for auto-detect. */
|
||||||
date_pattern: string | null;
|
date_pattern: string | null;
|
||||||
/** DNS resolution mode. */
|
/** DNS resolution mode. */
|
||||||
use_dns: string;
|
use_dns: DNSMode;
|
||||||
/** Prefix regex prepended to every failregex. */
|
/** Prefix regex prepended to every failregex. */
|
||||||
prefregex: string;
|
prefregex: string;
|
||||||
/** List of failure regex patterns. */
|
/** List of failure regex patterns. */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* - `backend/app/models/geo.py` (GeoDetail / IpLookupResponse)
|
* - `backend/app/models/geo.py` (GeoDetail / IpLookupResponse)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { BantimeEscalation } from "./config";
|
import type { BantimeEscalation, BackendType, LogEncoding } from "./config";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Jail statistics
|
// Jail statistics
|
||||||
@@ -48,7 +48,7 @@ export interface JailSummary {
|
|||||||
/** Whether the jail is in idle mode (monitoring paused). */
|
/** Whether the jail is in idle mode (monitoring paused). */
|
||||||
idle: boolean;
|
idle: boolean;
|
||||||
/** Backend type used for log access (e.g. `"systemd"`, `"polling"`). */
|
/** Backend type used for log access (e.g. `"systemd"`, `"polling"`). */
|
||||||
backend: string;
|
backend: BackendType;
|
||||||
/** Observation window in seconds before a ban is triggered. */
|
/** Observation window in seconds before a ban is triggered. */
|
||||||
find_time: number;
|
find_time: number;
|
||||||
/** Duration of a ban in seconds (negative = permanent). */
|
/** Duration of a ban in seconds (negative = permanent). */
|
||||||
@@ -88,7 +88,7 @@ export interface Jail {
|
|||||||
/** Whether the jail is in idle mode. */
|
/** Whether the jail is in idle mode. */
|
||||||
idle: boolean;
|
idle: boolean;
|
||||||
/** Backend type (systemd, polling, etc.). */
|
/** Backend type (systemd, polling, etc.). */
|
||||||
backend: string;
|
backend: BackendType;
|
||||||
/** Log file paths monitored by this jail. */
|
/** Log file paths monitored by this jail. */
|
||||||
log_paths: string[];
|
log_paths: string[];
|
||||||
/** Fail-regex patterns used to identify offenders. */
|
/** Fail-regex patterns used to identify offenders. */
|
||||||
@@ -98,7 +98,7 @@ export interface Jail {
|
|||||||
/** Date-pattern used for timestamp parsing, or empty string. */
|
/** Date-pattern used for timestamp parsing, or empty string. */
|
||||||
date_pattern: string;
|
date_pattern: string;
|
||||||
/** Log file encoding (e.g. `"UTF-8"`). */
|
/** Log file encoding (e.g. `"UTF-8"`). */
|
||||||
log_encoding: string;
|
log_encoding: LogEncoding;
|
||||||
/** Action names attached to this jail. */
|
/** Action names attached to this jail. */
|
||||||
actions: string[];
|
actions: string[];
|
||||||
/** Observation window in seconds. */
|
/** Observation window in seconds. */
|
||||||
|
|||||||
Reference in New Issue
Block a user