discourse/public/javascripts/embed.js
Gina Haeussge f0fc38418c FEATURE: Support referrerPolicy on embed iframe
This commit adds a new property "discourseReferrerPolicy" to the
set of supported configuration properties for the comment embed
script. If provided the value will be used to set the "referrerPolicy"
attribute on the iframe created to display the comments. This in turn
will allow embedding pages to define a more lenient referer policy on
the embed iframe for pages whose default policy is so strict it
keeps the comment embed from working.

Example:

  * Setup:
    * Discourse hosted at discourse.example.com
    * Comments embedded at example.com
    * Referrer-Policy at example.com set to 'same-origin'
  * Without this commit:
    * Loading the comments fails due to the referer being empty
  * With this commit and no adjusted configuration:
    * Loading the comments fails due to the referer being empty
      (= same behaviour as without the commit)
  * With this commit and DiscourseEmbed.discourseReferrerPolicy =
    'no-referrer-when-downgrade' as additional configuration:
    * Loading the comments succeeds

Note that this change is of special interest for embedding pages
wanting to restrict data flows under the terms of the GDPR since
it allows selectively whitelisting comment embeds while preventing
referer leaking by default.
2018-06-25 14:59:34 +10:00

97 lines
2.4 KiB
JavaScript

(function() {
var DE = window.DiscourseEmbed || {};
var comments = document.getElementById('discourse-comments');
var iframe = document.createElement('iframe');
['discourseUrl', 'discourseEmbedUrl', 'discourseUserName', 'discourseReferrerPolicy'].forEach(function(i) {
if (window[i]) { DE[i] = DE[i] || window[i]; }
});
var queryParams = {};
if (DE.discourseEmbedUrl) {
if (DE.discourseEmbedUrl.indexOf('/') === 0) {
console.error("discourseEmbedUrl must be a full URL, not a relative path");
}
queryParams.embed_url = encodeURIComponent(DE.discourseEmbedUrl);
}
if (DE.discourseUserName) {
queryParams.discourse_username = DE.discourseUserName;
}
if (DE.topicId) {
queryParams.topic_id = DE.topicId;
}
var src = DE.discourseUrl + 'embed/comments';
var keys = Object.keys(queryParams);
if (keys.length > 0) {
src += "?";
for (var i=0; i<keys.length; i++) {
if (i > 0) { src += "&"; }
var k = keys[i];
src += k + "=" + queryParams[k];
}
}
iframe.src = src;
iframe.id = 'discourse-embed-frame';
iframe.width = "100%";
iframe.frameBorder = "0";
iframe.scrolling = "no";
if (DE.discourseReferrerPolicy) {
// See https://www.w3.org/TR/html5/semantics-embedded-content.html#the-iframe-element
iframe.referrerPolicy = DE.discourseReferrerPolicy;
}
comments.appendChild(iframe);
// Thanks http://amendsoft-javascript.blogspot.ca/2010/04/find-x-and-y-coordinate-of-html-control.html
function findPosY(obj)
{
var top = 0;
if(obj.offsetParent)
{
while(1)
{
top += obj.offsetTop;
if(!obj.offsetParent)
break;
obj = obj.offsetParent;
}
}
else if(obj.y)
{
top += obj.y;
}
return top;
}
function normalizeUrl(url) {
return url.toLowerCase().replace(/^https?(\:\/\/)?/, '');
}
function postMessageReceived(e) {
if (!e) { return; }
if (normalizeUrl(DE.discourseUrl).indexOf(normalizeUrl(e.origin)) === -1) { return; }
if (e.data) {
if (e.data.type === 'discourse-resize' && e.data.height) {
iframe.height = e.data.height + "px";
}
if (e.data.type === 'discourse-scroll' && e.data.top) {
// find iframe offset
var destY = findPosY(iframe) + e.data.top;
window.scrollTo(0, destY);
}
}
}
window.addEventListener('message', postMessageReceived, false);
})();