Stage 6: jail management — backend service, routers, tests, and frontend
- jail_service.py: list/detail/control/ban/unban/ignore-list/IP-lookup - jails.py router: 11 endpoints including ignore list management - bans.py router: active bans, ban, unban - geo.py router: IP lookup with geo enrichment - models: Jail.actions, ActiveBan.country/.banned_at optional, GeoDetail - 217 tests pass (40 service + 36 router + 141 existing), 76% coverage - Frontend: types/jail.ts, api/jails.ts, hooks/useJails.ts - JailsPage: jail overview table with controls, ban/unban forms, active bans table, IP lookup - JailDetailPage: full detail, start/stop/idle/reload, patterns, ignore list management
This commit is contained in:
210
frontend/src/types/jail.ts
Normal file
210
frontend/src/types/jail.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* TypeScript interfaces mirroring the backend jail Pydantic models.
|
||||
*
|
||||
* Backend sources:
|
||||
* - `backend/app/models/jail.py`
|
||||
* - `backend/app/models/ban.py` (ActiveBan / ActiveBanListResponse)
|
||||
* - `backend/app/models/geo.py` (GeoDetail / IpLookupResponse)
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Jail statistics
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Live filter+actions counters for a single jail.
|
||||
*
|
||||
* Mirrors `JailStatus` from `backend/app/models/jail.py`.
|
||||
*/
|
||||
export interface JailStatus {
|
||||
/** Number of IPs currently banned under this jail. */
|
||||
currently_banned: number;
|
||||
/** Total bans issued since fail2ban started. */
|
||||
total_banned: number;
|
||||
/** Current number of log-line matches that have not yet led to a ban. */
|
||||
currently_failed: number;
|
||||
/** Total log-line matches since fail2ban started. */
|
||||
total_failed: number;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Jail list (overview)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Lightweight snapshot of one jail for the overview table.
|
||||
*
|
||||
* Mirrors `JailSummary` from `backend/app/models/jail.py`.
|
||||
*/
|
||||
export interface JailSummary {
|
||||
/** Machine-readable jail name (e.g. `"sshd"`). */
|
||||
name: string;
|
||||
/** Whether the jail is enabled in the configuration. */
|
||||
enabled: boolean;
|
||||
/** Whether fail2ban is currently monitoring the jail. */
|
||||
running: boolean;
|
||||
/** Whether the jail is in idle mode (monitoring paused). */
|
||||
idle: boolean;
|
||||
/** Backend type used for log access (e.g. `"systemd"`, `"polling"`). */
|
||||
backend: string;
|
||||
/** Observation window in seconds before a ban is triggered. */
|
||||
find_time: number;
|
||||
/** Duration of a ban in seconds (negative = permanent). */
|
||||
ban_time: number;
|
||||
/** Maximum log-line failures before a ban is issued. */
|
||||
max_retry: number;
|
||||
/** Live ban/failure counters, or `null` when unavailable. */
|
||||
status: JailStatus | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response from `GET /api/jails`.
|
||||
*
|
||||
* Mirrors `JailListResponse` from `backend/app/models/jail.py`.
|
||||
*/
|
||||
export interface JailListResponse {
|
||||
/** All known jails. */
|
||||
jails: JailSummary[];
|
||||
/** Total number of jails. */
|
||||
total: number;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Jail detail
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Full configuration and state of a single jail.
|
||||
*
|
||||
* Mirrors `Jail` from `backend/app/models/jail.py`.
|
||||
*/
|
||||
export interface Jail {
|
||||
/** Machine-readable jail name. */
|
||||
name: string;
|
||||
/** Whether the jail is running. */
|
||||
running: boolean;
|
||||
/** Whether the jail is in idle mode. */
|
||||
idle: boolean;
|
||||
/** Backend type (systemd, polling, etc.). */
|
||||
backend: string;
|
||||
/** Log file paths monitored by this jail. */
|
||||
log_paths: string[];
|
||||
/** Fail-regex patterns used to identify offenders. */
|
||||
fail_regex: string[];
|
||||
/** Ignore-regex patterns used to whitelist log lines. */
|
||||
ignore_regex: string[];
|
||||
/** Date-pattern used for timestamp parsing, or empty string. */
|
||||
date_pattern: string;
|
||||
/** Log file encoding (e.g. `"UTF-8"`). */
|
||||
log_encoding: string;
|
||||
/** Action names attached to this jail. */
|
||||
actions: string[];
|
||||
/** Observation window in seconds. */
|
||||
find_time: number;
|
||||
/** Ban duration in seconds; negative means permanent. */
|
||||
ban_time: number;
|
||||
/** Maximum failures before ban is applied. */
|
||||
max_retry: number;
|
||||
/** Live counters, or `null` when not available. */
|
||||
status: JailStatus | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response from `GET /api/jails/{name}`.
|
||||
*
|
||||
* Mirrors `JailDetailResponse` from `backend/app/models/jail.py`.
|
||||
*/
|
||||
export interface JailDetailResponse {
|
||||
/** Full jail configuration. */
|
||||
jail: Jail;
|
||||
/** Current ignore list (IPs / networks that are never banned). */
|
||||
ignore_list: string[];
|
||||
/** Whether the jail ignores the server's own IP addresses. */
|
||||
ignore_self: boolean;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Jail command response
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generic acknowledgement from jail control endpoints.
|
||||
*
|
||||
* Mirrors `JailCommandResponse` from `backend/app/models/jail.py`.
|
||||
*/
|
||||
export interface JailCommandResponse {
|
||||
/** Human-readable result message. */
|
||||
message: string;
|
||||
/** Target jail name, or `"*"` for operations on all jails. */
|
||||
jail: string;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Active bans
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A single currently-active ban entry.
|
||||
*
|
||||
* Mirrors `ActiveBan` from `backend/app/models/ban.py`.
|
||||
*/
|
||||
export interface ActiveBan {
|
||||
/** Banned IP address. */
|
||||
ip: string;
|
||||
/** Jail that issued the ban. */
|
||||
jail: string;
|
||||
/** ISO 8601 UTC timestamp the ban started, or `null` when unavailable. */
|
||||
banned_at: string | null;
|
||||
/** ISO 8601 UTC timestamp the ban expires, or `null` for permanent bans. */
|
||||
expires_at: string | null;
|
||||
/** Number of times this IP has been banned before. */
|
||||
ban_count: number;
|
||||
/** ISO 3166-1 alpha-2 country code, or `null` when unknown. */
|
||||
country: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response from `GET /api/bans/active`.
|
||||
*
|
||||
* Mirrors `ActiveBanListResponse` from `backend/app/models/ban.py`.
|
||||
*/
|
||||
export interface ActiveBanListResponse {
|
||||
/** List of all currently active bans. */
|
||||
bans: ActiveBan[];
|
||||
/** Total number of active bans. */
|
||||
total: number;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Geo / IP lookup
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Geo-location information for an IP address.
|
||||
*
|
||||
* Mirrors `GeoDetail` from `backend/app/models/geo.py`.
|
||||
*/
|
||||
export interface GeoDetail {
|
||||
/** ISO 3166-1 alpha-2 country code (e.g. `"DE"`), or `null`. */
|
||||
country_code: string | null;
|
||||
/** Country name (e.g. `"Germany"`), or `null`. */
|
||||
country_name: string | null;
|
||||
/** Autonomous System Number string (e.g. `"AS3320"`), or `null`. */
|
||||
asn: string | null;
|
||||
/** Organisation name associated with the IP, or `null`. */
|
||||
org: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response from `GET /api/geo/lookup/{ip}`.
|
||||
*
|
||||
* Mirrors `IpLookupResponse` from `backend/app/models/geo.py`.
|
||||
*/
|
||||
export interface IpLookupResponse {
|
||||
/** The queried IP address. */
|
||||
ip: string;
|
||||
/** Jails in which the IP is currently banned. */
|
||||
currently_banned_in: string[];
|
||||
/** Geo-location data, or `null` when the lookup failed. */
|
||||
geo: GeoDetail | null;
|
||||
}
|
||||
Reference in New Issue
Block a user