Files
2025-07-27 21:49:34 -04:00

64 lines
2.3 KiB
Python

from flask import Blueprint, render_template, request, redirect, url_for, session, abort
from functools import wraps
from datetime import datetime
from app.models import User
from app.supabase_client import get_supabase
auth_bp = Blueprint('auth', __name__)
def log_auth_event(user_id: str, action: str, details: str = None):
"""Log authentication events to audit trail"""
supabase = get_supabase()
event_data = {
'user_id': user_id,
'action': action,
'timestamp': datetime.utcnow().isoformat(),
'details': details or '',
'ip_address': request.remote_addr
}
try:
supabase.table('auth_audit').insert(event_data).execute()
except Exception as e:
print(f"Failed to log auth event: {e}")
def role_required(role):
"""Decorator to require specific role"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if role == 'calibrate' and not session.get('can_calibrate'):
abort(403)
if role == 'review' and not session.get('can_review'):
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
email = request.form.get('email')
user = User.get_by_email(email)
if user:
session['user_id'] = user.id
session['user_name'] = user.name
session['can_calibrate'] = user.can_calibrate
session['can_review'] = user.can_review
log_auth_event(user.id, 'login', f'IP: {request.remote_addr}')
return redirect(url_for('index'))
log_auth_event('unknown', 'failed_login', f'Email: {email}, IP: {request.remote_addr}')
return render_template('auth/login.html', error="Invalid user")
# GET request - show login form
users = User.get_all()
if not users:
return render_template('auth/login.html', users=[], error="No users exist in database")
return render_template('auth/login.html', users=users)
@auth_bp.route('/logout')
def logout():
if 'user_id' in session:
log_auth_event(session['user_id'], 'logout')
session.clear()
return redirect(url_for('auth.login'))