from flask import redirect, render_template, request, session, url_for import auth from core.flask_app import app @app.route("/login", methods=["GET", "POST"]) def login(): if session.get("user_id"): return redirect(url_for("index")) error = None email = "" next_url = request.values.get("next") or "" if not (next_url.startswith("/") and not next_url.startswith("//")): next_url = "" if request.method == "POST": email = request.form.get("email", "").strip() password = request.form.get("password", "") next_url = request.form.get("next") or next_url user = auth.get_user_by_email(email) # Anti-bruteforce (voir auth/rate_limit.py) : vérifié AVANT le mot # de passe lui-même — un compte verrouillé ne doit même pas # apprendre si le mot de passe tapé était le bon. locked_seconds = auth.seconds_locked_remaining(user) if user else 0 if locked_seconds: error = auth.lockout_message(locked_seconds) elif not user or not auth.verify_password(user, password): if user: just_locked_minutes = auth.record_failed_attempt(user["id"]) if just_locked_minutes: error = auth.lockout_message(just_locked_minutes * 60) if not error: error = "Adresse email ou mot de passe incorrect." else: # Mot de passe correct, mais pas encore connecté : le second # facteur (TOTP) reste à vérifier — voir login_2fa.py. Session # "en attente" distincte de "user_id" (la vraie connexion), # pour qu'un mot de passe seul ne suffise jamais à se connecter. session["pending_login_user_id"] = user["id"] session["pending_login_next"] = next_url return redirect(url_for("login_2fa")) return render_template("auth/login.html", error=error, email=email, next_url=next_url)