You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
2.2 KiB
73 lines
2.2 KiB
from flask.views import MethodView |
|
from flask_smorest import Blueprint |
|
from marshmallow import Schema, fields |
|
from .. import returns, ram_db, decorators |
|
from ..db_utils import get_user |
|
from ..models import User |
|
from ..decorators import ensure_logged_in |
|
|
|
from pyotp import TOTP |
|
|
|
bp = Blueprint('login', __name__, description='Login operations') |
|
|
|
class LoginParams(Schema): |
|
username = fields.String() |
|
code = fields.String() |
|
|
|
class LoginResult(returns.SuccessSchema): |
|
token = fields.String() |
|
|
|
class LoginSuccessSchema(returns.SuccessSchema): |
|
token = fields.String() |
|
|
|
@bp.route('/') |
|
class Login(MethodView): |
|
@bp.arguments(LoginParams, as_kwargs=True) |
|
@bp.response(401, returns.ErrorSchema, description='Login failure') |
|
@bp.response(200, LoginSuccessSchema) |
|
def post(self, username: str, code: str): |
|
"""Login via username and TOTP code""" |
|
user: User | None = get_user(username=username) |
|
if user is None: |
|
return returns.abort(returns.INVALID_DETAILS) |
|
|
|
otp = TOTP(user.otp) |
|
if not otp.verify(code, valid_window=1): |
|
return returns.abort(returns.INVALID_DETAILS) |
|
|
|
token = ram_db.login_user(user.id) |
|
return returns.success(token=token) |
|
|
|
@ensure_logged_in |
|
@bp.doc(security=[{'Token': []}]) |
|
@bp.response(401, returns.ErrorSchema, description='Login failure') |
|
@bp.response(204) |
|
def delete(self): |
|
"""Logout""" |
|
ram_db.logout_user(decorators.token) |
|
|
|
@bp.post('/logout') |
|
@ensure_logged_in |
|
@bp.doc(security=[{'Token': []}]) |
|
@bp.response(401, returns.ErrorSchema, description='Login failure') |
|
@bp.response(204) |
|
def logout_route(): |
|
"""Logout""" |
|
ram_db.logout_user(decorators.token) |
|
|
|
@bp.route('/whoami') |
|
class WhoAmI(MethodView): |
|
class WhoAmISchema(returns.SuccessSchema): |
|
user = fields.Nested(User.UserSchema) |
|
|
|
@bp.response(401, returns.ErrorSchema, description='Login failure') |
|
@bp.response(200, WhoAmISchema) |
|
@bp.doc(security=[{'Token': []}]) |
|
@ensure_logged_in |
|
def get(self): |
|
"""Get information about currently logged in user""" |
|
user: User | None = get_user(user_id=decorators.user_id) |
|
# if user is not None: |
|
# user = user.to_json() |
|
|
|
return returns.success(user=user)
|
|
|