61 lines
1.8 KiB
Python
61 lines
1.8 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
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"
|
|
|
|
|
|
_BOT_ID_API_RE = re.compile(r"^/api/bots/([^/]+)(?:/.*)?$")
|
|
_BOT_ID_PUBLIC_RE = re.compile(r"^/public/bots/([^/]+)(?:/.*)?$")
|
|
_BOT_PANEL_ONLY_ROUTE_METHODS = [
|
|
(re.compile(r"^/api/bots/[^/]+$"), {"DELETE"}),
|
|
(re.compile(r"^/api/bots/[^/]+/(?:enable|disable|deactivate)$"), {"POST"}),
|
|
]
|
|
|
|
_PUBLIC_PATHS = {
|
|
"/api/panel/auth/status",
|
|
"/api/panel/auth/login",
|
|
"/api/panel/auth/logout",
|
|
"/api/health",
|
|
"/api/health/cache",
|
|
"/api/system/defaults",
|
|
}
|
|
|
|
_BOT_PUBLIC_AUTH_RE = re.compile(r"^/api/bots/[^/]+/auth/(?:login|logout|status)$")
|
|
|
|
|
|
def extract_bot_id(path: str) -> Optional[str]:
|
|
raw = str(path or "").strip()
|
|
match = _BOT_ID_API_RE.match(raw) or _BOT_ID_PUBLIC_RE.match(raw)
|
|
if not match or not match.group(1):
|
|
return None
|
|
return match.group(1).strip() or None
|
|
|
|
|
|
def resolve_route_access_mode(path: str, method: str) -> RouteAccessMode:
|
|
raw_path = str(path or "").strip()
|
|
verb = str(method or "GET").strip().upper()
|
|
|
|
if raw_path in _PUBLIC_PATHS or _BOT_PUBLIC_AUTH_RE.fullmatch(raw_path):
|
|
return RouteAccessMode.PUBLIC
|
|
|
|
if raw_path.startswith("/public/bots/"):
|
|
return RouteAccessMode.PUBLIC_BOT_OR_PANEL
|
|
|
|
if _BOT_ID_API_RE.fullmatch(raw_path):
|
|
if any(pattern.fullmatch(raw_path) and verb in methods for pattern, methods in _BOT_PANEL_ONLY_ROUTE_METHODS):
|
|
return RouteAccessMode.PANEL_ONLY
|
|
return RouteAccessMode.BOT_OR_PANEL
|
|
|
|
if raw_path.startswith("/api/"):
|
|
return RouteAccessMode.PANEL_ONLY
|
|
|
|
return RouteAccessMode.PUBLIC
|