diff --git a/admin/class-convertkit-admin-refresh-resources.php b/admin/class-convertkit-admin-refresh-resources.php index 57caddb80..9c9418a8d 100644 --- a/admin/class-convertkit-admin-refresh-resources.php +++ b/admin/class-convertkit-admin-refresh-resources.php @@ -40,7 +40,22 @@ public function register_routes() { '/resources/refresh/(?P[a-zA-Z0-9-_]+)', array( 'methods' => WP_REST_Server::CREATABLE, + 'args' => array( + // Resource: Validate resource is included in the request, a valid resource + // and sanitize the resource. + 'resource' => array( + 'required' => true, + 'validate_callback' => function ( $param ) { + + return is_string( $param ) && in_array( $param, array( 'forms', 'landing_pages', 'tags', 'posts', 'products', 'restrict_content' ), true ); + + }, + 'sanitize_callback' => 'sanitize_text_field', + ), + ), 'callback' => array( $this, 'refresh_resources' ), + + // Only refresh resources for users who can edit posts. 'permission_callback' => function () { return current_user_can( 'edit_posts' ); }, diff --git a/includes/class-convertkit-gutenberg.php b/includes/class-convertkit-gutenberg.php index 4c8fc5d4b..7dd864190 100644 --- a/includes/class-convertkit-gutenberg.php +++ b/includes/class-convertkit-gutenberg.php @@ -82,6 +82,7 @@ public function register_routes() { return rest_ensure_response( convertkit_get_blocks() ); }, + // Only refresh resources for users who can edit posts. 'permission_callback' => function () { return current_user_can( 'edit_posts' ); }, diff --git a/includes/class-convertkit-output-restrict-content.php b/includes/class-convertkit-output-restrict-content.php index 17e97b822..5cd431b06 100644 --- a/includes/class-convertkit-output-restrict-content.php +++ b/includes/class-convertkit-output-restrict-content.php @@ -131,6 +131,52 @@ public function register_routes() { '/restrict-content/subscriber-authentication', array( 'methods' => WP_REST_Server::CREATABLE, + 'args' => array( + // Email: Validate email is included in the request, is a valid email address + // and sanitize the email address. + 'convertkit_email' => array( + 'required' => true, + 'validate_callback' => function ( $param ) { + + return is_string( $param ) && is_email( $param ); + + }, + 'sanitize_callback' => 'sanitize_email', + ), + + // Post ID: Validate post ID is included in the request and is an integer. + 'convertkit_post_id' => array( + 'required' => true, + 'validate_callback' => function ( $param ) { + + return is_numeric( $param ); + + }, + 'sanitize_callback' => 'absint', + ), + + // Resource Type: Validate resource type is included in the request and is a string. + 'convertkit_resource_type' => array( + 'required' => true, + 'validate_callback' => function ( $param ) { + + return is_string( $param ); + + }, + 'sanitize_callback' => 'sanitize_text_field', + ), + + // Resource ID: Validate resource ID is included in the request and is an integer. + 'convertkit_resource_id' => array( + 'required' => true, + 'validate_callback' => function ( $param ) { + + return is_numeric( $param ); + + }, + 'sanitize_callback' => 'absint', + ), + ), 'callback' => function ( $request ) { // Initialize classes that will be used. @@ -181,6 +227,8 @@ public function register_routes() { ) ); }, + + // No authentication required, as this is on the frontend site. 'permission_callback' => '__return_true', ) ); @@ -191,6 +239,40 @@ public function register_routes() { '/restrict-content/subscriber-verification', array( 'methods' => WP_REST_Server::CREATABLE, + 'args' => array( + // Post ID: Validate post ID is an integer if included in the request. + 'convertkit_post_id' => array( + 'required' => false, + 'validate_callback' => function ( $param ) { + + return is_numeric( $param ); + + }, + 'sanitize_callback' => 'absint', + ), + + // Token: Validate token is included in the request and is a string. + 'token' => array( + 'required' => true, + 'validate_callback' => function ( $param ) { + + return is_string( $param ); + + }, + 'sanitize_callback' => 'sanitize_text_field', + ), + + // Subscriber Code: Validate subscriber code is included in the request and is a string. + 'subscriber_code' => array( + 'required' => true, + 'validate_callback' => function ( $param ) { + + return is_string( $param ); + + }, + 'sanitize_callback' => 'sanitize_text_field', + ), + ), 'callback' => function ( $request ) { // Initialize classes that will be used. @@ -234,6 +316,8 @@ public function register_routes() { ) ); }, + + // No authentication required, as this is on the frontend site. 'permission_callback' => '__return_true', ) ); diff --git a/tests/Integration/RESTAPITest.php b/tests/Integration/RESTAPITest.php index 53b49ce89..e84ce8c4d 100644 --- a/tests/Integration/RESTAPITest.php +++ b/tests/Integration/RESTAPITest.php @@ -151,7 +151,12 @@ public function testRefreshResourcesWithInvalidResourceType() $response = rest_get_server()->dispatch( $request ); // Assert response is unsuccessful. - $this->assertSame( 500, $response->get_status() ); + $this->assertSame( 400, $response->get_status() ); + + // Assert response data has the expected keys and data. + $data = $response->get_data(); + $this->assertEquals( 'rest_invalid_param', $data['code'] ); + $this->assertEquals( 'Invalid parameter(s): resource', $data['message'] ); } /**