Spaces:
Sleeping
Sleeping
| import os, sqlite3, secrets, smtplib, hashlib | |
| from email.mime.text import MIMEText | |
| from email.mime.multipart import MIMEMultipart | |
| from flask import Flask, request, jsonify | |
| import stripe | |
| app = Flask(__name__) | |
| STRIPE_SECRET = os.environ.get("STRIPE_SECRET_KEY", "") | |
| STRIPE_WEBHOOK = os.environ.get("STRIPE_WEBHOOK_SECRET", "") | |
| GMAIL_USER = os.environ.get("GMAIL_USER", "dayron100813@gmail.com") | |
| GMAIL_PASS = os.environ.get("GMAIL_PASS", "") | |
| DB_PATH = "/data/usuarios.db" | |
| AUTH_SECRET = os.environ.get("AUTH_SECRET", "fenix-secret-interno") | |
| stripe.api_key = STRIPE_SECRET | |
| PLANES = { | |
| "hobby": {"apps_dia": 3, "nombre": "Fénix Hobby"}, | |
| "pro": {"apps_dia": 8, "nombre": "Fénix Pro"}, | |
| "agencia": {"apps_dia": 15, "nombre": "Fénix Agencia"}, | |
| } | |
| def get_db(): | |
| os.makedirs("/data", exist_ok=True) | |
| conn = sqlite3.connect(DB_PATH) | |
| conn.row_factory = sqlite3.Row | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS usuarios ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| email TEXT UNIQUE NOT NULL, | |
| password_hash TEXT NOT NULL, | |
| plan TEXT NOT NULL, | |
| stripe_customer_id TEXT, | |
| activo INTEGER DEFAULT 1, | |
| apps_hoy INTEGER DEFAULT 0, | |
| fecha_reset TEXT DEFAULT '', | |
| creado_en TEXT DEFAULT (datetime('now')) | |
| ) | |
| """) | |
| conn.commit() | |
| return conn | |
| def hash_pass(pw): | |
| return hashlib.sha256(pw.encode()).hexdigest() | |
| def enviar_email(dest, asunto, cuerpo_html): | |
| try: | |
| msg = MIMEMultipart("alternative") | |
| msg["Subject"] = asunto | |
| msg["From"] = GMAIL_USER | |
| msg["To"] = dest | |
| msg.attach(MIMEText(cuerpo_html, "html")) | |
| with smtplib.SMTP_SSL("smtp.gmail.com", 465) as s: | |
| s.login(GMAIL_USER, GMAIL_PASS) | |
| s.sendmail(GMAIL_USER, dest, msg.as_string()) | |
| print(f"[EMAIL] Enviado a {dest}") | |
| except Exception as e: | |
| print(f"[EMAIL] Error: {e}") | |
| def crear_usuario(email, plan, stripe_customer_id=""): | |
| password = secrets.token_urlsafe(10) | |
| db = get_db() | |
| try: | |
| db.execute( | |
| "INSERT INTO usuarios (email, password_hash, plan, stripe_customer_id) VALUES (?,?,?,?)", | |
| (email, hash_pass(password), plan, stripe_customer_id) | |
| ) | |
| db.commit() | |
| except sqlite3.IntegrityError: | |
| # Usuario ya existe — actualizar plan | |
| db.execute("UPDATE usuarios SET plan=?, activo=1 WHERE email=?", (plan, email)) | |
| db.commit() | |
| password = None # no mandamos nueva contraseña si ya existe | |
| db.close() | |
| return password | |
| def webhook(): | |
| payload = request.data | |
| sig = request.headers.get("Stripe-Signature", "") | |
| try: | |
| event = stripe.Webhook.construct_event(payload, sig, STRIPE_WEBHOOK) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 400 | |
| if event["type"] == "checkout.session.completed": | |
| session = event["data"]["object"] | |
| email = session.get("customer_details", {}).get("email", "") | |
| customer = session.get("customer", "") | |
| amount = session.get("amount_total", 0) | |
| # Detectar plan por precio | |
| if amount <= 1900: | |
| plan = "hobby" | |
| elif amount <= 7900: | |
| plan = "pro" | |
| else: | |
| plan = "agencia" | |
| if email: | |
| password = crear_usuario(email, plan, customer) | |
| nombre_plan = PLANES[plan]["nombre"] | |
| if password: | |
| cuerpo = f""" | |
| <h2>🔥 Bienvenido a Fénix-Forja</h2> | |
| <p>Tu cuenta ha sido creada con el plan <b>{nombre_plan}</b>.</p> | |
| <p><b>Email:</b> {email}<br> | |
| <b>Contraseña:</b> {password}</p> | |
| <p>Accede aquí: <a href="https://cristobal299-fenix-fabfica.hf.space"> | |
| https://cristobal299-fenix-fabfica.hf.space</a></p> | |
| <p>Límite: {PLANES[plan]['apps_dia']} apps por día.</p> | |
| <hr><p style="color:gray;font-size:12px">Fénix-Forja — Fábrica autónoma de apps</p> | |
| """ | |
| enviar_email(email, f"🔥 Tus credenciales de Fénix-Forja ({nombre_plan})", cuerpo) | |
| print(f"[WEBHOOK] Usuario {email} → plan {plan}") | |
| return jsonify({"ok": True}) | |
| def verificar(): | |
| """Fénix llama aquí para comprobar login. Requiere AUTH_SECRET.""" | |
| data = request.json or {} | |
| secret = data.get("secret", "") | |
| if secret != AUTH_SECRET: | |
| return jsonify({"ok": False, "error": "No autorizado"}), 403 | |
| email = data.get("email", "").strip().lower() | |
| password = data.get("password", "") | |
| if not email or not password: | |
| return jsonify({"ok": False, "error": "Faltan datos"}) | |
| db = get_db() | |
| user = db.execute( | |
| "SELECT * FROM usuarios WHERE email=? AND password_hash=? AND activo=1", | |
| (email, hash_pass(password)) | |
| ).fetchone() | |
| db.close() | |
| if not user: | |
| return jsonify({"ok": False, "error": "Credenciales incorrectas"}) | |
| return jsonify({ | |
| "ok": True, | |
| "plan": user["plan"], | |
| "apps_dia": PLANES.get(user["plan"], {}).get("apps_dia", 3), | |
| "email": user["email"], | |
| }) | |
| def contador(): | |
| """Incrementa el contador de apps del día y comprueba el límite.""" | |
| data = request.json or {} | |
| secret = data.get("secret", "") | |
| if secret != AUTH_SECRET: | |
| return jsonify({"ok": False}), 403 | |
| email = data.get("email", "").strip().lower() | |
| from datetime import date | |
| hoy = str(date.today()) | |
| db = get_db() | |
| user = db.execute("SELECT * FROM usuarios WHERE email=?", (email,)).fetchone() | |
| if not user: | |
| db.close() | |
| return jsonify({"ok": False, "error": "Usuario no encontrado"}) | |
| apps_hoy = user["apps_hoy"] if user["fecha_reset"] == hoy else 0 | |
| limite = PLANES.get(user["plan"], {}).get("apps_dia", 3) | |
| if apps_hoy >= limite: | |
| db.close() | |
| return jsonify({"ok": False, "error": f"Límite diario alcanzado ({limite} apps/día)", "limite": limite}) | |
| db.execute( | |
| "UPDATE usuarios SET apps_hoy=?, fecha_reset=? WHERE email=?", | |
| (apps_hoy + 1, hoy, email) | |
| ) | |
| db.commit() | |
| db.close() | |
| return jsonify({"ok": True, "apps_hoy": apps_hoy + 1, "limite": limite}) | |
| def health(): | |
| return jsonify({"status": "ok", "service": "fenix-auth"}) | |
| if __name__ == "__main__": | |
| app.run(host="0.0.0.0", port=7860) | |