64 lines
2.3 KiB
Python
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'))
|