From 7a682b46629c00f8f2d222132f2c69f159725139 Mon Sep 17 00:00:00 2001 From: matthieu Date: Wed, 20 May 2026 00:59:31 +0200 Subject: [PATCH] =?UTF-8?q?docs(mail)=20:=20checklist=20prod=20+=20s=C3=A9?= =?UTF-8?q?curit=C3=A9,=20guide=20int=C3=A9gration=20complet,=20mention=20?= =?UTF-8?q?README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + docs/mail-cron-setup.md | 19 +++++++ docs/mail-integration.md | 108 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 docs/mail-integration.md diff --git a/README.md b/README.md index 17a7a59..6b863e0 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Application de gestion de projet avec suivi du temps et portail client. - Profil utilisateur avec avatar (crop circulaire) - Notifications temps réel - Intégration Gitea (issues, repos) +- Intégration Mail IMAP (boîte partagée OVH, voir `docs/mail-integration.md`) - Serveur MCP pour assistants IA - Multi-langue (i18n) @@ -73,6 +74,7 @@ make shell-root # Shell root dans le container PHP make dev-nuxt # Dev server Nuxt (hot reload, port 3002) make cache-clear # Vider le cache Symfony make logs-dev # Tail logs Symfony +make mail-sync # Synchroniser la boîte mail IMAP (voir docs/mail-cron-setup.md) ``` ### Base de données diff --git a/docs/mail-cron-setup.md b/docs/mail-cron-setup.md index 0193cd1..78a5b2e 100644 --- a/docs/mail-cron-setup.md +++ b/docs/mail-cron-setup.md @@ -51,6 +51,16 @@ sudo crontab -u deploy -e La clé doit être la même que celle utilisée pour chiffrer le password lors de la configuration. +## Checklist setup production + +1. [ ] Définir `ENCRYPTION_KEY` dans les variables d'environnement production +2. [ ] Créer le compte mail dédié (ex: `lesstime@votre-domaine.fr`) chez OVH +3. [ ] Accéder à `/admin` → onglet "Mail" → renseigner les credentials IMAP/SMTP +4. [ ] Cliquer "Tester la connexion" → vérifier le succès +5. [ ] Cocher "Activer la synchronisation" → Enregistrer +6. [ ] Installer le cron OS (voir section "Installation du cron") +7. [ ] Vérifier les logs après la première sync : `make logs-dev` (chercher `mail.sync`) + ## Commandes utiles ```bash @@ -86,6 +96,15 @@ Les messages loggés par `MailSyncService` sont préfixés `mail.sync`. - Les corps de mails, passwords et pièces jointes ne sont **jamais loggés** - Le lock `flock` évite les runs parallèles (fichier dans `/tmp/sf.mail.sync..lock`) +## Rappels sécurité + +- La page `/mail` et tous les endpoints `/api/mail/*` sont refusés aux `ROLE_CLIENT` exclusifs +- Le sidebar "Messagerie" est masqué pour les utilisateurs ROLE_CLIENT sans ROLE_USER +- Le password IMAP est chiffré via libsodium secretbox avant stockage (jamais en clair en base) +- Les corps de mails sont sanitisés via DOMPurify avant affichage (voir `frontend/utils/sanitizeMailHtml.ts`) +- Les pixels tracking distants sont remplacés par un placeholder +- Aucun body mail, password ou contenu de pièce jointe n'est loggé + ## Production En production, préférer un cron système ou un job scheduler (Kubernetes CronJob, ECS Scheduled Task, etc.). diff --git a/docs/mail-integration.md b/docs/mail-integration.md new file mode 100644 index 0000000..e01bb6f --- /dev/null +++ b/docs/mail-integration.md @@ -0,0 +1,108 @@ +# Intégration Mail — Vue d'ensemble + +## Fonctionnalités + +- Lecture de la boîte mail partagée (IMAP) depuis Lesstime +- Navigation par dossiers (arbre récursif avec compteurs non-lus) +- Liste paginée des messages (infinite scroll, cursor-based) +- Lecture des corps de mail sanitisés (DOMPurify — protection XSS + pixels tracking) +- Création d'une tâche Lesstime depuis un mail (sujet → titre, texte → description) +- Lien mail ↔ tâche (bidirectionnel) +- Onglet "Mails" dans le TaskDrawer pour retrouver les mails liés à une tâche +- Synchronisation IMAP automatique via cron OS (toutes les 10 min) +- Déclenchement manuel de sync depuis l'UI (bouton Refresh) +- Badge non-lus en temps réel dans la sidebar (polling 30s) + +## Endpoints API + +| Méthode | URL | Rôle | Description | +|---------|-----|------|-------------| +| GET | `/api/mail/configuration` | ROLE_ADMIN | Lire la config singleton | +| PATCH | `/api/mail/configuration` | ROLE_ADMIN | Mettre à jour la config | +| POST | `/api/mail/configuration/test` | ROLE_ADMIN | Tester la connexion IMAP | +| GET | `/api/mail/folders` | ROLE_USER | Arbre des dossiers + unread | +| GET | `/api/mail/messages` | ROLE_USER | Liste paginée (param: folder, cursor, limit) | +| GET | `/api/mail/messages/{id}` | ROLE_USER | Détail + body (cached 5 min) | +| POST | `/api/mail/messages/{id}/read` | ROLE_USER | Marquer lu/non-lu | +| POST | `/api/mail/messages/{id}/flag` | ROLE_USER | Marquer étoilé/non-étoilé | +| POST | `/api/mail/messages/{id}/create-task` | ROLE_USER | Créer tâche depuis mail | +| POST | `/api/mail/messages/{id}/link-task` | ROLE_USER | Lier mail à tâche existante | +| DELETE | `/api/mail/messages/{id}/link-task/{taskId}` | ROLE_USER | Supprimer le lien | +| GET | `/api/tasks/{id}/mails` | ROLE_USER | Mails liés à une tâche | +| GET | `/api/mail/attachments/{id}` | ROLE_USER | Télécharger une pièce jointe | +| POST | `/api/mail/sync` | ROLE_USER | Déclencher sync async (Messenger) | + +Tous les endpoints `/api/mail/*` refusent explicitement `ROLE_CLIENT`. + +## Sécurité + +- ROLE_CLIENT exclusif : accès refusé à tous les endpoints mail et à la page `/mail` +- Le sidebar "Messagerie" est masqué pour les ROLE_CLIENT +- Password IMAP chiffré via libsodium secretbox (env `ENCRYPTION_KEY`) +- Corps de mail sanitisés via DOMPurify (`sanitizeMailHtml.ts`) — script/iframe/object/embed/on*/javascript: bloqués +- Pixels tracking distants (img src http) remplacés par placeholder +- Aucun body, password ou contenu de pièce jointe dans les logs + +## Dépendances + +### Backend +- `webklex/php-imap` : client IMAP PHP +- `symfony/lock` : Symfony Lock pour éviter les syncs parallèles +- `symfony/messenger` : dispatch asynchrone `MailSyncRequested` +- `libsodium` (ext PHP) : chiffrement du password IMAP + +### Frontend +- `dompurify` + `@types/dompurify` : sanitization HTML des corps de mail + +## Fichiers clés + +### Backend +- `src/Entity/MailConfiguration.php` — entité singleton (credentials, enabled) +- `src/Entity/MailFolder.php` — dossier IMAP synced +- `src/Entity/MailMessage.php` — message IMAP synced (headers, flags) +- `src/Entity/TaskMailLink.php` — lien tâche ↔ mail +- `src/Mail/ImapMailProvider.php` — implémentation IMAP (webklex) +- `src/Service/MailSyncService.php` — algorithme de sync (UID FETCH, resync flags) +- `src/Controller/Mail/` — controllers custom (test, folders, messages, sync) +- `src/State/Mail/` — providers/processors API Platform (configuration) + +### Frontend +- `frontend/pages/mail.vue` — page principale 3 colonnes +- `frontend/components/mail/` — MailFolderTree, MailMessageList, MailMessageViewer, MailRefreshButton +- `frontend/components/admin/AdminMailTab.vue` — onglet config admin +- `frontend/stores/mail.ts` — store Pinia (folders, messages, polling) +- `frontend/services/mail.ts` — service API (toutes les méthodes) +- `frontend/services/dto/mail.ts` — types TypeScript +- `frontend/utils/sanitizeMailHtml.ts` — DOMPurify wrapper + +## Synchronisation cron + +Voir `docs/mail-cron-setup.md` pour la configuration détaillée. + +Résumé : + +```bash +# Cron OS (toutes les 10 min) +*/10 * * * * cd /path/to/Lesstime && make mail-sync >> /var/log/lesstime-mail-sync.log 2>&1 + +# Commandes Makefile +make mail-sync # Sync complète +make mail-sync FOLDER=INBOX # Sync d'un dossier +make mail-sync DRYRUN=1 # Simulation sans écriture +``` + +## Configuration admin + +1. Aller sur `/admin` → onglet "Mail" +2. Renseigner les credentials IMAP/SMTP (OVH : `ssl0.ovh.net`, port 993/465, SSL) +3. Cliquer "Tester la connexion" +4. Activer la synchronisation → Enregistrer +5. Configurer le cron OS + +## Variables d'environnement + +| Variable | Description | Obligatoire | +|----------|-------------|-------------| +| `ENCRYPTION_KEY` | Clé hex 32 bytes libsodium pour chiffrer le password IMAP | Oui | +| `LOCK_DSN` | DSN Symfony Lock (défaut: `flock`) | Non | +| `MESSENGER_TRANSPORT_DSN` | Transport Messenger pour sync async | Recommandé (prod) |