121 lines
3.8 KiB
Python
121 lines
3.8 KiB
Python
"""
|
|
Authentication routes for SneakyScanner.
|
|
|
|
Provides login and logout endpoints for user authentication.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from flask import Blueprint, current_app, flash, redirect, render_template, request, url_for
|
|
from flask_login import login_user, logout_user, current_user
|
|
|
|
from web.auth.models import User
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
bp = Blueprint('auth', __name__)
|
|
|
|
|
|
@bp.route('/login', methods=['GET', 'POST'])
|
|
def login():
|
|
"""
|
|
Login page and authentication endpoint.
|
|
|
|
GET: Render login form
|
|
POST: Authenticate user and create session
|
|
|
|
Returns:
|
|
GET: Rendered login template
|
|
POST: Redirect to dashboard on success, login page with error on failure
|
|
"""
|
|
# If already logged in, redirect to dashboard
|
|
if current_user.is_authenticated:
|
|
return redirect(url_for('main.dashboard'))
|
|
|
|
# Check if password is set
|
|
if not User.has_password_set(current_app.db_session):
|
|
flash('Application password not set. Please contact administrator.', 'error')
|
|
logger.warning("Login attempted but no password is set")
|
|
return render_template('login.html', password_not_set=True)
|
|
|
|
if request.method == 'POST':
|
|
password = request.form.get('password', '')
|
|
|
|
# Authenticate user
|
|
user = User.authenticate(password, current_app.db_session)
|
|
|
|
if user:
|
|
# Login successful
|
|
login_user(user, remember=request.form.get('remember', False))
|
|
logger.info(f"User logged in successfully from {request.remote_addr}")
|
|
|
|
# Redirect to next page or dashboard
|
|
next_page = request.args.get('next')
|
|
if next_page:
|
|
return redirect(next_page)
|
|
return redirect(url_for('main.dashboard'))
|
|
else:
|
|
# Login failed
|
|
flash('Invalid password', 'error')
|
|
logger.warning(f"Failed login attempt from {request.remote_addr}")
|
|
|
|
return render_template('login.html')
|
|
|
|
|
|
@bp.route('/logout')
|
|
def logout():
|
|
"""
|
|
Logout endpoint.
|
|
|
|
Destroys the user session and redirects to login page.
|
|
|
|
Returns:
|
|
Redirect to login page
|
|
"""
|
|
if current_user.is_authenticated:
|
|
logger.info(f"User logged out from {request.remote_addr}")
|
|
logout_user()
|
|
flash('You have been logged out successfully', 'info')
|
|
|
|
return redirect(url_for('auth.login'))
|
|
|
|
|
|
@bp.route('/setup', methods=['GET', 'POST'])
|
|
def setup():
|
|
"""
|
|
Initial password setup page.
|
|
|
|
Only accessible when no password is set. Allows setting the application password.
|
|
|
|
Returns:
|
|
GET: Rendered setup template
|
|
POST: Redirect to login page on success
|
|
"""
|
|
# If password already set, redirect to login
|
|
if User.has_password_set(current_app.db_session):
|
|
flash('Password already set. Please login.', 'info')
|
|
return redirect(url_for('auth.login'))
|
|
|
|
if request.method == 'POST':
|
|
password = request.form.get('password', '')
|
|
confirm_password = request.form.get('confirm_password', '')
|
|
|
|
# Validate passwords
|
|
if not password:
|
|
flash('Password is required', 'error')
|
|
elif len(password) < 8:
|
|
flash('Password must be at least 8 characters', 'error')
|
|
elif password != confirm_password:
|
|
flash('Passwords do not match', 'error')
|
|
else:
|
|
# Set password
|
|
from web.utils.settings import PasswordManager, SettingsManager
|
|
settings_manager = SettingsManager(current_app.db_session)
|
|
PasswordManager.set_app_password(settings_manager, password)
|
|
|
|
logger.info(f"Application password set from {request.remote_addr}")
|
|
flash('Password set successfully! You can now login.', 'success')
|
|
return redirect(url_for('auth.login'))
|
|
|
|
return render_template('setup.html')
|