Files
zulip/static/js/templates.js
Anders Kaseorg c9796ba7f7 CVE-2020-9444: Prevent reverse tabnabbing attacks.
While we could fix this issue by changing the markdown processor,
doing so is not a robust solution, because even a momentary bug in the
markdown processor could allow cached messages that do not follow our
security policy.

This change ensures that even if our markdown processor has bugs that
result in rendered content that does not properly follow our policy of
using rel="noopener noreferrer" on links, we'll still do something
reasonable.

Co-authored-by: Tim Abbott <tabbott@zulipchat.com>
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-01 13:35:31 -07:00

84 lines
2.7 KiB
JavaScript

const util = require("./util");
// Below, we register Zulip-specific extensions to the handlebars API.
//
// IMPORTANT: When adding a new handlebars helper, update the
// knownHelpers array in the webpack config so that webpack knows your
// helper is registered at runtime and don't try to require them when
// bundling.
// We don't want to wait for DOM ready to register the Handlebars helpers
// below. There's no need to, as they do not access the DOM.
// Furthermore, waiting for DOM ready would introduce race conditions with
// other DOM-ready callbacks that attempt to render templates.
Handlebars.registerHelper('plural', function (condition, one, other) {
return condition === 1 ? one : other;
});
Handlebars.registerHelper({
eq: function (a, b) { return a === b; },
and: function () {
// last argument is Handlebars options
if (arguments.length < 2) {
return true;
}
let i;
for (i = 0; i < arguments.length - 2; i += 1) {
if (!arguments[i] || Handlebars.Utils.isEmpty(arguments[i])) {
return arguments[i];
}
}
return arguments[i];
},
or: function () {
// last argument is Handlebars options
if (arguments.length < 2) {
return false;
}
let i;
for (i = 0; i < arguments.length - 2; i += 1) {
if (arguments[i] && !Handlebars.Utils.isEmpty(arguments[i])) {
return arguments[i];
}
}
return arguments[i];
},
not: function (a) { return !a || Handlebars.Utils.isEmpty(a); },
});
Handlebars.registerHelper('t', function (i18n_key) {
// Marks a string for translation.
// Example usage:
// {{t "some English text"}}
const result = i18n.t(i18n_key);
return new Handlebars.SafeString(result);
});
Handlebars.registerHelper('tr', function (context, options) {
// Marks a block for translation.
// Example usage 1:
// {{#tr context}}
// <p>some English text</p>
// {{/tr}}
//
// Example usage 2:
// {{#tr context}}
// <p>This __variable__ will get value from context</p>
// {{/tr}}
//
// Notes:
// 1. `context` is very important. It can be `this` or an
// object or key of the current context.
// 2. Use `__` instead of `{{` and `}}` to declare expressions
const result = i18n.t(options.fn(context).trim().split("\n").map(s => s.trim()).join(" "), context);
return new Handlebars.SafeString(result);
});
Handlebars.registerHelper(
"rendered_markdown",
content => new Handlebars.SafeString(util.clean_user_content_links(content))
);
window.templates = exports;