Render the SVG block in a shadow DOM - #328
Conversation
…that to false. Add a filter around this so sites can opt-in to this security enhancement as desired
…ring those styles don't leak. Add a filter to turn this off
…the editor. This adds the same isolation guard in the editor that we have on the frontend
…ky with the current utils package
|
I have the new tests all passing here, we do have some existing test failures coming out of WP 7.1. I think these will be addressed once we can update to the latest Cypress Utils package (which I think is still stuck getting a proper release out). I did rewrite some of the new tests here to work around that, could do the same for the other failures but have left those alone for now |
peterwilsoncc
left a comment
There was a problem hiding this comment.
This is testing well and looks good.
I've added a few notes inline but there's nothing major that I have picked up.
|
|
||
| Mostly, yes. The Inline SVG block renders an SVG that carries its own `<style>` element inside a shadow root, because CSS inside an inline SVG is otherwise applied to the whole page rather than just the SVG. Stylesheets cannot reach into a shadow root, so theme CSS such as `.entry-content svg { fill: red; }` will not apply to those SVGs. | ||
|
|
||
| Inherited properties still cross the boundary, so setting `color` on an ancestor and using `currentColor` inside the SVG works, as do CSS custom properties. SVGs that do not contain a `<style>` element are rendered exactly as before and can be styled normally. |
There was a problem hiding this comment.
"exactly as before" doesn't really make sense to a new user.
| Inherited properties still cross the boundary, so setting `color` on an ancestor and using `currentColor` inside the SVG works, as do CSS custom properties. SVGs that do not contain a `<style>` element are rendered exactly as before and can be styled normally. | |
| Inherited properties still cross the boundary, so setting `color` on an ancestor and using `currentColor` inside the SVG works, as do CSS custom properties. SVGs that do not contain a `<style>` element are rendered without the shadow root and can be styled by theme stylesheets. |
| 'safe_svg_inline_use_shadow_dom', | ||
| svg_has_stylesheet( $contents ), | ||
| $contents, | ||
| $attributes['imageID'] |
There was a problem hiding this comment.
Let plugin know whether the SVG has a stylesheet.
| $attributes['imageID'] | |
| $attributes['imageID'], | |
| svg_has_stylesheet( $contents ) |
| /** | ||
| * Test that SVGs carrying a stylesheet are recognised. | ||
| */ | ||
| public function test_svg_has_stylesheet() { |
There was a problem hiding this comment.
Nit: might be nice to use a data provider here so the test completes for each item even if a previous one fails.
| /** | ||
| * Test that SVGs without a stylesheet are left alone. | ||
| */ | ||
| public function test_svg_has_no_stylesheet() { |
There was a problem hiding this comment.
as above re data provider.
|
|
||
| Mostly, yes. The Inline SVG block renders an SVG that carries its own `<style>` element inside a shadow root, because CSS inside an inline SVG is otherwise applied to the whole page rather than just the SVG. Stylesheets cannot reach into a shadow root, so theme CSS such as `.entry-content svg { fill: red; }` will not apply to those SVGs. | ||
|
|
||
| Inherited properties still cross the boundary, so setting `color` on an ancestor and using `currentColor` inside the SVG works, as do CSS custom properties. SVGs that do not contain a `<style>` element are rendered exactly as before and can be styled normally. |
There was a problem hiding this comment.
| Inherited properties still cross the boundary, so setting `color` on an ancestor and using `currentColor` inside the SVG works, as do CSS custom properties. SVGs that do not contain a `<style>` element are rendered exactly as before and can be styled normally. | |
| Inherited properties still cross the boundary, so setting `color` on an ancestor and using `currentColor` inside the SVG works, as do CSS custom properties. SVGs that do not contain a `<style>` element are rendered without the shadow root and can be styled by theme stylesheets. |
peterwilsoncc
left a comment
There was a problem hiding this comment.
This looks good to me and is testing well.
Testing notes:
- styled SVGs uploaded on the
developbranch are rendered in shadow DOM on this branch - styles within SVGs can no longer effect the site styles (I was testing with
body {background: grey;} - SVGs without style elements render without a shadow DOM on this branch
- CSS vars and current color are applied to the SVG
Description of the Change
When rendering an SVG in our SVG block, we don't strip out any styles. This can result in someone adding styles that impact other areas of the page and by rendering the SVG, they can impact how the rest of the page looks.
To address this, this PR introduces new handling within the SVG block for any SVG that comes with it's own styles, wrapping those SVGs in a shadow DOM which keeps the styles isolated. This only applies to SVGs that come with styles (though can be turned on/off using the new
safe_svg_inline_use_shadow_domfilter) so for majority of use cases, this won't change anything.Note though for SVGs that do ship with their own styles, theme CSS will no longer be able to target them because of this shadow DOM. That styling will need to be done from within the SVG itself or you can opt out using the
safe_svg_inline_use_shadow_domfilter.In addition, replace the use of
ReactSVGwith our own customInlineSvgcomponent that will offer the same protections within the block editor.We've also introduced the new
removeRemoteReferencesproperty of the sanitizer (coming in v1.0.0) and set that to false by default. This can be turned on with the newsafe_svg_remove_remote_referencesfilter, which will then strip out any remote references, making the SVG markup even more secure.How to test the Change
NOTE: The code here is dependent on the update in #327 so that will either need merged first before testing this or you'll need to manually pull that change in locally when testing.
Basic testing across the plugin is desired here to ensure these changes don't break any existing functionality. Main thing to test is the SVG block.
Beyond that, the automated tests this PR ships with contains some SVG files you can use for testing to ensure the styles they load don't leak into the main document.
Changelog Entry
Credits
Props @darylldoyle, @dkotter
Checklist: