76 lines
2.2 KiB
Python
76 lines
2.2 KiB
Python
"""
|
|
Auth Service registry — generic, pluggable authentication for any service.
|
|
|
|
Add a new service (Plex, Seerr, etc.) by:
|
|
1. Subclassing AuthService
|
|
2. Dropping the module in this package
|
|
3. Calling register_auth_service() at import time
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass
|
|
from typing import Optional
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# AuthResult — returned by AuthService authentication
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@dataclass
|
|
class AuthResult:
|
|
"""Outcome of an authentication attempt."""
|
|
success: bool
|
|
external_user_id: Optional[str] = None
|
|
external_name: Optional[str] = None
|
|
credentials: Optional[dict] = None
|
|
error_message: Optional[str] = None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# AuthService — abstract base class
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class AuthService(ABC):
|
|
"""A service that users can authenticate against (Jellyfin, Seerr, Plex, etc.)
|
|
|
|
Subclasses must implement:
|
|
- name : unique identifier used in URLs and DB keys
|
|
- display_name : human-readable label shown in Discord
|
|
"""
|
|
|
|
@property
|
|
@abstractmethod
|
|
def name(self) -> str:
|
|
"""Unique service name: "jellyfin", "seerr", etc."""
|
|
...
|
|
|
|
@property
|
|
@abstractmethod
|
|
def display_name(self) -> str:
|
|
"""Human-readable: "Jellyfin", "Seerr", "Plex" """
|
|
...
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Global registry
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_registry: dict[str, AuthService] = {}
|
|
|
|
|
|
def register_auth_service(svc: AuthService) -> None:
|
|
"""Register an AuthService so it can be looked up by name."""
|
|
_registry[svc.name] = svc
|
|
|
|
|
|
def get_auth_service(name: str) -> AuthService | None:
|
|
"""Look up a registered AuthService by name."""
|
|
return _registry.get(name)
|
|
|
|
|
|
def list_auth_services() -> list[str]:
|
|
"""Return names of all registered auth services."""
|
|
return list(_registry.keys())
|