Add mass unban: DELETE /api/bans/all clears all active bans

- Send fail2ban's `unban --all` command via new `unban_all_ips()` service
  function; returns the count of unbanned IPs
- Add `UnbanAllResponse` Pydantic model (message + count)
- Add `DELETE /api/bans/all` router endpoint; handles 502 on socket error
- Frontend: `bansAll` endpoint constant, `unbanAllBans()` API call,
  `UnbanAllResponse` type, `unbanAll` action in `useActiveBans` hook
- JailsPage: "Clear All Bans" button (visible when bans > 0) with a
  Fluent UI confirmation Dialog before executing the operation
- 7 new tests (3 service, 4 router); 440 total pass, 82% coverage
This commit is contained in:
2026-03-07 21:16:49 +01:00
parent 207be94c42
commit 4773ae1c7a
11 changed files with 382 additions and 10 deletions

View File

@@ -1014,3 +1014,25 @@ async def lookup_ip(
"currently_banned_in": currently_banned_in,
"geo": geo,
}
async def unban_all_ips(socket_path: str) -> int:
"""Unban every currently banned IP across all fail2ban jails.
Uses fail2ban's global ``unban --all`` command, which atomically removes
every active ban from every jail in a single socket round-trip.
Args:
socket_path: Path to the fail2ban Unix domain socket.
Returns:
The number of IP addresses that were unbanned.
Raises:
~app.utils.fail2ban_client.Fail2BanConnectionError: If the socket
cannot be reached.
"""
client = Fail2BanClient(socket_path=socket_path, timeout=_SOCKET_TIMEOUT)
count: int = int(_ok(await client.send(["unban", "--all"])))
log.info("all_ips_unbanned", count=count)
return count