From 7e7a6a1aebc9d24687fb20cb39b9d2c6e4ab653e Mon Sep 17 00:00:00 2001 From: Luna Mendes Date: Sun, 17 Jun 2018 14:24:24 -0300 Subject: [PATCH] blueprints.gateway: add implementations for gateway urls - config: add DEBUG, IS_SSL, WEBSERVER_URL - remove HOST, PORT - litecord: add auth module --- config.example.py | 9 ++++--- litecord/auth.py | 45 ++++++++++++++++++++++++++++++++++ litecord/blueprints/auth.py | 7 +++++- litecord/blueprints/gateway.py | 31 ++++++++++++++++++++--- run.py | 4 +++ 5 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 litecord/auth.py diff --git a/config.example.py b/config.example.py index 6346ba1..19864d9 100644 --- a/config.example.py +++ b/config.example.py @@ -2,8 +2,10 @@ MODE = 'Development' class Config: - HOST = 'localhost' - PORT = 8081 + """Default configuration values for litecord.""" + DEBUG = False + IS_SSL = False + WEBSERVER_URL = 'localhost:5000' POSTGRES = {} @@ -18,4 +20,5 @@ class Development(Config): class Production(Config): - pass + DEBUG = False + IS_SSL = True diff --git a/litecord/auth.py b/litecord/auth.py new file mode 100644 index 0000000..e325d6b --- /dev/null +++ b/litecord/auth.py @@ -0,0 +1,45 @@ +import base64 +import logging + +from itsdangerous import Signer, BadSignature +from quart import request, current_app as app + +from .errors import AuthError + + +log = logging.getLogger(__name__) + + +async def token_check(): + """Check token information.""" + try: + token = request.headers['Authorization'] + except KeyError: + raise AuthError('No token provided') + + user_id, _hmac = token.split('.') + + user_id = base64.b64decode(user_id.encode('utf-8')) + try: + user_id = int(user_id) + except ValueError: + raise AuthError('Invalid user ID type') + + pwd_hash = await app.db.fetchval(""" + SELECT password_hash + FROM users + WHERE id = $1 + """, user_id) + + if not pwd_hash: + raise AuthError('User ID not found') + + signer = Signer(pwd_hash) + + try: + signer.unsign(token) + log.debug(f'login for uid {user_id} successful') + return user_id + except BadSignature: + log.warning('token fail for uid {user_id}') + raise AuthError('Invalid token') diff --git a/litecord/blueprints/auth.py b/litecord/blueprints/auth.py index 992a8ec..5d2fa78 100644 --- a/litecord/blueprints/auth.py +++ b/litecord/blueprints/auth.py @@ -29,8 +29,11 @@ async def check_password(pwd_hash, given_password) -> bool: pwd_hash = pwd_hash.encode('utf-8') given_password = given_password.encode('utf-8') + print(repr(pwd_hash)) + print(repr(given_password)) + future = app.loop.run_in_executor( - None, bcrypt.checkpw, pwd_hash, given_password) + None, bcrypt.checkpw, given_password, pwd_hash) return await future @@ -70,6 +73,8 @@ async def register(): @bp.route('/login', methods=['POST']) async def login(): """Login one user into Litecord.""" + print(request.headers) + j = await request.get_json() email, password = j['email'], j['password'] diff --git a/litecord/blueprints/gateway.py b/litecord/blueprints/gateway.py index 7cdff33..05b9cd0 100644 --- a/litecord/blueprints/gateway.py +++ b/litecord/blueprints/gateway.py @@ -1,10 +1,35 @@ -from quart import Blueprint, jsonify +from quart import Blueprint, jsonify, current_app as app + +from ..auth import token_check bp = Blueprint('gateway', __name__) +def get_gw(): + proto = 'wss://' if app.config['IS_SSL'] else 'ws://' + return f'{proto}{app.config["WEBSERVER_URL"]}/ws' + + @bp.route('/gateway') def api_gateway(): - return jsonify({"url": "..."}) + return jsonify({ + 'url': get_gw() + }) -# TODO: /gateway/bot (requires token) + +@bp.route('/gateway/bot') +async def api_gateway_bot(): + user_id = await token_check() + + guild_count = await app.db.fetchval(""" + SELECT COUNT(*) + FROM members + WHERE user_id = $1 + """, user_id) + + shards = max(int(guild_count / 1200), 1) + + return jsonify({ + 'url': get_gw(), + 'shards': shards, + }) diff --git a/run.py b/run.py index 0b4a1ca..a683948 100644 --- a/run.py +++ b/run.py @@ -16,6 +16,10 @@ log = logging.getLogger(__name__) def make_app(): app = Quart(__name__) app.config.from_object(f'config.{config.MODE}') + + if app.config['DEBUG']: + logging.basicConfig(level=logging.DEBUG) + return app