Sans ce correctif, l'access token Directus (~15 min) expirait silencieusement,
rendant toutes les requêtes API 401 sans déconnecter l'utilisateur.
- Ajout de refreshDirectusToken() : POST /auth/refresh avec rotation du refresh_token
- accessTokenExpires stocké dès la connexion (expires Directus - marge 60s)
- jwt callback : token valide → pass-through, token expiré → refresh, échec → error flag
- session callback : propagation de session.error = 'RefreshAccessTokenError'
(permet au client de forcer un signOut si le refresh_token est lui-même expiré)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
export-pdf-button et print-button injectaient marked(content) directement
dans innerHTML / document.write. Un lien Markdown javascript: passait le
filtre hasRestrictedChar et pouvait s'exécuter.
Ajout de DOMPurify.sanitize() via import dynamique (déjà présent en dep
transitive de jspdf) sur les deux composants, avec whitelist de tags
et d'attributs stricte. markdown-renderer n'est pas touché car
react-markdown-preview utilise rehype-sanitize en interne.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ajout de lib/rate-limit.js : fabrique de limiter en mémoire (closure +
Map avec nettoyage lazy), sans dépendance externe, réutilisable
- Ajout de middleware.js : intercepte /api/auth/register (5 req/15min)
et /api/auth/callback/credentials (10 req/5min), répond 429 + Retry-After
- Ajout de tasks/todo.md et tasks/lessons.md (suivi CLAUDE.md)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>