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

14 KiB
Raw Blame History

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:

<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.tsInactiveJail 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:
    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):
    #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):

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:

[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.