fix: A43 TERMINÉ + A38 phase 1 — CSRF rendu côté serveur, helper unique (v7.33.0)
A43 (les 4 items sont clos) :
- `__CSRF_PLACEHOLDER__` supprimé : ContextVar CSRF_TOKEN posée par
CSRFMiddleware avant call_next (même mécanique que le nonce CSP),
global `{{ csrf_token() }}` dans templating, base.html rend
`{"X-CSRF-Token":{{ csrf_token()|tojson }}}` — vide si cookie absent,
`htmx:configRequest` re-lit le cookie à chaque appel → plus jamais de
jeton factice servi.
- Palette : `fetch('/api/search…')` SANS header (GET ∈ SAFE_METHODS →
CSRF inapplicable) — le JSON.parse du body-attr par frappe disparaît.
- utcnow déprécié = 0 dans app/**.py ; health loggé (A25) + booléens db/
gitea = raison ; probe réseau = voulu (test de connectivité).
A38 phase 1 (CSRF unifié) :
- `window.getCsrf()` unique dans le <head> de base.html.
- 76 lectures brutes du cookie → getCsrf() dans 13 fichiers (47 formes
`(…||[])[1]||''`, 25 déclarations `const X = match(…)` avec conversion
de leurs usages `X?X[1]:''` → `X` (noms collectés PAR FICHIER, jamais
de règle globale), 4 formes espacées).
- Définitions dupliquées supprimées : card_detail.html (multi-lignes),
database_table.js (1 ligne dans IIFE → chute sur le global).
- Les 3 variantes de base.html (IIFE getCsrf + 2 getCsrfToken) →
`return getCsrf()`.
- welcome.html garde sa lecture locale (page autonome sans base) ;
reste exactement 1 raw dans base.html (la déf head) + 2 dans welcome.
Test : test_csrf_server_rendered_no_placeholder (pas de placeholder +
token du hx-headers == cookie csrf_token).
suite **1092/1092** · ruff OK · node --check vert · docs à jour
This commit is contained in:
@@ -1,5 +1,40 @@
|
||||
# Changelog - FlowDeck
|
||||
|
||||
## v7.33.0 (2026-10-01) — Audit : A43 TERMINÉ + A38 phase 1 (CSRF unifié)
|
||||
|
||||
### Fixed
|
||||
|
||||
- **A43-1 — plus de `__CSRF_PLACEHOLDER__` servi** : ContextVar
|
||||
`CSRF_TOKEN` posée par `CSRFMiddleware` **avant** `call_next` (même
|
||||
mécanique que le nonce CSP), global `{{ csrf_token() }}` ajouté à
|
||||
templating ; `base.html` rend `{"X-CSRF-Token":{{ csrf_token()|tojson }}}`
|
||||
— vide si le cookie est absent sur cette 1ʳᵉ requête, mais
|
||||
`htmx:configRequest` re-lit le cookie à chaque appel → jamais de jeton
|
||||
factice. Test `test_csrf_server_rendered_no_placeholder` (pas de
|
||||
placeholder + token == cookie)
|
||||
- **A43-2 — palette : plus de re-parse par frappe** : `fetch('/api/search…')`
|
||||
sans header (GET ∈ `SAFE_METHODS` → le CSRF ne s'applique pas) — le
|
||||
`JSON.parse(document.body.getAttribute('hx-headers'))` par frappe disparaît
|
||||
|
||||
### Changed
|
||||
|
||||
- **A38 phase 1 — helper CSRF unique** : `window.getCsrf()` défini dans le
|
||||
`<head>` de `base.html` (le plus tôt possible) ; **76 lectures brutes du
|
||||
cookie → `getCsrf()`** dans 13 fichiers (47 formes `(…||[])[1]||''`,
|
||||
25 déclarations `const X = match(…)` + leurs usages `X?X[1]:''` → `X`,
|
||||
4 formes espacées) ; définitions dupliquées supprimées (`card_detail`,
|
||||
`database_table`) ; les 3 variantes de `base.html` (IIFE + 2
|
||||
`getCsrfToken`) unifiées sur `return getCsrf()` ; `welcome.html` garde sa
|
||||
lecture locale (page autonome documentée)
|
||||
|
||||
### Notes
|
||||
|
||||
- A43 = **TERMINÉ** (4/4 : utcnow déprécié = 0 dans app/**.py, health
|
||||
loggé, placeholder, palette)
|
||||
- A38 reste : 12 fonctions dupliquées entre templates (wrappeur) + 21
|
||||
méthodes jumelles library/local_workspace
|
||||
- Suite complète : **1092/1092** · ruff OK · node --check vert
|
||||
|
||||
## v7.32.0 (2026-10-01) — Audit : A28 TERMINÉ (board, dernier lot)
|
||||
|
||||
### Changed
|
||||
|
||||
Reference in New Issue
Block a user