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

Apply styles to SVG text elements directly as allowed by strict CSPs #7256

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

martian111
Copy link
Contributor

This addresses another part of the Plotly code that uses inline CSS (should be related to #2355). This case is less severe than the situation fixed by PR #7109 because it only affects some "advanced" configurations, such as those using "pseudo-HTML" in data set names or in hovertemplate settings. Plots that did not utilize "pseudo-HTML" were not impacted. Even if it did use "pseudo-HTML", depending on how much text formatting was done, the impact of strict CSPs may not be too noticeable. For example, bolded text would have rendered, but without the bold font.

Strict Content Security Policies (those without 'unsafe-inline' keyword) does not permit inline styles (setting the 'style' attribute in code). However, setting individual style properties on an element object is allowed.

Therefore, this fixes the "svg_text_utils.js" by changing the code that retrieves, manipulates, and applies the style attribute strings of the "pseudo-HTML" configuration to instead parse and/or apply styles directly on the element. In other words, instead of using d3.select(node).attr("style", "some string value"), use d3.select(node).style(name, value) as shown in the D3JS docs: https://d3js.org/d3-selection/selecting#select

With this method, in addition to it being allowed by string CSPs, the D3 JS library and/or the browser seems to do some level of input validation and normalization. As such, unit test cases were updated to account for this differences, which includes:

  • Order and format of the attributes were changed. For example, there will be a space after the colon of the CSS style when read back from the browser.
  • Invalid style attributes would not be applied. Thus, fixed test cases with actual valid styles.
  • Setting the "color" style attribute in SVG text spans actually normalizes to setting the "fill" color attribute.
  • Using "Times New Roman" font will cause "make-baseline" test to fail due to "error 525: plotly.js error" when run by the Kaleido Python library. Root cause of that is probably too deep to get into and removing it does not change the substance of that test case (using "Times, serif" achieves the same result).

Testing

I tested using the plotly-basic.js build before and after the fix and configured a basic scatter chart with a hovertemplate configuration containing a lot of formatting using the "pseudo-HTML" allowed by this library. When hovering on the data points, it's very obvious when styles are properly applied.

Note: The "before fix" CSB uses the plotly-basic.js built from master that is the base of this branch since it needs PR #7109 to work properly.

Strict Content Security Policies (those without 'unsafe-inline' keyword)
does not permit inline styles (setting the 'style' attribute in code).
However, setting individual style properties on an element object is
allowed.

Therefore, fix the "svg_text_utils.js" by changing the code that
retrieves, manipulates and applies the style attribute strings of the
"pseudo-HTML" configuration to instead parse and/or apply styles
directly on the element. In other words, instead of using
`d3.select(node).attr("style", "some string value")`, use
`d3.select(node).style(name, value)` as shown in the D3JS docs:
https://d3js.org/d3-selection/selecting#select

With this method, in addition to it being allowed by string CSPs, the
D3 JS library and/or the browser seems to do some level of input
validation and normalization. As such, unit test cases were updated to
account for this differences, which includes:
- Order and format of the attributes were changed. For example,
  there will be a space after the colon of the CSS style when read back
  from the browser.
- Invalid style attributes would not be applied. Thus, fixed test cases
  with actual valid styles.
- Setting the "color" style attribute in SVG text actually normalizes to
  setting the "fill" color attribute.
- Using "Times New Roman" font will cause "make-baseline" test to fail
  due to "error 525: plotly.js error" when run by the Kaleido Python
  library. Root cause of that is probably too deep to get into and
  removing it does not change the substance of that test case (using
  "Times, serif" achieves the same result).
@martian111
Copy link
Contributor Author

Hi @archmoj and @birkskyum, this new PR also relates to strict CSPs. I mentioned "another issue" in PR #7109 since this is unrelated to fixes discussed in that PR and its history. Instead, it relates to "pseudo-HTML" configurations that convert to SVG text elements/spans, such as those generated by formatted hovertemplate configurations. Please let me know if you think this is also helpful and if there is anything else I need to change or consider. I haven't used Plotly too extensively and only have basic experience with scatter plots, so hope this does cause issues elsewhere. Thanks!

@gvwilson gvwilson added community community contribution P2 considered for next cycle fix fixes something broken labels Oct 28, 2024
draftlogs/7256_fix.md Outdated Show resolved Hide resolved
Copy link
Contributor

@archmoj archmoj left a comment

Choose a reason for hiding this comment

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

Great fix and simplifications.
💃

@@ -3,7 +3,7 @@
{
"x": ["<b>b</b> <i>i</i>", "line <em>1</em><br>line <b>2</b>"],
"y": ["sub<sub>1</sub>", "sup<sup>2</sup>"],
"name": "<b>test</b> <i>pseudo</i>HTML<br><sup>3</sup>H<sub>2</sub>O is <em>heavy!</em><br>and <span style=\"color:#f00;font-family:'Times New Roman', Times, serif\">Fonts,</span><br>oh my?"
"name": "<b>test</b> <i>pseudo</i>HTML<br><sup>3</sup>H<sub>2</sub>O is <em>heavy!</em><br>and <span style=\"color:#f00;font-family:'Times', serif\">Fonts,</span><br>oh my?"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this change necessary? Would the former family list be handled differently by the new code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I remember correctly (it's been a while now), it caused errors with the test automation when run by CircleCI (don't have exact details at the moment). I assumed it was an environment/setup issue, for example, font not installed. Removing Times New Roman helped get the test case to run and pass without errors. I believe the spirit of the test case is intact to show that the font style did get applied as expected.

Copy link
Collaborator

Choose a reason for hiding this comment

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

hmph, the CI env hasn't changed though, so if the same input that used to work now causes errors, doesn't that mean there's something different now about how we're handling these attributes?

Overall this is a fantastic change! Just want to make sure we aren't creating a subtle bug along the way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community community contribution fix fixes something broken P2 considered for next cycle
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants