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.
- package/package.json +1 -1
- 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.
|
|
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
|
-
|
|
403
|
-
|
|
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);
|