Files
BanGUI/Docs/Tasks.md
Lukas c110352e9e Config page tasks 1-4: dropdowns, key props, inactive jail full GUI, banaction fix
Task 1: Backend/LogEncoding/DatePattern dropdowns in JailConfigDetail
- Added BACKENDS, LOG_ENCODINGS, DATE_PATTERN_PRESETS constants
- Backend and Log Encoding: <Input readOnly> → <Select> (editable, auto-saves)
- Date Pattern: <Input> → <Combobox freeform> with presets
- Extended JailConfigUpdate model (backend, log_encoding) and service
- Added readOnly prop to JailConfigDetail (all fields, toggles, buttons)
- Extended RegexList with readOnly prop

Task 2: Fix raw action/filter config always blank
- Added key={selectedAction.name} to ActionDetail in ActionsTab
- Added key={selectedFilter.name} to FilterDetail in FiltersTab

Task 3: Inactive jail full GUI same as active jails
- Extended InactiveJail Pydantic model with all config fields
- Added _parse_time_to_seconds helper to config_file_service
- Updated _build_inactive_jail to populate all extended fields
- Extended InactiveJail TypeScript type to match
- Rewrote InactiveJailDetail to reuse JailConfigDetail (readOnly=true)

Task 4: Fix banaction interpolation error when activating jails
- _write_local_override_sync now includes banaction=iptables-multiport
  and banaction_allports=iptables-allports in every .local file
2026-03-14 09:28:30 +01:00

