Skip to content
This repository has been archived by the owner. It is now read-only.

fix(client): All template writes are by default HTML escaped. #4296

Merged
merged 1 commit into from Oct 25, 2016

Conversation

@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented Oct 18, 2016

A new Mustache helper function unsafeTranslate, has been added
for unsafe writes, to be used when inserting HTML.

All interpolation variables passed to unsafeTranslate must be
prefixed with escaped or else an exception is thrown. This is
to remind the developer to escape the variable in the most
appropriate way.

The t helper function now HTML escapes by default.

Rename some function/variable names for consistency:

  • displaySuccessUnsafe => unsafeDisplaySuccess
  • displayErrorUnsafe => unsafeDisplayError
  • successUnsafe => unsafeSuccess
*/
unsafeTranslate (text, context = this.getContext()) {
if (Strings.hasUnsafeVariables(text)) {
throw new Error(`Unsafe string to translate: ${text}`);

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 18, 2016
Author Member

Instead of a hard exception, maybe just log these for a train to see if we missed any?

@shane-tomlinson shane-tomlinson self-assigned this Oct 18, 2016
@shane-tomlinson shane-tomlinson force-pushed the shane-tomlinson/unsafe-html-in-templates branch 3 times, most recently from be82ecd to 9a6ad53 Oct 18, 2016
* @returns {Boolean} true if string has HTML, false otw.
*/
function hasHTML(string) {
if (/&\D+;/i.test(string)) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 19, 2016
Author Member

Extract these regexp's into constants

*/
unsafeTranslate (text, context = this.getContext()) {
if (Strings.hasUnsafeVariables(text)) {
const err = AuthErrors.toError('UNSAFE_VARIABLE_NAME');

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 19, 2016
Author Member

Maybe rename the error to UNSAFE_INTERPOLATION_VARIABLE_NAME

@@ -75,7 +75,7 @@ define(function (require, exports, module) {

if (email && isOpenWebmailButtonVisible) {
_.extend(context, {
unsafeWebmailLink: this.getWebmailLink(email),
escapedWebmailLink: this.getWebmailLink(email),

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 19, 2016
Author Member

I don't see where this is escaped!

@@ -19,8 +19,7 @@ define(function (require, exports, module) {
const TOOLTIP_MESSAGES = {
FOCUS_PROMPT_MESSAGE: t('8 characters minimum, but longer if you plan to sync passwords.'),
INITIAL_PROMPT_MESSAGE: t('A strong, unique password will keep your Firefox data safe from intruders.'),
WARNING_PROMPT_MESSAGE: t('This is a common password; please consider another one.'),
WARNING_PROMPT_MESSAGE_WITH_LINK: t('This is a common password; please consider another one.')

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 19, 2016
Author Member

the _WITH_LINK variant didn't have a link, so I consolidated the two messages.

@@ -551,6 +597,14 @@ define(function (require, exports, module) {
});
});

describe('unsafeDisplaySuccess', () => {
it('allows HTML in messages', () => {
const expected = 'a message<div>with html</div>';

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 19, 2016
Author Member

use HTML_MESSAGE instead.

view.unsafeTranslate(HTML_MESSAGE), UNESCAPED_HTML_TRANSLATION);
assert.isFalse(view.logError.called);

view.unsafeTranslate('%(unsafeVariableName)s');

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 19, 2016
Author Member

Extract this string to a constant.

@shane-tomlinson shane-tomlinson force-pushed the shane-tomlinson/unsafe-html-in-templates branch 2 times, most recently from 3a94829 to 3e085e5 Oct 19, 2016
@shane-tomlinson shane-tomlinson changed the title WIP: fix(client): All template writes are by default HTML escaped. fix(client): All template writes are by default HTML escaped. Oct 19, 2016
@shane-tomlinson shane-tomlinson removed their assignment Oct 19, 2016
@shane-tomlinson
Copy link
Member Author

@shane-tomlinson shane-tomlinson commented Oct 19, 2016

@mozilla/fxa-devs - who wants it?

Copy link
Member

@seanmonstar seanmonstar left a comment

I absolutely love the explicit naming: unsafeTranslate and escapedFoo. This PR just gives me a warm fuzzy feeling inside. Thank you!

if (Strings.hasHTML(text)) {
const err = AuthErrors.toError('HTML_WILL_BE_ESCAPED');
err.string = text;
this.logError(err);

This comment has been minimized.

@seanmonstar

seanmonstar Oct 19, 2016
Member

In production does this error get sent to us, like sentry or something?

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Oct 21, 2016
Author Member

Yup, exactly, the string itself will be part of the message displayed in Sentry.

var t = function (msg) {
return msg;
};
const HTML_CHAR_CODE_REGEXP = /&\D+;/i;

This comment has been minimized.

@seanmonstar

seanmonstar Oct 19, 2016
Member

This won't catch when the escape code is numeric. &gt; and &#63; are equivalent, this regex won't catch the latter.

* @returns {Boolean} true if has unsafe variables, false otw.
*/
function hasUnsafeVariables(string) {
if (UNNAMED_VARIABLE_REGEXP.test(string)) {

This comment has been minimized.

@seanmonstar

seanmonstar Oct 19, 2016
Member

This could use || instead:

return UNNAMED_VARIABLE_REGEXP.test(string) || UNSAFE_VARIABLE_REGEXP.test(string);

If you feel the ifs read more easily, ignore me.

const NAMED_VARIABLE_REGEXP = /\%\(([a-zA-Z]+)\)s/g;
const UNNAMED_VARIABLE_REGEXP = /%s/g;
// safe variables have an `escaped` prefix.
const UNSAFE_VARIABLE_REGEXP = /\%\(((?!escaped)[a-zA-Z]+)\)s/g;

This comment has been minimized.

@seanmonstar

seanmonstar Oct 19, 2016
Member

We've been moving away from a postfix-Hungarian notation for RegExps in the auth server. I don't know if that's desirable here as well.

@shane-tomlinson shane-tomlinson force-pushed the shane-tomlinson/unsafe-html-in-templates branch from 3e085e5 to 8aaa194 Oct 21, 2016
@shane-tomlinson
Copy link
Member Author

@shane-tomlinson shane-tomlinson commented Oct 21, 2016

@seanmonstar - updated!

@shane-tomlinson shane-tomlinson force-pushed the shane-tomlinson/unsafe-html-in-templates branch from 8aaa194 to 47b1317 Oct 21, 2016
Copy link
Member

@seanmonstar seanmonstar left a comment

All tidy! Looks good from here, except that Travis went red. It might be because of the DNS outage, so I just gave it a kick. Merge when travis is green!

@shane-tomlinson shane-tomlinson force-pushed the shane-tomlinson/unsafe-html-in-templates branch from 47b1317 to fd6a8d0 Oct 24, 2016
A new Mustache helper function `unsafeTranslate`, has been added
for unsafe writes, to be used when inserting HTML.

All interpolation variables passed to `unsafeTranslate` must be
prefixed with `escaped` or else an exception is thrown. This is
to remind the developer to escape the variable in the most
appropriate way.

The `t` helper function now HTML escapes by default.

Rename some function/variable names for consistency:

* `displaySuccessUnsafe` => `unsafeDisplaySuccess`
* `displayErrorUnsafe` => `unsafeDisplayError`
* `successUnsafe` => `unsafeSuccess`
@shane-tomlinson shane-tomlinson force-pushed the shane-tomlinson/unsafe-html-in-templates branch from fd6a8d0 to 06d994f Oct 25, 2016
@shane-tomlinson shane-tomlinson merged commit 4329101 into master Oct 25, 2016
4 checks passed
4 checks passed
ci/circleci Your tests passed on CircleCI!
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details
coverage/coveralls Coverage decreased (-0.02%) to 98.728%
Details
@shane-tomlinson shane-tomlinson deleted the shane-tomlinson/unsafe-html-in-templates branch Oct 25, 2016
@rfk rfk added this to the FxA-0: quality milestone Nov 8, 2016
@rfk
Copy link
Member

@rfk rfk commented Nov 8, 2016

@shane-tomlinson does this fix the issue reported by cure53?

@shane-tomlinson
Copy link
Member Author

@shane-tomlinson shane-tomlinson commented Nov 8, 2016

@rfk - yes
screen shot 2016-11-08 at 12 06 28

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

3 participants