Ajoute 4 mécanismes moteur manquants pour le thème sécurité incendie : étiquette, carte, image SVG inline, bouton avec pièce jointe

Contenu et mécanisme uniquement, aucun style ajouté (voir consigne du
24/09/2026) : deux nouveaux kinds de contenu (badge/carte, rendu en
div brutes sans CSS), un mode SVG inline pour l'image (svg_markup,
nettoyé par un nouveau sanitizer allow-list avant chaque rendu) et un
fichier téléchargeable joignable à un bouton (upload/download routes,
stockage sous db.support_dir). Le futur système de templates portera
l'habillage visuel de ces éléments.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-24 08:12:29 +02:00
co-authored by Claude Sonnet 5
parent e7c6ed7159
commit a34bcf4159
15 changed files with 668 additions and 18 deletions
+38 -2
View File
@@ -30,8 +30,25 @@ regroupement à chaque appel.
récursivement.
- **Texte** (`titre`/`paragraphe`) : `<div>` stylé selon `style` (préréglage
taille/graisse/interligne) et `bold`/`italic`/`underline`/`align`/`color`.
- **Image** : `<img>`, ou un bloc placeholder si `src` est vide.
- **Bouton** : `<button>` avec son `label` et un `data-target` optionnel.
- **Image** : `<img>`, ou un bloc placeholder si `src` est vide — OU, si
`attributes["svg_markup"]` est non vide (prioritaire sur `src`), un
`<div>` portant directement ce fragment SVG nettoyé par
`sanitize_svg_markup` (voir `sanitize_svg_markup.py` ci-dessous) : un
contenu vectoriel dessiné/collé par le créateur plutôt qu'un fichier
hébergé, sans aucun style qui lui soit propre.
- **Bouton** : `<button>` avec son `label`, un `data-target` optionnel
(navigation) et un `data-attachment-filename` optionnel — marqueur
mécanique posé quand un fichier a été joint (voir
`routes/document/document_element_upload_attachment.py`), jamais
l'URL de téléchargement elle-même (ce renderer ne connaît pas le slug
du support ; `static/document/js/document-editor.js` l'assemble à
partir de `data-element-id` + `FORGE_DOCUMENT.slug`, même principe que
le reste des appels AJAX de l'éditeur).
- **Étiquette** (`badge`) : `<div>` portant `attributes["content"]`
échappé — contenu pur, aucun attribut de style.
- **Carte** (`carte`) : `<div>` composé de trois blocs enfants
(`label`/`title`/`description`, tous échappés) — contenu pur, aucune
couleur/forme choisie ici (voir `element_kind_labels.md`).
- **Liste à puces/numérotée** (`liste_puces`/`liste_numerotee`) :
`<ul>` ou `<ol>` selon le `kind` (fonction privée `_render_list`,
partagée par les deux) — un `<li>` par entrée de `attributes["items"]`.
@@ -146,3 +163,22 @@ regroupement à chaque appel.
du type (voir `document_engine/labels/element_kind_labels.py`) —
emplacement réservé, formulaire de contenu dédié hors périmètre de
cette passe.
## `sanitize_svg_markup.py` — nettoyage du contenu SVG inline d'une image
### `sanitize_svg_markup(markup: str) -> str`
Nettoie un fragment SVG selon une LISTE BLANCHE de balises/attributs
(`_ALLOWED_TAGS`/`_ALLOWED_ATTRS`, privées) — construit sur
`html.parser.HTMLParser` (tokenizer de balises pur, sans DTD ni
résolution d'entité externe) plutôt qu'un analyseur XML, qui resterait
exposé aux attaques classiques d'entité externe sur une entrée non
fiable. Toute balise absente de la liste blanche (`<script>`,
`<foreignObject>`, `<a>`, `<use>`, `<image>`...) disparaît AVEC son
contenu ; tout attribut absent (`on*`, `style`, `href`/`xlink:href`,
`class`...) disparaît seul, la balise porteuse étant conservée si elle
est autorisée. Appelé à CHAQUE rendu (`_render_image`), jamais
seulement à l'écriture — même défense en profondeur que
`html.escape` sur les autres kinds.
- **Retour** : le fragment SVG nettoyé, sûr à insérer tel quel dans le
HTML rendu.
- **Exceptions** : aucune.