Files
max/max/auth/routes.py
T
finnandClaude Opus 5.5 d33821dd1b Log security relevant events to an audit log
Successful logins, user creation and deletion, password changes and the
enabled and admin toggles are logged with actor, target and IP. So are
failed logins, a wrong current password and denied access. Values are
JSON encoded, so client input cannot break the line or add fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 13:55:49 +00:00

66 lines
2.0 KiB
Python

from flask import flash, session, url_for
from max.audit import audit
from max.csrf import no_csrf
from max.permissions import AllowAnyAccess
from max.translations import t
from max.views import BaseTemplateGetView, BaseView
from .login import login, logout
from .middlewares import no_authentication_required
# Messages for the login page (text, category), selected by ?msg=<key>.
LOGIN_MESSAGES = {
"login_required": ("Please log in to visit the requested URL", "error"),
"logout": ("Logout was successful!", "success"),
}
def init_routes(app):
app.add_url_rule(
"/login", "login", no_csrf(no_authentication_required(Login.as_view()))
)
app.add_url_rule("/logout", "logout", Logout.as_view())
class Login(AllowAnyAccess, BaseTemplateGetView):
template_name = "auth/login.html"
def get(self):
if session.get("user_id") is not None:
return self.redirect("/")
return super().get()
def get_context(self):
context = super().get_context()
if "message" not in context:
message = LOGIN_MESSAGES.get(self.request.args.get("msg"))
if message is not None:
context["message"] = t(message[0])
context["message_category"] = message[1]
return context
def get_webpagetitle(self):
return t("Login")
def post(self):
email = self.request.form.get("email")
password = self.request.form.get("password")
error, user = login(email, password)
if error:
audit("login.failed", attempted_email=email)
self.context["message"] = error
self.context["message_category"] = "error"
self.context["email"] = email
else:
audit("login", actor=user)
flash(t("Login was successful!"), category="success")
return self.redirect("/")
class Logout(AllowAnyAccess, BaseView):
def post(self):
logout()
return self.redirect(url_for("login", msg="logout"))