File size: 3,049 Bytes
7d66e3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import os
import jwt
from datetime import datetime, timedelta
from functools import wraps
from flask import request, jsonify
from models.user import User

# Secret key for JWT
SECRET_KEY = os.environ.get('JWT_SECRET')

def generate_token(user_id, permissions, expiration_hours=24*30):  # 30-day token by default
    """Generate JWT token for authentication"""
    payload = {
        'user_id': str(user_id),
        'permissions': permissions,
        'exp': datetime.utcnow() + timedelta(hours=expiration_hours)
    }
    return jwt.encode(payload, SECRET_KEY, algorithm='HS256')

def decode_token(token):
    """Decode JWT token and return payload"""
    try:
        return jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
    except:
        return None

def token_required(f):
    """
    Fixed decorator for routes that require a valid token.
    This version passes current_user as a kwarg instead of an arg,
    avoiding parameter conflicts with URL path parameters.
    """
    @wraps(f)
    def decorated(*args, **kwargs):
        token = None
        auth_header = request.headers.get('Authorization')
        
        if auth_header:
            if auth_header.startswith('Bearer '):
                token = auth_header.split(" ")[1]
        
        if not token:
            return jsonify({'message': 'Token is missing'}), 401
        
        data = decode_token(token)
        if not data:
            return jsonify({'message': 'Token is invalid or expired'}), 401
        
        current_user = User.find_by_id(data['user_id'])
        if not current_user:
            return jsonify({'message': 'User not found'}), 401
        
        # Pass current_user as a keyword argument instead of positional argument
        kwargs['current_user'] = current_user
        return f(*args, **kwargs)
    
    return decorated

def admin_required(f):
    """
    Fixed decorator for routes that require admin permissions.
    This version passes current_user as a kwarg instead of an arg,
    avoiding parameter conflicts with URL path parameters.
    """
    @wraps(f)
    def decorated(*args, **kwargs):
        token = None
        auth_header = request.headers.get('Authorization')
        
        if auth_header:
            if auth_header.startswith('Bearer '):
                token = auth_header.split(" ")[1]
        
        if not token:
            return jsonify({'message': 'Token is missing'}), 401
        
        data = decode_token(token)
        if not data:
            return jsonify({'message': 'Token is invalid or expired'}), 401
        
        if data['permissions'] != 'Admin':
            return jsonify({'message': 'Admin permissions required'}), 403
        
        current_user = User.find_by_id(data['user_id'])
        if not current_user:
            return jsonify({'message': 'User not found'}), 401
        
        # Pass current_user as a keyword argument instead of positional argument
        kwargs['current_user'] = current_user
        return f(*args, **kwargs)
    
    return decorated