Make WordPress Core

Changeset 41392


Ignore:
Timestamp:
09/19/2017 07:43:34 AM (9 years ago)
Author:
ocean90
Message:

Widgets: Prevent visual Text widget from decoding encoded HTML.

Also apply the_editor_content filters on widget text with format_for_editor() as is done for the post editor.

Merge of [41260] to the 4.8 branch.

Amends [40631].
Props westonruter, azaozz.
See #35243.
Fixes #41596.

Location:
branches/4.8
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/4.8

  • branches/4.8/src/wp-admin/js/widgets/text-widgets.js

    r41133 r41392  
    8181                        _.each( control.fields, function( fieldInput, fieldName ) {
    8282                                fieldInput.on( 'input change', function updateSyncField() {
    83                                         var syncInput = control.syncContainer.find( 'input[type=hidden].' + fieldName );
     83                                        var syncInput = control.syncContainer.find( '.sync-input.' + fieldName );
    8484                                        if ( syncInput.val() !== fieldInput.val() ) {
    8585                                                syncInput.val( fieldInput.val() );
     
    8989
    9090                                // Note that syncInput cannot be re-used because it will be destroyed with each widget-updated event.
    91                                 fieldInput.val( control.syncContainer.find( 'input[type=hidden].' + fieldName ).val() );
     91                                fieldInput.val( control.syncContainer.find( '.sync-input.' + fieldName ).val() );
    9292                        });
    9393                },
     
    145145
    146146                        if ( ! control.fields.title.is( document.activeElement ) ) {
    147                                 syncInput = control.syncContainer.find( 'input[type=hidden].title' );
     147                                syncInput = control.syncContainer.find( '.sync-input.title' );
    148148                                control.fields.title.val( syncInput.val() );
    149149                        }
    150150
    151                         syncInput = control.syncContainer.find( 'input[type=hidden].text' );
     151                        syncInput = control.syncContainer.find( '.sync-input.text' );
    152152                        if ( control.fields.text.is( ':visible' ) ) {
    153153                                if ( ! control.fields.text.is( document.activeElement ) ) {
  • branches/4.8/src/wp-includes/widgets/class-wp-widget-text.php

    r41391 r41392  
    336336         * @access public
    337337         * @see WP_Widget_Visual_Text::render_control_template_scripts()
     338         * @see _WP_Editors::editor()
    338339         *
    339340         * @param array $instance Current settings.
     
    350351                ?>
    351352                <?php if ( ! $this->is_legacy_instance( $instance ) ) : ?>
    352                         <input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="title" type="hidden" value="<?php echo esc_attr( $instance['title'] ); ?>">
    353                         <input id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>" class="text" type="hidden" value="<?php echo esc_attr( $instance['text'] ); ?>">
    354                         <input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" class="filter" type="hidden" value="on">
    355                         <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value="on">
     353                        <?php
     354
     355                        if ( user_can_richedit() ) {
     356                                add_filter( 'the_editor_content', 'format_for_editor', 10, 2 );
     357                                $default_editor = 'tinymce';
     358                        } else {
     359                                $default_editor = 'html';
     360                        }
     361
     362                        /** This filter is documented in wp-includes/class-wp-editor.php */
     363                        $text = apply_filters( 'the_editor_content', $instance['text'], $default_editor );
     364
     365                        // Reset filter addition.
     366                        if ( user_can_richedit() ) {
     367                                remove_filter( 'the_editor_content', 'format_for_editor' );
     368                        }
     369
     370                        // Prevent premature closing of textarea in case format_for_editor() didn't apply or the_editor_content filter did a wrong thing.
     371                        $escaped_text = preg_replace( '#</textarea#i', '&lt;/textarea', $text );
     372
     373                        ?>
     374                        <input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="title sync-input" type="hidden" value="<?php echo esc_attr( $instance['title'] ); ?>">
     375                        <textarea id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>" class="text sync-input" hidden><?php echo $escaped_text; ?></textarea>
     376                        <input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" class="filter sync-input" type="hidden" value="on">
     377                        <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual sync-input" type="hidden" value="on">
    356378                <?php else : ?>
    357379                        <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value="">
  • branches/4.8/tests/phpunit/tests/widgets/text-widget.php

    r41391 r41392  
    447447         */
    448448        function test_form() {
    449                 $widget = new WP_Widget_Text();
     449                add_filter( 'user_can_richedit', '__return_true' );
     450                $widget = new WP_Widget_Text();
     451                $widget->_set( 2 );
    450452                $instance = array(
    451453                        'title' => 'Title',
     
    459461                $form = ob_get_clean();
    460462                $this->assertContains( 'class="visual" type="hidden" value=""', $form );
    461                 $this->assertNotContains( 'class="visual" type="hidden" value="on"', $form );
     463                $this->assertNotContains( 'class="visual sync-input" type="hidden" value="on"', $form );
    462464
    463465                $instance = array(
     
    470472                $widget->form( $instance );
    471473                $form = ob_get_clean();
    472                 $this->assertContains( 'class="visual" type="hidden" value="on"', $form );
    473                 $this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
     474                $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
     475                $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
    474476
    475477                $instance = array(
     
    482484                $widget->form( $instance );
    483485                $form = ob_get_clean();
    484                 $this->assertContains( 'class="visual" type="hidden" value="on"', $form );
    485                 $this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
    486 
    487                 $instance = array(
    488                         'title' => 'Title',
    489                         'text' => 'Text',
     486                $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
     487                $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
     488
     489                $instance = array(
     490                        'title' => 'Title',
     491                        'text' => 'This is some HTML Code: <code>&lt;strong&gt;BOLD!&lt;/strong&gt;</code>',
    490492                        'filter' => true,
    491493                        'visual' => true,
     
    495497                $widget->form( $instance );
    496498                $form = ob_get_clean();
    497                 $this->assertContains( 'class="visual" type="hidden" value="on"', $form );
    498                 $this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
     499                $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
     500                $this->assertContains( '&lt;code&gt;&amp;lt;strong&amp;gt;BOLD!', $form );
     501                $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
     502
     503                remove_filter( 'user_can_richedit', '__return_true' );
     504                add_filter( 'user_can_richedit', '__return_false' );
     505                $instance = array(
     506                        'title' => 'Title',
     507                        'text' => 'Evil:</textarea><script>alert("XSS")</script>',
     508                        'filter' => true,
     509                        'visual' => true,
     510                );
     511                $this->assertFalse( $widget->is_legacy_instance( $instance ) );
     512                ob_start();
     513                $widget->form( $instance );
     514                $form = ob_get_clean();
     515                $this->assertNotContains( 'Evil:</textarea>', $form );
     516                $this->assertContains( 'Evil:&lt;/textarea>', $form );
    499517        }
    500518
Note: See TracChangeset for help on using the changeset viewer.