fix(2meet-data-optimizer): drop router query vars a caller passed in
- pre_get_posts clears wpdo_post_clauses / _sort / _copy_route / _count_sql before anything else: new WP_Query( array( … ) ) could preset them - posts_orderby whitelists the copy route's direction - Found in the 2.4 security review (Low L2; not reachable from URLs) - Verify: PostQueryRouterCopyTest (1 new); integration 604, unit 704, phpcs 0 - PR: PR-132
This commit is contained in:
@@ -138,6 +138,11 @@ class TMDO_Post_Query_Router {
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function pre_get_posts( \WP_Query $query ): void {
|
public function pre_get_posts( \WP_Query $query ): void {
|
||||||
|
// The router's query vars are its own: drop any a caller passed in.
|
||||||
|
foreach ( array( self::QUERY_VAR, self::SORT_VAR, self::COPY_VAR, self::COUNT_VAR ) as $var ) {
|
||||||
|
$query->set( $var, '' );
|
||||||
|
}
|
||||||
|
|
||||||
// Mode gate: only run when post mode is reads_from_flat.
|
// Mode gate: only run when post mode is reads_from_flat.
|
||||||
if ( ! self::is_router_active() ) {
|
if ( ! self::is_router_active() ) {
|
||||||
return;
|
return;
|
||||||
@@ -389,7 +394,7 @@ class TMDO_Post_Query_Router {
|
|||||||
if ( empty( $copy ) ) {
|
if ( empty( $copy ) ) {
|
||||||
return $orderby;
|
return $orderby;
|
||||||
}
|
}
|
||||||
return '`' . self::table_alias( $copy['post_type'], $copy['group'] ) . '`.`post_date` ' . $copy['order'];
|
return '`' . self::table_alias( $copy['post_type'], $copy['group'] ) . '`.`post_date` ' . ( 'ASC' === $copy['order'] ? 'ASC' : 'DESC' );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -107,6 +107,32 @@ class PostQueryRouterCopyTest extends TestCase {
|
|||||||
$this->assertStringEndsWith( "`post_date` DESC, FIELD({$wpdb->posts}.ID,5,9) DESC, ({$wpdb->posts}.ID IN (3,4)) DESC, " . self::ALIAS . '.`post_id` DESC LIMIT 0, 10', $sql );
|
$this->assertStringEndsWith( "`post_date` DESC, FIELD({$wpdb->posts}.ID,5,9) DESC, ({$wpdb->posts}.ID IN (3,4)) DESC, " . self::ALIAS . '.`post_id` DESC LIMIT 0, 10', $sql );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The router's query vars are its own: values a caller passed in
|
||||||
|
* (new WP_Query( array( 'wpdo_post_copy_route' => … ) )) are dropped
|
||||||
|
* (2.4 security review L2).
|
||||||
|
*/
|
||||||
|
public function test_query_vars_passed_by_a_caller_are_dropped(): void {
|
||||||
|
$query = new WP_Query();
|
||||||
|
foreach ( array(
|
||||||
|
'post_type' => 'rc_item',
|
||||||
|
'orderby' => 'title',
|
||||||
|
'wpdo_post_copy_route' => array( 'post_type' => 'rc_item', 'group' => 'rc_core', 'statuses' => array( 'publish' ), 'order' => 'DESC, (SELECT 1)' ),
|
||||||
|
'wpdo_post_sort' => array( 'post_type' => 'rc_item', 'group' => 'rc_core', 'column' => 'rc_price', 'order' => 'ASC' ),
|
||||||
|
'wpdo_post_clauses' => array( 'rc_item' => array() ),
|
||||||
|
'wpdo_post_count_sql' => 'SELECT 1',
|
||||||
|
) as $k => $v ) {
|
||||||
|
$query->set( $k, $v );
|
||||||
|
}
|
||||||
|
$router = new TMDO_Post_Query_Router();
|
||||||
|
$router->pre_get_posts( $query );
|
||||||
|
|
||||||
|
foreach ( array( 'wpdo_post_copy_route', 'wpdo_post_sort', 'wpdo_post_clauses', 'wpdo_post_count_sql' ) as $var ) {
|
||||||
|
$this->assertEmpty( $query->get( $var ), $var );
|
||||||
|
}
|
||||||
|
$this->assertSame( 'wp_posts.post_title ASC', $router->posts_orderby( 'wp_posts.post_title ASC', $query ) );
|
||||||
|
}
|
||||||
|
|
||||||
public function test_copy_route_keeps_group_by_with_another_join(): void {
|
public function test_copy_route_keeps_group_by_with_another_join(): void {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$sql = $this->request( " LEFT JOIN wp_term_relationships ON ({$wpdb->posts}.ID = wp_term_relationships.object_id)" );
|
$sql = $this->request( " LEFT JOIN wp_term_relationships ON ({$wpdb->posts}.ID = wp_term_relationships.object_id)" );
|
||||||
|
|||||||
Reference in New Issue
Block a user