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

Global Styles: Make the config resilient to changes to safecss_filter_attr() #30888

Merged
merged 2 commits into from
Apr 22, 2021
Merged

Global Styles: Make the config resilient to changes to safecss_filter_attr() #30888

merged 2 commits into from
Apr 22, 2021

Conversation

p-jackson
Copy link
Member

@p-jackson p-jackson commented Apr 16, 2021

Description

Unsafe user styles are removed from Global Styles by WP_Theme_JSON::remove_insecure_properties(), however the test for whether a style is unsafe is too strict, and makes us more likely to break if WordPress core changes.

remove_insecure_properties() relies on a particular implementation of the core safecss_filter_attr() function: that it leaves the CSS unchanged if it's safe. But this is an assumption that could change in the future: maybe it removes whitespace around the :; or it converts lowercase colours (#abcabc) to uppercase (#ABCABC). The output of the filter would still be valid but it would break the saving of Global Styles in Gutenberg. In fact safecss_filter_attr() already does break this assumption, we just happen to be getting away with it at the moment because of the way we're calling it.
In general it doesn't feel like we should assume filtering functions will return the input unchanged.

Switching the semantics of the safety check from "style was unchanged" to "style was not stripped" fits better with the description of the safecss_filter_attr() function.

This PR:

  • Refactors the safety check into a new private method
  • Changes the semantics of the safety check
  • Includes a unit test to check a CSS value that is safe but currently rejected in the current implementation (we might not want to merge this, but included for demonstration purposes, let me know what you think)

How has this been tested?

Added a unit test that stretches the remove_insecure_properties() method a little to show how it could fail for unexpected reasons. It adds trailing whitespace to a CSS colour declaration, which failed before I made the change. However it didn't fail when adding leading whitespace, just due to the idiosyncrasies of how safecss_filter_attr() is implemented. Which is sort of my point.

In terms of manual test, this code is exercised when updating and saving Global Styles in the site editor as user without the unfiltered_html permission. I've smoke tested this and it works as expected.

Types of changes

Bug fix (or code quality)

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).

CC @nosolosw @vindl

The CSS values in the theme object can not be unsafe, but we also
shouldn't be so strict that values that would be accepted by a CSS
parser are rejected.
@gziolo gziolo requested a review from ockham April 16, 2021 10:03
@gziolo gziolo added the Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json label Apr 16, 2021
@gziolo gziolo changed the title Make Global Styles resilient to changes to safecss_filter_attr() Global Styles: Make the config resilient to changes to safecss_filter_attr() Apr 16, 2021
@gziolo gziolo added [Type] Enhancement A suggestion for improvement. [Type] Code Quality Issues or PRs that relate to code quality [Feature] Full Site Editing and removed [Type] Enhancement A suggestion for improvement. labels Apr 16, 2021
@gziolo gziolo requested a review from vindl April 16, 2021 10:04
* @param string $property_value Value in a CSS declaration, i.e. the `red` in `color: red`.
* @return boolean
*/
private static function validate_style_declaration( $property_name, $property_value ) {
Copy link
Member

Choose a reason for hiding this comment

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

Can we call this is_safe_declaration or something along those lines?

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree, it has no side-effects and returns a boolean so should start with is_

I've gone with is_safe_css_declaration to disambiguate. There's a lot of different types of declaration in this file, and this method assumes it has already been converted into CSS syntax.

private static function validate_style_declaration( $property_name, $property_value ) {
$style_to_validate = $property_name . ': ' . $property_value;
$filtered = esc_html( safecss_filter_attr( $style_to_validate ) );
return ! empty( trim( $filtered ) );
Copy link
Member

@oandregal oandregal Apr 21, 2021

Choose a reason for hiding this comment

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

This is a better check, thanks! By reading the safecss_filter_attr code I've found other cases in which the current code could have failed:

  • the input string has some null value (null, backspace)
  • the input string has new line characters (\t, \r, \n)
  • the input string has leading or trailing whitespace

note that "input string" is property: value

Copy link
Member

@oandregal oandregal left a comment

Choose a reason for hiding this comment

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

Thanks for taking a look at this, Philip. I've left a comment I'd like us to address (method name) before merging, other than this is ready.

The method was assuming a particular implementation of the
safecss_filter_attr() function. In the future it could do something like
remove whitespace around the ":", or convert lowercase colours (#abcabc)
to uppercase (#ABCABC), which would break saving of Global Styles in
Gutenberg. In general it doesn't feel like we should assume filtering
functions will return the input unchanged.

Switching the semantics of the check from "style was unchanged" to
"style was not stripped" fits better with the description of the
safecss_filter_attr() function.
@oandregal oandregal merged commit c3709a3 into WordPress:trunk Apr 22, 2021
@oandregal
Copy link
Member

Thanks, Philip! This was a good sleuthing and well-scoped PR.

@github-actions github-actions bot added this to the Gutenberg 10.6 milestone Apr 22, 2021
@oandregal oandregal added the [Type] Bug An existing feature does not function as intended label Apr 22, 2021
@p-jackson p-jackson deleted the remove-insecure-properties-accepts-all-valid-styles branch May 4, 2021 23:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Type] Bug An existing feature does not function as intended [Type] Code Quality Issues or PRs that relate to code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants