modified: web/app.py

modified:   web/blueprints/auth.py
	modified:   web/blueprints/group_admin.py
	modified:   web/blueprints/site_admin.py
	new file:   web/limiter.py
	modified:   web/panel_db.py
	modified:   web/requirements.txt
	new file:   web/templates/429.html
	new file:   web/templates/admin/audit_log.html
	modified:   web/templates/admin/base.html
This commit is contained in:
simon
2026-04-14 13:02:41 +02:00
parent 452d50e5b5
commit 3b78f5dfb1
10 changed files with 564 additions and 35 deletions

View File

@@ -5,18 +5,21 @@ Getrennte Login-Seiten für Site-Admins und normale Nutzer/Gruppen-Admins.
import json
from datetime import datetime
from flask import Blueprint, render_template, request, redirect, url_for, session, flash
from panel_db import accept_group_invite, check_login, get_invite_by_token, get_user_groups
from panel_db import accept_group_invite, check_login, get_invite_by_token, get_user_groups, log_audit_event
from limiter import limiter
auth = Blueprint("auth", __name__)
@auth.route("/login", methods=["GET", "POST"])
@limiter.limit("15 per minute", methods=["POST"])
def login():
if session.get("user_id"):
return redirect(url_for("panel.dashboard"))
error = None
if request.method == "POST":
user = check_login(request.form.get("username", ""), request.form.get("password", ""))
username = request.form.get("username", "")
user = check_login(username, request.form.get("password", ""))
if user and user["is_site_admin"]:
flash("Please use the Site Admin login.", "warning")
return redirect(url_for("auth.admin_login"))
@@ -26,29 +29,56 @@ def login():
error = "You are not assigned to any group. Please contact an admin."
else:
_set_user_session(user, groups)
log_audit_event(
user["id"], user["username"], "user.login",
entity_type="user", entity_id=user["id"],
ip_address=request.remote_addr,
)
return redirect(url_for("panel.dashboard"))
else:
log_audit_event(
None, None, "user.login_failed",
details={"username": username},
ip_address=request.remote_addr,
)
error = "Incorrect username or password."
return render_template("auth/login.html", error=error)
@auth.route("/admin/login", methods=["GET", "POST"])
@limiter.limit("10 per minute", methods=["POST"])
def admin_login():
if session.get("is_site_admin"):
return redirect(url_for("site_admin.dashboard"))
error = None
if request.method == "POST":
user = check_login(request.form.get("username", ""), request.form.get("password", ""))
username = request.form.get("username", "")
user = check_login(username, request.form.get("password", ""))
if user and user["is_site_admin"]:
session["user_id"] = user["id"]
session["username"] = user["username"]
session["is_site_admin"] = True
session["group_id"] = None
session["permissions"] = {}
log_audit_event(
user["id"], user["username"], "admin.login",
entity_type="user", entity_id=user["id"],
ip_address=request.remote_addr,
)
return redirect(url_for("site_admin.dashboard"))
elif user:
log_audit_event(
user["id"], user["username"], "admin.login_failed",
details={"reason": "no_admin_privileges"},
ip_address=request.remote_addr,
)
error = "No Site Admin privileges."
else:
log_audit_event(
None, None, "admin.login_failed",
details={"username": username},
ip_address=request.remote_addr,
)
error = "Incorrect username or password."
return render_template("auth/admin_login.html", error=error)
@@ -74,6 +104,7 @@ def switch_group(group_id):
@auth.route("/invite/<token>", methods=["GET", "POST"])
@limiter.limit("20 per minute", methods=["POST"])
def accept_invite(token):
if session.get("user_id"):
return redirect(url_for("panel.dashboard"))
@@ -103,6 +134,14 @@ def accept_invite(token):
if result.get("error") == "username_or_email_taken":
error = "The invited username or email is already in use. Please contact your administrator."
else:
log_audit_event(
result.get("user_id"), invite["invited_username"],
"invite.accepted",
entity_type="invite", entity_id=invite["id"],
details={"group_id": invite.get("group_id"), "role": invite.get("role")},
group_id=invite.get("group_id"),
ip_address=request.remote_addr,
)
flash("Your account has been created. You can now sign in.", "success")
return redirect(url_for("auth.login"))