Make WordPress Core


Ignore:
Timestamp:
12/14/2018 03:19:48 AM (8 years ago)
Author:
pento
Message:

Embeds: Filter HTML response in oEmbed proxy controller.

Adapts the response from WP_oEmbed_Controller::get_proxy_item() so that the response is correctly filtered and embeds work properly in JavaSccript editors. Introduces new get_oembed_response_data_for_url() function for preparing internal oEmbed responses.

Merges [43810] from the 5.0 branch to trunk.

Props danielbachhuber, imath, swissspidy.
Fixes #45142.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/tests/phpunit/tests/oembed/controller.php

    r42724 r44154  
    1515        const YOUTUBE_VIDEO_ID   = 'OQSNhk5ICTI';
    1616        const INVALID_OEMBED_URL = 'https://www.notreallyanoembedprovider.com/watch?v=awesome-cat-video';
     17        const UNTRUSTED_PROVIDER_URL = 'https://www.untrustedprovider.com';
    1718
    1819        public static function wpSetUpBeforeClass( $factory ) {
     
    5051
    5152                add_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10, 3 );
     53                add_filter( 'oembed_result', array( $this, 'filter_oembed_result' ), 10, 3 );
    5254                $this->request_count = 0;
     55
     56                $this->oembed_result_filter_count = 0;
    5357        }
    5458
     
    6064
    6165                remove_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10 );
     66                remove_filter( 'oembed_result', array( $this, 'filter_oembed_result' ), 10 );
    6267        }
    6368
     
    6873         */
    6974        public $request_count = 0;
     75
     76        /**
     77         * Count of the number of times the oembed_result filter was called.
     78         *
     79         * @var int
     80         */
     81        public $oembed_result_filter_count = 0;
    7082
    7183        /**
     
    8193
    8294                $parsed_url = wp_parse_url( $url );
    83                 parse_str( $parsed_url['query'], $query_params );
     95                $query      = isset( $parsed_url['query'] ) ? $parsed_url['query'] : '';
     96                parse_str( $query, $query_params );
    8497                $this->request_count += 1;
    8598
     
    100113                                                'thumbnail_height' => $query_params['maxheight'],
    101114                                                'height'           => $query_params['maxheight'],
    102                                                 'html'             => '<iframe width="' . $query_params['maxwidth'] . '" height="' . $query_params['maxheight'] . '" src="https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID . '?feature=oembed" frameborder="0" allowfullscreen></iframe>',
     115                                                'html'             => '<b>Unfiltered</b><iframe width="' . $query_params['maxwidth'] . '" height="' . $query_params['maxheight'] . '" src="https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID . '?feature=oembed" frameborder="0" allowfullscreen></iframe>',
    103116                                                'author_name'      => 'Yosemitebear62',
    104117                                                'thumbnail_url'    => 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg',
     
    107120                                ),
    108121                        );
    109                 } else {
     122                }
     123
     124                if ( $url === self::UNTRUSTED_PROVIDER_URL ) {
    110125                        return array(
    111126                                'response' => array(
    112                                         'code' => 404,
     127                                        'code' => 200,
     128                                ),
     129                                'body'     => '<html><head><link rel="alternate" type="application/json+oembed" href="' . self::UNTRUSTED_PROVIDER_URL . '" /></head><body></body></html>',
     130                        );
     131                }
     132
     133                if ( ! empty( $query_params['url'] ) && false !== strpos( $query_params['url'], self::UNTRUSTED_PROVIDER_URL ) ) {
     134                        return array(
     135                                'response' => array(
     136                                        'code' => 200,
     137                                ),
     138                                'body'     => wp_json_encode(
     139                                        array(
     140                                                'version'          => '1.0',
     141                                                'type'             => 'rich',
     142                                                'provider_name'    => 'Untrusted',
     143                                                'provider_url'     => self::UNTRUSTED_PROVIDER_URL,
     144                                                'html'             => '<b>Filtered</b><a href="">Unfiltered</a>',
     145                                                'author_name'      => 'Untrusted Embed Author',
     146                                                'title'            => 'Untrusted Embed',
     147                                        )
    113148                                ),
    114149                        );
    115150                }
     151
     152                return array(
     153                        'response' => array(
     154                                'code' => 404,
     155                        ),
     156                );
     157        }
     158
     159        /**
     160         * Filters 'oembed_result' to ensure correct type.
     161         *
     162         * @param string|false $data The returned oEmbed HTML.
     163         * @param string       $url  URL of the content to be embedded.
     164         * @param array        $args Optional arguments, usually passed from a shortcode.
     165         * @return string
     166         */
     167        public function filter_oembed_result( $data, $url, $args ) {
     168                if ( ! is_string( $data ) && false !== $data ) {
     169                        $this->fail( 'Unexpected type for $data.' );
     170                }
     171                $this->assertInternalType( 'string', $url );
     172                $this->assertInternalType( 'array', $args );
     173                $this->oembed_result_filter_count++;
     174                return $data;
    116175        }
    117176
     
    544603
    545604                $this->assertNotEmpty( $data );
    546                 $this->assertTrue( is_object( $data ) );
     605                $this->assertInternalType( 'object', $data );
    547606                $this->assertEquals( 'YouTube', $data->provider_name );
    548607                $this->assertEquals( 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg', $data->thumbnail_url );
     
    586645                $this->assertEquals( $data['code'], 'rest_invalid_param' );
    587646        }
     647
     648        /**
     649         * @ticket 45142
     650         */
     651        function test_proxy_with_internal_url() {
     652                wp_set_current_user( self::$editor );
     653
     654                $user = self::factory()->user->create_and_get( array(
     655                        'display_name' => 'John Doe',
     656                ) );
     657                $post = self::factory()->post->create_and_get( array(
     658                        'post_author' => $user->ID,
     659                        'post_title'  => 'Hello World',
     660                ) );
     661
     662                $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
     663                $request->set_param( 'url', get_permalink( $post->ID ) );
     664                $request->set_param( 'maxwidth', 400 );
     665
     666                $response = rest_get_server()->dispatch( $request );
     667                $data     = $response->get_data();
     668
     669                $data = (array) $data;
     670
     671                $this->assertNotEmpty( $data );
     672
     673                $this->assertArrayHasKey( 'version', $data );
     674                $this->assertArrayHasKey( 'provider_name', $data );
     675                $this->assertArrayHasKey( 'provider_url', $data );
     676                $this->assertArrayHasKey( 'author_name', $data );
     677                $this->assertArrayHasKey( 'author_url', $data );
     678                $this->assertArrayHasKey( 'title', $data );
     679                $this->assertArrayHasKey( 'type', $data );
     680                $this->assertArrayHasKey( 'width', $data );
     681
     682                $this->assertEquals( '1.0', $data['version'] );
     683                $this->assertEquals( get_bloginfo( 'name' ), $data['provider_name'] );
     684                $this->assertEquals( get_home_url(), $data['provider_url'] );
     685                $this->assertEquals( $user->display_name, $data['author_name'] );
     686                $this->assertEquals( get_author_posts_url( $user->ID, $user->user_nicename ), $data['author_url'] );
     687                $this->assertEquals( $post->post_title, $data['title'] );
     688                $this->assertEquals( 'rich', $data['type'] );
     689                $this->assertTrue( $data['width'] <= $request['maxwidth'] );
     690        }
     691
     692        /**
     693         * @ticket 45142
     694         */
     695        function test_proxy_with_static_front_page_url() {
     696                wp_set_current_user( self::$editor );
     697
     698                $post = self::factory()->post->create_and_get( array(
     699                        'post_title'  => 'Front page',
     700                        'post_type'   => 'page',
     701                        'post_author' => 0,
     702                ) );
     703
     704                update_option( 'show_on_front', 'page' );
     705                update_option( 'page_on_front', $post->ID );
     706
     707                $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
     708                $request->set_param( 'url', home_url() );
     709                $request->set_param( 'maxwidth', 400 );
     710
     711                $response = rest_get_server()->dispatch( $request );
     712                $data     = $response->get_data();
     713
     714                $this->assertInternalType( 'object', $data );
     715
     716                $data = (array) $data;
     717
     718                $this->assertNotEmpty( $data );
     719
     720                $this->assertArrayHasKey( 'version', $data );
     721                $this->assertArrayHasKey( 'provider_name', $data );
     722                $this->assertArrayHasKey( 'provider_url', $data );
     723                $this->assertArrayHasKey( 'author_name', $data );
     724                $this->assertArrayHasKey( 'author_url', $data );
     725                $this->assertArrayHasKey( 'title', $data );
     726                $this->assertArrayHasKey( 'type', $data );
     727                $this->assertArrayHasKey( 'width', $data );
     728
     729                $this->assertEquals( '1.0', $data['version'] );
     730                $this->assertEquals( get_bloginfo( 'name' ), $data['provider_name'] );
     731                $this->assertEquals( get_home_url(), $data['provider_url'] );
     732                $this->assertEquals( get_bloginfo( 'name' ), $data['author_name'] );
     733                $this->assertEquals( get_home_url(), $data['author_url'] );
     734                $this->assertEquals( $post->post_title, $data['title'] );
     735                $this->assertEquals( 'rich', $data['type'] );
     736                $this->assertTrue( $data['width'] <= $request['maxwidth'] );
     737
     738                update_option( 'show_on_front', 'posts' );
     739        }
     740
     741        /**
     742         * @ticket 45142
     743         */
     744        public function test_proxy_filters_result_of_untrusted_oembed_provider() {
     745                wp_set_current_user( self::$editor );
     746
     747                $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
     748                $request->set_param( 'url', self::UNTRUSTED_PROVIDER_URL );
     749                $request->set_param( 'maxwidth', 456 );
     750                $request->set_param( 'maxheight', 789 );
     751                $request->set_param( '_wpnonce', wp_create_nonce( 'wp_rest' ) );
     752
     753                $response = rest_get_server()->dispatch( $request );
     754                $data     = $response->get_data();
     755
     756                $this->assertEquals( 1, $this->oembed_result_filter_count );
     757                $this->assertInternalType( 'object', $data );
     758                $this->assertEquals( 'Untrusted', $data->provider_name );
     759                $this->assertEquals( self::UNTRUSTED_PROVIDER_URL, $data->provider_url );
     760                $this->assertEquals( 'rich', $data->type );
     761                $this->assertFalse( $data->html );
     762        }
     763
     764        /**
     765         * @ticket 45142
     766         */
     767        public function test_proxy_does_not_filter_result_of_trusted_oembed_provider() {
     768                wp_set_current_user( self::$editor );
     769
     770                $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
     771                $request->set_param( 'url', 'https://www.youtube.com/watch?v=' . self::YOUTUBE_VIDEO_ID );
     772                $request->set_param( 'maxwidth', 456 );
     773                $request->set_param( 'maxheight', 789 );
     774                $request->set_param( '_wpnonce', wp_create_nonce( 'wp_rest' ) );
     775
     776                $response = rest_get_server()->dispatch( $request );
     777                $data     = $response->get_data();
     778
     779                $this->assertEquals( 1, $this->oembed_result_filter_count );
     780                $this->assertInternalType( 'object', $data );
     781
     782                $this->assertStringStartsWith( '<b>Unfiltered</b>', $data->html );
     783        }
    588784}
Note: See TracChangeset for help on using the changeset viewer.