Un jeton unique par session (core/csrf.py, exposé côté Jinja via csrf_token()) est vérifié sur toute requête non-GET par un before_request (core/csrf_guard.py), dans le même esprit que core/auth_guard.py : une seule garde globale plutôt que de toucher aux ~90 routes existantes une par une. L'app entière fait déjà transiter ses formulaires par fetch() : pjax.js intercepte chaque <form> interne et le transforme lui-même en requête fetch (aucun usage de l'attribut d'échappement data-no-pjax nulle part dans le repo, confirmé par grep). Il suffit donc de patcher window.fetch UNE SEULE FOIS (static/csrf_fetch.js) pour y ajouter automatiquement l'en-tête X-CSRFToken sur toute requête non-GET, formulaires pjax comme fetch() écrits à la main dans screen_edit.html/game_dashboard.html/ play.html — sans modifier un seul appel existant. La vérification est désactivée quand app.config["TESTING"] est actif (même convention que Flask-WTF/WTF_CSRF_ENABLED), pour ne pas avoir à ajouter le jeton aux ~170 tests existants qui appellent les routes directement via le client de test Flask. tests/test_csrf.py réactive volontairement la garde pour la mettre à l'épreuve pour de vrai (GET jamais bloqué, POST sans jeton/avec mauvais jeton -> 400, POST avec le bon jeton via l'en-tête ou le champ de formulaire -> succès). templates/play.html reçoit les mêmes deux balises que base.html car il est autonome (ne l'étend pas, propre <html>/<head>). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
36 lines
1.5 KiB
Python
36 lines
1.5 KiB
Python
"""
|
|
app.py — moteur Forge, point d'entrée.
|
|
|
|
Lance un serveur web local. Fonctionnalités construites pour l'instant
|
|
(le reste viendra au fur et à mesure) :
|
|
1. Créer un jeu (dossier + index.html/css/js + base de données dédiée).
|
|
2. Définir des "objets" (comme des tables de base de données, avec des
|
|
champs typés, et des relations vers d'autres objets déjà définis).
|
|
3. Le moteur lit ces définitions et génère lui-même le formulaire adapté
|
|
pour saisir des données et les enregistrer dans la vraie base SQLite.
|
|
4. CRUD complet sur les trois niveaux (jeu / objet / donnée) : renommer
|
|
et supprimer un jeu, modifier une définition d'objet (ajouter/retirer
|
|
des champs) et la supprimer, modifier et supprimer une ligne de
|
|
données — avec blocage/avertissement quand une suppression casserait
|
|
une relation existante.
|
|
"""
|
|
|
|
import threading
|
|
import webbrowser
|
|
|
|
from core.flask_app import app
|
|
from core import jinja_filters # noqa: F401 - enregistre les filtres Jinja
|
|
import routes # noqa: F401 - enregistre toutes les routes sur `app`
|
|
from core import auth_guard # noqa: F401 - enregistre la garde de connexion (après les routes)
|
|
from core import csrf # noqa: F401 - enregistre csrf_token() comme variable globale Jinja
|
|
from core import csrf_guard # noqa: F401 - enregistre la vérification du jeton CSRF
|
|
|
|
|
|
def _open_browser():
|
|
webbrowser.open("http://127.0.0.1:5050/")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
threading.Timer(1.0, _open_browser).start()
|
|
app.run(host="127.0.0.1", port=5050, debug=True, use_reloader=False)
|