"""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")