Files
RelayOps/backend/app/api/deps.py
2026-06-07 02:32:28 +03:00

118 lines
3.5 KiB
Python

from collections.abc import Callable
from fastapi import Depends, Header, status
from fastapi.security import OAuth2PasswordBearer
from jwt import InvalidTokenError
from sqlalchemy.orm import Session
from app.core.config import settings
from app.core.errors import raise_api_error
from app.core.security import decode_access_token
from app.db.session import get_db
from app.services.log_service import LogService
from app.services.service_control import ServiceControlService
from app.services.server_runtime import ServerRuntimeService
from app.services.telegram_service import TelegramService
from app.models.user import User
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login", auto_error=False)
def get_current_user(
db: Session = Depends(get_db),
token: str | None = Depends(oauth2_scheme),
) -> User:
if not token:
raise_api_error(
status_code=status.HTTP_401_UNAUTHORIZED,
code="unauthorized",
message="Authentication required.",
)
try:
payload = decode_access_token(token)
user_id = int(payload["sub"])
token_version = int(payload["ver"])
except (InvalidTokenError, KeyError, ValueError):
raise_api_error(
status_code=status.HTTP_401_UNAUTHORIZED,
code="invalid_token",
message="Authentication token is invalid.",
)
user = db.get(User, user_id)
if user is None:
raise_api_error(
status_code=status.HTTP_401_UNAUTHORIZED,
code="user_not_found",
message="Authenticated user does not exist.",
)
# Reject tokens from older login sessions after logout or auth-relevant
# user updates without introducing per-token server storage.
if user.token_version != token_version:
raise_api_error(
status_code=status.HTTP_401_UNAUTHORIZED,
code="invalid_token",
message="Authentication token is invalid.",
)
if not user.is_active:
raise_api_error(
status_code=status.HTTP_403_FORBIDDEN,
code="user_inactive",
message="User account is inactive.",
)
return user
def require_roles(*allowed_roles: str) -> Callable[[User], User]:
def dependency(current_user: User = Depends(get_current_user)) -> User:
if current_user.role not in allowed_roles:
raise_api_error(
status_code=status.HTTP_403_FORBIDDEN,
code="forbidden",
message="Insufficient permissions.",
)
return current_user
return dependency
def get_server_runtime_service() -> ServerRuntimeService:
return ServerRuntimeService()
def get_service_control_service() -> ServiceControlService:
return ServiceControlService()
def get_log_service() -> LogService:
return LogService()
def get_telegram_service() -> TelegramService:
return TelegramService()
def require_telegram_bot_secret(
bot_secret: str | None = Header(default=None, alias="X-Telegram-Bot-Secret"),
) -> str:
if not settings.telegram_bot_api_secret:
raise_api_error(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
code="telegram_bot_secret_unavailable",
message="Telegram bot integration is not configured.",
)
if bot_secret != settings.telegram_bot_api_secret:
raise_api_error(
status_code=status.HTTP_401_UNAUTHORIZED,
code="invalid_bot_secret",
message="Telegram bot authentication failed.",
)
return bot_secret