chore: initialize project repository

This commit is contained in:
Codex
2026-09-09 21:55:37 +08:00
commit b1497fd2c6
167 changed files with 17690 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
from dataclasses import dataclass
from pathlib import Path
from typing import Protocol
from uuid import uuid4
import jwt
from app.core.config import Settings
from app.core.contracts import RequestContext
from app.core.errors import UnauthorizedAgentError
class RevocationStore(Protocol):
def is_revoked(self, jti: str) -> bool: ...
@dataclass(frozen=True)
class EmptyRevocationStore:
def is_revoked(self, jti: str) -> bool:
return False
class JwtAuthenticator:
def __init__(self, settings: Settings, revocation_store: RevocationStore | None = None) -> None:
self._settings = settings
self._revocation_store = revocation_store or EmptyRevocationStore()
self._public_key = self._load_public_key()
def _load_public_key(self) -> str:
path = Path(self._settings.jwt_public_key_path)
if not path.is_absolute():
path = Path.cwd() / path
try:
return path.read_text(encoding="utf-8")
except OSError as exc:
raise RuntimeError(f"JWT public key cannot be read: {path}") from exc
def authenticate(self, token: str) -> RequestContext:
if not token:
raise UnauthorizedAgentError("missing bearer token")
try:
claims = jwt.decode(
token,
self._public_key,
algorithms=[self._settings.jwt_algorithm],
issuer=self._settings.jwt_issuer,
audience=self._settings.jwt_audience,
leeway=self._settings.jwt_clock_skew_seconds,
options={"require": ["sub", "iss", "aud", "exp", "nbf", "jti"]},
)
except jwt.PyJWTError as exc:
raise UnauthorizedAgentError("invalid bearer token") from exc
jti = str(claims["jti"])
if self._revocation_store.is_revoked(jti):
raise UnauthorizedAgentError("revoked bearer token")
subject = claims["sub"]
if (not isinstance(subject, str) or not subject.isascii()
or not subject.isdecimal() or len(subject) > 20
or not 0 < int(subject) <= 18446744073709551615):
raise UnauthorizedAgentError("invalid subject")
return RequestContext(user_id=str(claims["sub"]), trace_id=str(uuid4()))