Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create tf-wbr-string for safe word-breaking #2586

Merged
merged 4 commits into from
Aug 22, 2019
Merged

Conversation

wchargin
Copy link
Contributor

Summary:
Prior to this commit, tf-runs-selector used innerHTML to inset word
breaks into text, without explicit attention to sanitization. It
happened to “accidentally” to a pretty good job of preventing XSS
because it inserts <wbr> after each any equals sign, making it
impossible(?) to set any attribute value without closing the tag. But
some lesser injection vectors, like remote CSS fetching, are still
possible with a bit of thought.

This commit introduces a new component, tf-wbr-string, that performs
the word-breaking safely with Polymer APIs.

Test Plan:
Run TensorBoard, and verify that the data location at the bottom of the
runs selector is still rendered properly. Inspect the tf-wbr-string in
the dev tools, and note that wbrs appear in the appropriate places.
Then, select the tf-wbr-string element and use $0.value = "…" to
make sure that it breaks correctly in a variety of cases (empty string,
consecutive delimiters, leading delimiters, trailing delimiters).

Note that git grep inner tensorboard/components/tf_runs_selector no
longer returns any results.

wchargin-branch: tf-wbr-string

Summary:
Prior to this commit, `tf-runs-selector` used `innerHTML` to inset word
breaks into text, without explicit attention to sanitization. It
happened to “accidentally” to a pretty good job of preventing XSS
because it inserts `<wbr>` after each any equals sign, making it
impossible(?) to set any attribute value without closing the tag. But
some lesser injection vectors, like remote CSS fetching, are still
possible with a bit of thought.

This commit introduces a new component, `tf-wbr-string`, that performs
the word-breaking safely with Polymer APIs.

Test Plan:
Run TensorBoard, and verify that the data location at the bottom of the
runs selector is still rendered properly. Inspect the `tf-wbr-string` in
the dev tools, and note that `wbr`s appear in the appropriate places.
Then, select the `tf-wbr-string` element and use `$0.value = "…"` to
make sure that it breaks correctly in a variety of cases (empty string,
consecutive delimiters, leading delimiters, trailing delimiters).

Note that `git grep inner tensorboard/components/tf_runs_selector` no
longer returns any results.

wchargin-branch: tf-wbr-string
Copy link
Contributor

@nfelt nfelt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#628 (comment) 🤣 🥝 (couldn't resist)

result.push({contents: value, last: true});
break;
} else {
const part = value.slice(0, idx + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't idx + 1 only correct if the delimiter match is exactly 1 character? If that's all we want to support it should be documented as such, and then in that case maybe we should construct the regex ourselves to control for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; good point. I’ll make the pattern private.

while (true) {
const idx = value.search(delimiterPattern);
if (idx === -1) {
result.push({contents: value, last: true});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If value was empty (i.e. the last delimiter matched is at the end of the string), then we'll be pushing an extra <wbr> onto the end, which seems unnecessary.

Seems like a fix would just be to do while (value) instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either seems fine with me (they should have the same effect), but sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using while (value) doesn’t actually prevent the last-added part from
having last: false on an input like "a/", and thus doesn’t prevent
the extra <wbr>. Given that the unnecessary <wbr>s do no harm, and
this code is clearly proving too complicated for my tiny brain, I’ve
gone the other way and just included the <wbr> after every part. Much
simpler. Everybody’s a winner.

@wchargin
Copy link
Contributor Author

#628 (comment)

Truth be told, I did not remember writing that comment while writing
this PR, but each one of those thoughts did go through my head once
again. :sigh:

wchargin-source: 4dfbf39f201a0498b48577c870859bf2788bd35e
wchargin-branch: tf-wbr-string
Copy link
Contributor Author

@wchargin wchargin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the course of implementing your suggestion, I have reversed course
entirely. PTAL.

*/
delimiterPattern: {
type: Object /* RegExp */,
value: /([\/=\-_,])/,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve also taken this opportunity to reformat the /[\/=\-_,]/ pattern
for clarity: it does not match a backslash, it does match a hyphen, and
it does not match a caret (ASCII value 0x5E between backslash 0x5C and
underscore 0x5F). This is of course unambiguous in the original form,
but I don’t think that it was as obvious as with /[/=_,-]/.

while (true) {
const idx = value.search(delimiterPattern);
if (idx === -1) {
result.push({contents: value, last: true});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using while (value) doesn’t actually prevent the last-added part from
having last: false on an input like "a/", and thus doesn’t prevent
the extra <wbr>. Given that the unnecessary <wbr>s do no harm, and
this code is clearly proving too complicated for my tiny brain, I’ve
gone the other way and just included the <wbr> after every part. Much
simpler. Everybody’s a winner.

@wchargin wchargin requested a review from nfelt August 22, 2019 00:25
wchargin-source: 12011a79f5e3316129e975f92494a11d5fc3481f
wchargin-branch: tf-wbr-string

<!--
tf-wbr-string safely renders a string, with <wbr> elements inserted
around select delimiters.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

am I reading it correctly that wbr will be added at the end? Also, since delimiter is no longer configurable, can we just write out all the delimiter this would break? e.g., this will be "noop" for input like aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

am I reading it correctly that wbr will be added at the end?

Yes. (#2586 (comment))

Also, since delimiter is no longer configurable, can we just write out
all the delimiter this would break?

Not sure what you mean—are you asking that we specify the delimiter
pattern in this doc comment? Sure, if you like.

e.g., this will be "noop" for input like
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa right?

Yes (as the previous implementation was).

wchargin-source: d4e09ef7a43d7779e2cfdec4d32952e1de750614
wchargin-branch: tf-wbr-string
while (true) {
const idx = value.search(delimiterPattern);
if (idx === -1) {
result.push(value);
Copy link
Contributor

@stephanwlee stephanwlee Aug 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stating obvious: the value can be an empty string and you are pushing an empty string into the result which can cause <wbr><wbr> which probably has zero visual impact.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep!

@wchargin wchargin merged commit 56a9fd0 into master Aug 22, 2019
@wchargin wchargin deleted the wchargin-tf-wbr-string branch August 22, 2019 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants