Files
at2-webapp-dicta2stream/auth_router.py
oib 17616ac5b8 feat: Add database migrations and auth system
- Add Alembic for database migrations
- Implement user authentication system
- Update frontend styles and components
- Add new test audio functionality
- Update stream management and UI
2025-07-02 09:37:03 +02:00

107 lines
3.0 KiB
Python

"""Authentication routes for dicta2stream"""
from fastapi import APIRouter, Depends, Request, Response, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlmodel import Session
from models import Session as DBSession, User
from database import get_db
from auth import get_current_user
router = APIRouter()
security = HTTPBearer()
@router.post("/logout")
async def logout(
request: Request,
response: Response,
db: Session = Depends(get_db),
credentials: HTTPAuthorizationCredentials = Depends(security)
):
"""Log out by invalidating the current session"""
token = credentials.credentials
# Find and invalidate the session
session = db.exec(
select(DBSession)
.where(DBSession.token == token)
.where(DBSession.is_active == True) # noqa: E712
).first()
if session:
session.is_active = False
db.add(session)
db.commit()
# Clear the session cookie
response.delete_cookie(
key="sessionid", # Must match the cookie name in main.py
httponly=True,
secure=True, # Must match the cookie settings from login
samesite="lax",
path="/"
)
return {"message": "Successfully logged out"}
@router.get("/me")
async def get_current_user_info(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get current user information"""
return {
"username": current_user.username,
"email": current_user.email,
"created_at": current_user.token_created.isoformat(),
"is_confirmed": current_user.confirmed
}
@router.get("/sessions")
async def list_sessions(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""List all active sessions for the current user"""
sessions = DBSession.get_active_sessions(db, current_user.username)
return [
{
"id": s.id,
"ip_address": s.ip_address,
"user_agent": s.user_agent,
"created_at": s.created_at.isoformat(),
"last_used_at": s.last_used_at.isoformat(),
"expires_at": s.expires_at.isoformat()
}
for s in sessions
]
@router.post("/sessions/{session_id}/revoke")
async def revoke_session(
session_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Revoke a specific session"""
session = db.get(DBSession, session_id)
if not session or session.user_id != current_user.username:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Session not found"
)
if not session.is_active:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Session is already inactive"
)
session.is_active = False
db.add(session)
db.commit()
return {"message": "Session revoked"}