"""Utilities shared by fail2ban-related services.""" from __future__ import annotations import json from datetime import UTC, datetime def ts_to_iso(unix_ts: int) -> str: """Convert a Unix timestamp to an ISO 8601 UTC string.""" return datetime.fromtimestamp(unix_ts, tz=UTC).isoformat() def parse_data_json(raw: object) -> tuple[list[str], int]: """Extract matches and failure count from the fail2ban bans.data value.""" if raw is None: return [], 0 obj: dict[str, object] = {} if isinstance(raw, str): try: parsed = json.loads(raw) if isinstance(parsed, dict): obj = parsed except json.JSONDecodeError: return [], 0 elif isinstance(raw, dict): obj = raw raw_matches = obj.get("matches") matches = [str(m) for m in raw_matches] if isinstance(raw_matches, list) else [] raw_failures = obj.get("failures") failures = 0 if isinstance(raw_failures, (int, float, str)): try: failures = int(raw_failures) except (ValueError, TypeError): failures = 0 return matches, failures