ajoute la visio de classe : Jitsi auto-hébergé, jetons du portail, prof seul modérateur
Jitsi (docker-jitsi-meet, version figée) derrière Nginx sur meet.syllabuslab.fr, accès par jeton JWT signé par le portail, modération du micro, mains levées synchronisées avec l'application. Pare-feu : UDP 10000 et pont interne br-visio (accords d'Adam). Jicofo n'authentifie plus lui-même : il donnait le rôle de propriétaire aux élèves. Capacité ramenée à 20 VM. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
dd4f9c3c55
commit
ec4eae3744
36 changed files with 1406 additions and 18 deletions
|
|
@ -625,3 +625,49 @@ Vérifié en production : `/ide` 1 script en ligne, 0 erreur de syntaxe, `sandbo
|
|||
- 6 tests Pest (41 au total) ; vérifié en production : `/rejoindre` 200 avec CSP stricte, code faux refusé avec message, table créée, nettoyage planifié.
|
||||
|
||||
**Clé des sauvegardes** : je ne peux ni ne dois voir la copie d'Adam. Procédure de preuve ajoutée au runbook des sauvegardes : un message chiffré sur le serveur avec la clé publique, que la copie doit déchiffrer sur le Mac. Fichier de test déposé sur le Bureau d'Adam. Corrigé aussi la commande de copie du runbook (un `scp` d'un fichier de root échouait).
|
||||
|
||||
## 2026-10-12 — Étape 15 : visio de classe
|
||||
|
||||
Démarrée après validation des étapes 1 à 11 par Adam. Décisions : [ADR 0005](adr/0005-visio-jitsi.md).
|
||||
|
||||
**Fait**
|
||||
|
||||
- **Jitsi Meet auto-hébergé** (docker-jitsi-meet `stable-11248`, version vérifiée sur le dépôt officiel, images figées), rôle Ansible `visio` : configuration d'après le `docker-compose.yml` officiel, JVB sur le réseau de l'hôte, secrets générés une fois sur le serveur, contrôle au déploiement que Jicofo voit un JVB opérationnel.
|
||||
- **Pare-feu** (deux accords explicites d'Adam, filet anti-coupure de 5 min, vérification SSH depuis le Mac, règles de NAT d'OpenStack intactes) : UDP 10000 ouvert ; pont `br-visio` autorisé en `forward` pour les échanges entre conteneurs.
|
||||
- **Accès par jeton JWT** signé par le portail (HS256, une salle imprévisible par séance, nom non modifiable : prénom et initiale pour les élèves) ; pas d'invités. **Prof seul modérateur** par le module natif `token_affiliation` (vérifié dans l'image : `context.user.moderator`).
|
||||
- **Pages prof et élève** reprises de `design/resources/views/visio.blade.php` : « En direct » et chrono, « Couper tous les micros », « Terminer la visio », mains levées (premier arrivé en haut, « Donner la parole »), salle d'attente (élèves présents tant que la visio est fermée, « Tout admettre » l'ouvre), chat des élèves désactivé par défaut avec interrupteur ; côté élève : statut, micro, caméra, « Lever la main », « Quitter ». La grille factice est remplacée par la vraie visio (IFrame API, `external_api.js` servi par `meet`).
|
||||
- **Main levée synchronisée** : l'événement Jitsi `raiseHandUpdated` met à jour l'état du portail (cache Redis, verrou) ; quand le prof donne la parole (`askToUnmute`, qui autorise le micro sous modération d'après la documentation officielle), le portail baisse la main.
|
||||
- `meet.syllabuslab.fr` ajouté au certificat ; site intégrable dans le seul portail (`frame-ancestors`) ; `Permissions-Policy` du portail : caméra, micro et partage d'écran délégués à `meet` seulement ; CSP stricte complétée (`frame-src` et `script-src` vers `meet`).
|
||||
- **Capacité ramenée à 20 VM** (Jitsi ≈ 710 Mo après une visio à trois, plafonds 1 Go + 512 Mo) : Nova et portail alignés.
|
||||
- 6 tests Pest de la visio (47 au total) ; test réel en navigateurs `portail/tests/Reels/visio-e2e.mjs` (Playwright 1.64, Chromium, caméra et micro simulés) ; politique de confidentialité complétée (visio sans enregistrement).
|
||||
|
||||
**Problèmes rencontrés et solution**
|
||||
|
||||
1. Conteneurs Jitsi en boucle : leurs volumes doivent appartenir à l'uid 1000 (ils tournent sous cet utilisateur).
|
||||
2. **Jicofo ne joignait pas Prosody** (« Connect timed out ») : le module `br_netfilter` fait passer le trafic entre conteneurs d'un même réseau Docker par la chaîne `forward`, dont la politique est `drop`. Jamais vu avant parce que tous les autres conteneurs ne sont joints que depuis l'hôte. Règle `br-visio` (accord d'Adam).
|
||||
3. DNS de `meet` absent au départ : test complet d'abord joué en résolvant `meet` vers le serveur dans Chromium (`--host-resolver-rules`, certificat du portail accepté), puis rejoué en conditions réelles une fois le DNS créé par Adam et le certificat étendu.
|
||||
4. Tinker resté ouvert en attente de saisie sur le serveur, bloquant la suite : lancé désormais avec `< /dev/null` (runbook).
|
||||
5. **Un élève pouvait ouvrir son micro sans la parole** — trouvé par le test en navigateurs. En observant les messages XMPP envoyés par chaque navigateur, aucun client n'approuvait les élèves : c'est **Jicofo**, avec son authentification active par défaut, qui donnait le rôle de propriétaire à tout utilisateur authentifié, élèves compris (ils échappaient donc aussi à la modération et pouvaient modérer les autres). `JICOFO_ENABLE_AUTH=0` : Prosody vérifie toujours chaque jeton, `token_affiliation` seul attribue les rôles. Vérifié dans les journaux : élèves `PARTICIPANT`, liste des autorisés = le prof, puis l'élève à qui il donne la parole.
|
||||
|
||||
**Critère vérifié (vrai DNS, vrai certificat, trois navigateurs + un intrus)**
|
||||
|
||||
```
|
||||
prof : visio ouverte, Jitsi chargé
|
||||
prof : · 3 en ligne (le prof et les deux élèves)
|
||||
prof : main levée reçue de « Lea M. »
|
||||
Yanis tente d'ouvrir son micro sans la parole → « En sourdine »
|
||||
Léa : sa main est baissée (parole donnée)
|
||||
Léa ouvre son micro → « Tu as la parole »
|
||||
intrus sans jeton : le prof voit toujours « · 3 en ligne » ; écran de l'intrus : « … Authentication required … »
|
||||
CRITÈRE DE L’ÉTAPE 15 : RÉUSSI
|
||||
```
|
||||
|
||||
Données et fichiers de test supprimés (accord d'Adam).
|
||||
|
||||
**Comprendre**
|
||||
|
||||
Dans une visio, l'image et le son ne sont que la partie visible : la sécurité tient dans *qui a quel rôle*. Ici, trois composants pouvaient en décider — Prosody (le serveur de messagerie), le module `token_affiliation` (qui lit le jeton signé par le portail) et Jicofo (l'organisateur des conférences) — et le moins attendu, Jicofo, accordait silencieusement le rôle de propriétaire à tout le monde. Aucune lecture de configuration ne l'aurait montré : il a fallu un test qui joue la situation réelle (un élève tente de parler sans y être autorisé) puis observer les messages échangés pour remonter à la cause. L'autre leçon est réseau : un pare-feu « tout refuser » protège aussi contre ses propres conteneurs, et une règle doit alors être la plus étroite possible (ici, un seul pont, dans les deux sens).
|
||||
|
||||
**Suite**
|
||||
|
||||
Étape 16 : nettoyage.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue