Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Template library from Messages app now available in shared/js

74 views
Skip to first unread message

Rick Waldron

unread,
Aug 30, 2013, 5:53:51 PM8/30/13
to dev-gaia
Dearest Gaia Developers,

Pleased to announce that we've moved the templating mechanism that was
developed for Messages app to shared/js. Tests can be found and executed
from system/test/unit/template_test.js.

Several months ago, Julien Wajsberg (:julienw) and I worked together to
move all of the markup strings out of the Messages application program code
and into string templates that could be stored in the application's
index.html. In this effort, we developed a very simple but very useful
string interpolation mechanism that effectively solved all of our
templating needs while abiding the restrictions of FirefoxOS's Content
Security Policy. As Bocoup expanded our attention to the Clock app, we
realized that the same needs existed there. The solution was to move the
Template code out of Messages and into shared/js; through coordination with
peers in Clock, Messages and "shared/js", we've successfully moved the code
today.

Using the Template library is simple:

1. Add <script src="shared/js/template.js"></script> to your index.html

2. Create your template as a comment node inside of any type of element,
place in index.html:

<span id="emphasis-template">
<!-- <${tag}>${value}</${tag}> -->
</span>

<span id="greeting-template">
<!-- Hello ${name}! -->
</span>

3. In your JavaScript code, initialize an instance of this template:

// Template will accept either an id string or a node!
var emphasis = new Template('emphasis-template');
var greeting = new Template(document.getElementById('greeting-template'));


4. Generate a safe markup string with specified values by calling the
`interpolate` method of the template object:

greeting.interpolate({
name: 'World'
});

// Hello World!

Simple partial nesting is supported, just tell `interpolate` which
properties are "safe":

var name = emphasis.interpolate({
tag: 'b',
value: 'World'
});

// we know that the value of 'name' has already been escaped :)
greeting.interpolate({ name: name }, { safe: ['name'] });

// Hello <b>World</b>!


Markup strings produced by Template are innerHTML safe (unless explicitly
marked otherwise, as shown above):

greeting.interpolate({
name: '<script>alert("hi!")' + '</script>'
});

// &lt;script&gt;alert(&quot;hi!&quot;)&lt;/script&gt;


Template instances disallow modification of the template string once the
object is initialized, but the toString() method will return the raw
template as a string:

greeting.toString();

// Hello ${name}!

emphasis.toString();

// <${tag}>${value}</${tag}>



It's important to remember that Template and WebComponent are not at odds
with each other and exist to serve to different purposes; read more here:
https://bugzilla.mozilla.org/show_bug.cgi?id=908950#c6

Finally, we're exploring the addition of two methods that will allow a
program to specify a dom element or document fragment as an insertion
target for the interpolated string output. If you know of any other
general-purpose functionality that might be helpful, please let me know!

Rick

Andrew Sutherland

unread,
Aug 30, 2013, 6:59:58 PM8/30/13
to dev-...@lists.mozilla.org
On 08/30/2013 05:53 PM, Rick Waldron wrote:
> Markup strings produced by Template are innerHTML safe (unless explicitly
> marked otherwise, as shown above):

I think there are some potential risks if strings are interpolated in
contexts other than textContent-equivalents. I've filed
https://bugzilla.mozilla.org/show_bug.cgi?id=911373 under the Gaia
component since it doesn't seem like we have an appropriate component
for code in shared/js. (I'm calling that out here since this might make
discovery of the bug harder for people who might file dupes of it.)

Andrew

Kevin Grandon

unread,
Aug 30, 2013, 7:30:28 PM8/30/13
to Rick Waldron, dev-gaia
Thanks for doing this! We have several different templating solutions all over gaia, so finally having something in shared/ is a good thing. Once we address any escaping concerns it would be good to see if we can leverage this elsewhere.

I would like to work with you guys to use our new html import polyfill to load the template strings from external files. It should just be a slight change and will keep the index.html file much easier to manage.

Best,
Kevin
Markup strings produced by Template are innerHTML safe (unless explicitly
marked otherwise, as shown above):

greeting.interpolate({
name: '<script>alert("hi!")' + '</script>'
});

