Files
max/max/auth/login.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

46 lines
1.3 KiB
Python

from flask import session
from max.db import get_user_by_email
from max.translations import t
from .hashing import BLF_CRYPT_PREFIX, check_password
from .passwords import rehash_password_if_needed
# Hash of a random, unknown password. It is checked for unknown users, so the
# response time does not tell whether an email exists.
DUMMY_HASH = (
BLF_CRYPT_PREFIX + "$2b$12$J27D9dEpQ5ff/I48HG05p.97oJGTO7UiaKGIbVuzV6nw0lo6gZ5wq"
)
LOGIN_FAILED_MESSAGE = "Email or password is wrong, or the account is deactivated"
def login(email, password):
"""Returns (error, None) if the login failed, else (None, user)"""
if not isinstance(email, str) or not isinstance(password, str):
return t(LOGIN_FAILED_MESSAGE), None
if not email or not password:
return t(LOGIN_FAILED_MESSAGE), None
user = get_user_by_email(email)
if user is None:
check_password(password, DUMMY_HASH)
return t(LOGIN_FAILED_MESSAGE), None
if not check_password(password, user.passwordhash):
return t(LOGIN_FAILED_MESSAGE), None
if not user.enabled:
return t(LOGIN_FAILED_MESSAGE), None
rehash_password_if_needed(user, password)
# Start a new session (new id, new CSRF token) against session fixation.
session.clear()
session["user_id"] = user.id
return None, user
def logout():
session.clear()