113 lines
3.5 KiB
Python
113 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, Request, Response
|
|
|
|
from app.auth.repository import SessionRecord
|
|
from app.auth.schemas import LoginRequest, PasswordChangeRequest, SetupRequest
|
|
from app.auth.service import AuthService, SessionTokens
|
|
from app.core.config import AppSettings
|
|
from app.core.network import client_ip, is_loopback_client, use_secure_cookie
|
|
from app.dependencies import get_app_settings, get_auth_service, require_session
|
|
|
|
router = APIRouter(prefix="/api/v1/auth", tags=["auth"])
|
|
|
|
|
|
def _set_auth_cookies(
|
|
request: Request,
|
|
response: Response,
|
|
tokens: SessionTokens,
|
|
settings: AppSettings,
|
|
) -> None:
|
|
max_age = settings.session_days * 86400
|
|
secure = use_secure_cookie(request, settings)
|
|
response.set_cookie(
|
|
"fluxip_session",
|
|
tokens.session_token,
|
|
max_age=max_age,
|
|
httponly=True,
|
|
secure=secure,
|
|
samesite="strict",
|
|
path="/",
|
|
)
|
|
response.set_cookie(
|
|
"fluxip_csrf",
|
|
tokens.csrf_token,
|
|
max_age=max_age,
|
|
httponly=False,
|
|
secure=secure,
|
|
samesite="strict",
|
|
path="/",
|
|
)
|
|
|
|
|
|
def _clear_auth_cookies(request: Request, response: Response, settings: AppSettings) -> None:
|
|
secure = use_secure_cookie(request, settings)
|
|
response.delete_cookie("fluxip_session", path="/", secure=secure, samesite="strict")
|
|
response.delete_cookie("fluxip_csrf", path="/", secure=secure, samesite="strict")
|
|
|
|
|
|
@router.get("/bootstrap")
|
|
def bootstrap(request: Request, service: AuthService = Depends(get_auth_service)) -> dict:
|
|
return {"data": service.bootstrap_state(request.cookies.get("fluxip_session"))}
|
|
|
|
|
|
@router.post("/setup", status_code=201)
|
|
def setup(
|
|
payload: SetupRequest,
|
|
request: Request,
|
|
response: Response,
|
|
service: AuthService = Depends(get_auth_service),
|
|
settings: AppSettings = Depends(get_app_settings),
|
|
) -> dict:
|
|
tokens = service.setup(payload, loopback_client=is_loopback_client(request, settings))
|
|
_set_auth_cookies(request, response, tokens, settings)
|
|
return {"data": {"username": payload.username}}
|
|
|
|
|
|
@router.post("/login")
|
|
def login(
|
|
payload: LoginRequest,
|
|
request: Request,
|
|
response: Response,
|
|
service: AuthService = Depends(get_auth_service),
|
|
settings: AppSettings = Depends(get_app_settings),
|
|
) -> dict:
|
|
client_key = client_ip(request, settings)
|
|
tokens = service.login(payload, client_key)
|
|
_set_auth_cookies(request, response, tokens, settings)
|
|
return {"data": {"username": payload.username}}
|
|
|
|
|
|
@router.post("/logout", status_code=204)
|
|
def logout(
|
|
request: Request,
|
|
response: Response,
|
|
_: SessionRecord = Depends(require_session),
|
|
service: AuthService = Depends(get_auth_service),
|
|
settings: AppSettings = Depends(get_app_settings),
|
|
) -> Response:
|
|
service.logout(request.cookies.get("fluxip_session"))
|
|
_clear_auth_cookies(request, response, settings)
|
|
response.status_code = 204
|
|
return response
|
|
|
|
|
|
@router.get("/me")
|
|
def me(session: SessionRecord = Depends(require_session)) -> dict:
|
|
return {"data": {"username": session.username}}
|
|
|
|
|
|
@router.put("/password", status_code=204)
|
|
def change_password(
|
|
payload: PasswordChangeRequest,
|
|
request: Request,
|
|
response: Response,
|
|
_: SessionRecord = Depends(require_session),
|
|
service: AuthService = Depends(get_auth_service),
|
|
settings: AppSettings = Depends(get_app_settings),
|
|
) -> Response:
|
|
service.change_password(payload)
|
|
_clear_auth_cookies(request, response, settings)
|
|
response.status_code = 204
|
|
return response
|