# Get rid of jQuery .html() or .append() with Handlebars and Backbone

**URL:** <https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308>\
**Category:** Development\
**Created:** [August 16, 2016, 12:41pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308 "2016-08-16T12:41:14Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![blunderboy](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/blunderboy/32/21629_2.png) [@blunderboy](https://discourse.mozilla.org/u/blunderboy)\
**Post date:** [August 16, 2016, 12:41pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/1 "2016-08-16T12:41:15Z")

</div>

Hi Mozilla team,

I have a Mozilla Addon - Requestly. I have ported it from Chrome Extension. Most of the code is same with minor tweaks. I have submitted it for review [here](https://addons.mozilla.org/en-US/developers/addon/requestly_ff/versions). But It has been rejected with the following reasons:

1. Unsafe eval from remote Url - Accepted
2. Code uses jQuery html/append or something similar

Actually my app/addon is based on Backbone+Handlebars. The way I use handlebars is generate the markup with Handlebars compile and then passing a json object. Then I append the markup as innerHTML/jQuery.html of existing DOM Node.

Based on different routes, I render different views in the same element thus calling it as single page app.

Can somebody please let me know how can I get this approach approved with Mozilla Addon Reviewer team. I am also open to fix anything in my implementation if there needs be.

Please also note that current code is also working on Chrome Store from couple of years and it also passed their review mechanism.

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [August 16, 2016, 9:20pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/2 "2016-08-16T21:20:25Z")

</div>

> [@blunderboy](#):
>
> Please also note that current code is also working on Chrome Store from couple of years and it also passed their review mechanism.

The Chrome Store has no review mechanism. So there was nothing to pass.

I have an add-on myself which loads markup and assings it to an elements `.innerHTML`.

To get this accepted by the reviewers you have to make it script injection impossible, and you should do so in a way that is easy to understaind. In my case that is:

```auto
element.innerHTML = sanatize(potentiallyUnsafeHtml);

/**
 * Removes any tags (not their content) that are not listed in 'allowed' and any attributes except for href (not data: or javascript:) and title (order must be href, title)
 * NOTE: Is only secure to assign this directly to .innerHTML or .outerHTML, any concatination sanatize(s1) + sanatize(s2) or passing it to docuent.write() may still be unsafe
 * @param {string} html Untrusted HTML markup
 * @return {[type]} Sanitized, undangerous, simple HTML
 * @license CC-by 4.0
 * @author Niklas Gollenstede
 */
function sanatize(html) {
    const allowed = /^(?:a|b|big|br|code|div|i|p|pre|li|ol|ul|span|sup|sub|tt|math|semantics|annotation(?:-xml)?|m(?:enclose|error|fenced|frac|i|n|o|over|padded|root|row|s|space|sqrt|sub|supsubsup|table|td|text|tr|under|underover))$/;
    return html.replace(
        (/<(\/?)(\w+)[^>]*?(\s+href="(?!(?:javascript|data):)[^"]*?")?(\s+title="[^"]*?")?[^>]*?>/g),
        (match, slash, tag, href, title) => allowed.test(tag) ? ('<'+ slash + tag + (title || '') + (href || '') +'>') : ''
    );
}

```

---

<div class="post-metadata">

**Author:** ![blunderboy](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/blunderboy/32/21629_2.png) [@blunderboy](https://discourse.mozilla.org/u/blunderboy)\
**Post date:** [August 17, 2016, 12:05pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/3 "2016-08-17T12:05:49Z")

</div>

Thanks @NilkasG. Let me add this sanitization to my code as well.  
Thanks for your help.

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [August 17, 2016, 12:28pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/4 "2016-08-17T12:28:11Z")

</div>

You are welcome. Feel free to do so.  
I’ve edited the header to include a license and a NOTE on the security, and have also removed the target="\_blank" insertion.

---

<div class="post-metadata">

**Author:** ![blunderboy](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/blunderboy/32/21629_2.png) [@blunderboy](https://discourse.mozilla.org/u/blunderboy)\
**Post date:** [August 17, 2016, 4:39pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/5 "2016-08-17T16:39:38Z")

</div>

@NilkasG Thanks man!!

So Can I use your code as is now including license. Is that right ?  
Thanks once again!!

---

<div class="post-metadata">

**Author:** ![nipunja](https://avatars.discourse-cdn.com/v4/letter/n/e9a140/32.png) [@nipunja](https://discourse.mozilla.org/u/nipunja)\
**Post date:** [November 16, 2016, 7:36pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/6 "2016-11-16T19:36:43Z")

</div>

Hey sachin,  
I am also looking for a sanitizer which passes the FF addon review panel. Does adding this sanitizer worked for u ?

---

<div class="post-metadata">

**Author:** ![noitidart](https://avatars.discourse-cdn.com/v4/letter/n/9f8e36/32.png) [@noitidart](https://discourse.mozilla.org/u/noitidart)\
**Post date:** [November 16, 2016, 7:40pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/7 "2016-11-16T19:40:15Z")

</div>

This one is approved by the AMO reviewers -

```
function escapeHTML(str) { return str.replace(/[&"'<>]/g, (m) => ({ "&": "&amp;", '"': "&quot;", "'": "&#39;", "<": "&lt;", ">": "&gt;" })[m]); }

```

[https://developer.mozilla.org/en-US/Add-ons/Overlay\_Extensions/XUL\_School/DOM\_Building\_and\_HTML\_Insertion#innerHTML\_with\_HTML\_Escaping](https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/DOM_Building_and_HTML_Insertion#innerHTML_with_HTML_Escaping)

---

<div class="post-metadata">

**Author:** ![nipunja](https://avatars.discourse-cdn.com/v4/letter/n/e9a140/32.png) [@nipunja](https://discourse.mozilla.org/u/nipunja)\
**Post date:** [November 16, 2016, 8:34pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/8 "2016-11-16T20:34:00Z")

</div>

@noitidart@jorgev Thanks for the quick reply. The link that you pointed basically does a html encode and would render html as a text. I am more interested in loading remote html safely (see the last section). It talks about using nsIParserUtils.parseFragment() .

I have some question regarding the usage of nsIParserUtils.parseFragment(). Can we use nsIParserUtils.parseFragment() from Webextension. As per the documentation it seems this can used only via legacy ADD-ON SDK flow.

Is there an equivalent of nsIParserUtils.parseFragment() API which can be used in WebExtension flow.

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [November 16, 2016, 11:47pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/9 "2016-11-16T23:47:39Z")

</div>

> [@nipunja](#):
>
> Can we use nsIParserUtils.parseFragment() from Webextension

Nope. As a general rule, if it starts with `nsI` you can’t.

> Is there an equivalent of nsIParserUtils.parseFragment()

Nope. You will have to bring your own sanitizer.  
If the output of the `sanatize` function above still contains enough information, you can use that. It is quite performant (I don’t think one can do much better) and works.

Otherwise, if you use `XMLHttpRequest`s to get your markup, you could set it `responseType` to `document` and selectively “clone” the returned DOM.  
(I don’t think `XMLHttpRequest` evaluates any scripts when building the DOM, but I am not sure about that.)

If that doesn’t work for you either, I’d suggest [htmlparser2 - npm](https://www.npmjs.com/package/htmlparser2).

---

<div class="post-metadata">

**Author:** ![surisriram](https://avatars.discourse-cdn.com/v4/letter/s/e480ec/32.png) [@surisriram](https://discourse.mozilla.org/u/surisriram)\
**Post date:** [November 30, 2016, 6:01pm UTC](https://discourse.mozilla.org/t/get-rid-of-jquery-html-or-append-with-handlebars-and-backbone/10308/10 "2016-11-30T18:01:14Z")

</div>

nipun,

were you able to get your add on pass review with [https://www.npmjs.com/package/htmlparser2](https://www.npmjs.com/package/htmlparser2). Please do let me know, i am having the same issue.
