-
Notifications
You must be signed in to change notification settings - Fork 119
fix(client): All template writes are by default HTML escaped. #4296
fix(client): All template writes are by default HTML escaped. #4296
Conversation
*/ | ||
unsafeTranslate (text, context = this.getContext()) { | ||
if (Strings.hasUnsafeVariables(text)) { | ||
throw new Error(`Unsafe string to translate: ${text}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of a hard exception, maybe just log these for a train to see if we missed any?
be82ecd
to
9a6ad53
Compare
* @returns {Boolean} true if string has HTML, false otw. | ||
*/ | ||
function hasHTML(string) { | ||
if (/&\D+;/i.test(string)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract these regexp"s into constants
*/ | ||
unsafeTranslate (text, context = this.getContext()) { | ||
if (Strings.hasUnsafeVariables(text)) { | ||
const err = AuthErrors.toError('UNSAFE_VARIABLE_NAME'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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>'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use HTML_MESSAGE
instead.
view.unsafeTranslate(HTML_MESSAGE), UNESCAPED_HTML_TRANSLATION); | ||
assert.isFalse(view.logError.called); | ||
|
||
view.unsafeTranslate('%(unsafeVariableName)s'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract this string to a constant.
3a94829
to
3e085e5
Compare
@mozilla/fxa-devs - who wants it? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In production does this error get sent to us, like sentry or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won"t catch when the escape code is numeric. >
and ?
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)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use ||
instead:
return UNNAMED_VARIABLE_REGEXP.test(string) || UNSAFE_VARIABLE_REGEXP.test(string);
If you feel the if
s 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
3e085e5
to
8aaa194
Compare
@seanmonstar - updated! |
8aaa194
to
47b1317
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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!
47b1317
to
fd6a8d0
Compare
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`
fd6a8d0
to
06d994f
Compare
@shane-tomlinson does this fix the issue reported by cure53? |
@rfk - yes |
A new Mustache helper function
unsafeTranslate
, has been addedfor unsafe writes, to be used when inserting HTML.
All interpolation variables passed to
unsafeTranslate
must beprefixed with
escaped
or else an exception is thrown. This isto 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