summary refs log tree commit diff
diff options
context:
space:
mode:
authorKegan Dougal <kegan@matrix.org>2014-10-15 14:42:14 +0100
committerKegan Dougal <kegan@matrix.org>2014-10-15 14:42:14 +0100
commitda19fd0d1aa526a1136af4389feb8f862952329d (patch)
tree43792a76e23b3526f88e2a36ed43fc078cc27a68
parentRemove org.matrix.custom.text.html event type and replace it with 'format' an... (diff)
downloadsynapse-da19fd0d1aa526a1136af4389feb8f862952329d.tar.xz
Add unsanitizedLinky filter to fix links in formatted messages.
This filter is identical to ngSanitize's linky but instead of
sanitizing text which isn't linkified in the addText function,
it doesn't.
-rw-r--r--webclient/app-filter.js59
-rw-r--r--webclient/room/room.html3
2 files changed, 57 insertions, 5 deletions
diff --git a/webclient/app-filter.js b/webclient/app-filter.js
index fc16492ef3..654783cb60 100644
--- a/webclient/app-filter.js
+++ b/webclient/app-filter.js
@@ -1,12 +1,12 @@
 /*
  Copyright 2014 OpenMarket Ltd
- 
+
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
- 
+
  http://www.apache.org/licenses/LICENSE-2.0
- 
+
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -80,4 +80,55 @@ angular.module('matrixWebClient')
     return function(text) {
         return $sce.trustAsHtml(text);
     };
-}]);
\ No newline at end of file
+}])
+// Exactly the same as ngSanitize's linky but instead of pushing sanitized
+// text in the addText function, we just push the raw text. This is ONLY SAFE
+// IF THIS IS USED IN CONJUNCTION WITH NG-BIND-HTML which sweeps with $sanitize
+// already.
+.filter('unsanitizedLinky', ['$sanitize', function($sanitize) {
+  var LINKY_URL_REGEXP =
+        /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/,
+      MAILTO_REGEXP = /^mailto:/;
+
+  return function(text, target) {
+    if (!text) return text;
+    var match;
+    var raw = text;
+    var html = [];
+    var url;
+    var i;
+    while ((match = raw.match(LINKY_URL_REGEXP))) {
+      // We can not end in these as they are sometimes found at the end of the sentence
+      url = match[0];
+      // if we did not match ftp/http/mailto then assume mailto
+      if (match[2] == match[3]) url = 'mailto:' + url;
+      i = match.index;
+      addText(raw.substr(0, i));
+      addLink(url, match[0].replace(MAILTO_REGEXP, ''));
+      raw = raw.substring(i + match[0].length);
+    }
+    addText(raw);
+    return $sanitize(html.join(''));
+
+    function addText(text) {
+      if (!text) {
+        return;
+      }
+      html.push(text);
+    }
+
+    function addLink(url, text) {
+      html.push('<a ');
+      if (angular.isDefined(target)) {
+        html.push('target="');
+        html.push(target);
+        html.push('" ');
+      }
+      html.push('href="');
+      html.push(url);
+      html.push('">');
+      addText(text);
+      html.push('</a>');
+    }
+  };
+}]);
diff --git a/webclient/room/room.html b/webclient/room/room.html
index 479b4c9a05..79a60585a5 100644
--- a/webclient/room/room.html
+++ b/webclient/room/room.html
@@ -121,7 +121,8 @@
                         <span ng-show='msg.content.msgtype === "m.text"' 
                               class="message"
                               ng-class="containsBingWord(msg.content.body) && msg.user_id != state.user_id ? msg.echo_msg_state + ' messageBing' : msg.echo_msg_state"
-                              ng-bind-html="(msg.content.msgtype === 'm.text' && msg.type === 'm.room.message' && msg.content.format === 'org.matrix.custom.html') ? msg.content.formatted_body :
+                              ng-bind-html="(msg.content.msgtype === 'm.text' && msg.type === 'm.room.message' && msg.content.format === 'org.matrix.custom.html') ? 
+                                                                                        (msg.content.formatted_body | unsanitizedLinky) :
                                              (msg.content.msgtype === 'm.text' && msg.type === 'm.room.message') ? (msg.content.body | linky:'_blank') : '' "/>
 
                         <span ng-show='msg.type === "m.call.invite" && msg.user_id == state.user_id'>Outgoing Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span>