From 5c90d9ed8e84b4e22f7db4faa914b61b9217c45f Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Mon, 14 Nov 2016 16:36:33 +0000 Subject: [PATCH] REST API: Validate and Sanitize registered meta based off the schema. With the addition of Array support in our schema validation functions, it's now possible to use these in the meta validation and sanitization steps. Also, this increases the test coverage of using registered via meta the API significantly. Fixes #38531. Props rachelbaker, tharsheblows. Built from https://develop.svn.wordpress.org/trunk@39222 git-svn-id: http://core.svn.wordpress.org/trunk@39162 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/rest-api.php | 10 ++++ .../fields/class-wp-rest-meta-fields.php | 49 ++++++++++++------- wp-includes/version.php | 2 +- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/wp-includes/rest-api.php b/wp-includes/rest-api.php index d59f570c02..8e48f892f7 100644 --- a/wp-includes/rest-api.php +++ b/wp-includes/rest-api.php @@ -998,6 +998,9 @@ function rest_validate_value_from_schema( $value, $args, $param = '' ) { if ( ! is_array( $value ) ) { $value = preg_split( '/[\s,]+/', $value ); } + if ( ! wp_is_numeric_array( $value ) ) { + return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: type name */ __( '%1$s is not of type %2$s.' ), $param, 'array' ) ); + } foreach ( $value as $index => $v ) { $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); if ( is_wp_error( $is_valid ) ) { @@ -1107,6 +1110,9 @@ function rest_sanitize_value_from_schema( $value, $args ) { foreach ( $value as $index => $v ) { $value[ $index ] = rest_sanitize_value_from_schema( $v, $args['items'] ); } + // Normalize to numeric array so nothing unexpected + // is in the keys. + $value = array_values( $value ); return $value; } if ( 'integer' === $args['type'] ) { @@ -1140,5 +1146,9 @@ function rest_sanitize_value_from_schema( $value, $args ) { } } + if ( 'string' === $args['type'] ) { + return strval( $value ); + } + return $value; } diff --git a/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php b/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php index e48a307a51..c4200a68d2 100644 --- a/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php +++ b/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php @@ -84,7 +84,7 @@ abstract class WP_REST_Meta_Fields { $response[ $name ] = $value; } - return (object) $response; + return $response; } /** @@ -133,10 +133,24 @@ abstract class WP_REST_Meta_Fields { */ if ( is_null( $request[ $name ] ) ) { $result = $this->delete_meta_value( $object_id, $name ); - } elseif ( $args['single'] ) { - $result = $this->update_meta_value( $object_id, $name, $request[ $name ] ); + if ( is_wp_error( $result ) ) { + return $result; + } + continue; + } + + $is_valid = rest_validate_value_from_schema( $request[ $name ], $args['schema'], 'meta.' . $name ); + if ( is_wp_error( $is_valid ) ) { + $is_valid->add_data( array( 'status' => 400 ) ); + return $is_valid; + } + + $value = rest_sanitize_value_from_schema( $request[ $name ], $args['schema'] ); + + if ( $args['single'] ) { + $result = $this->update_meta_value( $object_id, $name, $value ); } else { - $result = $this->update_multi_meta_value( $object_id, $name, $request[ $name ] ); + $result = $this->update_multi_meta_value( $object_id, $name, $value ); } if ( is_wp_error( $result ) ) { @@ -319,12 +333,13 @@ abstract class WP_REST_Meta_Fields { $default_args = array( 'name' => $name, 'single' => $args['single'], + 'type' => ! empty( $args['type'] ) ? $args['type'] : null, 'schema' => array(), 'prepare_callback' => array( $this, 'prepare_value' ), ); $default_schema = array( - 'type' => null, + 'type' => $default_args['type'], 'description' => empty( $args['description'] ) ? '' : $args['description'], 'default' => isset( $args['default'] ) ? $args['default'] : null, ); @@ -332,20 +347,18 @@ abstract class WP_REST_Meta_Fields { $rest_args = array_merge( $default_args, $rest_args ); $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] ); - if ( empty( $rest_args['schema']['type'] ) ) { - // Skip over meta fields that don't have a defined type. - if ( empty( $args['type'] ) ) { - continue; - } + $type = ! empty( $rest_args['type'] ) ? $rest_args['type'] : null; + $type = ! empty( $rest_args['schema']['type'] ) ? $rest_args['schema']['type'] : $type; - if ( $rest_args['single'] ) { - $rest_args['schema']['type'] = $args['type']; - } else { - $rest_args['schema']['type'] = 'array'; - $rest_args['schema']['items'] = array( - 'type' => $args['type'], - ); - } + if ( ! in_array( $type, array( 'string', 'boolean', 'integer', 'number' ) ) ) { + continue; + } + + if ( empty( $rest_args['single'] ) ) { + $rest_args['schema']['items'] = array( + 'type' => $rest_args['type'], + ); + $rest_args['schema']['type'] = 'array'; } $registered[ $rest_args['name'] ] = $rest_args; diff --git a/wp-includes/version.php b/wp-includes/version.php index cf79be638f..8a8747bde7 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.7-beta3-39221'; +$wp_version = '4.7-beta3-39222'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.