Buckler/buckler_fastapi.py

75 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""
Session interface middlewares to integrate the fastapi app with Buckler.
"""
import json
from datetime import datetime
import httpx
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from starlette.middleware.base import BaseHTTPMiddleware
import config
class BucklerSessionMiddleware(BaseHTTPMiddleware):
"""
Verifies the user with the configured Buckler app and retrieves any
session data they may have. Redirects them to the login page otherwise.
"""
def __init__(self, app):
super().__init__(app)
async def dispatch(self, request: Request, call_next):
user_id = request.cookies.get('userid', '')
user_sid = request.cookies.get('session', '')
url = config.buckler['url'] + '/get_session'
params = {
'app_id': config.buckler['app_id'],
'app_key': config.buckler['app_key'],
'userid': user_id,
'session': user_sid }
async with httpx.AsyncClient() as client:
resp = await client.get(url, params=params)
data = resp.json()
if data.get('error'): # user not logged in
response = RedirectResponse(config.buckler['login_url'])
response.set_cookie('redirect', config.server_homepage)
return response
request.state.session = data.get('session_data')
request.state.meta = data.get('meta')
response = await call_next(request)
if request.state.session != data['session_data']: # session data modified
url = config.buckler['url'] + '/set_session'
data = json.dumps(request.state.session)
async with httpx.AsyncClient() as client:
await client.post(url, params=params, data=data)
last_used = datetime.fromisoformat(request.state.meta['last_used'])
now = datetime.now(last_used.tzinfo)
delta = now - last_used
if delta.seconds > 600:
response.set_cookie(
'userid',
user_id,
domain=config.server_domain,
max_age=30*24*60*60,
secure=True,
httponly=True,
samesite='strict')
response.set_cookie(
'session',
user_sid,
domain=config.server_domain,
max_age=30*24*60*60,
secure=True,
httponly=True,
samesite='strict')
return response