// &lt;script&gt;alert(&quot;hi!&quot;)&lt;/script&gt;


Template instances disallow modification of the template string once the
object is initialized, but the toString() method will return the raw
template as a string:

greeting.toString();

// Hello ${name}!

emphasis.toString();

// <${tag}>${value}</${tag}>



It's important to remember that Template and WebComponent are not at odds
with each other and exist to serve to different purposes; read more here:
https://bugzilla.mozilla.org/show_bug.cgi?id=908950#c6

Finally, we're exploring the addition of two methods that will allow a
program to specify a dom element or document fragment as an insertion
target for the interpolated string output. If you know of any other
general-purpose functionality that might be helpful, please let me know!

Rick
_______________________________________________
dev-gaia mailing list
dev-...@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-gaia

John Hu

unread,
Sep 1, 2013, 11:09:10 PM9/1/13
to Rick Waldron, dev-gaia
Hi Rick,

This is an awesome work.

I am trying to use Lazy Loader to write template originally that lazy loader helps me to turn comments as a real dom node in the specified place. With the dom node, I use cloneNode(true) to have a new instance of template and use querySelector to wire the data and listener in. I noticed Julien had answered about the comment part: we use those comments as templates we can render several times with different parameters[1]. May you show me how we render several times with different parameters with this Template object?? And is it cloneable?? And is it possible to control the insertion place of it?? In my case, I want the template to be rendered several times at the same place but with specified order. So, I use insertBefore to have the order correct, before.

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=908950#c1


John Hu

Julien Wajsberg

unread,
Sep 2, 2013, 2:15:38 AM9/2/13
to John Hu, Rick Waldron, dev-gaia
Le 02/09/2013 05:09, John Hu a écrit :
> Hi Rick,
>
> This is an awesome work.
>
> I am trying to use Lazy Loader to write template originally that lazy loader helps me to turn comments as a real dom node in the specified place. With the dom node, I use cloneNode(true) to have a new instance of template and use querySelector to wire the data and listener in. I noticed Julien had answered about the comment part: we use those comments as templates we can render several times with different parameters[1]. May you show me how we render several times with different parameters with this Template object?? And is it cloneable?? And is it possible to control the insertion place of it?? In my case, I want the template to be rendered several times at the same place but with specified order. So, I use insertBefore to have the order correct, before.

Our templates engine is really a wrapper around strings, so you can do
what you want with it. In your case, you'll probably want to create a
node using createElement and inject its content using innerHTML or
textContent. And then insert the node wherever you want.

You can also use insertAdjacentHTML [3] to achieve the same result.

see example [1] where we use it for attachments in MMS and [2] when
displaying a message.

[1]
https://github.com/mozilla-b2g/gaia/blob/master/apps/sms/js/attachment.js#L170-L174
[2]
https://github.com/mozilla-b2g/gaia/blob/master/apps/sms/js/thread_ui.js#L1175-L1180
[3]
https://developer.mozilla.org/en-US/docs/Web/API/element.insertAdjacentHTML

signature.asc

Paul Theriault

unread,
Sep 3, 2013, 10:21:25 PM9/3/13
to dev-gaia
Really glad we are moving toward a template for HTML, thank you for pushing this forward.

Just to second what Andrew said though, I think there is more work to be done on the template to make it less easy to shoot yourself in the foot from a security perspective. I'm interested in finding the right balance between usefulness and security though.

Maybe this is already obvious to everyone on the list, but I just want to spell out the risks, just to be clear.

>
> <span id="emphasis-template">
> <!-- <${tag}>${value}</${tag}> -->
> </span>


This example is clearly not safe if 'tag' is at all attacker controlled. Is this pattern really necessary?

I propose that we limit usage to setting:
1. Attribute values
2. values in text nodes

If that is possible, then it is very easy to change template.js to interpolate using DOM methods, for which we no longer need to sanitize or worry about quoting. I really like this approach since it means the HTML structure defined in the template can't be modified by data, so it makes it much easier to review. I had a first attempt at implementing this change in https://bugzilla.mozilla.org/show_bug.cgi?id=911373. I'm interested though to know if this will break valid developer use cases (or enough of them to make template.js less relevant) ?

