chore: initial project scaffold and gitignore

This commit is contained in:
2026-04-03 07:33:32 +00:00
commit 3e3acbd13d
41 changed files with 3658 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
"""Bearer token authentication and authorization."""
from __future__ import annotations
from dataclasses import dataclass
from enum import StrEnum
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from app.core.config import Settings, get_settings
class Permission(StrEnum):
READ = "read"
TRADE_WRITE = "trade-write"
ADMIN = "admin"
@dataclass(frozen=True)
class AuthContext:
token: str
permission: Permission
security = HTTPBearer(auto_error=False)
def _resolve_permission(token: str, settings: Settings) -> Permission | None:
if token in settings.admin_tokens:
return Permission.ADMIN
if token in settings.trade_write_tokens:
return Permission.TRADE_WRITE
if token in settings.read_tokens:
return Permission.READ
return None
def _has_permission(current: Permission, required: Permission) -> bool:
if current == Permission.ADMIN:
return True
if current == required:
return True
if current == Permission.TRADE_WRITE and required == Permission.READ:
return True
return False
def require_permission(
required: Permission,
credentials: HTTPAuthorizationCredentials | None = Depends(security),
settings: Settings = Depends(get_settings),
) -> AuthContext:
if credentials is None or credentials.scheme.lower() != "bearer":
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing bearer token")
permission = _resolve_permission(credentials.credentials, settings)
if permission is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
if not _has_permission(permission, required):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Insufficient permission")
return AuthContext(token=credentials.credentials, permission=permission)
def permission_dependency(required: Permission):
def dependency(
credentials: HTTPAuthorizationCredentials | None = Depends(security),
settings: Settings = Depends(get_settings),
) -> AuthContext:
return require_permission(required, credentials=credentials, settings=settings)
return dependency
require_read = permission_dependency(Permission.READ)
require_trade_write = permission_dependency(Permission.TRADE_WRITE)
require_admin = permission_dependency(Permission.ADMIN)