From 1153c8ba0dd1fce42415e1e8cd5de7916bf60f40 Mon Sep 17 00:00:00 2001 From: iou1name Date: Sun, 28 Jul 2024 15:33:46 -0400 Subject: [PATCH] add fastapi app middleware --- buckler_fastapi.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 buckler_fastapi.py diff --git a/buckler_fastapi.py b/buckler_fastapi.py new file mode 100644 index 0000000..c2fe47c --- /dev/null +++ b/buckler_fastapi.py @@ -0,0 +1,74 @@ +#!/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