Wysiwyg-editor: Option to allow links to contain invalid URLs

Created on 5 May 2016  路  12Comments  路  Source: froala/wysiwyg-editor

We use the editor to allow people to define email templates, where people can fill in mail-merge template tags like {{user.name}}. This works fine in the simple case since it's nothing special for Froala other than text.

However people also often want to insert these template tags as the href in links since the tags could include a URL (or part of a URL). The problem is that Froala strips out this link href since it's an "invalid" URL.

Steps to reproduce:
Create a link with {{custom.foo}} as the href.

Desired behavior:
HTML that looks like <a href="{{custom.foo}}">my text</a>

Actual behavior:
(no anchor link created)

bug

Most helpful comment

The code above seems to break the editor and create an infinite self-referencing loop.

var original_helpers = $.FE.MODULES.helpers; 
$.FE.MODULES.helpers = function (editor) { 
  var helpers = original_helpers(editor);  // this causes an endless loop

I've changed it to this instead and it seems to work:
$.FE.MODULES.helpers.sanitizeURL = function (url) { return url; };

All 12 comments

Thanks!

Using these values as href works:

{{lead.display_name}}
{{lead.custom.[Leads]}}

However values with spaces, etc. get HTML escaped:

e.g. Using an href of:

{{lead.custom.[Org Discount $]}}

produces an href of:

{{lead.custom.[Org%20Discount%20%24]}}

Is this fixable?

@stefanneculai Any thoughts on this comment above?

@philfreo the editor is sanitizing the urls in order to prevent XSS attacks. If you want to permit different URLs, you could use the following code to change the default behavior. Just make sure you include it before initializing the editor.

var original_helpers = $.FE.MODULES.helpers; 
$.FE.MODULES.helpers = function (editor) { 
  var helpers = original_helpers(editor); 

  var isURL = helpers.isURL();  

  // This is the original sanitizer.
  helpers.sanitizeURL = function (url) { 
      if (/^(https?:|ftps?:|)\/\//i.test(url)) {
        if (!isURL(url) && !isURL('http:' + url)) {
          return '';
        }
      }
      else {
        url = encodeURIComponent(url)
                  .replace(/%23/g, '#')
                  .replace(/%2F/g, '/')
                  .replace(/%25/g, '%')
                  .replace(/mailto%3A/gi, 'mailto:')
                  .replace(/file%3A/gi, 'file:')
                  .replace(/sms%3A/gi, 'sms:')
                  .replace(/tel%3A/gi, 'tel:')
                  .replace(/notes%3A/gi, 'notes:')
                  .replace(/data%3Aimage/gi, 'data:image')
                  .replace(/blob%3A/gi, 'blob:')
                  .replace(/webkit-fake-url%3A/gi, 'webkit-fake-url:')
                  .replace(/%3F/g, '?')
                  .replace(/%3D/g, '=')
                  .replace(/%26/g, '&')
                  .replace(/&amp;/g, '&')
                  .replace(/%2C/g, ',')
                  .replace(/%3B/g, ';')
                  .replace(/%2B/g, '+')
                  .replace(/%40/g, '@')
                  .replace(/%5B/g, '[')
                  .replace(/%5D/g, ']')
                  .replace(/%7B/g, '{')
                  .replace(/%7D/g, '}');
      }

      return url;
  }; 

  return helpers;
} 

The code above seems to break the editor and create an infinite self-referencing loop.

var original_helpers = $.FE.MODULES.helpers; 
$.FE.MODULES.helpers = function (editor) { 
  var helpers = original_helpers(editor);  // this causes an endless loop

I've changed it to this instead and it seems to work:
$.FE.MODULES.helpers.sanitizeURL = function (url) { return url; };

Just a heads up for anyone that uses the code above from fyneworks, this will allow XSS attacks in the editor because the urls are not getting sanitized at all.

Thanks for the heads up! We went on to implement the following:

var original_sanitizeURL = $.FE.MODULES.helpers.sanitizeURL;
$.FE.MODULES.helpers.sanitizeURL = function (url) {
    if(url.match(/^\#\w+\#$/gi)) return url; // special cms markup
    return original_sanitizeURL(url); // use FE's original 
};

:-)

Hi there, so i tried the above suggestion but I couldnt get it to work - the code inside the function is never executed. see this jsfiddle. https://jsfiddle.net/63qq3uqk/

We have the same usecase with invalid urls because they are used as template-variables and later injected, so we need this as well!

@dularion please see: https://jsfiddle.net/63qq3uqk/3/

Thank you very much @stefanneculai

@philfreo the editor is sanitizing the urls in order to prevent XSS attacks. If you want to permit different URLs, you could use the following code to change the default behavior. Just make sure you include it before initializing the editor.

var original_helpers = $.FE.MODULES.helpers; 
$.FE.MODULES.helpers = function (editor) { 
  var helpers = original_helpers(editor); 

  var isURL = helpers.isURL();  

  // This is the original sanitizer.
  helpers.sanitizeURL = function (url) { 
      if (/^(https?:|ftps?:|)\/\//i.test(url)) {
        if (!isURL(url) && !isURL('http:' + url)) {
          return '';
        }
      }
      else {
        url = encodeURIComponent(url)
                  .replace(/%23/g, '#')
                  .replace(/%2F/g, '/')
                  .replace(/%25/g, '%')
                  .replace(/mailto%3A/gi, 'mailto:')
                  .replace(/file%3A/gi, 'file:')
                  .replace(/sms%3A/gi, 'sms:')
                  .replace(/tel%3A/gi, 'tel:')
                  .replace(/notes%3A/gi, 'notes:')
                  .replace(/data%3Aimage/gi, 'data:image')
                  .replace(/blob%3A/gi, 'blob:')
                  .replace(/webkit-fake-url%3A/gi, 'webkit-fake-url:')
                  .replace(/%3F/g, '?')
                  .replace(/%3D/g, '=')
                  .replace(/%26/g, '&')
                  .replace(/&amp;/g, '&')
                  .replace(/%2C/g, ',')
                  .replace(/%3B/g, ';')
                  .replace(/%2B/g, '+')
                  .replace(/%40/g, '@')
                  .replace(/%5B/g, '[')
                  .replace(/%5D/g, ']')
                  .replace(/%7B/g, '{')
                  .replace(/%7D/g, '}');
      }

      return url;
  }; 

  return helpers;
} 

I got: Uncaught TypeError: isURL is not a function, can you help me.
test froala wysiwyg.html:64 Uncaught TypeError: isURL is not a function
at Object.helpers.sanitizeURL (test froala wysiwyg.html:64)
at froala_editor.pkgd.min.js:7
at E (froala_editor.pkgd.min.js:7)
at E (froala_editor.pkgd.min.js:7)
at E (froala_editor.pkgd.min.js:7)
at E (froala_editor.pkgd.min.js:7)
at d (froala_editor.pkgd.min.js:7)
at m (froala_editor.pkgd.min.js:7)
at Object.html (froala_editor.pkgd.min.js:7)
at d (froala_editor.pkgd.min.js:7)
helpers.sanitizeURL @ test froala wysiwyg.html:64
(anonymous) @ froala_editor.pkgd.min.js:7
E @ froala_editor.pkgd.min.js:7
E @ froala_editor.pkgd.min.js:7
E @ froala_editor.pkgd.min.js:7
E @ froala_editor.pkgd.min.js:7
d @ froala_editor.pkgd.min.js:7
m @ froala_editor.pkgd.min.js:7
html @ froala_editor.pkgd.min.js:7
d @ froala_editor.pkgd.min.js:7
l @ froala_editor.pkgd.min.js:7
t @ froala_editor.pkgd.min.js:7

after a babel update the syntax proposed here failed for me (t[e] is not a constructor).

following still worked:

const original_helpers = $.FE.MODULES.helpers; 
$.FE.MODULES.helpers = function(editor) {
  return {
   ...original_helpers(editor),
   sanitizeURL(url) { 
     /* .do you stuff */ 
    return url;
   },
}

Was this page helpful?
0 / 5 - 0 ratings