File size: 1,739 Bytes
72b125b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | """Bearer-token auth for the mobile app (Flask sessions are unreliable on native clients)."""
from flask import current_app, request, session
from itsdangerous import BadSignature, SignatureExpired, URLSafeTimedSerializer
TOKEN_SALT = "anicove-mobile-auth"
TOKEN_MAX_AGE = 30 * 24 * 60 * 60
def _serializer():
return URLSafeTimedSerializer(current_app.config["SECRET_KEY"], salt=TOKEN_SALT)
def issue_mobile_token(user_id, username, avatar=None):
return _serializer().dumps({
"user_id": str(user_id),
"username": username,
"avatar": avatar,
})
def parse_mobile_token(token):
try:
return _serializer().loads(token, max_age=TOKEN_MAX_AGE)
except (BadSignature, SignatureExpired, TypeError, ValueError):
return None
def require_mobile_auth():
"""Return (user_id, username, avatar) from session or Bearer token."""
if session.get("username") and session.get("_id") is not None:
return str(session["_id"]), session["username"], session.get("avatar")
header = request.headers.get("Authorization") or ""
token = ""
if header.lower().startswith("bearer "):
token = header.split(" ", 1)[1].strip()
if not token:
token = (request.headers.get("X-Auth-Token") or "").strip()
if not token:
data = request.get_json(silent=True) or {}
token = str(data.get("token") or request.args.get("token") or "").strip()
if not token:
return None
payload = parse_mobile_token(token)
if not payload or not payload.get("user_id") or not payload.get("username"):
return None
return str(payload["user_id"]), payload["username"], payload.get("avatar")
|