From 7b5d5ef57289c00b0314522b2c2981e4fc7a0f6c Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 26 Feb 2016 18:31:29 +0100 Subject: Issue #617: Create sandbox resouces --- web-ui/app/js/sandbox.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 web-ui/app/js/sandbox.js (limited to 'web-ui/app/js') diff --git a/web-ui/app/js/sandbox.js b/web-ui/app/js/sandbox.js new file mode 100644 index 00000000..f9e708d6 --- /dev/null +++ b/web-ui/app/js/sandbox.js @@ -0,0 +1,9 @@ +(function () { + 'use strict'; + + window.onmessage = function (e) { + if (e.data.html) { + document.body.innerHTML = e.data.html; + } + }; +})(); -- cgit v1.2.3 From 9cbf33071f895a3ca1c9dad398d964e189e4a766 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 26 Feb 2016 18:33:10 +0100 Subject: Issue #617: Add sandbox to user-agent --- web-ui/app/js/mail_view/ui/mail_view.js | 46 ++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'web-ui/app/js') diff --git a/web-ui/app/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js index dfc57585..d15788bb 100644 --- a/web-ui/app/js/mail_view/ui/mail_view.js +++ b/web-ui/app/js/mail_view/ui/mail_view.js @@ -71,7 +71,51 @@ define( attachments: attachments })); - this.$node.find('.bodyArea').html(viewHelpers.formatMailBody(data.mail)); + var $iframe = $("#read-sandbox"); + var iframe = $iframe[0]; + + var content = viewHelpers.formatMailBody(data.mail); + + iframe.onload = function() { + // use iframe-resizer to dynamically adapt iframe size to its content + var config = { + resizedCallback: scaleToFit, + checkOrigin: false + }; + $iframe.iFrameResize(config); + + // transform scale iframe to fit container width + // necessary if iframe is wider than container + function scaleToFit() { + var parentWidth = $iframe.parent().width(); + var w = $iframe.width(); + var scale = 'none'; + + // only scale html mails + var mail = data.mail; + if (mail && mail.htmlBody && (w > parentWidth)) { + scale = parentWidth / w; + scale = 'scale(' + scale + ',' + scale + ')'; + } + + $iframe.css({ + '-webkit-transform-origin': '0 0', + '-moz-transform-origin': '0 0', + '-ms-transform-origin': '0 0', + 'transform-origin': '0 0', + '-webkit-transform': scale, + '-moz-transform': scale, + '-ms-transform': scale, + 'transform': scale + }); + } + + iframe.contentWindow.postMessage({ + html: content + }, '*'); + }; + + this.trigger(document, events.search.highlightResults, {where: '.bodyArea'}); this.trigger(document, events.search.highlightResults, {where: '.subjectArea'}); -- cgit v1.2.3 From 1ae14c78bcf79db82d492f9b9a9ae186433ac8fc Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Tue, 1 Mar 2016 19:06:36 +0100 Subject: Issue #617: Remove highlighting for sandboxed content --- web-ui/app/js/mail_list/ui/mail_list.js | 1 - web-ui/app/js/mail_view/ui/mail_view.js | 1 - 2 files changed, 2 deletions(-) (limited to 'web-ui/app/js') diff --git a/web-ui/app/js/mail_list/ui/mail_list.js b/web-ui/app/js/mail_list/ui/mail_list.js index 18d36049..0f6c4fb5 100644 --- a/web-ui/app/js/mail_list/ui/mail_list.js +++ b/web-ui/app/js/mail_list/ui/mail_list.js @@ -81,7 +81,6 @@ define( this.renderMails = function (mails) { _.each(mails, this.appendMail, this); this.trigger(document, events.search.highlightResults, {where: '#mail-list'}); - this.trigger(document, events.search.highlightResults, {where: '.bodyArea'}); this.trigger(document, events.search.highlightResults, {where: '.subjectArea'}); this.trigger(document, events.search.highlightResults, {where: '.msg-header .recipients'}); }; diff --git a/web-ui/app/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js index d15788bb..fbbba409 100644 --- a/web-ui/app/js/mail_view/ui/mail_view.js +++ b/web-ui/app/js/mail_view/ui/mail_view.js @@ -117,7 +117,6 @@ define( - this.trigger(document, events.search.highlightResults, {where: '.bodyArea'}); this.trigger(document, events.search.highlightResults, {where: '.subjectArea'}); this.trigger(document, events.search.highlightResults, {where: '.msg-header .recipients'}); this.trigger(document, events.ui.replyBox.showReplyContainer); -- cgit v1.2.3 From 23b175742f20d96e5b5d3d9cfcc0ed7067197f92 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Thu, 3 Mar 2016 12:25:25 +0100 Subject: Issue #617: Highlight search terms by altering mail content --- web-ui/app/js/helpers/sanitizer.js | 32 ++++++++++++++++++++++------- web-ui/app/js/mail_view/ui/mail_view.js | 10 ++++++++- web-ui/app/js/page/events.js | 2 ++ web-ui/app/js/search/results_highlighter.js | 29 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 8 deletions(-) (limited to 'web-ui/app/js') diff --git a/web-ui/app/js/helpers/sanitizer.js b/web-ui/app/js/helpers/sanitizer.js index eea1f0f7..443e8602 100644 --- a/web-ui/app/js/helpers/sanitizer.js +++ b/web-ui/app/js/helpers/sanitizer.js @@ -23,6 +23,16 @@ define(['DOMPurify', 'he'], function (DOMPurify, he) { */ var sanitizer = {}; + sanitizer.whitelist = [{ + // highlight tag open + pre: '<em class="search-highlight">', + post: '' + }, { + // highlight tag close + pre: '</em>', + post: '' + }]; + /** * Adds html line breaks to a plaintext with line breaks (incl carriage return) * @@ -55,16 +65,24 @@ define(['DOMPurify', 'he'], function (DOMPurify, he) { }; /** - * Runs a given dirty body through he, thereby encoding everything - * as HTML entities. - * - * @param {string} dirtyBody The unsanitized string - * @return {string} Safe-to-display HTML string - */ + * Runs a given dirty body through he, thereby encoding everything + * as HTML entities. + * + * @param {string} dirtyBody The unsanitized string + * @return {string} Safe-to-display HTML string + */ sanitizer.purifyText = function (dirtyBody) { - return he.encode(dirtyBody, { + var escapedBody = he.encode(dirtyBody, { encodeEverything: true }); + + this.whitelist.forEach(function(entry) { + while (escapedBody.indexOf(entry.pre) > -1) { + escapedBody = escapedBody.replace(entry.pre, entry.post); + } + }); + + return escapedBody; }; /** diff --git a/web-ui/app/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js index fbbba409..d952fed7 100644 --- a/web-ui/app/js/mail_view/ui/mail_view.js +++ b/web-ui/app/js/mail_view/ui/mail_view.js @@ -257,9 +257,17 @@ define( this.trigger(events.mail.want, {mail: this.attr.ident, caller: this}); }; + this.highlightMailContent = function (event, data) { + // we can't directly manipulate the iFrame to highlight the content + // so we need to take an indirection where we directly manipulate + // the mail content to accomodate the highlighting + this.trigger(document, events.mail.highlightMailContent, data); + }; + this.after('initialize', function () { - this.on(this, events.mail.here, this.displayMail); this.on(this, events.mail.notFound, this.openNoMessageSelectedPane); + this.on(this, events.mail.here, this.highlightMailContent); + this.on(document, events.mail.display, this.displayMail); this.on(document, events.dispatchers.rightPane.clear, this.teardown); this.on(document, events.mail.tags.updated, this.tagsUpdated); this.on(document, events.mail.deleted, this.mailDeleted); diff --git a/web-ui/app/js/page/events.js b/web-ui/app/js/page/events.js index 7a0dbf9d..ad15e76e 100644 --- a/web-ui/app/js/page/events.js +++ b/web-ui/app/js/page/events.js @@ -121,6 +121,8 @@ define(function () { mail: { here: 'mail:here', want: 'mail:want', + display: 'mail:display', + highlightMailContent: 'mail:highlightMailContent', send: 'mail:send', send_failed: 'mail:send_failed', sent: 'mail:sent', diff --git a/web-ui/app/js/search/results_highlighter.js b/web-ui/app/js/search/results_highlighter.js index 9e3ba167..831be0cd 100644 --- a/web-ui/app/js/search/results_highlighter.js +++ b/web-ui/app/js/search/results_highlighter.js @@ -40,6 +40,7 @@ define( var domIdent = data.where; if(this.attr.keywords) { _.each(this.attr.keywords, function (keyword) { + keyword = escapeRegExp(keyword); $(domIdent).highlightRegex(new RegExp(keyword, 'i'), { tagType: 'em', className: 'search-highlight' @@ -57,12 +58,40 @@ define( }); }; + this.highlightString = function (string) { + _.each(this.attr.keywords, function (keyword) { + keyword = escapeRegExp(keyword); + var regex = new RegExp('(' + keyword + ')', 'ig'); + string = string.replace(regex, '$1'); + }); + return string; + }; + + /* + * Alter data.mail.textPlainBody to highlight each of this.attr.keywords + * and pass it back to the mail_view when done + */ + this.highlightMailContent = function(ev, data){ + var mail = data.mail; + mail.textPlainBody = this.highlightString(mail.textPlainBody); + this.trigger(document, events.mail.display, data); + }; + + /* + * Escapes the special charaters used regular expressions that + * would cause problems with strings in the RegExp constructor + */ + function escapeRegExp(string){ + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + this.after('initialize', function () { this.on(document, events.search.perform, this.getKeywordsSearch); this.on(document, events.ui.tag.select, this.clearHighlights); this.on(document, events.search.resetHighlight, this.clearHighlights); this.on(document, events.search.highlightResults, this.highlightResults); + this.on(document, events.mail.highlightMailContent, this.highlightMailContent); }); } }); -- cgit v1.2.3