discovery-media-player 0.1.18 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server/handler.js +55 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discovery-media-player",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Self-hosted document viewer: per-recipient tracked links, reading analytics, live presentation. The core knows nothing about the application hosting it — everything it borrows arrives through an injected context.",
5
5
  "keywords": [
6
6
  "pdf-viewer",
package/server/handler.js CHANGED
@@ -399,12 +399,63 @@ var Live=(function(){
399
399
  ch.on('presence',{event:'sync'},function(){renderPres(ch.presenceState());});
400
400
  // Plus d'abonnement à la table des messages : elle n'est plus publiée ni lisible
401
401
  // publiquement. Tout passe par la diffusion, et l'historique par la route de chat.
402
- ch.on('broadcast',{event:'msg'},function(p){if(p&&p.payload&&addMsg(p.payload))notifyMsg(p.payload);});
403
- ch.on('broadcast',{event:'msg-upd'},function(p){if(p&&p.payload)updateMsg(p.payload);});
402
+ // ⚠️⚠️ TOUT CE BLOC VIT DANS UN TEMPLATE LITERAL : AUCUN BACKTICK, MÊME EN COMMENTAIRE.
403
+ // Un seul termine la chaîne qui porte tout le script navigateur, et l'erreur remonte
404
+ // ailleurs — « Unexpected token » sur une ligne qui n'a rien fait. Cinq fois sur ce fichier.
405
+ // Le lint l'attrape à chaque fois ; ça coûte un aller-retour, pas une panne.
406
+ //
407
+ // ⚠️ UNE DIFFUSION EST UN SIGNAL, PAS UNE VÉRITÉ.
408
+ //
409
+ // Ce canal est PUBLIC : la clé publiable et le slug sont dans la page, donc tout participant
410
+ // peut émettre. Appliquer directement la charge utile revenait à laisser n'importe quel
411
+ // spectateur annoncer la fin de la présentation, changer la page affichée, verrouiller le
412
+ // chat, ou publier un message signé du nom de quelqu'un d'autre.
413
+ //
414
+ // Déplacer l'émission vers le serveur n'y changerait rien : sur un canal public, un
415
+ // attaquant émet quand même, et le client ne distingue pas les deux sources. La seule
416
+ // défense qui tienne est de CESSER DE CROIRE le transport — on relit auprès du serveur, qui
417
+ // est déjà la source de vérité (routes state=1 et chat=1, elles existaient).
418
+ //
419
+ // Un attaquant peut donc toujours émettre : il déclenche une relecture, et n'obtient rien.
420
+ // C'est une meilleure propriété que d'essayer de l'empêcher — elle vaut aussi le jour où le
421
+ // transport lui-même a un défaut.
422
+ //
423
+ // ⚠️ 'map' et 'typing' restent appliqués tels quels, et c'est un choix : ce sont des signaux
424
+ // ÉPHÉMÈRES (mouvements de carte, « untel écrit »), sans état serveur à confronter et à
425
+ // fréquence élevée. Les revérifier coûterait un aller-retour par déplacement de souris pour
426
+ // protéger… un déplacement de souris. Ce qui fait autorité — la page affichée, le document,
427
+ // la fin de la présentation — passe par 'state', qui est relu.
428
+ function relire(url,applique){
429
+ fetch('/api/doc?present='+encodeURIComponent(SLUG)+url)
430
+ .then(function(r){return r.json();})
431
+ .then(function(d){if(d&&d.ok)applique(d);})
432
+ .catch(function(){});
433
+ }
434
+ var _relEtat=null,_relChat=null;
435
+ // Groupé : dix diffusions d'affilée ne doivent pas produire dix requêtes.
436
+ function relireEtat(){clearTimeout(_relEtat);_relEtat=setTimeout(function(){
437
+ relire('&state=1',function(d){if(d.state&&_onState)_onState(d.state);});
438
+ },120);}
439
+ function relireChat(){clearTimeout(_relChat);_relChat=setTimeout(function(){
440
+ relire('&chat=1',function(d){
441
+ // ⚠️ NOTIFIER CE QUI VIENT D'ARRIVER, ET SEULEMENT ÇA. 'addMsg' rend faux pour un
442
+ // message déjà connu — la relecture ramène tout l'historique, donc sans cette condition
443
+ // la pastille de non-lus compterait chaque message à chaque relecture. Et sans l'appel,
444
+ // elle ne compte plus rien : c'est la régression que le test d'un hôte a attrapée en
445
+ // lisant le source de ce paquet, à travers la frontière de deux dépôts.
446
+ if(d.messages)d.messages.forEach(function(m){if(addMsg(m))notifyMsg(m);else updateMsg(m);});
447
+ if(typeof d.locked!=='undefined')applyLock(d.locked);
448
+ });
449
+ },120);}
450
+
451
+ // Le message reçu sert à savoir QU'IL SE PASSE quelque chose, et à notifier ; son CONTENU
452
+ // vient de la relecture. Sans ça, une notification pourrait afficher un texte forgé.
453
+ ch.on('broadcast',{event:'msg'},function(){relireChat();});
454
+ ch.on('broadcast',{event:'msg-upd'},function(){relireChat();});
455
+ ch.on('broadcast',{event:'lock'},function(){relireChat();});
456
+ ch.on('broadcast',{event:'state'},function(){relireEtat();});
404
457
  ch.on('broadcast',{event:'typing'},function(p){onTyping(p&&p.payload);});
405
- ch.on('broadcast',{event:'lock'},function(p){if(p&&p.payload)applyLock(p.payload.locked);});
406
458
  ch.on('broadcast',{event:'map'},function(p){if(_onMap&&p&&p.payload)_onMap(p.payload);});
407
- ch.on('broadcast',{event:'state'},function(p){if(_onState&&p&&p.payload)_onState(p.payload);});
408
459
  ch.subscribe(function(st){if(st==='SUBSCRIBED'){ch.track({name:me.name,email:me.email,avatar:me.avatar,role:me.role,member:!!me.member,uid:attKey(me)});sendAttend();}});
409
460
  _tyIv=setInterval(renderTyping,1500);
410
461
  _atIv=setInterval(sendAttend,25000);