89 lines
2.6 KiB
Python
89 lines
2.6 KiB
Python
"""
|
|
Database session management for WebAuthn authentication.
|
|
|
|
This module provides session management using database tokens instead of JWT tokens.
|
|
Session tokens are stored in the database and validated on each request.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from uuid import UUID
|
|
|
|
from fastapi import Request
|
|
|
|
from ..db import sql
|
|
|
|
|
|
def get_client_info(request: Request) -> dict:
|
|
"""Extract client information from FastAPI request and return as dict."""
|
|
# Get client IP (handle X-Forwarded-For for proxies)
|
|
# Get user agent
|
|
return {
|
|
"client_ip": request.client.host if request.client else "",
|
|
"user_agent": request.headers.get("user-agent", "")[:500],
|
|
}
|
|
|
|
|
|
def get_client_info_from_websocket(ws) -> dict:
|
|
"""Extract client information from WebSocket connection and return as dict."""
|
|
# Get client IP from WebSocket
|
|
client_ip = None
|
|
if hasattr(ws, "client") and ws.client:
|
|
client_ip = ws.client.host
|
|
|
|
# Check for forwarded headers
|
|
if hasattr(ws, "headers"):
|
|
forwarded_for = ws.headers.get("x-forwarded-for")
|
|
if forwarded_for:
|
|
client_ip = forwarded_for.split(",")[0].strip()
|
|
|
|
# Get user agent from WebSocket headers
|
|
user_agent = None
|
|
if hasattr(ws, "headers"):
|
|
user_agent = ws.headers.get("user-agent")
|
|
# Truncate user agent if too long
|
|
if user_agent and len(user_agent) > 500: # Keep some margin
|
|
user_agent = user_agent[:500]
|
|
|
|
return {
|
|
"client_ip": client_ip,
|
|
"user_agent": user_agent,
|
|
"timestamp": datetime.now().isoformat(),
|
|
"connection_type": "websocket",
|
|
}
|
|
|
|
|
|
async def create_session_token(
|
|
user_id: UUID, credential_id: bytes, info: dict | None = None
|
|
) -> str:
|
|
"""Create a session token for a user."""
|
|
return await sql.create_session_by_credential_id(user_id, credential_id, None, info)
|
|
|
|
|
|
async def validate_session_token(token: str) -> Optional[dict]:
|
|
"""Validate a session token."""
|
|
session_data = await sql.get_session(token)
|
|
if not session_data:
|
|
return None
|
|
|
|
return {
|
|
"user_id": session_data["user_id"],
|
|
"credential_id": session_data["credential_id"],
|
|
"created_at": session_data["created_at"],
|
|
}
|
|
|
|
|
|
async def refresh_session_token(token: str) -> Optional[str]:
|
|
"""Refresh a session token."""
|
|
return await sql.refresh_session(token)
|
|
|
|
|
|
async def delete_session_token(token: str) -> None:
|
|
"""Delete a session token."""
|
|
await sql.delete_session(token)
|
|
|
|
|
|
async def logout_session(token: str) -> None:
|
|
"""Log out a user by deleting their session token."""
|
|
await sql.delete_session(token)
|