-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Conversation
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
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.
#628 (comment) 🤣 🥝 (couldn't resist)
result.push({contents: value, last: true}); | ||
break; | ||
} else { | ||
const part = value.slice(0, idx + 1); |
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.
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.
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.
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}); |
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.
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?
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.
Either seems fine with me (they should have the same effect), but sure.
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.
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.
Truth be told, I did not remember writing that comment while writing |
wchargin-source: 4dfbf39f201a0498b48577c870859bf2788bd35e wchargin-branch: tf-wbr-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.
In the course of implementing your suggestion, I have reversed course
entirely. PTAL.
*/ | ||
delimiterPattern: { | ||
type: Object /* RegExp */, | ||
value: /([\/=\-_,])/, |
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’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}); |
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.
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-source: 12011a79f5e3316129e975f92494a11d5fc3481f wchargin-branch: tf-wbr-string
|
||
<!-- | ||
tf-wbr-string safely renders a string, with <wbr> elements inserted | ||
around select delimiters. |
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.
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?
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.
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); |
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.
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.
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.
Yep!
Summary:
Prior to this commit,
tf-runs-selector
usedinnerHTML
to inset wordbreaks 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 itimpossible(?) 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 performsthe 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
inthe dev tools, and note that
wbr
s appear in the appropriate places.Then, select the
tf-wbr-string
element and use$0.value = "…"
tomake 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
nolonger returns any results.
wchargin-branch: tf-wbr-string