diff options
author | lonkaars <l.leblansch@gmail.com> | 2021-04-16 11:37:52 +0200 |
---|---|---|
committer | lonkaars <l.leblansch@gmail.com> | 2021-04-16 11:37:52 +0200 |
commit | b9a935cf545db36d714b44fdea96f448de67271e (patch) | |
tree | a615e2a569a76c42f28f0f70b572be306b07c6c5 | |
parent | 433fbdac908ca600cf8ecc254c5a4bc17dca3477 (diff) |
all login_token()'s removed in favor of @auth_required()
-rw-r--r-- | api/events.py | 32 | ||||
-rw-r--r-- | api/game/info.py | 19 | ||||
-rw-r--r-- | api/game/socket.py | 5 | ||||
-rw-r--r-- | api/hierarchy.py | 59 | ||||
-rw-r--r-- | api/user/avatar.py | 20 |
5 files changed, 60 insertions, 75 deletions
diff --git a/api/events.py b/api/events.py index 150f403..695edb1 100644 --- a/api/events.py +++ b/api/events.py @@ -1,34 +1,10 @@ -from flask import Blueprint, request, make_response -from flask_socketio import SocketIO, emit, Namespace, join_room, leave_room, rooms +from flask_socketio import join_room from socket_io import io -from auth.login_token import token_login -from http import cookies - -from game.cleanup import set_interval -import time - - -# get token from flask_socketio's request.environment -def get_token(environ): - cookie = environ.get("HTTP_COOKIE") - if not cookie: return None - - parsed = cookies.SimpleCookie() - parsed.load(cookie) - - token = parsed.get("token") - if not token: return None - - return token.value +from hierarchy import io_auth_required # global socket connection @io.on("connect") -def connect(): - token = get_token(request.environ) - if not token: return - - user_id = token_login(token) - if not user_id: return - +@io_auth_required("none") +def connect(data, user_id): join_room("user-" + user_id) diff --git a/api/game/info.py b/api/game/info.py index 73c31ff..b150dbc 100644 --- a/api/game/info.py +++ b/api/game/info.py @@ -4,6 +4,7 @@ from db import cursor from user.info import format_user from rating import outcome from ruleset import resolve_ruleset +from hierarchy import game_id_with_viewer import valid @@ -33,6 +34,7 @@ def format_game(game_id, user_id=None): is_player_1 = game[4] != user_id # get opponent from perspective of `user_id` + #TODO: return .players as array of player_1 and player_2 but format_user()'d opponent = game[4] if is_player_1 else game[3] # parse moves into list and return empty list if moves string is empty @@ -61,20 +63,9 @@ game_info = Blueprint('game_info', __name__) @game_info.route('/info', methods=['POST']) -def index(): - data = request.get_json() - if not data: return "", 400 - - game_id = data.get("id") or "" - if not game_id: return "", 400 - - user_id = None - token = request.cookies.get("token") or "" - if token: user_id = token_login(token) - - if not valid.game_id(game_id): return "", 403 - - return format_game(game_id, user_id), 200 +@game_id_with_viewer +def index(game_id, viewer): + return format_game(game_id, viewer), 200 dynamic_route = ["/game", game_info] diff --git a/api/game/socket.py b/api/game/socket.py index 6038586..69dc07e 100644 --- a/api/game/socket.py +++ b/api/game/socket.py @@ -4,7 +4,6 @@ from game.voerbak_connector import bord from db import cursor, connection from socket_io import io from hierarchy import io_auth_required -from auth.login_token import token_login import time import json @@ -23,12 +22,12 @@ def participants_only(func): game_id = data["game_id"] if not game_id or \ - not game_id in games: + not game_id in games: return game = games[game_id] if game.player_1_id != user_id and \ - game.player_2_id != user_id: + game.player_2_id != user_id: return return func(data, user_id, game) diff --git a/api/hierarchy.py b/api/hierarchy.py index 2e7db66..206e27c 100644 --- a/api/hierarchy.py +++ b/api/hierarchy.py @@ -7,30 +7,37 @@ import valid ranks = ["none", "user", "moderator", "admin", "bot"] -def util_two_person(func): +def util_two_id(type="user"): ''' + type?: "user" | "game" ! only used internally ! func(token_id?: str, explicit_id?: str) This decorator doesn't check for hierarchy constraints, but does make sure that token_id or explicit_id are valid user_id's ''' - def wrapper(): - token_id = None - explicit_id = None + def decorator(func): + def wrapper(): + token_id = None + explicit_id = None - token = request.cookies.get("token") or "" - if token: token_id = token_login(token) + token = request.cookies.get("token") or "" + if token: token_id = token_login(token) - data = request.get_json() - if data: explicit_id = data.get("id") + data = request.get_json() + if data: explicit_id = data.get("id") - if explicit_id and not valid.user_id(explicit_id): explicit_id = None + # if there's an explicit_id, validate it using `type` + if explicit_id and \ + not valid.validate(explicit_id, type): + explicit_id = None - return func(token_id, explicit_id) + return func(token_id, explicit_id) - wrapper.__name__ = func.__name__ - return wrapper + wrapper.__name__ = func.__name__ + return wrapper + + return decorator def two_person(func): @@ -39,9 +46,9 @@ def two_person(func): endpoint(user_1_id: str, user_2_id: str) no authentication, just runs endpoint() if both token_id and - explicit_id are present from @util_two_person. + explicit_id are present from @util_two_id. ''' - @util_two_person + @util_two_id("user") def wrapper(token_id, explicit_id): if not all_def([token_id, explicit_id]): return "", 400 @@ -61,7 +68,7 @@ def one_person(func): doesn't check for authentication expects that func takes these arguments: (user_id, viewer?) ''' - @util_two_person + @util_two_id("user") def wrapper(token_id, explicit_id): if all_notdef([token_id, explicit_id]): return "", 400 @@ -72,6 +79,22 @@ def one_person(func): return wrapper +def game_id_with_viewer(func): + ''' + endpoint should have two parameters: + endpoint(game_id: str, viewer?: str) + ''' + @util_two_id("game") + def wrapper(token_id, game_id): + if all_notdef([token_id, game_id]): + return "", 400 + + return func(game_id, token_id) + + wrapper.__name__ = func.__name__ + return wrapper + + def auth_required(level): ''' level = "none" | "user" | "moderator" | "admin" | "bot" @@ -80,10 +103,10 @@ def auth_required(level): @auth_required function decorator (use after @flask.Blueprint.route() decorator) This decorator only runs endpoint() if token_id from - @util_two_person is not None and passes hierarchy constraints + @util_two_id is not None and passes hierarchy constraints ''' def decorator(func): - @util_two_person + @util_two_id("user") def wrapper(token_id, explicit_id): if not token_id: if level == ranks[0]: @@ -118,7 +141,7 @@ def io_auth_required(level): ''' def decorator(func): # data is the original @io.on data - def wrapper(data): + def wrapper(data={}): token = request.cookies.get("token") or "" user_id = token_login(token) diff --git a/api/user/avatar.py b/api/user/avatar.py index eebe52b..f55db4a 100644 --- a/api/user/avatar.py +++ b/api/user/avatar.py @@ -1,6 +1,5 @@ from flask import Blueprint, request, Response from db import cursor -from auth.login_token import token_login from hierarchy import auth_required from os.path import exists from codecs import decode @@ -12,11 +11,9 @@ avatar = Blueprint('avatar', __name__) @avatar.route('/avatar', methods=["GET"]) -def get_avatar(): - token = request.cookies.get("token") or "" - login = token_login(token) or "" - - user_id = request.args.get("id") or login +@auth_required("none") +def get_avatar(token_id): + user_id = request.args.get("id") or token_id if not user_id: return "", 400 if not valid.user_id(user_id): return "", 403 @@ -27,15 +24,14 @@ def get_avatar(): return Response(avatar or default_avatar, 200, mimetype="image/png") -@avatar.route( - '/avatar', methods=["POST"] -) #TODO: pillow image size validation (client side resize) +#TODO: pillow image size validation (client side resize) +@avatar.route('/avatar', methods=["POST"]) @auth_required("user") -def update_avatar(login): +def update_avatar(user_id): if not request.data: return "", 400 - open(f"database/avatars/{login}.png", - "wb").write(decode(request.data, "base64")) + open(f"database/avatars/{user_id}.png", "wb") \ + .write(decode(request.data, "base64")) return "", 200 |