Database reworked simpler, JWTs replaced by sessions table and random tokens. Accessing Add device link is currently broken.
This commit is contained in:
88
passkey/util/session.py
Normal file
88
passkey/util/session.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user