docs: add Claude AI assistant rules and configuration
Add comprehensive rule documentation for AI-assisted development covering authentication surfaces, outbound-call safety invariants, and other project conventions to guide Claude's understanding of critical system behaviors.
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
"""WebSocket API — Real-time call events and audio classification stream."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import secrets
|
||||
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
||||
|
||||
from api.deps import get_gateway
|
||||
from config import get_settings
|
||||
from auth import is_owner, resolve_from_header_or_query
|
||||
from db.database import session_scope
|
||||
from models.events import EventType, GatewayEvent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -17,21 +15,21 @@ router = APIRouter()
|
||||
|
||||
async def _authorize(websocket: WebSocket) -> bool:
|
||||
"""
|
||||
Check the static bearer token before accepting the socket.
|
||||
Require the owner before accepting the socket.
|
||||
|
||||
Browsers can't set headers on WebSocket connects, so a `token`
|
||||
query parameter is accepted alongside the Authorization header.
|
||||
Browsers can't set headers on WebSocket connects, so the Casdoor JWT (or
|
||||
a PAT) is accepted on the `?token=` query param alongside the Authorization
|
||||
header — the same narrow fallback the recording download uses. In dev mode
|
||||
the owner resolves tokenlessly. A non-owner or absent credential closes the
|
||||
socket with code 4401.
|
||||
"""
|
||||
token = get_settings().api_token.get_secret_value()
|
||||
if not token:
|
||||
q_token = websocket.query_params.get("token")
|
||||
auth_header = websocket.headers.get("authorization")
|
||||
async with session_scope() as session:
|
||||
user = await resolve_from_header_or_query(session, auth_header, q_token)
|
||||
if user is not None and is_owner(user):
|
||||
return True
|
||||
supplied = websocket.query_params.get("token", "")
|
||||
auth = websocket.headers.get("authorization", "")
|
||||
if auth.lower().startswith("bearer "):
|
||||
supplied = auth[7:]
|
||||
if secrets.compare_digest(supplied, token):
|
||||
return True
|
||||
await websocket.close(code=4401, reason="Missing or invalid bearer token")
|
||||
await websocket.close(code=4401, reason="Owner authentication required")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user