From 1615233fa2b2d136042c033480e9bedafa8d5e54 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Fri, 8 Mar 2019 22:04:50 +0000 Subject: [PATCH] Privacy: Be less restrictive of the HTML tags allowed in user data exports. Previously, only `a` and `br` tags were allowed in the `value` table cell for each field included in the HTML file generated when a user is exporting their personal data. Instead of relying on a hardcoded list of allowed tags, the `wp_kses()` call in `wp_privacy_generate_personal_data_export_group_html()` will now fallback to the default list of allowed tags (which includes `i`, `strong`, `em`, and other basic HTML formatting tags). Also, a new context of `personal_data_export` will now be passed to the `wp_kses()` call. As a result, the list of HTML tags and attributes allowed in the export file can now be filtered using the `wp_kses_allowed_html` filter and checking for the `personal_data_export` context. Fixes #44044. Props tz-media, desrosj, pento, birgire, garrett-eclipse. git-svn-id: https://develop.svn.wordpress.org/trunk@44824 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/file.php | 16 +- ...acyGeneratePersonalDataExportGroupHtml.php | 200 ++++++++++++++++++ 2 files changed, 203 insertions(+), 13 deletions(-) create mode 100644 tests/phpunit/tests/privacy/wpPrivacyGeneratePersonalDataExportGroupHtml.php diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index efc846b9eb..03f6e3c7b6 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -1956,17 +1956,7 @@ function wp_print_request_filesystem_credentials_modal() { * @return string The HTML for this group and its items. */ function wp_privacy_generate_personal_data_export_group_html( $group_data ) { - $allowed_tags = array( - 'a' => array( - 'href' => array(), - 'target' => array(), - ), - 'br' => array(), - ); - $allowed_protocols = array( 'http', 'https' ); - $group_html = ''; - - $group_html .= '

' . esc_html( $group_data['group_label'] ) . '

'; + $group_html = '

' . esc_html( $group_data['group_label'] ) . '

'; $group_html .= '
'; foreach ( (array) $group_data['items'] as $group_item_id => $group_item_data ) { @@ -1975,14 +1965,14 @@ function wp_privacy_generate_personal_data_export_group_html( $group_data ) { foreach ( (array) $group_item_data as $group_item_datum ) { $value = $group_item_datum['value']; - // If it looks like a link, make it a link + // If it looks like a link, make it a link. if ( false === strpos( $value, ' ' ) && ( 0 === strpos( $value, 'http://' ) || 0 === strpos( $value, 'https://' ) ) ) { $value = '' . esc_html( $value ) . ''; } $group_html .= ''; $group_html .= '' . esc_html( $group_item_datum['name'] ) . ''; - $group_html .= '' . wp_kses( $value, $allowed_tags, $allowed_protocols ) . ''; + $group_html .= '' . wp_kses( $value, 'personal_data_export' ) . ''; $group_html .= ''; } diff --git a/tests/phpunit/tests/privacy/wpPrivacyGeneratePersonalDataExportGroupHtml.php b/tests/phpunit/tests/privacy/wpPrivacyGeneratePersonalDataExportGroupHtml.php new file mode 100644 index 0000000000..f9f6dd5249 --- /dev/null +++ b/tests/phpunit/tests/privacy/wpPrivacyGeneratePersonalDataExportGroupHtml.php @@ -0,0 +1,200 @@ + 'Test Data Group', + 'items' => array( + array( + array( + 'name' => 'Field 1 Name', + 'value' => 'Field 1 Value', + ), + array( + 'name' => 'Field 2 Name', + 'value' => 'Field 2 Value', + ), + ), + ), + ); + + $actual = wp_privacy_generate_personal_data_export_group_html( $data ); + $expected_table_markup = '
Field 1 NameField 1 Value
Field 2 NameField 2 Value
'; + + $this->assertContains( '

Test Data Group

