Add the dated lot-level report (versions, protocol, results, mobile and keyboard checks, verified vs untested) and point the README at it. Prove the Quick Connect API limitation on the real installed server by refusing an unknown secret with 404, and check that no credential label remains.
9.3 KiB
Validation du lot #7 — connexion du compagnon par Quick Connect
Rapport du 18 septembre 2026. Ce document est le rapport de lot ; le détail
ticket par ticket (contrat HTTP, mesures, revues) reste dans
issue-8.md, qui couvre les lots #8 à #12. Aucun serveur de
l'utilisateur n'a été touché : tout s'exécute sur un conteneur jetable supprimé
en sortie.
Versions
| Élément | Version |
|---|---|
| Jellyfin Server | 12.0.0, image jellyfin/jellyfin:12.0@sha256:baba630419915985442f315f08b0cf46d9f4c8a0cc4bd38e94a6d35751dd5ef5, Linux x64 |
| Plugin Compagnon | 0.5.0, archive dist/compagnon-0.5.0-jellyfin-12.0.0.zip, SHA-256 10917490c28b606f0395aa5efe51a7e3727b95e1bff4d880d96ee208b807c434 |
| Interface compagnon | servie par le plugin, Version="0.5.0" dans l'en-tête Jellyfin |
| Navigateur compagnon | Chromium 149.0.7827.55 (headless), Playwright 1.61.1 |
| Outils | Node.js 24.18.0, .NET SDK 10 (image épinglée), ffmpeg du conteneur Jellyfin |
Protocole
bash tests/run.sh # serveur jetable, paquet installé, tests réels
node --test tests/quick-connect.test.mjs # frontière navigateur/API seule
tests/run.sh compile le plugin en Release (avertissements bloquants), construit
l'archive, lance le serveur 12.0.0 sur un port local libre, crée un compte
administrateur de préparation et deux comptes ordinaires (Alice, Bob), une vidéo
de deux minutes avec timecode et des pistes SRT/VTT/ASS, active Quick Connect,
puis installe l'archive et redémarre. Il vérifie d'abord que le plugin sert le
compagnon sans préfixe, configure ensuite <BaseUrl>/jellyfin</BaseUrl> et
exécute la suite complète sous /jellyfin. Le conteneur est supprimé en
sortie.
Les scénarios à la frontière navigateur/API interceptent les routes avec
Playwright pour produire les états qu'un serveur réel ne donne pas à la demande
(code expiré par 404, Quick Connect désactivé, panne, 500 temporaire). Les
scénarios installés utilisent le vrai serveur : approbation par un compte
authentifié, révocation réelle de jeton, coupure réseau réelle
(context.setOffline).
Résultats
Exécution complète du 18 septembre 2026 : compilation C# Release 0 erreur,
0 avertissement, vérification TypeScript réussie, 27 tests sur 27 en
97,4 s ; le contrôle sans préfixe réussit avant la suite sous /jellyfin.
Les exécutions précédentes du rapport issue-8.md (17, 18, 20, 22, 25 puis
26 tests) étaient toutes réussies.
| Critère du lot #7 | Vérification |
|---|---|
| Le README décrit l'approbation Quick Connect, la reconnexion conservée et la déconnexion ; plus de mot de passe ni de jeton seulement en mémoire | Section Installation (approbation dans un client connecté), puis conservation dans ce navigateur, refus de jeton, panne et « Se déconnecter » avec révocation ; le formulaire identifiant/mot de passe n'existe plus dans l'interface |
| Un rapport daté consigne versions, protocole, résultats et limites | Ce document, avec le détail par ticket dans issue-8.md |
| Passage complet des tests installés, y compris derrière le préfixe de base | tests/run.sh : contrôle sans préfixe puis 26/26 sous /jellyfin |
| Aucun contrôle identifiant/mot de passe, aucune requête d'authentification par mot de passe, aucun jeton visible | noPassword() à la frontière (aucun input[type=password], #username, #login, aucun libellé identifiant/mot de passe, aucun AuthenticateByName) ; journal réseau installé sans AuthenticateByName ; jeton absent de l'URL, des messages affichés et de la console (compagnon.connexion ne contient que jeton, compte, appareil) |
| Contrôles mobile (375 px) et clavier des écrans de connexion, d'expiration et de déconnexion consignés | Tableau ci-dessous ; les scénarios navigateur utilisent 375 × 812 et les écrans de connexion, d'expiration et de déconnexion vérifient l'absence de débordement horizontal |
| Environnement installé indisponible : écart rapporté | Non rencontré : l'image est épinglée et l'exécution complète a eu lieu ; si Docker est absent, tests/run.sh échoue sans conclure |
| Limite de l'API Quick Connect de la version supportée rapportée avec preuves | Voir « Limite observée » ci-dessous ; aucun repli par mot de passe ni jeton de Jellyfin Web n'a été ajouté |
Mobile (375 px) et clavier
| Écran | Contrôle | Résultat |
|---|---|---|
| Connexion | Code affiché dans un role="status" aria-live, visible à 375 px sans débordement ; aucun champ ni libellé identifiant/mot de passe |
Vérifié (frontière « stay usable by keyboard at 375 px » ; noPassword) |
| Connexion | Approbation réelle par un compte authentifié puis suivi d'une lecture réelle, à 375 px | Vérifié (installé « real playback is followed… », « ordinary account logs in… ») |
| Expiration | « Générer un nouveau code » focalisé, activé par Entrée seule, nouveau code affiché ; sur le serveur installé, un vrai code régénéré est approuvé | Vérifié (frontière « stay usable by keyboard… » ; installé « an expired code is replaced… ») |
| Déconnexion | Depuis le sélecteur focalisé, Tab puis Entrée atteignent « Se déconnecter », l'état « Déconnecté. » s'affiche et « Se connecter » prend le focus | Vérifié (frontière « stay usable by keyboard… » ; installé « explicit disconnect revokes… », « ordinary account logs in… ») |
| Déconnexion | Révocation réelle du jeton, autres clients intacts, message si la révocation n'est pas confirmée | Vérifié (installé, « explicit disconnect revokes… ») |
Jeton et absence de mot de passe
- Aucun champ ni libellé d'identifiant/mot de passe ne subsiste : le formulaire a été remplacé par le panneau Quick Connect, et les contrôles le vérifient sur le HTML servi comme sur le journal réseau.
- Le compagnon n'émet aucune requête
Users/AuthenticateByName; le mot de passe n'est utilisé que par les tests pour préparer les comptes et le client approbateur (commentaire en tête detests/installed.test.mjs). - Le jeton du compagnon n'apparaît ni dans l'URL de la page, ni dans un message
affiché, ni dans la console ; seul
compagnon.connexionle conserve, avec l'identifiant de compte et d'appareil, et il est effacé à la déconnexion comme à un refus d'authentification.
Limite observée dans l'API Quick Connect 12.0
GET QuickConnect/Connect?secret= répond 404 aussi bien pour un secret
inconnu que pour un code expiré : le serveur ne fournit pas de signal distinct
d'expiration. Le compagnon interprète donc tout 404 comme « Ce code a expiré.
Générez un nouveau code. », ce qui reste sûr (aucune approbation possible) mais
ne distingue pas un secret invalide d'un code périmé. Preuves : contrat relevé
dans issue-8.md, refus réel d'un secret inconnu par le serveur 12.0 installé
(installed.test.mjs, « an unknown Quick Connect secret is refused with 404 »),
test frontière qui produit le 404 d'expiration (quick-connect.test.mjs,
« an expired code is identified… ») et test installé qui force le même 404 sur le
serveur réel, le délai d'expiration de dix minutes n'étant pas attendu
(installed.test.mjs, « an expired code is replaced… »).
Aucune méthode de connexion de repli et aucun jeton de Jellyfin Web n'ont été introduits pour contourner cette limite, conformément au périmètre.
Cas non testés ou hors qualification
- Interface d'approbation d'un vrai client Jellyfin : l'approbation est
exercée par l'API authentifiée
QuickConnect/Authorize, pas en pilotant l'écran « Réglages → Quick Connect » de Jellyfin Web. - Expiration réelle de dix minutes : non attendue ; l'état est obtenu par interception (frontière) ou 404 forcé sur le serveur réel.
- Quick Connect désactivé côté serveur : obtenu par interception, pas en modifiant la configuration du serveur jetable.
- Panne réseau : coupure réelle
context.setOffline; l'erreur serveur 500 est interceptée. - Appareil mobile physique : seulement un viewport 375 × 812 dans Chromium headless, pas un navigateur mobile réel ni un lecteur d'écran.
- HTTPS, reverse proxy et fournisseurs SSO : hors qualification, comme aux lots précédents ; Quick Connect est le seul chemin de connexion.
- Objectif de synchronisation < 500 ms : non atteint (voir
issue-8.md), hors de ce lot. Stream.jsonnatif sans contrôle de droits : limite serveur déjà documentée et contournée par la route authentifiée du plugin, hors de ce lot.
Revue
Deux agents ont examiné séparément les axes normes et spécification. Normes :
aucun écart aux règles écrites du dépôt ; le SHA-256, les versions et les
durées du rapport correspondent à l'archive et au journal d'exécution ; les
attributions de tests trop larges ont été corrigées. Spec : la limite Quick
Connect n'était appuyée que sur des 404 simulés ; un contrôle réel de refus d'un
secret inconnu sur le serveur installé a été ajouté, et le contrôle
noPassword() vérifie désormais aussi l'absence de libellé identifiant/mot de
passe. L'affirmation sur le débordement horizontal a été restreinte aux écrans
réellement vérifiés. Aucun repli de connexion ni jeton de Jellyfin Web n'a été
introduit.