diff --git a/server/decorators.py b/server/decorators.py new file mode 100644 index 0000000..9376615 --- /dev/null +++ b/server/decorators.py @@ -0,0 +1,12 @@ +from http import HTTPStatus +from functools import wraps + +def no_content(fn): + @wraps(fn) + def wrapper(*args, **kargs): + result = fn(*args, **kargs) + if result is None: + return None, HTTPStatus.NO_CONTENT + else: + return result + return wrapper diff --git a/server/login.py b/server/login.py index 1ea39de..1ca14da 100644 --- a/server/login.py +++ b/server/login.py @@ -4,6 +4,7 @@ from flask import Blueprint, request from pyotp import TOTP import db_utils +from decorators import no_content import models import ram_db import returns @@ -41,9 +42,15 @@ def ensure_logged_in(fn): user_id = ram_db.get_user(token) if user_id is None: return returns.INVALID_AUTHORIZATION - return fn(user_id=user_id, *args, **kargs) + return fn(user_id=user_id, token=token, *args, **kargs) return wrapper +@login.post('/logout') +@ensure_logged_in +@no_content +def logout(token: str): + ram_db.logout_user(token) + @login.get('/whoami') @ensure_logged_in def whoami(user_id): diff --git a/server/ram_db.py b/server/ram_db.py index b11ace0..631422c 100644 --- a/server/ram_db.py +++ b/server/ram_db.py @@ -14,10 +14,16 @@ def login_user(user_id: int) -> str: token = str(uuid4()) if len(USED_TOKENS) > 10_000_000: USED_TOKENS.clear() + for token in LOGGED_IN_USERS: + USED_TOKENS.add(token) USED_TOKENS.add(token) LOGGED_IN_USERS[token] = user_id, datetime.now() return token +def logout_user(token: str): + if token in LOGGED_IN_USERS: + del LOGGED_IN_USERS[token] + def get_user(token: str) -> int | None: if token not in LOGGED_IN_USERS: return None