98 lines
2.8 KiB
Python
98 lines
2.8 KiB
Python
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
|