fix(csrf): token valido quanto la sessione, errorhandler JSON per fetch (#12)
WTF_CSRF_TIME_LIMIT=None: la pagina di misura resta aperta ore, il token a 1h scadeva a metà turno. Aggiunto errorhandler(CSRFError) in app.py: risposte JSON/fetch (Accept, Content-Type, X-Requested-With) ricevono 400 JSON con csrf_expired, le altre un flash + redirect. Lato B1 (task_execute.html) resta da gestire client-side, fuori da questo commit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,9 +5,9 @@ import re
|
||||
from datetime import date
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from flask import Flask, redirect, url_for, session, request
|
||||
from flask_babel import Babel
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
from flask import Flask, flash, jsonify, redirect, url_for, session, request
|
||||
from flask_babel import Babel, gettext as _
|
||||
from flask_wtf.csrf import CSRFError, CSRFProtect
|
||||
from markupsafe import Markup, escape
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
|
||||
@@ -101,6 +101,36 @@ def create_app() -> Flask:
|
||||
referrer = None
|
||||
return redirect(referrer or url_for("auth.login"))
|
||||
|
||||
@app.errorhandler(CSRFError)
|
||||
def handle_csrf_error(error):
|
||||
"""CSRF token expired or missing (#12): a stale page, not a network failure.
|
||||
|
||||
WTF_CSRF_TIME_LIMIT is None so a token only goes bad with the session
|
||||
itself, but a tab left open across a forced logout (or missing token)
|
||||
still lands here. Fetch/JSON callers get a body they can branch on
|
||||
instead of an HTML error page that breaks `response.json()`; page
|
||||
loads get a flash and a redirect back to where they were.
|
||||
"""
|
||||
wants_json = (
|
||||
request.accept_mimetypes.best_match(["application/json", "text/html"])
|
||||
== "application/json"
|
||||
or (request.content_type or "").startswith("application/json")
|
||||
or request.headers.get("X-Requested-With") == "XMLHttpRequest"
|
||||
)
|
||||
if wants_json:
|
||||
return (
|
||||
jsonify({"error": True, "csrf_expired": True, "detail": error.description}),
|
||||
400,
|
||||
)
|
||||
|
||||
flash(_("Sessione scaduta: effettua nuovamente l'accesso."), "error")
|
||||
referrer = request.referrer
|
||||
if referrer:
|
||||
parsed = urlparse(referrer)
|
||||
if parsed.netloc and parsed.netloc != request.host:
|
||||
referrer = None
|
||||
return redirect(referrer or url_for("auth.login"))
|
||||
|
||||
@app.template_filter("rich_text")
|
||||
def rich_text_filter(value):
|
||||
"""Render a task description keeping its line breaks and its bold.
|
||||
|
||||
Reference in New Issue
Block a user