#!/usr/bin/env python3 """ Dashboard template for viewing honeypot statistics. Customize this template to change the dashboard appearance. """ import html from datetime import datetime from zoneinfo import ZoneInfo def _escape(value) -> str: """Escape HTML special characters to prevent XSS attacks.""" if value is None: return "" return html.escape(str(value)) def format_timestamp(iso_timestamp: str, time_only: bool = False) -> str: """Format ISO timestamp for display with timezone conversion Args: iso_timestamp: ISO format timestamp string (UTC) time_only: If True, return only HH:MM:SS, otherwise full datetime """ try: # Parse UTC timestamp dt = datetime.fromisoformat(iso_timestamp) if time_only: return dt.strftime("%H:%M:%S") return dt.strftime("%Y-%m-%d %H:%M:%S") except Exception: # Fallback for old format return ( iso_timestamp.split("T")[1][:8] if "T" in iso_timestamp else iso_timestamp ) def generate_dashboard(stats: dict, dashboard_path: str = "") -> str: """Generate dashboard HTML with access statistics Args: stats: Statistics dictionary dashboard_path: The secret dashboard path for generating API URLs """ # Generate IP rows with clickable functionality for dropdown stats top_ips_rows = ( "\n".join([f""" {i+1} {_escape(ip)} {count}
Loading stats...
""" for i, (ip, count) in enumerate(stats["top_ips"])]) or 'No data' ) # Generate paths rows (CRITICAL: paths can contain XSS payloads) top_paths_rows = ( "\n".join( [ f'{i+1}{_escape(path)}{count}' for i, (path, count) in enumerate(stats["top_paths"]) ] ) or 'No data' ) # Generate User-Agent rows (CRITICAL: user agents can contain XSS payloads) top_ua_rows = ( "\n".join( [ f'{i+1}{_escape(ua[:80])}{count}' for i, (ua, count) in enumerate(stats["top_user_agents"]) ] ) or 'No data' ) # Generate suspicious accesses rows with clickable IPs suspicious_rows = ( "\n".join([f""" {_escape(log["ip"])} {_escape(log["path"])} {_escape(log["user_agent"][:60])} {format_timestamp(log["timestamp"], time_only=True)}
Loading stats...
""" for log in stats["recent_suspicious"][-10:]]) or 'No suspicious activity detected' ) # Generate honeypot triggered IPs rows with clickable IPs honeypot_rows = ( "\n".join([f""" {_escape(ip)} {_escape(", ".join(paths))} {len(paths)}
Loading stats...
""" for ip, paths in stats.get("honeypot_triggered_ips", [])]) or 'No honeypot triggers yet' ) # Generate attack types rows with clickable IPs attack_type_rows = ( "\n".join([f""" {_escape(log["ip"])} {_escape(log["path"])} {_escape(", ".join(log["attack_types"]))} {_escape(log["user_agent"][:60])} {format_timestamp(log["timestamp"],time_only=True)}
Loading stats...
""" for log in stats.get("attack_types", [])[-10:]]) or 'No attacks detected' ) # Generate credential attempts rows with clickable IPs credential_rows = ( "\n".join([f""" {_escape(log["ip"])} {_escape(log["username"])} {_escape(log["password"])} {_escape(log["path"])} {format_timestamp(log["timestamp"], time_only=True)}
Loading stats...
""" for log in stats.get("credential_attempts", [])[-20:]]) or 'No credentials captured yet' ) return f""" Krawl Dashboard
Export Malicious IPs

Krawl Dashboard

{stats['total_accesses']}
Total Accesses
{stats['unique_ips']}
Unique IPs
{stats['unique_paths']}
Unique Paths
{stats['suspicious_accesses']}
Suspicious Accesses
{stats.get('honeypot_ips', 0)}
Honeypot Caught
{len(stats.get('credential_attempts', []))}
Credentials Captured

Honeypot Triggers by IP

{honeypot_rows}
IP Address Accessed Paths Count

Recent Suspicious Activity

{suspicious_rows}
IP Address Path User-Agent Time

Captured Credentials

{credential_rows}
IP Address Username Password Path Time

Detected Attack Types

{attack_type_rows}
IP Address Path Attack Types User-Agent Time

Top IP Addresses

{top_ips_rows}
# IP Address Access Count

Top Paths

{top_paths_rows}
# Path Access Count

Top User-Agents

{top_ua_rows}
# User-Agent Count
"""