Commit cf8e1da2 authored by Jérome Perrin's avatar Jérome Perrin

officejs_support_request_ui: use a handlbars template for comments

This prevents html injection for Mr. <script>
parent a5fcbc4f
...@@ -10,10 +10,32 @@ ...@@ -10,10 +10,32 @@
<script src="renderjs.js" type="text/javascript"></script> <script src="renderjs.js" type="text/javascript"></script>
<!-- custom script --> <!-- custom script -->
<script src="handlebars.js" type="text/javascript"></script>
<script src="gadget_erp5_global.js" type="text/javascript"></script> <script src="gadget_erp5_global.js" type="text/javascript"></script>
<script src="gadget_erp5_pt_form_view_discussable.js" type="text/javascript"></script> <script src="gadget_erp5_pt_form_view_discussable.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="gadget_erp5_pt_form_view_discussable.css"> <link rel="stylesheet" type="text/css" href="gadget_erp5_pt_form_view_discussable.css">
<!-- templates -->
<script id="template-document-list" type="text/x-handlebars-template">
{{#if comments }}
{{#each comments }}
<li>By <strong>{{ user }}</strong> -
<time datetime="{{ date }}" title="{{ date_formatted }}">{{ date_relative }}</time>
<br/>
{{{ text }}}
{{#if attachment_link }}
<br/>
<strong>Attachment: </strong>
<a href="{{attachment_link}}">{{ attachment_name }}</a>
{{/if}}
<hr id="post_item">
</li>
{{/each }}
{{else }}
<p><em>No comment yet.</em></p><hr id="post_item">
{{/if }}
</script>
</head> </head>
<body> <body>
<!-- XXX this is a form replacement --> <!-- XXX this is a form replacement -->
......
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1538971816.32</float> <float>1539136980.8</float>
<string>GMT+9</string> <string>GMT+9</string>
</tuple> </tuple>
</state> </state>
......
/*global window, rJS, RSVP, calculatePageTitle, FormData, URI, jIO, moment */ /*global window, rJS, RSVP, calculatePageTitle, FormData, URI, jIO, moment, Handlebars */
/*jslint nomen: true, indent: 2, maxerr: 3 */ /*jslint nomen: true, indent: 2, maxerr: 3 */
(function (window, rJS, RSVP, calculatePageTitle, moment) { (function (window, rJS, RSVP, calculatePageTitle, moment, Handlebars) {
"use strict"; "use strict";
var gadget_klass = rJS(window),
comment_list_template = Handlebars.compile(
gadget_klass.__template_element.getElementById("template-document-list").innerHTML
);
rJS(window) gadget_klass
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Acquired methods // Acquired methods
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -68,11 +72,9 @@ ...@@ -68,11 +72,9 @@
}); });
}) })
.onStateChange(function () { .onStateChange(function () {
/** @type {GadgetInstance} */
var gadget = this; var gadget = this;
// render the erp5 form // render the erp5 form
return this.getDeclaredGadget("erp5_form") return gadget.getDeclaredGadget("erp5_form")
.push(function (erp5_form) { .push(function (erp5_form) {
return gadget.getDeclaredGadget("editor") return gadget.getDeclaredGadget("editor")
.push(function (editor) { .push(function (editor) {
...@@ -166,55 +168,37 @@ ...@@ -166,55 +168,37 @@
); );
}) })
.push(function (post_list) { .push(function (post_list) {
var queue_list = [], i = 0; function getPostWithLinkAndLocalDate(post) {
if (post_list.length) { post.date_formatted = moment(post.date).format('LLLL');
for (i = 0; i < post_list.length; i += 1) { post.date_relative = moment(post.date).fromNow();
if (post_list[i].attachment_link !== null && post_list[i].attachment_link.indexOf("image_module") !== -1) { if (post.attachment_link === null) {
queue_list.push(gadget.getImageUrl(post_list[i].attachment_link)); return post;
} else if (post_list[i].attachment_link !== null && post_list[i].attachment_link.indexOf("document_module") !== -1) {
queue_list.push(gadget.getDocumentUrl(post_list[i].attachment_link));
} else {
queue_list.push(null);
}
} }
} if (post.attachment_link.indexOf("image_module") !== -1) {
queue_list.push(post_list); return gadget.getImageUrl(post.attachment_link).push(
return RSVP.all(queue_list); function (attachment_link) {
}) post.attachment_link = attachment_link;
.push(function (result_list) { return post;
var s = '', i, comments = gadget.element.querySelector("#post_list"),
plain_content, post_list = result_list.pop();
if (post_list.length) {
for (i = 0; i < post_list.length; i += 1) {
s += '<li>' +
'By <strong>' + post_list[i].user + '</strong>' +
' - <time datetime="' + post_list[i].date + '" title="' + moment(post_list[i].date).format('LLLL') + '">' + moment(post_list[i].date).fromNow() + '</time><br/>';
if (post_list[i].attachment_link !== null && result_list[i] !== null) {
post_list[i].attachment_link = result_list[i];
}
if (post_list[i].text) {
plain_content = post_list[i].text;
if (post_list[i].attachment_link) {
s += plain_content + '<strong>Attachment: </strong>' +
'<a href=\"' +
post_list[i].attachment_link + '\">' + post_list[i].attachment_name +
'</a>';
} else {
s += plain_content;
} }
} else { );
if (post_list[i].attachment_link) {
s += '<strong>Attachment: </strong>' + '<a href=\"' +
post_list[i].attachment_link + '\">' + post_list[i].attachment_name +
'</a>';
}
}
s += '<hr id=post_item>'; // XXX XSS attack!
} }
comments.innerHTML = s; return gadget.getDocumentUrl(post.attachment_link).push(
} else { function (attachment_link) {
comments.innerHTML = "<p><em>No comment yet.</em></p><hr id=post_item>"; post.attachment_link = attachment_link;
return post;
}
);
} }
// build links with attachments and localized dates
var queue_list = [], i = 0;
for (i = 0; i < post_list.length; i += 1) {
queue_list.push(getPostWithLinkAndLocalDate(post_list[i]));
}
return RSVP.all(queue_list);
})
.push(function (comment_list) {
var comments = gadget.element.querySelector("#post_list");
comments.innerHTML = comment_list_template({comments: comment_list});
}); });
}) })
.declareJob('submitPostComment', function () { .declareJob('submitPostComment', function () {
...@@ -276,4 +260,4 @@ ...@@ -276,4 +260,4 @@
.onEvent('submit', function () { .onEvent('submit', function () {
this.submitPostComment(); this.submitPostComment();
}); });
}(window, rJS, RSVP, calculatePageTitle, moment)); }(window, rJS, RSVP, calculatePageTitle, moment, Handlebars));
\ No newline at end of file \ No newline at end of file
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1539135182.86</float> <float>1539140577.69</float>
<string>GMT+9</string> <string>GMT+9</string>
</tuple> </tuple>
</state> </state>
......
...@@ -72,6 +72,22 @@ ...@@ -72,6 +72,22 @@
<td>//ol[@id="post_list"]//li[1]/p</td> <td>//ol[@id="post_list"]//li[1]/p</td>
<td>Post test 1</td> <td>Post test 1</td>
</tr> </tr>
<tr>
<td>waitForText</td>
<td>//ol[@id="post_list"]//li[1]/p</td>
<td>Post test 1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//ol[@id="post_list"]//li[1]/strong</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//ol[@id="post_list"]//li[1]/time</td>
<td>a few seconds ago</td>
</tr>
<!-- The "just posted" message is available because it is retrieved from memcached, <!-- The "just posted" message is available because it is retrieved from memcached,
eventhough it's not ingested yet. But this works only for one message, so to first message eventhough it's not ingested yet. But this works only for one message, so to first message
posted when opening the SR and the second one posted as a comment, we need to flush posted when opening the SR and the second one posted as a comment, we need to flush
...@@ -120,6 +136,17 @@ displayed ...@@ -120,6 +136,17 @@ displayed
<td>//ol[@id="post_list"]//li[1]/p</td> <td>//ol[@id="post_list"]//li[1]/p</td>
<td>Post test 1</td> <td>Post test 1</td>
</tr> </tr>
<tr>
<td>assertText</td>
<td>//ol[@id="post_list"]//li[1]/strong</td>
<td>A1 Corporation</td>
</tr>
<tr>
<td>assertText</td>
<td>//ol[@id="post_list"]//li[1]/time</td>
<td>a few seconds ago</td>
</tr>
<!-- flush activities and post one more message, to exercice ingesting post <!-- flush activities and post one more message, to exercice ingesting post
posted from support request comment, which uses a different code path than posted from support request comment, which uses a different code path than
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment