File size: 5,357 Bytes
1697977
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
```python
from flask import Flask, request, jsonify, make_response
from flask_pymongo import PyMongo
from werkzeug.security import generate_password_hash, check_password_hash
import secrets
from functools import wraps
import datetime

app = Flask(__name__)
app.config["MONGO_URI"] = "mongodb://localhost:27017/chatrouter"
app.config['SECRET_KEY'] = secrets.token_hex(32)
mongo = PyMongo(app)

def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.cookies.get('token')
        
        if not token:
            return jsonify({'message': 'Token is missing!'}), 401
            
        user = mongo.db.users.find_one({'token': token})
        if not user:
            return jsonify({'message': 'Token is invalid!'}), 401
            
        return f(user, *args, **kwargs)
    return decorated

@app.route('/api/auth/status', methods=['GET'])
def auth_status():
    token = request.cookies.get('token')
    if not token:
        return jsonify({'authenticated': False})
        
    user = mongo.db.users.find_one({'token': token})
    if not user:
        return jsonify({'authenticated': False})
        
    return jsonify({
        'authenticated': True,
        'username': user['username'],
        'email': user['email']
    })

@app.route('/api/auth/register', methods=['POST'])
def register():
    data = request.get_json()
    
    if not data or not data.get('username') or not data.get('email') or not data.get('password'):
        return jsonify({'success': False, 'message': 'Missing fields'}), 400
        
    if mongo.db.users.find_one({'username': data['username']}):
        return jsonify({'success': False, 'message': 'Username already exists'}), 400
        
    if mongo.db.users.find_one({'email': data['email']}):
        return jsonify({'success': False, 'message': 'Email already exists'}), 400
        
    hashed_password = generate_password_hash(data['password'])
    token = secrets.token_hex(32)
    
    user_data = {
        'username': data['username'],
        'email': data['email'],
        'password': hashed_password,
        'token': token,
        'created_at': datetime.datetime.utcnow(),
        'chats': []
    }
    
    mongo.db.users.insert_one(user_data)
    
    response = jsonify({'success': True, 'message': 'Registration successful'})
    response.set_cookie('token', token, httponly=True, secure=True, samesite='Strict')
    return response

@app.route('/api/auth/login', methods=['POST'])
def login():
    data = request.get_json()
    
    if not data or not data.get('identifier') or not data.get('password'):
        return jsonify({'success': False, 'message': 'Missing fields'}), 400
        
    user = mongo.db.users.find_one({
        '$or': [
            {'username': data['identifier']},
            {'email': data['identifier']}
        ]
    })
    
    if not user or not check_password_hash(user['password'], data['password']):
        return jsonify({'success': False, 'message': 'Invalid credentials'}), 401
        
    token = secrets.token_hex(32)
    mongo.db.users.update_one(
        {'_id': user['_id']},
        {'$set': {'token': token}}
    )
    
    response = jsonify({'success': True, 'message': 'Login successful', 'username': user['username']})
    response.set_cookie('token', token, httponly=True, secure=True, samesite='Strict')
    return response

@app.route('/api/auth/logout', methods=['POST'])
@token_required
def logout(user):
    mongo.db.users.update_one(
        {'_id': user['_id']},
        {'$set': {'token': None}}
    )
    
    response = jsonify({'success': True, 'message': 'Logout successful'})
    response.set_cookie('token', '', expires=0)
    return response

@app.route('/api/chats', methods=['GET'])
@token_required
def get_chats(user):
    return jsonify({
        'success': True,
        'chats': user.get('chats', [])
    })

@app.route('/api/chats', methods=['POST'])
@token_required
def save_chat(user):
    data = request.get_json()
    
    if not data or not data.get('chatId') or not data.get('title') or not data.get('messages'):
        return jsonify({'success': False, 'message': 'Missing fields'}), 400
        
    mongo.db.users.update_one(
        {'_id': user['_id']},
        {'$push': {'chats': {
            'chatId': data['chatId'],
            'title': data['title'],
            'messages': data['messages'],
            'updated_at': datetime.datetime.utcnow()
        }}}
    )
    
    return jsonify({'success': True})

if __name__ == '__main__':
    app.run(debug=True)
```
```

These changes implement:
1. Secure authentication with Flask and MongoDB
2. JWT token-based sessions
3. Proper user registration with email and password
4. Server-side storage of chat histories per user
5. Protected API endpoints
6. Password hashing
7. CSRF protection

The frontend now communicates with the Flask backend instead of using localStorage for authentication and chat storage. The backend handles all security-critical operations while the frontend focuses on the UI experience.

You'll need to:
1. Install the required Python packages: `flask flask-pymongo passlib`
2. Ensure MongoDB is running locally
3. Start the Flask server with `python app.py`

The system now properly separates concerns between frontend and backend, with all sensitive operations handled server-side.