# myapp/utils.py from functools import wraps import secrets import jwt from flask import request, jsonify, current_app from bson.objectid import ObjectId def token_required(f): """ Decorator to ensure a valid JWT token is present in the request header and injects the corresponding user document into the decorated function. """ @wraps(f) def decorated(*args, **kwargs): token = None auth_header = request.headers.get("Authorization") if auth_header: # Check for "Bearer " prefix and extract token parts = auth_header.split() if len(parts) == 2 and parts[0].lower() == "bearer": token = parts[1] # Optional: Allow raw token directly (as in original code) elif len(parts) == 1: token = auth_header if not token: return jsonify({"message": "Token is missing."}), 401 try: # Use current_app.config to access SECRET_KEY and JWT_ALGORITHM secret_key = current_app.config['SECRET_KEY'] # Provide a default algorithm if not explicitly configured algorithm = current_app.config.get('JWT_ALGORITHM', 'HS256') # Decode the token data = jwt.decode(token, secret_key, algorithms=[algorithm]) # --- Use current_app to access extensions --- from ..extensions import mongo # Import here to avoid circular dependency user_id_str = data.get("user_id") if not user_id_str: return jsonify({"message": "Token payload missing user_id."}), 401 # Access the 'users' collection via the mongo instance current_user_doc = mongo.db.users.find_one({"_id": ObjectId(user_id_str)}) # --- End database access change --- if not current_user_doc: # Even if token is valid, user might have been deleted return jsonify({"message": "User associated with token not found."}), 401 # Convert ObjectId back to string for consistency if needed, # or pass the whole document as is. Passing document is often useful. # current_user_doc['_id'] = str(current_user_doc['_id']) # Optional conversion except jwt.ExpiredSignatureError: # Specific error for expired token return jsonify({"message": "Token has expired."}), 401 except jwt.InvalidTokenError as e: # Specific error for other JWT validation issues current_app.logger.warning(f"Invalid token encountered: {e}") # Log the specific error return jsonify({"message": "Token is invalid."}), 401 except Exception as e: # Catch other potential errors (e.g., ObjectId conversion, DB connection issues) current_app.logger.error(f"Error during token verification: {e}", exc_info=True) # Return a more generic message for unexpected return jsonify({"message": "Token verification failed."}), 401 # Inject the fetched user document into the decorated function return f(current_user_doc, *args, **kwargs) return decorated # This is a placeholder for background task functions. # For example, you could use Celery to process URLs asynchronously. def process_url(url_id): # Retrieve URL document by url_id, perform scraping, summarization, and update processingStatus. # This function should be called by a background worker. pass # This function will generate a pass key for frontend-backend communication def generate_passkey(): return secrets.token_hex(16)