fenix-auth / app.py
Tu Nombre
feat: backend auth Stripe + login + contador
57bd6af
Raw
History Blame Contribute Delete
6.62 kB
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
@app.route("/webhook", methods=["POST"])
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})
@app.route("/verificar", methods=["POST"])
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"],
})
@app.route("/contador", methods=["POST"])
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})
@app.route("/health")
def health():
return jsonify({"status": "ok", "service": "fenix-auth"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860)