aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlonkaars <l.leblansch@gmail.com>2021-04-16 11:37:52 +0200
committerlonkaars <l.leblansch@gmail.com>2021-04-16 11:37:52 +0200
commitb9a935cf545db36d714b44fdea96f448de67271e (patch)
treea615e2a569a76c42f28f0f70b572be306b07c6c5
parent433fbdac908ca600cf8ecc254c5a4bc17dca3477 (diff)
all login_token()'s removed in favor of @auth_required()
-rw-r--r--api/events.py32
-rw-r--r--api/game/info.py19
-rw-r--r--api/game/socket.py5
-rw-r--r--api/hierarchy.py59
-rw-r--r--api/user/avatar.py20
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