207 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BanGUI — Task List
This document breaks the entire BanGUI project into development stages, ordered so that each stage builds on the previous one. Every task is described in prose with enough detail for a developer to begin work. References point to the relevant documentation.
---
## ✅ Task 1 — Convert Backend, Log Encoding, and Date Pattern to Dropdowns in Jail Config
**Completed.** Backend and Log Encoding are now `<Select>` dropdowns; Date Pattern is a `<Combobox>` with presets. Both are wired to auto-save. The `JailConfigDetail` component also gained a `readOnly` prop (wired throughout all fields, toggles, and buttons) in preparation for Task 3. Backend updated `JailConfigUpdate` model to accept `backend` and `log_encoding`, and `update_jail_config` sends them to the daemon.
---
## ✅ Task 2 — Fix Raw Action Configuration Always Blank in Actions Tab
**Completed.** Added `key={selectedAction.name}` to `<ActionDetail>` in `ActionsTab.tsx` and `key={selectedFilter.name}` to `<FilterDetail>` in `FiltersTab.tsx`. This forces a full remount on item switch, resetting `RawConfigSection`'s `loadedRef` so it re-fetches content for every selected item.
---
## ✅ Task 3 — Give Inactive Jail Configs the Same GUI as Active Ones
**Completed.** Extended `InactiveJail` backend Pydantic model with all config fields (`ban_time_seconds`, `find_time_seconds`, `log_encoding`, `backend`, `date_pattern`, `use_dns`, `prefregex`, `fail_regex`, `ignore_regex`, `bantime_escalation`). Added `_parse_time_to_seconds` helper to `config_file_service.py` and updated `_build_inactive_jail` to populate all new fields. Extended the `InactiveJail` TypeScript type to match. Rewrote `InactiveJailDetail` to map fields into a `JailConfig`-compatible object and render `JailConfigDetail` with `readOnly=true`, showing filter/port/source_file as informational fields above the shared form.
---
## ✅ Task 4 — Fix `banaction` Interpolation Error When Activating Jails
**Completed.** `_write_local_override_sync` now always writes `banaction = iptables-multiport` and `banaction_allports = iptables-allports` into the per-jail `.local` file (Option A), ensuring fail2ban can resolve the `%(banaction)s` interpolation used in `action_`.
**Problem:** In the Config → Jails page, the **Backend**, **Log Encoding**, and **Date Pattern** fields for active jails are currently plain text `<Input>` fields (Backend and Log Encoding are read-only, Date Pattern is a free-text input). These should be `<Select>` dropdowns so users pick from valid options instead of typing arbitrary values.
**Where to change:**
- **`frontend/src/components/config/JailsTab.tsx`** — the `JailConfigDetail` component, around lines 250270. This is the right-pane form for active jails. Replace the three `<Input>` fields with `<Select>` dropdowns.
**Dropdown options to use:**
### Backend
Reference: `fail2ban-master/config/jail.conf` lines 115132. The `JailFileForm.tsx` already defines a `BACKENDS` constant at line 163 — reuse or mirror it.
| Value | Label |
|-------------|----------------------------------------------|
| `auto` | auto — pyinotify, then polling |
| `polling` | polling — standard polling algorithm |
| `pyinotify` | pyinotify — requires pyinotify library |
| `systemd` | systemd — uses systemd journal |
| `gamin` | gamin — legacy file alteration monitor |
### Log Encoding
Reference: `fail2ban-master/config/jail.conf` lines 145150. The option `auto` uses the system locale; the rest are standard Python codec names.
| Value | Label |
|----------|---------------------------------------|
| `auto` | auto — use system locale |
| `ascii` | ascii |
| `utf-8` | utf-8 |
| `latin-1` | latin-1 (ISO 8859-1) |
### Date Pattern
Date Pattern should remain a **combobox** (editable dropdown) since users may enter custom patterns, but offer common presets as suggestions.
| Value | Label |
|--------------------------------|---------------------------------------|
| *(empty)* | auto-detect (leave blank) |
| `{^LN-BEG}` | {^LN-BEG} — line beginning |
| `%%Y-%%m-%%d %%H:%%M:%%S` | YYYY-MM-DD HH:MM:SS |
| `%%d/%%b/%%Y:%%H:%%M:%%S` | DD/Mon/YYYY:HH:MM:SS (Apache) |
| `%%b %%d %%H:%%M:%%S` | Mon DD HH:MM:SS (syslog) |
| `EPOCH` | EPOCH — Unix timestamp |
| `%%Y-%%m-%%dT%%H:%%M:%%S` | ISO 8601 |
| `TAI64N` | TAI64N |
**Implementation notes:**
1. Backend and Log Encoding are currently `readOnly`. They must become editable `<Select>` fields. Wire their `onChange` to local state and include them in the auto-save payload sent to the backend.
2. The backend model at `backend/app/models/config.py` line 67 already accepts `backend: str` and `log_encoding: str`, so no backend changes are needed unless you want to add server-side validation.
3. Date Pattern should use a Fluent UI `Combobox` (editable dropdown) instead of a `Select`, so users can still type a custom pattern.
4. Follow the existing DNS Mode dropdown pattern at lines 271280 of `JailsTab.tsx` as a reference for styling and onChange handling.
---
## Task 2 — Fix Raw Action Configuration Always Blank in Actions Tab
**Problem:** In the Config → Actions page, the **"Raw Action Configuration"** accordion section is always blank when expanded.
**Where to look:**
- **`frontend/src/components/config/ActionsTab.tsx`** — the `ActionDetail` component (lines 65185). The `fetchRaw` callback (line 82) calls `fetchActionFile(action.name)` and returns `result.content`.
- **`frontend/src/components/config/RawConfigSection.tsx`** — the collapsible raw editor. It uses a `loadedRef` (line 62) to fetch content only on first accordion expansion, and never resets.
- **`frontend/src/api/config.ts`** line 257 — `fetchActionFile()` calls `GET /config/actions/{name}`.
- **`backend/app/services/file_config_service.py`** line 734 — `get_action_file()` reads from `action.d/` using `_read_conf_file()`, which tries `.conf` first, then `.local`.
**Root cause investigation — check these two possibilities:**
### Possibility A: Stale `loadedRef` across action switches
`ActionDetail` at line 301 of `ActionsTab.tsx` is rendered **without a `key` prop**:
```tsx
<ActionDetail
action={selectedAction}
onAssignClick={() => { setAssignOpen(true); }}
onRemovedFromJail={handleRemovedFromJail}
/>
```
Without `key={selectedAction.name}`, React reuses the same component instance when switching between actions. The `RawConfigSection` inside `ActionDetail` keeps its `loadedRef.current = true` from a previous expansion, so it never re-fetches for the new action.
**Fix:** Add `key={selectedAction.name}` to `ActionDetail` so it fully unmounts/remounts on action switch, resetting all internal state including `loadedRef`.
### Possibility B: Backend returning empty content
The `_read_conf_file` function at `file_config_service.py` line 492 tries `.conf` first then `.local`. If the action only has a `.conf` file and it's readable, content should be returned. Verify by:
1. Checking browser DevTools Network tab for the `GET /api/config/actions/{name}` response body.
2. Confirming the response has a non-empty `content` field.
**Implementation:**
1. Add `key={selectedAction.name}` to the `<ActionDetail>` component in `ActionsTab.tsx` line 301.
2. Test by selecting different actions and expanding the raw config accordion — each should show the correct file content.
3. If the backend is returning empty content, debug `_read_conf_file` to check which file path it resolves and whether it can read the file.
---
## Task 3 — Give Inactive Jail Configs the Same GUI as Active Ones
**Problem:** In the Config → Jails page, **inactive jails** show a minimal read-only preview (`InactiveJailDetail` component) with only basic fields (filter, port, ban time, find time, max retry, log paths, actions, source file). **Active jails** like `bangui-sim` show a full editable form (`JailConfigDetail` component) with all fields including Backend, Log Encoding, Date Pattern, DNS Mode, Prefix Regex, editable log paths, Fail/Ignore Regex lists, Ban-time Escalation, and a Raw Configuration editor.
The inactive jail detail should display the same rich GUI as the active one — same layout, same fields — but in read-only mode (since the jail is not running on fail2ban).
**Where to change:**
- **`frontend/src/components/config/JailsTab.tsx`**:
- `InactiveJailDetail` component (lines 493580): the current minimal read-only view.
- `JailConfigDetail` component (lines ~200490): the full editable form for active jails.
- Selection logic at lines 721752 determines which component renders based on jail kind.
- **`frontend/src/types/config.ts`** — `InactiveJail` type (around line 484) defines the data shape for inactive jails. Compare with `JailConfig` to see which fields are missing.
- **Backend** — check that the inactive jail endpoint returns enough data. The backend model `InactiveJail` may need additional fields (backend, log_encoding, date_pattern, dns_mode, prefix_regex, failregex, ignoreregex, ban-time escalation settings) to match the active `JailConfig` model.
**Implementation approach:**
1. **Extend the `InactiveJail` model** in the backend (`backend/app/models/config.py`) to include all fields that `JailConfig` has: `backend`, `log_encoding`, `date_pattern`, `usedns`, `prefixregex`, `failregex`, `ignoreregex`, `bantime_increment` (escalation settings), etc.
2. **Update the backend service** that parses inactive jail configs to extract these additional fields from the `.conf`/`.local` files.
3. **Rewrite `InactiveJailDetail`** to mirror `JailConfigDetail`'s layout but with all fields in **read-only** mode (all `<Input>` have `readOnly`, all `<Select>` are disabled). Keep the "Activate Jail" button at the bottom.
4. Alternatively, refactor `JailConfigDetail` to accept a `readOnly` prop and reuse it for both active and inactive jails, avoiding code duplication.
5. Include the **Raw Configuration** accordion (using `RawConfigSection`) for inactive jails as well, pointed at the jail's config file.
**Testing:** Select an inactive jail and verify it shows the same fields and layout as an active jail like `bangui-sim`, with all values populated from the config file but not editable.
---
## Task 4 — Fix `banaction` Interpolation Error When Activating Jails
**Problem:** Activating certain jails (e.g. `airsonic-auth`) causes fail2ban to crash with:
```
ERROR Failed during configuration: Bad value substitution: option 'action'
in section 'airsonic-auth' contains an interpolation key 'banaction' which
is not a valid option name. Raw value: '%(action_)s'
```
**Root cause — the interpolation chain breaks:**
1. Most jails inherit `action = %(action_)s` from `[DEFAULT]`.
2. `action_` is defined in `fail2ban-master/config/jail.conf` line 212 as:
```ini
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
```
3. `banaction` is **commented out** in the `[DEFAULT]` section of `jail.conf` (line 208):
```ini
#banaction = iptables-multiport
#banaction_allports = iptables-allports
```
4. When BanGUI activates a jail, `_write_local_override_sync()` in `backend/app/services/config_file_service.py` (line 478) writes a `.local` file with only `enabled`, `bantime`, `findtime`, `maxretry`, `port`, and `logpath` — it does **not** include `banaction` or `action`.
5. fail2ban merges the configs, hits `%(banaction)s`, finds no value, and crashes.
**Where to change:**
- **`backend/app/services/config_file_service.py`** — function `_write_local_override_sync()` around line 478. This writes the per-jail `.local` override file.
- **`backend/app/models/config.py`** — the `ActivateJailRequest` or equivalent model that defines which fields are accepted when activating a jail.
**Fix options (pick one):**
### Option A: Write `banaction` in every jail `.local` file (recommended)
When BanGUI writes a jail `.local` file, include a `banaction` field with a sensible default (e.g. `iptables-multiport`). This ensures the interpolation chain always resolves.
1. Add a `banaction` field (defaulting to `iptables-multiport`) to the jail activation model/request.
2. In `_write_local_override_sync()`, always write `banaction = <value>` into the `[jailname]` section of the `.local` file.
3. Also include `banaction_allports = iptables-allports` as a fallback for jails that reference it.
### Option B: Write a global `jail.local` with DEFAULT banaction
Create or update a `jail.local` file in the fail2ban config directory with:
```ini
[DEFAULT]
banaction = iptables-multiport
banaction_allports = iptables-allports
```
This provides the missing defaults for all jails at once.
### Option C: Expose `banaction` in the jail config UI
Add `banaction` as a configurable field in the jail config form so users can choose the ban action (iptables-multiport, nftables-multiport, firewallcmd-rich-rules, etc.). Write the selected value to the `.local` file on save/activate.
**Testing:**
1. Activate `airsonic-auth` (or any jail that inherits `action = %(action_)s` without defining its own `banaction`).
2. Verify fail2ban starts without the interpolation error.
3. Verify `fail2ban-client status airsonic-auth` shows the jail running with the correct ban action.