Skip to content

Commit

Permalink
Merge pull request #915 from Automattic/add/amp-live-list-support
Browse files Browse the repository at this point in the history
Add support for amp-live-list requests
  • Loading branch information
westonruter committed Jan 29, 2018
2 parents e3aaaff + 91f2e79 commit 162fa9e
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 0 deletions.
68 changes: 68 additions & 0 deletions includes/class-amp-theme-support.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ class AMP_Theme_Support {
'attachment',
);

/**
* AMP-specific query vars that were purged.
*
* @since 0.7
* @see AMP_Theme_Support::purge_amp_query_vars()
* @var string[]
*/
public static $purged_amp_query_vars = array();

/**
* Initialize.
*/
Expand Down Expand Up @@ -93,6 +102,7 @@ public static function init() {
self::register_paired_hooks();
}

self::purge_amp_query_vars();
self::register_hooks();
self::$embed_handlers = self::register_content_embed_handlers();
self::$sanitizer_classes = amp_get_content_sanitizers();
Expand Down Expand Up @@ -183,6 +193,64 @@ public static function register_hooks() {
// @todo Add character conversion.
}

/**
* Remove query vars that come in requests such as for amp-live-list.
*
* WordPress should generally not respond differently to requests when these parameters
* are present. In some cases, when a query param such as __amp_source_origin is present
* then it would normally get included into pagination links generated by get_pagenum_link().
* The whitelist sanitizer empties out links that contain this string as it matches the
* blacklisted_value_regex. So by preemptively scrubbing any reference to these query vars
* we can ensure that WordPress won't end up referencing them in any way.
*
* @since 0.7
*/
public static function purge_amp_query_vars() {
$query_vars = array(
'__amp_source_origin',
'amp_latest_update_time',
);

// Scrub input vars.
foreach ( $query_vars as $query_var ) {
if ( ! isset( $_GET[ $query_var ] ) ) { // phpcs:ignore
continue;
}
self::$purged_amp_query_vars[ $query_var ] = wp_unslash( $_GET[ $query_var ] ); // phpcs:ignore
unset( $_REQUEST[ $query_var ], $_GET[ $query_var ] );
$scrubbed = true;
}

if ( isset( $scrubbed ) ) {
$build_query = function( $query ) use ( $query_vars ) {
$pattern = '/^(' . join( '|', $query_vars ) . ')(?==|$)/';
$pairs = array();
foreach ( explode( '&', $query ) as $pair ) {
if ( ! preg_match( $pattern, $pair ) ) {
$pairs[] = $pair;
}
}
return join( '&', $pairs );
};

// Scrub QUERY_STRING.
if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
$_SERVER['QUERY_STRING'] = $build_query( $_SERVER['QUERY_STRING'] );
}

// Scrub REQUEST_URI.
if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
list( $path, $query ) = explode( '?', $_SERVER['REQUEST_URI'], 2 );

$pairs = $build_query( $query );
$_SERVER['REQUEST_URI'] = $path;
if ( ! empty( $pairs ) ) {
$_SERVER['REQUEST_URI'] .= "?{$pairs}";
}
}
}
}

/**
* Register/override widgets.
*
Expand Down
49 changes: 49 additions & 0 deletions tests/test-class-amp-theme-support.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class Test_AMP_Theme_Support extends WP_UnitTestCase {
public function tearDown() {
parent::tearDown();
remove_theme_support( 'amp' );
$_REQUEST = array(); // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
$_SERVER['QUERY_STRING'] = '';
}

/**
Expand Down Expand Up @@ -133,4 +135,51 @@ public function test_finish_output_buffering() {

$this->assertContains( '<script async custom-element="amp-ad"', $sanitized_html );
}

/**
* Test purge_amp_query_vars.
*
* @covers AMP_Theme_Support::purge_amp_query_vars()
*/
public function test_purge_amp_query_vars() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
$bad_query_vars = array(
'amp_latest_update_time' => '1517199956',
'__amp_source_origin' => home_url(),
);
$ok_query_vars = array(
'bar' => 'baz',
);
$all_query_vars = array_merge( $bad_query_vars, $ok_query_vars );

$_SERVER['QUERY_STRING'] = build_query( $all_query_vars );

remove_action( 'wp', 'amp_maybe_add_actions' );
$this->go_to( add_query_arg( $all_query_vars, home_url( '/foo/' ) ) );
$_REQUEST = $_GET; // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
foreach ( $all_query_vars as $key => $value ) {
$this->assertArrayHasKey( $key, $_GET ); // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
$this->assertArrayHasKey( $key, $_REQUEST ); // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
$this->assertContains( "$key=$value", $_SERVER['QUERY_STRING'] );
$this->assertContains( "$key=$value", $_SERVER['REQUEST_URI'] );
}

AMP_Theme_Support::$purged_amp_query_vars = array();
AMP_Theme_Support::purge_amp_query_vars();
$this->assertEqualSets( AMP_Theme_Support::$purged_amp_query_vars, $bad_query_vars );

foreach ( $bad_query_vars as $key => $value ) {
$this->assertArrayNotHasKey( $key, $_GET ); // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
$this->assertArrayNotHasKey( $key, $_REQUEST ); // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
$this->assertNotContains( "$key=$value", $_SERVER['QUERY_STRING'] );
$this->assertNotContains( "$key=$value", $_SERVER['REQUEST_URI'] );
}
foreach ( $ok_query_vars as $key => $value ) {
$this->assertArrayHasKey( $key, $_GET ); // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
$this->assertArrayHasKey( $key, $_REQUEST ); // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
$this->assertContains( "$key=$value", $_SERVER['QUERY_STRING'] );
$this->assertContains( "$key=$value", $_SERVER['REQUEST_URI'] );
}
// phpcs:enable WordPress.Security.NonceVerification.NoNonceVerification
}
}

0 comments on commit 162fa9e

Please sign in to comment.