Implements the missing UI control for POST /api/jails/{name}/ignoreself:
- Add jailIgnoreSelf endpoint constant to endpoints.ts
- Add toggleIgnoreSelf(name, on) API function to jails.ts
- Expose toggleIgnoreSelf action from useJailDetail hook
- Replace read-only 'ignore self' badge with a Fluent Switch in
IgnoreListSection to allow enabling/disabling the flag per jail
- Add 5 vitest tests for checked/unchecked state and toggle behaviour
280 lines
8.7 KiB
TypeScript
280 lines
8.7 KiB
TypeScript
/**
|
|
* Jails API module.
|
|
*
|
|
* Wraps all backend endpoints under `/api/jails`, `/api/bans`, and
|
|
* `/api/geo` that relate to jail management.
|
|
*/
|
|
|
|
import { del, get, post } from "./client";
|
|
import { ENDPOINTS } from "./endpoints";
|
|
import type {
|
|
ActiveBanListResponse,
|
|
IpLookupResponse,
|
|
JailBannedIpsResponse,
|
|
JailCommandResponse,
|
|
JailDetailResponse,
|
|
JailListResponse,
|
|
UnbanAllResponse,
|
|
} from "../types/jail";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Jail overview
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Fetch the list of all fail2ban jails.
|
|
*
|
|
* @returns A {@link JailListResponse} containing summary info for each jail.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function fetchJails(): Promise<JailListResponse> {
|
|
return get<JailListResponse>(ENDPOINTS.jails);
|
|
}
|
|
|
|
/**
|
|
* Fetch full detail for a single jail.
|
|
*
|
|
* @param name - Jail name (e.g. `"sshd"`).
|
|
* @returns A {@link JailDetailResponse} with config, ignore list, and status.
|
|
* @throws {ApiError} On non-2xx responses (404 if the jail does not exist).
|
|
*/
|
|
export async function fetchJail(name: string): Promise<JailDetailResponse> {
|
|
return get<JailDetailResponse>(ENDPOINTS.jail(name));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Jail controls
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Start a stopped jail.
|
|
*
|
|
* @param name - Jail name.
|
|
* @returns A {@link JailCommandResponse} confirming the operation.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function startJail(name: string): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.jailStart(name), {});
|
|
}
|
|
|
|
/**
|
|
* Stop a running jail.
|
|
*
|
|
* @param name - Jail name.
|
|
* @returns A {@link JailCommandResponse} confirming the operation.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function stopJail(name: string): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.jailStop(name), {});
|
|
}
|
|
|
|
/**
|
|
* Toggle idle mode for a jail.
|
|
*
|
|
* @param name - Jail name.
|
|
* @param on - `true` to enable idle mode, `false` to disable.
|
|
* @returns A {@link JailCommandResponse} confirming the toggle.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function setJailIdle(
|
|
name: string,
|
|
on: boolean,
|
|
): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.jailIdle(name), on);
|
|
}
|
|
|
|
/**
|
|
* Reload configuration for a single jail.
|
|
*
|
|
* @param name - Jail name.
|
|
* @returns A {@link JailCommandResponse} confirming the reload.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function reloadJail(name: string): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.jailReload(name), {});
|
|
}
|
|
|
|
/**
|
|
* Reload configuration for **all** jails at once.
|
|
*
|
|
* @returns A {@link JailCommandResponse} confirming the operation.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function reloadAllJails(): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.jailsReloadAll, {});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Ignore list
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Return the ignore list for a jail.
|
|
*
|
|
* @param name - Jail name.
|
|
* @returns Array of IP addresses / CIDR networks on the ignore list.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function fetchIgnoreList(name: string): Promise<string[]> {
|
|
return get<string[]>(ENDPOINTS.jailIgnoreIp(name));
|
|
}
|
|
|
|
/**
|
|
* Add an IP or CIDR network to a jail's ignore list.
|
|
*
|
|
* @param name - Jail name.
|
|
* @param ip - IP address or CIDR network to add.
|
|
* @returns A {@link JailCommandResponse} confirming the addition.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function addIgnoreIp(
|
|
name: string,
|
|
ip: string,
|
|
): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.jailIgnoreIp(name), { ip });
|
|
}
|
|
|
|
/**
|
|
* Remove an IP or CIDR network from a jail's ignore list.
|
|
*
|
|
* @param name - Jail name.
|
|
* @param ip - IP address or CIDR network to remove.
|
|
* @returns A {@link JailCommandResponse} confirming the removal.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function delIgnoreIp(
|
|
name: string,
|
|
ip: string,
|
|
): Promise<JailCommandResponse> {
|
|
return del<JailCommandResponse>(ENDPOINTS.jailIgnoreIp(name), { ip });
|
|
}
|
|
|
|
/**
|
|
* Enable or disable the `ignoreself` flag for a jail.
|
|
*
|
|
* When enabled, fail2ban automatically adds the server's own IP addresses to
|
|
* the ignore list so the host can never ban itself.
|
|
*
|
|
* @param name - Jail name.
|
|
* @param on - `true` to enable, `false` to disable.
|
|
* @returns A {@link JailCommandResponse} confirming the change.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function toggleIgnoreSelf(
|
|
name: string,
|
|
on: boolean,
|
|
): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.jailIgnoreSelf(name), on);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Ban / unban
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Manually ban an IP address in a specific jail.
|
|
*
|
|
* @param jail - Jail name.
|
|
* @param ip - IP address to ban.
|
|
* @returns A {@link JailCommandResponse} confirming the ban.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function banIp(
|
|
jail: string,
|
|
ip: string,
|
|
): Promise<JailCommandResponse> {
|
|
return post<JailCommandResponse>(ENDPOINTS.bans, { jail, ip });
|
|
}
|
|
|
|
/**
|
|
* Unban an IP address from a specific jail or all jails.
|
|
*
|
|
* @param ip - IP address to unban.
|
|
* @param jail - Target jail name, or `undefined` to unban from all jails.
|
|
* @param unbanAll - When `true`, remove the IP from every jail.
|
|
* @returns A {@link JailCommandResponse} confirming the unban.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function unbanIp(
|
|
ip: string,
|
|
jail?: string,
|
|
unbanAll = false,
|
|
): Promise<JailCommandResponse> {
|
|
return del<JailCommandResponse>(ENDPOINTS.bans, { ip, jail, unban_all: unbanAll });
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Active bans
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Fetch all currently active bans across every jail.
|
|
*
|
|
* @returns An {@link ActiveBanListResponse} with geo-enriched entries.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function fetchActiveBans(): Promise<ActiveBanListResponse> {
|
|
return get<ActiveBanListResponse>(ENDPOINTS.bansActive);
|
|
}
|
|
|
|
/**
|
|
* Unban every currently banned IP across all jails in a single operation.
|
|
*
|
|
* Uses fail2ban's global `unban --all` command.
|
|
*
|
|
* @returns An {@link UnbanAllResponse} with the count of unbanned IPs.
|
|
* @throws {ApiError} On non-2xx responses.
|
|
*/
|
|
export async function unbanAllBans(): Promise<UnbanAllResponse> {
|
|
return del<UnbanAllResponse>(ENDPOINTS.bansAll);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Geo / IP lookup
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Look up ban status and geo-location for an IP address.
|
|
*
|
|
* @param ip - IP address to look up.
|
|
* @returns An {@link IpLookupResponse} with ban history and geo info.
|
|
* @throws {ApiError} On non-2xx responses (400 for invalid IP).
|
|
*/
|
|
export async function lookupIp(ip: string): Promise<IpLookupResponse> {
|
|
return get<IpLookupResponse>(ENDPOINTS.geoLookup(ip));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Jail-specific paginated bans
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Fetch the currently banned IPs for a specific jail, paginated.
|
|
*
|
|
* Only the requested page is geo-enriched on the backend, so this call
|
|
* remains fast even when a jail has thousands of banned IPs.
|
|
*
|
|
* @param jailName - Jail name (e.g. `"sshd"`).
|
|
* @param page - 1-based page number (default 1).
|
|
* @param pageSize - Items per page; max 100 (default 25).
|
|
* @param search - Optional case-insensitive IP substring filter.
|
|
* @returns A {@link JailBannedIpsResponse} with paginated ban entries.
|
|
* @throws {ApiError} On non-2xx responses (404 if jail unknown, 502 if fail2ban down).
|
|
*/
|
|
export async function fetchJailBannedIps(
|
|
jailName: string,
|
|
page = 1,
|
|
pageSize = 25,
|
|
search?: string,
|
|
): Promise<JailBannedIpsResponse> {
|
|
const params: Record<string, string> = {
|
|
page: String(page),
|
|
page_size: String(pageSize),
|
|
};
|
|
if (search !== undefined && search !== "") {
|
|
params.search = search;
|
|
}
|
|
const query = new URLSearchParams(params).toString();
|
|
return get<JailBannedIpsResponse>(`${ENDPOINTS.jailBanned(jailName)}?${query}`);
|
|
}
|