Add origin field and filter for ban sources (Tasks 1 & 2)

- Task 1: Mark imported blocklist IP addresses
  - Add BanOrigin type and _derive_origin() to ban.py model
  - Populate origin field in ban_service list_bans() and bans_by_country()
  - BanTable and MapPage companion table show origin badge column
  - Tests: origin derivation in test_ban_service.py and test_dashboard.py

- Task 2: Add origin filter to dashboard and world map
  - ban_service: _origin_sql_filter() helper; origin param on list_bans()
    and bans_by_country()
  - dashboard router: optional origin query param forwarded to service
  - Frontend: BanOriginFilter type + BAN_ORIGIN_FILTER_LABELS in ban.ts
  - fetchBans / fetchBansByCountry forward origin to API
  - useBans / useMapData accept and pass origin; page resets on change
  - BanTable accepts origin prop; DashboardPage adds segmented filter
  - MapPage adds origin Select next to time-range picker
  - Tests: origin filter assertions in test_ban_service and test_dashboard
This commit is contained in:
2026-03-07 20:03:43 +01:00
parent 706d2e1df8
commit 53d664de4f
28 changed files with 1637 additions and 103 deletions

View File

@@ -11,6 +11,22 @@
/** The four supported time-range presets for dashboard views. */
export type TimeRange = "24h" | "7d" | "30d" | "365d";
/**
* Filter for the origin of a ban.
*
* - `"all"` — no filter, show all bans.
* - `"blocklist"` — only bans from the blocklist-import jail.
* - `"selfblock"` — only bans detected by fail2ban itself.
*/
export type BanOriginFilter = "all" | "blocklist" | "selfblock";
/** Human-readable labels for each origin filter option. */
export const BAN_ORIGIN_FILTER_LABELS: Record<BanOriginFilter, string> = {
all: "All",
blocklist: "Blocklist",
selfblock: "Selfblock",
} as const;
/** Human-readable labels for each time-range preset. */
export const TIME_RANGE_LABELS: Record<TimeRange, string> = {
"24h": "Last 24 h",
@@ -47,6 +63,8 @@ export interface DashboardBanItem {
org: string | null;
/** How many times this IP was banned. */
ban_count: number;
/** Whether this ban came from a blocklist import or fail2ban itself. */
origin: "blocklist" | "selfblock";
}
/**

View File

@@ -128,3 +128,19 @@ export interface AddLogPathRequest {
log_path: string;
tail?: boolean;
}
// ---------------------------------------------------------------------------
// Map Color Thresholds
// ---------------------------------------------------------------------------
export interface MapColorThresholdsResponse {
threshold_high: number;
threshold_medium: number;
threshold_low: number;
}
export interface MapColorThresholdsUpdate {
threshold_high: number;
threshold_medium: number;
threshold_low: number;
}

View File

@@ -16,6 +16,8 @@ export interface MapBanItem {
asn: string | null;
org: string | null;
ban_count: number;
/** Whether this ban came from a blocklist import or fail2ban itself. */
origin: "blocklist" | "selfblock";
}
/** Response from GET /api/dashboard/bans/by-country */