05/06 Fix some notable and quality issues
This commit is contained in:
+4
-21
@@ -1,10 +1,9 @@
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, abort
|
||||
from flask_login import login_user, logout_user, login_required, current_user
|
||||
from urllib.parse import urlparse
|
||||
from app import db, limiter
|
||||
from app.models.user import User
|
||||
from app.utils.forms import LoginForm, UserForm, ProfileForm
|
||||
from app.utils.decorators import admin_required, supervisor_required
|
||||
from app.utils.decorators import admin_required, supervisor_required, safe_redirect_url
|
||||
import logging
|
||||
from app.utils.audit import log_action, ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE, ACTION_LOGIN, ACTION_LOGOUT
|
||||
|
||||
@@ -13,22 +12,6 @@ logger = logging.getLogger(__name__)
|
||||
bp = Blueprint('auth', __name__, url_prefix='/auth')
|
||||
|
||||
|
||||
def _safe_next(next_url: str | None) -> str:
|
||||
"""
|
||||
Validate that the redirect target is a relative URL on this host.
|
||||
Returns the safe URL, or the dashboard index if the URL is external/invalid.
|
||||
This prevents open-redirect attacks where an attacker crafts a login link
|
||||
containing next=https://evil.com to hijack post-login redirects.
|
||||
"""
|
||||
if not next_url:
|
||||
return url_for('dashboard.index')
|
||||
parsed = urlparse(next_url)
|
||||
# Reject any URL that specifies a network location (external host) or scheme
|
||||
if parsed.netloc or parsed.scheme:
|
||||
return url_for('dashboard.index')
|
||||
return next_url
|
||||
|
||||
|
||||
@bp.route('/login', methods=['GET', 'POST'])
|
||||
@limiter.limit('20 per minute; 5 per second')
|
||||
def login():
|
||||
@@ -52,7 +35,7 @@ def login():
|
||||
return render_template('auth/login.html', form=form)
|
||||
login_user(user, remember=form.remember_me.data)
|
||||
# Use validated next URL — never redirect blindly to request.args['next']
|
||||
next_page = _safe_next(request.args.get('next'))
|
||||
next_page = safe_redirect_url(request.args.get('next'))
|
||||
log_action(ACTION_LOGIN, 'User', user.id, user.username)
|
||||
flash(f'Welcome back, {user.username}!', 'success')
|
||||
return redirect(next_page)
|
||||
@@ -282,7 +265,7 @@ def toggle_active(user_id):
|
||||
f'account {action_label} by {current_user.username}',
|
||||
)
|
||||
flash(f'User {user.username} has been {action_label}.', 'success')
|
||||
return redirect(_safe_next(request.referrer) or url_for('auth.list_users'))
|
||||
return redirect(safe_redirect_url(request.referrer, fallback=url_for('auth.list_users')))
|
||||
|
||||
# ── Notification Matrix ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -334,4 +317,4 @@ def notification_matrix():
|
||||
matrix_roles = MATRIX_ROLES,
|
||||
defaults = MATRIX_DEFAULTS,
|
||||
state = state,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user