There are of course still security risks, for example: <-- <a href="${value}"> Some text </button> -->
This is potentially unsafe. CSP might save us from trivial malicious inputs like "javascript:alert(1)". But the attacker can control the link. Also some apps (e.g. SMS app) listens for hashchange events - if attacker can control value in the example above, he can probably control such apps to some degree.

This aside, restricting the usage of template.js it makes it easier to review (from a security perspective), and less easy to make mistakes. Thoughts?

Vivien Nicolas

unread,
Sep 6, 2013, 12:57:32 PM9/6/13
to dev-...@lists.mozilla.org
Any reasons to not use the <template> tag that has been implemented in
https://bugzilla.mozilla.org/show_bug.cgi?id=818976 instead of commented
code?

Rick Waldron

unread,
Sep 6, 2013, 3:28:21 PM9/6/13
to Vivien Nicolas, dev-gaia
On Fri, Sep 6, 2013 at 12:57 PM, Vivien Nicolas <vnic...@mozilla.com>wrote:

> Any reasons to not use the <template> tag that has been implemented in
> https://bugzilla.mozilla.org/**show_bug.cgi?id=818976<https://bugzilla.mozilla.org/show_bug.cgi?id=818976>instead of commented code?


I've filed a bug to update the uses in Messages, Clock and template_test.js
to use <template>, but the issue I do see is that <template>.content
produces a DocumentFragment when we really just want a string to
interpolate. This doesn't prevent Template from using <template>.innerHTML
to get the string that it wants.

Rick