', $actual ); + $this->assertContains( $expected_table_markup, $actual ); + } + + /** + * Test when a multiple data items are passed. + * + * @ticket 44044 + */ + public function test_group_html_generation_multiple_data_items() { + $data = array( + 'group_label' => 'Test Data Group', + 'items' => array( + array( + array( + 'name' => 'Field 1 Name', + 'value' => 'Field 1 Value', + ), + array( + 'name' => 'Field 2 Name', + 'value' => 'Field 2 Value', + ), + ), + array( + array( + 'name' => 'Field 1 Name', + 'value' => 'Another Field 1 Value', + ), + array( + 'name' => 'Field 2 Name', + 'value' => 'Another Field 2 Value', + ), + ), + ), + ); + + $actual = wp_privacy_generate_personal_data_export_group_html( $data ); + + $this->assertContains( '

Test Data Group

', $actual ); + $this->assertContains( 'Field 1 Value', $actual ); + $this->assertContains( 'Another Field 1 Value', $actual ); + $this->assertContains( 'Field 2 Value', $actual ); + $this->assertContains( 'Another Field 2 Value', $actual ); + $this->assertSame( 2, substr_count( $actual, 'Field 1 Name' ) ); + $this->assertSame( 2, substr_count( $actual, 'Field 2 Name' ) ); + $this->assertSame( 4, substr_count( $actual, '' ) ); + } + + /** + * Values that appear to be links should be wrapped in `` tags. + * + * @ticket 44044 + */ + public function test_links_become_anchors() { + $data = array( + 'group_label' => 'Test Data Group', + 'items' => array( + array( + array( + 'name' => 'HTTP Link', + 'value' => 'http://wordpress.org', + ), + array( + 'name' => 'HTTPS Link', + 'value' => 'https://wordpress.org', + ), + array( + 'name' => 'Link with Spaces', + 'value' => 'https://wordpress.org not a link.', + ), + ), + ), + ); + + $actual = wp_privacy_generate_personal_data_export_group_html( $data ); + + $this->assertContains( 'http://wordpress.org', $actual ); + $this->assertContains( 'https://wordpress.org', $actual ); + $this->assertContains( 'https://wordpress.org not a link.', $actual ); + } + + /** + * HTML in group labels should be escaped. + * + * @ticket 44044 + */ + public function test_group_labels_escaped() { + $data = array( + 'group_label' => '
Escape HTML in group lavels
', + 'items' => array(), + ); + + $actual = wp_privacy_generate_personal_data_export_group_html( $data ); + + $this->assertContains( '

<div>Escape HTML in group lavels</div>

', $actual ); + } + + /** + * Test that the exported data should contain allowed HTML. + * + * @ticket 44044 + */ + public function test_allowed_html_not_stripped() { + $data = array( + 'group_label' => 'Test Data Group', + 'items' => array( + array( + 'links' => array( + 'name' => 'Links are allowed', + 'value' => 'http://wordpress.org', + ), + 'formatting' => array( + 'name' => 'Simple formatting is allowed', + 'value' => 'bold, emphasis, italics, and strong are allowed.', + ), + ), + ), + ); + + $actual = wp_privacy_generate_personal_data_export_group_html( $data ); + + $this->assertContains( $data['items'][0]['links']['value'], $actual ); + $this->assertContains( $data['items'][0]['formatting']['value'], $actual ); + } + + /** + * Test that the exported data should not contain disallowed HTML. + * + * @ticket 44044 + */ + public function test_disallowed_html_is_stripped() { + $data = array( + 'group_label' => 'Test Data Group', + 'items' => array( + array( + 'scripts' => array( + 'name' => 'Script tags are not allowed.', + 'value' => '', + ), + 'images' => array( + 'name' => 'Images are not allowed', + 'value' => 'Alt text', + ), + ), + ), + ); + + $actual = wp_privacy_generate_personal_data_export_group_html( $data ); + + $this->assertNotContains( $data['items'][0]['scripts']['value'], $actual ); + $this->assertContains( 'Testing that script tags are stripped.', $actual ); + + $this->assertNotContains( $data['items'][0]['images']['value'], $actual ); + $this->assertContains( 'Images are not allowed', $actual ); + } +}