from __future__ import annotations from enum import Enum from typing import Optional class RouteAccessMode(str, Enum): PUBLIC = "public" PANEL_ONLY = "panel_only" BOT_OR_PANEL = "bot_or_panel" PUBLIC_BOT_OR_PANEL = "public_bot_or_panel" _PUBLIC_EXACT_PATHS = { "/api/health", "/api/health/cache", "/api/system/defaults", } _PANEL_AUTH_SEGMENTS = ("api", "panel", "auth") _BOT_PUBLIC_SEGMENTS = ("public", "bots") _BOT_API_SEGMENTS = ("api", "bots") _BOT_AUTH_SEGMENT = "auth" _BOT_PANEL_ONLY_ACTIONS = {"enable", "disable", "deactivate"} _BOT_PUBLIC_AUTH_ACTIONS = {"login", "logout", "status"} def _path_segments(path: str) -> list[str]: raw = str(path or "").strip().strip("/") if not raw: return [] return [segment for segment in raw.split("/") if segment] def extract_bot_id(path: str) -> Optional[str]: segments = _path_segments(path) if len(segments) < 3: return None if tuple(segments[:2]) not in {_BOT_API_SEGMENTS, _BOT_PUBLIC_SEGMENTS}: return None bot_id = str(segments[2] or "").strip() return bot_id or None def _is_panel_auth_route(segments: list[str]) -> bool: return tuple(segments[:3]) == _PANEL_AUTH_SEGMENTS def _is_public_bot_route(segments: list[str]) -> bool: return tuple(segments[:2]) == _BOT_PUBLIC_SEGMENTS and len(segments) >= 3 def _is_bot_auth_route(segments: list[str]) -> bool: return ( tuple(segments[:2]) == _BOT_API_SEGMENTS and len(segments) >= 5 and segments[3] == _BOT_AUTH_SEGMENT and segments[4] in _BOT_PUBLIC_AUTH_ACTIONS ) def _is_panel_only_bot_action(segments: list[str], method: str) -> bool: if tuple(segments[:2]) != _BOT_API_SEGMENTS or len(segments) < 3: return False if len(segments) == 3 and method == "DELETE": return True return len(segments) >= 4 and method == "POST" and segments[3] in _BOT_PANEL_ONLY_ACTIONS def _is_bot_scoped_api_route(segments: list[str]) -> bool: return tuple(segments[:2]) == _BOT_API_SEGMENTS and len(segments) >= 3 def resolve_route_access_mode(path: str, method: str) -> RouteAccessMode: raw_path = str(path or "").strip() verb = str(method or "GET").strip().upper() segments = _path_segments(raw_path) if raw_path in _PUBLIC_EXACT_PATHS: return RouteAccessMode.PUBLIC if _is_panel_auth_route(segments) or _is_bot_auth_route(segments): return RouteAccessMode.PUBLIC if _is_public_bot_route(segments): return RouteAccessMode.PUBLIC_BOT_OR_PANEL if _is_panel_only_bot_action(segments, verb): return RouteAccessMode.PANEL_ONLY if _is_bot_scoped_api_route(segments): return RouteAccessMode.BOT_OR_PANEL if raw_path.startswith("/api/"): return RouteAccessMode.PANEL_ONLY return RouteAccessMode.PUBLIC