>
> On 30/08/2013 23:53, Rick Waldron wrote:
>
>> Dearest Gaia Developers,
>>
>> Pleased to announce that we've moved the templating mechanism that was
>> developed for Messages app to shared/js. Tests can be found and executed
>> from system/test/unit/template_**test.js.
>>
>> Several months ago, Julien Wajsberg (:julienw) and I worked together to
>> move all of the markup strings out of the Messages application program
>> code
>> and into string templates that could be stored in the application's
>> index.html. In this effort, we developed a very simple but very useful
>> string interpolation mechanism that effectively solved all of our
>> templating needs while abiding the restrictions of FirefoxOS's Content
>> Security Policy. As Bocoup expanded our attention to the Clock app, we
>> realized that the same needs existed there. The solution was to move the
>> Template code out of Messages and into shared/js; through coordination
>> with
>> peers in Clock, Messages and "shared/js", we've successfully moved the
>> code
>> today.
>>
>> Using the Template library is simple:
>>
>> 1. Add <script src="shared/js/template.js"></**script> to your index.html
>>
>> 2. Create your template as a comment node inside of any type of element,
>> place in index.html:
>>
>> <span id="emphasis-template">
>> <!-- <${tag}>${value}</${tag}> -->
>> </span>
>>
>> <span id="greeting-template">
>> <!-- Hello ${name}! -->
>> </span>
>>
>> 3. In your JavaScript code, initialize an instance of this template:
>>
>> // Template will accept either an id string or a node!
>> var emphasis = new Template('emphasis-template');
>> var greeting = new Template(document.**getElementById('greeting-**
>> template'));
>>
>>
>> 4. Generate a safe markup string with specified values by calling the
>> `interpolate` method of the template object:
>>
>> greeting.interpolate({
>> name: 'World'
>> });
>>
>> // Hello World!
>>
>> Simple partial nesting is supported, just tell `interpolate` which
>> properties are "safe":
>>
>> var name = emphasis.interpolate({
>> tag: 'b',
>> value: 'World'
>> });
>>
>> // we know that the value of 'name' has already been escaped :)
>> greeting.interpolate({ name: name }, { safe: ['name'] });
>>
>> // Hello <b>World</b>!
>>
>>
>> Markup strings produced by Template are innerHTML safe (unless explicitly
>> marked otherwise, as shown above):
>>
>> greeting.interpolate({
>> name: '<script>alert("hi!")' + '</script>'
>> });
>>
>> // &lt;script&gt;alert(&quot;hi!&**quot;)&lt;/script&gt;
>>
>>
>> Template instances disallow modification of the template string once the
>> object is initialized, but the toString() method will return the raw
>> template as a string:
>>
>> greeting.toString();
>>
>> // Hello ${name}!
>>
>> emphasis.toString();
>>
>> // <${tag}>${value}</${tag}>
>>
>>
>>
>> It's important to remember that Template and WebComponent are not at odds
>> with each other and exist to serve to different purposes; read more here:
>> https://bugzilla.mozilla.org/**show_bug.cgi?id=908950#c6<https://bugzilla.mozilla.org/show_bug.cgi?id=908950#c6>
>>
>> Finally, we're exploring the addition of two methods that will allow a
>> program to specify a dom element or document fragment as an insertion
>> target for the interpolated string output. If you know of any other
>> general-purpose functionality that might be helpful, please let me know!
>>
>> Rick
>> ______________________________**_________________
>> dev-gaia mailing list
>> dev-...@lists.mozilla.org
>> https://lists.mozilla.org/**listinfo/dev-gaia<https://lists.mozilla.org/listinfo/dev-gaia>
>>
>> ______________________________**_________________
> dev-gaia mailing list
> dev-...@lists.mozilla.org
> https://lists.mozilla.org/**listinfo/dev-gaia<https://lists.mozilla.org/listinfo/dev-gaia>
>

Stefan Arentz

unread,
Sep 6, 2013, 5:05:44 PM9/6/13
to Rick Waldron, Vivien Nicolas, dev-gaia

On Sep 6, 2013, at 3:28 PM, Rick Waldron <waldro...@gmail.com> wrote:

> On Fri, Sep 6, 2013 at 12:57 PM, Vivien Nicolas <vnic...@mozilla.com>wrote:
>
>> Any reasons to not use the <template> tag that has been implemented in
>> https://bugzilla.mozilla.org/**show_bug.cgi?id=818976<https://bugzilla.mozilla.org/show_bug.cgi?id=818976>instead of commented code?
>
>
> I've filed a bug to update the uses in Messages, Clock and template_test.js
> to use <template>, but the issue I do see is that <template>.content
> produces a DocumentFragment when we really just want a string to
> interpolate. This doesn't prevent Template from using <template>.innerHTML
> to get the string that it wants.

What are the security implications here? Does the <template> tag have protection against content injection? Does it do proper context-aware escaping?

The W3C document for this feature is really dry and has no examples.

S.

Julien Wajsberg

unread,
Sep 7, 2013, 6:55:09 PM9/7/13
to Rick Waldron, Vivien Nicolas, dev-gaia
Le 06/09/2013 21:28, Rick Waldron a écrit :
> On Fri, Sep 6, 2013 at 12:57 PM, Vivien Nicolas <vnic...@mozilla.com>wrote:
>
>> Any reasons to not use the <template> tag that has been implemented in
>> https://bugzilla.mozilla.org/**show_bug.cgi?id=818976<https://bugzilla.mozilla.org/show_bug.cgi?id=818976>instead of commented code?
>
> I've filed a bug to update the uses in Messages, Clock and template_test.js
> to use <template>, but the issue I do see is that <template>.content
> produces a DocumentFragment when we really just want a string to
> interpolate. This doesn't prevent Template from using <template>.innerHTML
> to get the string that it wants.
>

Maybe the move to a more DOM-oriented approach as suggested by Paul
Theriault would play well with using the <template> element.

I think this should be done independantly in another library, so that we
can try things and investigate, and we'll switch apps when it's ready.

signature.asc

Kevin Grandon

unread,
Sep 7, 2013, 7:08:38 PM9/7/13
to Julien Wajsberg, Vivien Nicolas, Rick Waldron, dev-gaia
My personal preference would be to put the templates in external files like we do with our HTML import polyfill - using the <template> tag. We could do the same build time optimization that we do with custom elements to ensure there is no performance loss.

It's hard to visualize over email, so I'll submit a pull request for your consideration later this week or next.

Best,
Kevin
> _______________________________________________
> dev-gaia mailing list
> dev-...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-gaia
0 new messages