Files
nessar f1094ac0b6 docs: consolidate the lot #7 validation report (#13)
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.
2026-09-18 10:52:07 +02:00

13 KiB
Raw Permalink Blame History

Validation du lot #8 — connexion du compagnon par Quick Connect

Protocole

Paquet 0.5.0, Jellyfin Server 12.0.0 (image figée dans tests/run.sh), Jellyfin Web de cette image, Chromium 149.0.7827.55, Playwright 1.61.1. Comptes ordinaires Alice et Bob, compagnon de 375 × 812 pixels, hébergement sans préfixe puis suite complète sous /jellyfin.

bash tests/run.sh
node --test tests/quick-connect.test.mjs

tests/setup.mjs prépare le serveur jetable avec Quick Connect activé (QuickConnectAvailable) et vérifie qu'un compte ordinaire — jamais le compte administrateur de préparation — peut approuver un code. Le mot de passe n'est utilisé que pour préparer les comptes, le lecteur Jellyfin Web et le client approbateur ; le compagnon n'en envoie plus.

Contrat Quick Connect observé

Le contrat a été relevé sur le serveur 12.0.0 du conteneur et confirmé dans les sources du tag v12.0 (QuickConnectController, UserController, QuickConnectManager) :

Requête Réponse
GET QuickConnect/Enabled (anonyme) booléen
POST QuickConnect/Initiate (anonyme) { Secret, Code, Authenticated }
GET QuickConnect/Connect?secret= (anonyme) { …, Authenticated }, 404 si le secret est inconnu ou expiré
POST QuickConnect/Authorize?code= (authentifié) approbation par le compte appelant
POST Users/AuthenticateWithQuickConnect (anonyme) jeton du compte approbateur

