diff --git a/src/app.py b/src/app.py index 8d6f485..ae4e0dc 100644 --- a/src/app.py +++ b/src/app.py @@ -13,7 +13,7 @@ from fastapi import FastAPI, Request, Response from fastapi.staticfiles import StaticFiles from config import get_config -from tracker import AccessTracker +from tracker import AccessTracker, set_tracker from database import initialize_database from tasks_master import get_tasksmaster from logger import initialize_logging, get_app_logger @@ -40,6 +40,7 @@ async def lifespan(app: FastAPI): # Initialize tracker tracker = AccessTracker(config.max_pages_limit, config.ban_duration_seconds) + set_tracker(tracker) # Store in app.state for dependency injection app.state.config = config diff --git a/src/routes/honeypot.py b/src/routes/honeypot.py index 5d2f0ff..e2cb2b5 100644 --- a/src/routes/honeypot.py +++ b/src/routes/honeypot.py @@ -391,11 +391,23 @@ async def trap_page(request: Request, path: str): if "wordpress" in full_path.lower(): return HTMLResponse(html_templates.wordpress()) - if tracker.is_suspicious_user_agent(user_agent): + is_suspicious = tracker.is_suspicious_user_agent(user_agent) + + if is_suspicious: access_logger.warning( f"[SUSPICIOUS] {client_ip} - {user_agent[:50]} - {full_path}" ) + # Always record trap page access (feeds total counter + suspicious panel). + # Only store raw_request for suspicious/attack requests to avoid DB bloat. + tracker.record_access( + ip=client_ip, + path=full_path, + user_agent=user_agent, + method=request.method, + raw_request=build_raw_request(request) if is_suspicious else "", + ) + # Random error response if _should_return_error(config): error_code = _get_random_error_code() diff --git a/src/tasks/memory_cleanup.py b/src/tasks/memory_cleanup.py index 38a27a2..c82089d 100644 --- a/src/tasks/memory_cleanup.py +++ b/src/tasks/memory_cleanup.py @@ -28,21 +28,21 @@ def main(): Called periodically to prevent unbounded memory growth. """ try: - # Import here to avoid circular imports - from handler import Handler + from tracker import get_tracker - if not Handler.tracker: + tracker = get_tracker() + if not tracker: app_logger.warning("Tracker not initialized, skipping memory cleanup") return # Get memory stats before cleanup - stats_before = Handler.tracker.get_memory_stats() + stats_before = tracker.get_memory_stats() # Run cleanup - Handler.tracker.cleanup_memory() + tracker.cleanup_memory() # Get memory stats after cleanup - stats_after = Handler.tracker.get_memory_stats() + stats_after = tracker.get_memory_stats() # Log changes access_log_reduced = ( diff --git a/src/tracker.py b/src/tracker.py index b7b97d5..8c93a98 100644 --- a/src/tracker.py +++ b/src/tracker.py @@ -11,6 +11,20 @@ from wordlists import get_wordlists from database import get_database, DatabaseManager from ip_utils import is_local_or_private_ip, is_valid_public_ip +# Module-level singleton for background task access +_tracker_instance: "AccessTracker | None" = None + + +def get_tracker() -> "AccessTracker | None": + """Get the global AccessTracker singleton (set during app startup).""" + return _tracker_instance + + +def set_tracker(tracker: "AccessTracker"): + """Store the AccessTracker singleton for background task access.""" + global _tracker_instance + _tracker_instance = tracker + class AccessTracker: """ @@ -88,7 +102,7 @@ class AccessTracker: "path_traversal": r"\.\.", "sql_injection": r"('|--|;|\bOR\b|\bUNION\b|\bSELECT\b|\bDROP\b)", "xss_attempt": r"(