Cette erreur semble indiquer que Jitsi dans votre navigateur n’a pas accès au stockage local. Utilisez-vous un navigateur avec des paramètres de sécurité restrictifs qui pourraient empêcher les iframes d’utiliser le stockage local ?
quelque chose d’« amusant » dans ma console, ainsi que quelques erreurs, comme :
Content Security Policy : les paramètres de la page ont bloqué le chargement d’une ressource à l’adresse eval (« script-src »). Source : (function injected(eventName, injectedIntoContentWindow)
{
…
bien que cela fonctionne ![]()
vous pouvez essayer l’une de ces instances :
https://framatalk.org/accueil/fr/info/
Oui, j’ai configuré Chrome pour qu’il n’autorise pas les cookies tiers. La désactivation de ce paramètre résout ce problème. Ce serait bien d’avoir un moyen d’être alerté de cette cause, mais je suppose que c’est un problème assez rare.
Existe-t-il un moyen dans Jitsi d’ouvrir un appel vidéo dans un nouvel onglet ou une fenêtre contextuelle séparée ? Je me demande si les gens quitteront la page pendant l’appel pour continuer à naviguer sur le forum tout en parlant ou pour ajouter une réponse au sujet.
Peut-être pas, car cela compliquerait les csp_extensions dans about.json.
Non, la version actuelle du composant de thème ajoute déjà le chemin de l’API Jitsi aux sources du CSP. Cela est réalisé par cette ligne de about.json, comme l’a noté @Benjamin_D :
@pmusaraj Est-il possible de configurer cette nouvelle étape directement dans Discourse ?
oui, j’apprends au fur et à mesure…
Je me demande toujours pourquoi cette fonction : injected(eventName, injectedIntoContentWindow) etc… ne respecte pas la CSP
console
Politique de sécurité du contenu : les paramètres de la page ont bloqué le chargement d’une ressource à eval (“script-src”). Source : (function injected(eventName, injectedIntoContentWindow)
{
let checkRequest;
/*
- Wrapper de contexte de frame
- Dans certains cas limites, Chrome n’exécute pas les scripts de contenu à l’intérieur des frames.
- Des sites web ont commencé à abuser de ce fait pour accéder à des API non enveloppées via
- le contentWindow d’une frame (#4586, 5207). Par conséquent, tant que Chrome n’exécute pas
- les scripts de contenu de manière cohérente pour toutes les frames, nous devons veiller à
- (ré)injecter nos wrappers lorsque le contentWindow est accédé.
*/
let injectedToString = Function.prototype.toString.bind(injected);
let injectedFrames = new WeakSet();
let injectedFramesAdd = WeakSet.prototype.add.bind(injectedFrames);
let injectedFramesHas = WeakSet.prototype.has.bind(injectedFrames);
function injectIntoContentWindow(contentWindow)
{
if (contentWindow && !injectedFramesHas(contentWindow))
{
injectedFramesAdd(contentWindow);
try
{
contentWindow[eventName] = checkRequest;
contentWindow.eval(
“(” + injectedToString() + “)('” + eventName + “', true);”
);
delete contentWindow[eventName];
}
catch (e) {}
}
}
for (let element of [HTMLFrameElement, HTMLIFrameElement, HTMLObjectElement])
{
let contentDocumentDesc = Object.getOwnPropertyDescriptor(
element.prototype, “contentDocument”
);
let contentWindowDesc = Object.getOwnPropertyDescriptor(
element.prototype, “contentWindow”
);
// Apparemment, HTMLObjectElement.prototype.contentWindow n'existe pas
// dans d'anciennes versions de Chrome comme la 51.
if (!contentWindowDesc)
continue;
let getContentDocument = Function.prototype.call.bind(
contentDocumentDesc.get
);
let getContentWindow = Function.prototype.call.bind(
contentWindowDesc.get
);
contentWindowDesc.get = function()
{
let contentWindow = getContentWindow(this);
injectIntoContentWindow(contentWindow);
return contentWindow;
};
contentDocumentDesc.get = function()
{
injectIntoContentWindow(getContentWindow(this));
return getContentDocument(this);
};
Object.defineProperty(element.prototype, "contentWindow",
contentWindowDesc);
Object.defineProperty(element.prototype, "contentDocument",
contentDocumentDesc);
}
/*
- Wrapper RTCPeerConnection
- L’API webRequest dans Chrome ne permet pas encore de bloquer
- les connexions WebRTC.
- Voir https://bugs.chromium.org/p/chromium/issues/detail?id=707683
*/
let RealCustomEvent = window.CustomEvent;
// Si nous avons été injectés dans une frame via contentWindow, nous pouvons simplement
// récupérer la copie de checkRequest laissée pour nous par le document parent. Sinon,
// nous devons la configurer maintenant, ainsi que les fonctions de gestion d’événements.
if (injectedIntoContentWindow)
checkRequest = window[eventName];
else
{
let addEventListener = document.addEventListener.bind(document);
let dispatchEvent = document.dispatchEvent.bind(document);
let removeEventListener = document.removeEventListener.bind(document);
checkRequest = (url, callback) =>
{
let incomingEventName = eventName + “-” + url;
function listener(event)
{
callback(event.detail);
removeEventListener(incomingEventName, listener);
}
addEventListener(incomingEventName, listener);
dispatchEvent(new RealCustomEvent(eventName, {detail: {url}}));
};
}
// À appeler uniquement avant le code de la page, non renforcé.
function copyProperties(src, dest, properties)
{
for (let name of properties)
{
if (Object.prototype.hasOwnProperty.call(src, name))
{
Object.defineProperty(dest, name,
Object.getOwnPropertyDescriptor(src, name));
}
}
}
let RealRTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection;
// Firefox possède l’option (media.peerconnection.enabled) pour désactiver WebRTC,
// auquel cas RealRTCPeerConnection est indéfini.
if (typeof RealRTCPeerConnection != “undefined”)
{
let closeRTCPeerConnection = Function.prototype.call.bind(
RealRTCPeerConnection.prototype.close
);
let RealArray = Array;
let RealString = String;
let {create: createObject, defineProperty} = Object;
let normalizeUrl = url =>
{
if (typeof url != "undefined")
return RealString(url);
};
let safeCopyArray = (originalArray, transform) =>
{
if (originalArray == null || typeof originalArray != "object")
return originalArray;
let safeArray = RealArray(originalArray.length);
for (let i = 0; i < safeArray.length; i++)
{
defineProperty(safeArray, i, {
configurable: false, enumerable: false, writable: false,
value: transform(originalArray[i])
});
}
defineProperty(safeArray, "length", {
configurable: false, enumerable: false, writable: false,
value: safeArray.length
});
return safeArray;
};
// Il serait beaucoup plus simple d'utiliser la méthode .getConfiguration pour obtenir
// la configuration normalisée et sécurisée à partir de l'instance RTCPeerConnection.
// Malheureusement, elle n'est pas implémentée dans Chrome unstable 59.
// Voir https://www.chromestatus.com/feature/5271355306016768
let protectConfiguration = configuration =>
{
if (configuration == null || typeof configuration != "object")
return configuration;
let iceServers = safeCopyArray(
configuration.iceServers,
iceServer =>
{
let {url, urls} = iceServer;
// RTCPeerConnection n'itére pas sur les tableaux pseudo-arrays de urls.
if (typeof urls != "undefined" && !(urls instanceof RealArray))
urls = [urls];
return createObject(iceServer, {
url: {
configurable: false, enumerable: false, writable: false,
value: normalizeUrl(url)
},
urls: {
configurable: false, enumerable: false, writable: false,
value: safeCopyArray(urls, normalizeUrl)
}
});
}
);
return createObject(configuration, {
iceServers: {
configurable: false, enumerable: false, writable: false,
value: iceServers
}
});
};
let checkUrl = (peerconnection, url) =>
{
checkRequest(url, blocked =>
{
if (blocked)
{
// Appeler .close() lève une exception si déjà fermé.
try
{
closeRTCPeerConnection(peerconnection);
}
catch (e) {}
}
});
};
let checkConfiguration = (peerconnection, configuration) =>
{
if (configuration && configuration.iceServers)
{
for (let i = 0; i < configuration.iceServers.length; i++)
{
let iceServer = configuration.iceServers[i];
if (iceServer)
{
if (iceServer.url)
checkUrl(peerconnection, iceServer.url);
if (iceServer.urls)
{
for (let j = 0; j < iceServer.urls.length; j++)
checkUrl(peerconnection, iceServer.urls[j]);
}
}
}
}
};
// Chrome unstable (testé avec la version 59) a déjà implémenté
// setConfiguration, nous devons donc aussi envelopper cette méthode si elle existe.
// https://www.chromestatus.com/feature/5596193748942848
if (RealRTCPeerConnection.prototype.setConfiguration)
{
let realSetConfiguration = Function.prototype.call.bind(
RealRTCPeerConnection.prototype.setConfiguration
);
RealRTCPeerConnection.prototype.setConfiguration = function(configuration)
{
configuration = protectConfiguration(configuration);
// Appeler la vraie méthode en premier, afin qu'elle valide la configuration pour
// nous. De toute façon, checkRequest est asynchrone de toute manière.
realSetConfiguration(this, configuration);
checkConfiguration(this, configuration);
};
}
let WrappedRTCPeerConnection = function(...args)
{
if (!(this instanceof WrappedRTCPeerConnection))
return RealRTCPeerConnection();
let configuration = protectConfiguration(args[0]);
// Puisque l'ancien constructeur webkitRTCPeerConnection prend un deuxième
// argument optionnel, nous devons veiller à le transmettre. Nécessaire
// pour d'anciennes versions de Chrome comme la 51.
let constraints = undefined;
if (args.length > 1)
constraints = args[1];
let peerconnection = new RealRTCPeerConnection(configuration,
constraints);
checkConfiguration(peerconnection, configuration);
return peerconnection;
};
WrappedRTCPeerConnection.prototype = RealRTCPeerConnection.prototype;
let boundWrappedRTCPeerConnection = WrappedRTCPeerConnection.bind();
copyProperties(RealRTCPeerConnection, boundWrappedRTCPeerConnection,
["generateCertificate", "name", "prototype"]);
RealRTCPeerConnection.prototype.constructor = boundWrappedRTCPeerConnection;
if ("RTCPeerConnection" in window)
window.RTCPeerConnection = boundWrappedRTCPeerConnection;
if ("webkitRTCPeerConnection" in window)
window.webkitRTCPeerConnection = boundWrappedRTCPeerConnection;
}
})(‘abp-request-o6i81ij12x’, true);. bd833f87-4c58-41b0-a0cd-15b978834599:27:22
Avez-vous activé votre politique de sécurité du contenu ?
De plus, envoyez-moi un message privé pour me dire comment vous avez ajouté ce menu déroulant console si stylé. Gracias.
J’ai compris !
C’est l’adblock, ça n’a rien à voir avec Jitsi… ![]()
@sunjam il n’y a pas de nouvelle étape, le composant ajoute automatiquement le script à sa liste blanche.
Pas pour le moment, mais ce serait une bonne amélioration. Je m’en occuperai dès que j’aurai l’occasion.
Super cool ! Quelques remarques rapides —
Sur mobile, après avoir cliqué sur le bouton pour lancer l’événement, le lien « Continuer vers l’application » est parfois non cliquable ! Cela fonctionne lorsque l’on consulte directement dans Safari, mais pas dans Chrome, et pas non plus dans l’application iOS Discourse Hub…
Je rejoins cette demande : un moyen rapide de générer automatiquement un ID de salle pourrait être très utile. Je pense notamment aux personnes qui ne sont pas déjà très familières avec Jitsi : il n’est pas tout à fait clair si l’on doit entrer une salle existante dans ce champ, ou si l’on génère une nouvelle salle à la volée en utilisant simplement une chaîne aléatoire quelconque.
Bonne observation ! Cela est dû au fait que le lien « Continuer vers l’application » effectue une requête d’URL personnalisée commençant par org.jitsi.meet://. J’ai ajouté ce schéma de requête personnalisé à la liste blanche dans DiscourseHub, ce qui devrait résoudre le problème lors de la prochaine mise à jour de l’application. (Je ne pense malheureusement pas qu’il existe de correctif pour cela dans Chrome.)
J’ai ajouté une option de génération aléatoire : les utilisateurs n’ont qu’à laisser le champ ID vide, et un ID sera généré. J’ai également ajouté un texte explicatif à ce sujet :
Notez que l’ID ne contiendra pas de mots, mais sera un mélange aléatoire de lettres et de chiffres.
Y aurait-il une possibilité de prioriser cela ? Nous testons l’utilisation de Jitsi pour nos discussions internes.
Le problème est le suivant :
- Nous créons un fil de discussion en tant qu’événement en utilisant le plugin Calendrier, et nous y intégrons un appel Jitsi prévu à cette heure-là. Parfois, nous faisons cela après un sondage du style Doodle dans le même fil. Le lien Jitsi est placé dans le premier message.
- L’appel se lance, tout va bien.
- Quelqu’un utilise le même onglet pour rechercher quelque chose ou répondre dans le fil (par exemple pour rédiger des comptes rendus en direct) et cela fait quitter l’appel.
Ce ne devrait pas être trop difficile de faire en sorte que le lien ouvre une page vierge plutôt que d’être intégré dans une iframe, non ? Pas que j’aie les compétences pour le faire !
Eh bien, @nathank, ce composant est un peu excessif si vous souhaitez simplement un lien vers une salle Jitsi. Vous pouvez ajouter https://meet.jit.si/ROOMID à un lien, et cela devrait suffire sans avoir besoin d’un composant de thème sophistiqué.
Cependant, j’ai ajouté cette option au composant : vous pouvez maintenant choisir si vous souhaitez l’iframe pour mobile, pour ordinateur de bureau ou pour les deux :
Par défaut, la vidéoconférence est chargée dans une iframe. Si cette option est décochée, elle ouvrira l’appel vidéo dans une fenêtre complète. Avec la vidéoconférence BigBlueButton, cela était particulièrement souhaitable sur mobile, j’ai donc fait de même ici.
Notez également que le lien vers la salle Jitsi en fenêtre complète ne s’ouvre pas dans un nouvel onglet. Si vous souhaitez cela, utilisez une balise ancre avec target="_blank".
Cela me convient, mais moins pour mes utilisateurs moins techniques ! Merci pour l’amélioration de l’iframe, très utile. Je ne suis pas sûr qu’il soit logique que l’iframe soit la valeur par défaut sur mobile ; seriez-vous ouvert à modifier cela ?
J’ai découvert ailleurs que vous pouvez contourner la page « téléchargez l’application Jitsi » qui apparaît sur mobile en ajoutant #config.disableDeepLinking=true à l’ID de la salle :
https://meet.jit.si/YourMeetingNameHere#config.disableDeepLinking=true
J’ai essayé d’ajouter ce composant de thème à notre instance Discourse 2.7.0.beta3, mais quoi que je fasse, je ne vois pas d’icône supplémentaire dans la barre du compositeur pour lier à l’ID de la conférence.
L’option « afficher dans le menu déroulant des options » est cochée dans la configuration du composant de thème, elle devrait donc être visible. Une idée de où je pourrais chercher l’erreur ?
Oui, le problème est résolu maintenant, c’était peut-être un problème de cache.
Néanmoins, merci pour votre réponse.
J’aime vraiment la façon dont ce composant de thème fonctionne. Je me bats toujours avec les problèmes audio de Jitsi, sinon tout aurait fonctionné sans problème. Je me demandais si quelqu’un utilisait actuellement Jitsi sur son forum et n’avait aucune plainte à ce sujet. Mes problèmes audio sont peut-être dus à WebRTC ---- quelqu’un a-t-il également une expérience similaire ?