L'initiation exige les en-têtes MediaBrowser Client, Device, DeviceId et Version. Le code compte six chiffres et expire après dix minutes ; l'approbation crée une session nommée d'après l'appareil initiateur, donc la connexion obtenue appartient au compagnon et non au client approbateur. Le secret n'est ni affiché, ni conservé ; seul le jeton du compagnon est conservé. Il n'apparaît pas dans l'URL de la page : il n'est transmis que dans les appels exigés par Jellyfin (Connect?secret= pour l'état, puis le corps de AuthenticateWithQuickConnect).

Résultats

Exécution complète du 18 septembre 2026 : compilation C# Release sans avertissement (0 erreur, 0 avertissement), vérification TypeScript réussie, 25 tests sur 25. Le contrôle du plugin sans préfixe réussit avant la suite sous /jellyfin (98,8 s pour la suite complète). Le contrôle de révocation après « Se déconnecter » attend la fin de l'aller-retour réseau : sans cette attente, il lisait le jeton avant sa révocation (course du test, pas du compagnon). Les exécutions précédentes de ce rapport — 17 tests en 89,4 s, 18 en 91,1 s, 20 en 88,8 s puis 22 en 88,1 s — étaient toutes réussies. Le lot #13 complète ces preuves (refus réel d'un secret Quick Connect inconnu, absence de libellé identifiant/mot de passe) ; son rapport de lot consolidé est issue-7.md.

Critère du lot Vérification
Code réel obtenu du serveur jetable, approuvé par un compte authentifié, connexion automatique sans mot de passe, sans bouton de confirmation, sans copie de jeton Parcours installé : le test lit le code affiché, l'approbation est faite par un client authentifié, le compagnon se connecte seul
Instructions claires, lisibles à 375 px et utilisables au clavier Texte « Réglages → Quick Connect » dans un client déjà connecté ; code de 2,5 rem à chasse fixe ; largeur vérifiée ; action focalisée après un échec
Suivi du compte approbateur et non-régression des scénarios installés Suivi réel, choix de lecture, piste principale, piste d'aide et historique : mêmes assertions qu'aux lots #2 à #5
Aucun contrôle ni requête d'identifiant/mot de passe Aucun champ dans le HTML ; journal réseau du compagnon contrôlé
Une session Jellyfin Web ouverte ne connecte pas le compagnon Le compagnon relié à un contexte où Jellyfin Web est déjà connecté demande toujours son propre code
L'interrogation du résultat s'arrête dès la connexion réussie Nombre de QuickConnect/Connect constant 2,5 s après la connexion
Serveur jetable préparé avec Quick Connect et un compte ordinaire capable d'approbation Activé et vérifié par tests/setup.mjs et un test dédié
Connexion conservée entre les visites (#9) Reprise après rechargement et après redémarrage du navigateur sans nouvelle approbation ; seuls jeton, compte et appareil sont conservés ; un jeton réellement révoqué côté serveur est effacé à la réouverture et remplacé par Quick Connect
Donnée conservée illisible ou incomplète (#9) Sept formes invalides — dont un jeton fait d'espaces — repartent en Quick Connect, sans requête authentifiée ni écran bloqué
Code expiré annoncé et remplaçable (#10) « Ce code a expiré » est distinct d'une panne et l'interrogation s'arrête ; sur le serveur installé, « Générer un nouveau code » obtient un code neuf qu'un compte authentifié approuve, et le compagnon se connecte seul
Quick Connect désactivé (#10) Instructions d'activation et « Réessayer » focalisé ; une fois activé, le réessai affiche un code, sans autre méthode de connexion
Réponse tardive d'une tentative abandonnée (#10) Une observation de suivi retenue qui arrive après « Se déconnecter » ne restaure ni suivi ni détails
Déconnexion : arrêt du suivi et des pistes (#11) Le statut reste « Déconnecté. » passé le délai de sondage, une extraction retenue à travers la déconnexion ne rend rien, et « Se connecter » focalisé ramène à la demande d'approbation Quick Connect
Déconnexion : jeton révoqué, autres clients intacts (#11) Après le clic, Sessions/Logout fait répondre 401 au jeton du compagnon ; un client indépendant du même compte répond toujours 200
Déconnexion : révocation non confirmée (#11) Requête de révocation interrompue : le stockage local est vidé et le message précise que le serveur n'a pas confirmé la révocation
Déconnexion : plus aucun reste du compte précédent (#11) Détails, choix de lecture, pistes et historique vidés ; le sélecteur de lecture ne garde aucune option du compte précédent
Refus de jeton pendant le suivi (#12) Le serveur révoque réellement le jeton du compagnon pendant qu'il suit une lecture avec piste et historique affichés : le stockage local est vidé, détails, pistes et historique sont effacés et un nouveau code Quick Connect apparaît ; aucun élément d'un autre compte n'apparaît, plus aucune requête n'utilise le jeton refusé et celui-ci répond 401
Panne pendant le suivi (#12) Coupure réseau réelle : « Suivi indisponible », connexion conservée et aucun code Quick Connect ; au retour du réseau, les détails reviennent sans nouvelle approbation
Distinction refus / panne (#12) À la frontière navigateur/API : un 401 affiche « n’est plus acceptée » puis la demande d'approbation, un 500 affiche « Suivi indisponible » et conserve la connexion

La connexion est conservée dans le navigateur (compagnon.connexion : jeton, identifiant de compte, identifiant d'appareil) et reprise après rechargement et après fermeture du navigateur. Le contrôle vérifie que ces trois champs sont les seuls conservés, et que le jeton n'apparaît ni dans l'URL, ni dans un message affiché, ni dans la console. Un jeton refusé efface la connexion enregistrée et ramène à Quick Connect ; une panne réseau, elle, affiche « Suivi indisponible » sans effacer la connexion. « Se déconnecter » efface le stockage local, demande la révocation du jeton du compagnon et prévient lorsque le serveur ne l'a pas confirmée ; un autre client Jellyfin reste connecté.

« Se déconnecter » arrête le suivi et le chargement des pistes : une extraction retenue à travers la déconnexion ne repeuple pas l'historique, et un jeton révoqué dont le sondage aurait continué ne relance pas Quick Connect tout seul. L'affichage du compte précédent — détails, choix de lecture, pistes, historique — est vidé, y compris les options mémorisées du sélecteur de lecture. Une reconnexion voulue reste un geste explicite : « Se connecter », focalisé, mène à la demande d'approbation Quick Connect.

Un refus d'authentification reçu pendant le suivi — le jeton du compagnon est révoqué côté serveur alors qu'il suit une lecture — efface la connexion conservée et ramène à la demande d'approbation Quick Connect : détails, pistes et historique du compte précédent sont vidés, et la lecture d'un autre compte n'apparaît jamais. Le jeton refusé n'est ni réutilisé ni échangé, et il répond 401 après coup. Une panne réseau ou une erreur serveur temporaire reste récupérable : la connexion conservée n'est pas effacée, « Suivi indisponible » est annoncé et le suivi reprend dès le retour du serveur, sans nouvelle approbation. Les deux cas restent distincts : le refus annonce que la connexion n'est plus acceptée, la panne annonce un suivi indisponible. Ces deux comportements étaient déjà en place avec la connexion Quick Connect ; le lot #12 les éprouve aux deux échelles et les documente, sans changement d'interface.

Les contrôles à la frontière navigateur/API couvrent les états qu'un serveur réel ne produit pas à la demande : code expiré (404) puis régénération, Quick Connect désactivé, serveur indisponible, jeton enregistré refusé ou refusé pendant le suivi, donnée conservée illisible ou incomplète, et extraction de piste retenue à travers une déconnexion.

Aucune régression mesurée sur les lots précédents : les délais d'extraction embarquée restent du même ordre (SRT 42,0/10,8 ms, WebVTT 31,8/10,0 ms, ASS 36,1/13,7 ms à froid/à chaud), et l'endpoint natif Stream.json répond toujours HTTP 200 sans authentification. Dans le scénario de synchronisation dédié, les six écarts en lecture stable de cette exécution sont 1 231, 1 911, 1 591, 1 271, 1 951 et 1 631 ms : objectif de moins de 500 ms non atteint, comme au lot #3. Le recalage après déplacement est de 784 ms, sous l'objectif de deux secondes. Aucun de ces chiffres n'appartient à 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 ; les remises à zéro dupliquées, le nom des éléments d'interface, le secret Quick Connect gardé dans une variable de module et le message d'échec dupliqué ont été corrigés (resetConnectPanel, clearConnection, failUnexpected, secret limité à la tentative, type SavedConnection). Spec : la phrase sur le secret a été corrigée pour ne pas nier la transmission exigée par Jellyfin ; pour le lot #9, un jeton fait d'espaces est refusé dès la lecture et le contrôle de réouverture révoque réellement le jeton côté serveur ; pour le lot #10, « Générer un nouveau code » est approuvé sur le serveur installé et une réponse de suivi retardée est retenue à travers une déconnexion. Pour le lot #11, la revue a conduit à extraire la remise à zéro du sélecteur de lecture (resetSessionChooser), à vider les options mémorisées du compte précédent, et à empêcher qu'un échec de révocation tardif n'écrase l'état d'une tentative de reconnexion plus récente ; un test retient la révocation pendant qu'une reconnexion démarre. Pour le lot #12, la revue a fait préciser les preuves plutôt que le code : pistes et piste d'aide vidées après un refus, session d'un autre compte injectée pour prouver le filtrage, lecture et historique réels affichés avant la révocation sur le serveur installé, et message de refus observé en y retenant l'appel Quick Connect ; le helper de retenue et la fenêtre de sondage sont partagés entre les deux suites. Reste non testé par construction : une réponse tardive d'une tentative d'approbation remplacée, que l'interface ne peut pas produire (les gardes de génération la neutralisent).

Couverture et limites

Aucun changement serveur n'était nécessaire : Quick Connect appartient à Jellyfin et le plugin continue de ne servir que ses ressources statiques. Le lot ne touche que l'interface du compagnon, ses tests et sa documentation ; il ne modifie ni Jellyfin Web, ni l'endpoint natif, ni les autres clients. La session de Jellyfin Web n'est ni lue, ni modifiée, ni réutilisée : le compagnon ne lit que sa propre clé de stockage, et sa déconnexion ne révoque que son propre jeton.

Après une déconnexion explicite, le compagnon propose « Se connecter » au lieu de demander immédiatement un nouveau code : une reconnexion voulue reste un geste explicite, qui affiche alors la demande d'approbation Quick Connect (code et instructions). L'approbation est exercée par l'API authentifiée de Jellyfin (QuickConnect/Authorize) et non en pilotant l'écran « Réglages → Quick Connect » de Jellyfin Web ; l'interface d'approbation d'un client réel n'est donc pas qualifiée par ce lot. Les utilisateurs venus par SSO, HTTPS et les reverse proxies, et les autres clients Jellyfin restent hors de la qualification, comme aux lots précédents.