Skip to content

Commit 5bb0716

Browse files
committed
hotfix : cors
1 parent 1e8c74b commit 5bb0716

1 file changed

Lines changed: 35 additions & 129 deletions

File tree

servidor.py

Lines changed: 35 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,27 @@
1919
along with this program. If not, see <https://www.gnu.org/licenses/>.
2020
2121
'''
22-
2322
from flask import Flask, request, jsonify, redirect, url_for, send_from_directory, render_template
2423
from flask_socketio import SocketIO, join_room, leave_room, send
2524
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
2625
from werkzeug.utils import secure_filename
2726
from flask_argon2 import Argon2
28-
import os,json
27+
import os, json
2928
from argon2 import PasswordHasher
3029

3130
# --- CONFIGURACIÓN INICIAL ---
3231
app = Flask(__name__)
33-
#socketio = SocketIO(app, async_mode="eventlet")
34-
socketio = SocketIO(app, cors_allowed_origins="*") # este es el server real
35-
36-
37-
# Se recomienda usar una variable de entorno para la clave secreta
32+
socketio = SocketIO(app, cors_allowed_origins="*") # SocketIO envuelve a Flask
3833
app.secret_key = os.environ.get("SECRET_KEY", "a-very-secret-key-for-dev")
3934
argon2 = Argon2(app)
40-
#socketio = SocketIO(app)
35+
ph = PasswordHasher()
4136

42-
# --- CONFIGURACIÓN DE CARPETAS Y USUARIOS ---
37+
# --- CONFIGURACIÓN DE CARPETAS ---
4338
UPLOAD_FOLDER = './cuarentena'
4439
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
4540
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
4641

47-
# En un entorno de producción, las contraseñas nunca deben estar hardcodeadas.
48-
# Se generan hashes para las contraseñas por defecto.
49-
'''
50-
usuarios = {
51-
'admin': {'password': argon2.generate_password_hash('admin123'), 'rol': 'administrator'},
52-
'cliente': {'password': argon2.generate_password_hash('cliente123'), 'rol': 'cliente'},
53-
'usuario': {'password': argon2.generate_password_hash('usuario123'), 'rol': 'usuario'},
54-
}
55-
'''
56-
#import os, json
57-
#from argon2 import PasswordHasher
58-
59-
ph = PasswordHasher()
60-
61-
# Diccionario inicial con los 3 base
42+
# --- USUARIOS BASE ---
6243
users = {
6344
os.getenv("ADMIN_USER", "admin"): {
6445
"password": ph.hash(os.getenv("ADMIN_PASS", "admin123")),
@@ -74,24 +55,9 @@
7455
}
7556
}
7657

77-
# Cargar DEMO_USERS desde variable de entorno
78-
demo_users_env = os.getenv("DEMO_USERS", "[]")
79-
# import os, json
80-
81-
demo_users = json.loads(os.getenv("DEMO_USERS", "[]"))
58+
# --- DEMO USERS DESDE ENV ---
8259
try:
83-
for user in demo_users:
84-
print("Cargando usuario demo:", user["username"], "rol:", user["role"])
85-
demo_users = json.loads(demo_users_env)
86-
for u in demo_users:
87-
users[u["username"]] = {
88-
"password": ph.hash(u["password"]),
89-
"role": u.get("role", u['role'])
90-
}
91-
except Exception as e:
92-
print(f"[WARN] No se pudieron cargar demo_users: {e}")
93-
94-
'''try:
60+
demo_users_env = os.getenv("DEMO_USERS", "[]")
9561
demo_users = json.loads(demo_users_env)
9662
for u in demo_users:
9763
users[u["username"]] = {
@@ -100,29 +66,27 @@
10066
}
10167
except Exception as e:
10268
print(f"[WARN] No se pudieron cargar demo_users: {e}")
103-
'''
10469

105-
# --- GESTIÓN DE LOGIN Y USUARIOS ---
70+
# --- LOGIN MANAGER ---
10671
login_manager = LoginManager(app)
107-
login_manager.login_view = 'login' # Redirige a /login si no está autenticado
72+
login_manager.login_view = 'login'
10873

10974
class Usuario(UserMixin):
110-
def __init__(self, username):
75+
def __init__(self, username, role):
11176
self.id = username
112-
self.rol = usuarios[username]['rol']
77+
self.rol = role
11378

11479
@login_manager.user_loader
11580
def load_user(user_id):
116-
if user_id in usuarios:
117-
return Usuario(user_id)
81+
if user_id in users:
82+
return Usuario(user_id, users[user_id]['role'])
11883
return None
11984

120-
# --- RUTAS WEB (VISTAS) ---
121-
@app.get("/")
122-
def root():
123-
return {"status": "ok"}
85+
# --- RUTAS ---
12486
@app.route('/')
12587
def home():
88+
if current_user.is_authenticated:
89+
return redirect(url_for('inicio'))
12690
return redirect(url_for('login'))
12791

12892
@app.route('/login', methods=['GET', 'POST'])
@@ -132,9 +96,13 @@ def login():
13296
if request.method == 'POST':
13397
user = request.form['usuario']
13498
password = request.form['clave']
135-
if user in usuarios and argon2.check_password_hash(usuarios[user]['password'], password):
136-
login_user(Usuario(user))
137-
return redirect(url_for('inicio'))
99+
if user in users:
100+
try:
101+
ph.verify(users[user]['password'], password)
102+
login_user(Usuario(user, users[user]['role']))
103+
return redirect(url_for('inicio'))
104+
except Exception:
105+
pass
138106
return render_template("login.html", error="Credenciales inválidas.")
139107
return render_template("login.html")
140108

@@ -149,8 +117,7 @@ def logout():
149117
def inicio():
150118
return render_template('inicio.html', current_user=current_user)
151119

152-
# --- FUNCIONALIDAD DE ARCHIVOS (MicroNAS) ---
153-
120+
# --- FUNCIONALIDAD DE ARCHIVOS ---
154121
@app.route('/subir', methods=['GET', 'POST'])
155122
@login_required
156123
def subir():
@@ -162,8 +129,6 @@ def subir():
162129
archivo = request.files['archivo']
163130
if archivo.filename == '':
164131
return 'No se seleccionó ningún archivo', 400
165-
# Audit file -> I only trust UTF-8 (Concepto)
166-
# Aquí iría la lógica para validar el tipo de archivo antes de guardarlo.
167132
filename = secure_filename(archivo.filename)
168133
archivo.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
169134
return redirect(url_for('listar'))
@@ -188,112 +153,53 @@ def eliminar(nombre):
188153
try:
189154
os.remove(os.path.join(UPLOAD_FOLDER, secure_filename(nombre)))
190155
except FileNotFoundError:
191-
pass # Ignorar si el archivo no existe
156+
pass
192157
return redirect(url_for('listar'))
193158

194-
# --- RUTA PARA LA INTERFAZ DEL CHAT ---
195159
@app.route('/chat')
196160
@login_required
197161
def chat():
198162
return render_template('chat.html', current_user=current_user)
199163

200-
201-
# --- LÓGICA DEL SERVIDOR DE CHAT CON SOCKET.IO ---
202-
203-
# Almacenamiento en memoria para las salas y contraseñas (MVP)
204-
# En un sistema real, esto debería estar en una base de datos.
205-
chat_rooms = {}
164+
# --- SOCKET.IO ---
165+
chat_rooms = {}
206166

207167
@socketio.on('join')
208168
def on_join(data):
209-
"""
210-
Unirse a una sala de chat.
211-
"""
212169
username = current_user.id
213170
room_code = data['room']
214171
password = data['password']
215172
is_group = data.get('is_group', False)
216173

217-
# Lógica de "candado" y contraseña
218174
if room_code not in chat_rooms:
219175
chat_rooms[room_code] = argon2.generate_password_hash(password)
220-
room_owner = True
221176
else:
222-
room_owner = False
223177
if not argon2.check_password_hash(chat_rooms[room_code], password):
224-
send({'msg': 'Contraseña de la sala incorrecta.', 'type': 'error'})
178+
send({'msg': 'Contraseña incorrecta.', 'type': 'error'})
225179
return
226180

227181
join_room(room_code)
228-
229-
# Notificar a la sala que un nuevo usuario se ha unido
230-
message_data = {
231-
'msg': f"👋 {username} se ha unido a la sala.",
232-
'user': 'Servidor',
233-
'is_group': is_group
234-
}
235-
send(message_data, to=room_code)
236-
182+
send({'msg': f"👋 {username} se ha unido.", 'user': 'Servidor', 'is_group': is_group}, to=room_code)
237183

238184
@socketio.on('leave')
239185
def on_leave(data):
240-
"""
241-
Salir de una sala de chat.
242-
"""
243186
username = current_user.id
244187
room_code = data['room']
245-
is_group = data.get('is_group', False)
246-
247188
leave_room(room_code)
248-
249-
message_data = {
250-
'msg': f"🚪 {username} ha salido de la sala.",
251-
'user': 'Servidor',
252-
'is_group': is_group
253-
}
254-
send(message_data, to=room_code)
255-
189+
send({'msg': f"🚪 {username} ha salido.", 'user': 'Servidor'}, to=room_code)
256190

257191
@socketio.on('message')
258192
def handle_message(data):
259-
"""
260-
Recibir y reenviar mensajes.
261-
"""
262193
username = current_user.id
263194
room = data['room']
264-
message = data['msg']
195+
msg = data['msg']
265196
is_group = data.get('is_group', False)
266-
267-
# No guardar mensajes si es un chat grupal
268-
if is_group:
269-
# El mensaje es efímero, solo se reenvía
270-
pass
271-
else:
272-
# Aquí iría la lógica para guardar el mensaje en una base de datos o archivo
273-
# Para el MVP, simplemente lo reenviamos.
274-
pass
275-
276-
response_data = {
277-
'msg': message,
278-
'user': username,
279-
'is_group': is_group
280-
}
281-
282-
send(response_data, to=room)
283-
197+
send({'msg': msg, 'user': username, 'is_group': is_group}, to=room)
284198

285-
# --- INICIO DE LA APLICACIÓN ---
199+
# --- INICIO ---
286200
if __name__ == '__main__':
287-
# Usar host='0.0.0.0' para que sea accesible en la red local.
288-
# El puerto 8000 es el principal. Otros servicios podrían correr en otros puertos
289-
# usando el concepto de 'administrador_hilos.py' si fuera necesario.
290201
port = int(os.environ.get("PORT", 8080))
291202
socketio.run(app, host='0.0.0.0', port=port)
292203

293-
# 👇 agregado: esto es para gunicorn
294-
# le damos un alias 'app' que apunta a socketio
295-
#app = socketio
296-
socketio = SocketIO(app, async_mode="eventlet")
297-
application = socketio # Gunicorn usará esto
298-
299-
204+
# 👉 Para gunicorn/render
205+
application = app

0 commit comments

Comments
 (0)