Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ public function get_items_permissions_check( $request ) {
return $multisite_support;
}

foreach ( array( 'network', 'network_exclude' ) as $network_key ) {
if ( ! isset( $request[ $network_key ] ) ) {
continue;
}
$network_check = $this->check_network_ids( (array) $request[ $network_key ] );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}
}

if ( $this->check_edit_permission() ) {
return true;
}
Expand All @@ -142,30 +152,6 @@ public function get_items_permissions_check( $request ) {
return true;
}

if ( isset( $request['network'] ) ) {
$network_check = $this->check_network_ids_exist( (array) $request['network'] );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}

$network_access = $this->check_network_access( get_current_user_id(), (array) $request['network'] );
if ( is_wp_error( $network_access ) ) {
return $network_access;
}
}

if ( isset( $request['network_exclude'] ) ) {
$network_check = $this->check_network_ids_exist( (array) $request['network_exclude'] );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}

$network_access = $this->check_network_access( get_current_user_id(), (array) $request['network_exclude'] );
if ( is_wp_error( $network_access ) ) {
return $network_access;
}
}

return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to view sites.' ), array( 'status' => rest_authorization_required_code() ) );
}

Expand Down Expand Up @@ -436,15 +422,10 @@ public function get_item_permissions_check( $request ) {
}

if ( $site->network_id > 0 ) {
$network_check = $this->check_network_ids_exist( (array) $site->network_id );
$network_check = $this->check_network_ids( (array) $site->network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}

$network_access = $this->check_network_access( get_current_user_id(), (array) $site->network_id );
if ( is_wp_error( $network_access ) ) {
return $network_access;
}
}

$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
Expand All @@ -461,37 +442,27 @@ public function get_item_permissions_check( $request ) {
}

/**
* Validates that all network IDs in a request parameter exist.
* Validates that the given network IDs exist and are accessible to the current user.
*
* A user can always access the current network. Access to any other
* network requires the user to be a super admin of that network.
*
* @since 7.2.0
*
* @param int[] $network_ids Array of network IDs.
* @return true|WP_Error True if all network IDs are valid, WP_Error otherwise.
* @return true|WP_Error True if all network IDs exist and are accessible, WP_Error otherwise.
*/
protected function check_network_ids_exist( array $network_ids ) {
protected function check_network_ids( array $network_ids ) {
$current_network_id = get_current_network_id();
$user_id = get_current_user_id();

_prime_network_caches( $network_ids );
foreach ( $network_ids as $network_id ) {
if ( ! get_network( $network_id ) ) {
return new WP_Error( 'rest_network_id_invalid', __( 'Invalid network ID.' ), array( 'status' => 400 ) );
}
}

return true;
}

/**
* Checks if a user can access sites on the given networks.
*
* A user can always access the current network. Access to any other
* network requires the user to be a super admin of that network.
*
* @since 7.2.0
*
* @param int $user_id User ID.
* @param int[] $network_ids Array of network IDs.
* @return true|WP_Error True if the user can access all given networks, WP_Error otherwise.
*/
protected function check_network_access( $user_id, array $network_ids ) {
$current_network_id = get_current_network_id();
if ( count( $network_ids ) === 1 && $current_network_id === $network_ids[0] ) {
return true;
}
Expand Down Expand Up @@ -545,15 +516,10 @@ public function create_item_permissions_check( $request ) {

$network_id = isset( $request['network'] ) ? (int) $request['network'] : get_current_network_id();
if ( $network_id > 0 ) {
$network_check = $this->check_network_ids_exist( (array) $network_id );
$network_check = $this->check_network_ids( (array) $network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}

$network_access = $this->check_network_access( get_current_user_id(), (array) $network_id );
if ( is_wp_error( $network_access ) ) {
return $network_access;
}
}

if ( ! current_user_can( 'create_sites' ) ) {
Expand Down Expand Up @@ -683,15 +649,10 @@ public function update_item_permissions_check( $request ) {

$network_id = isset( $request['network'] ) ? (int) $request['network'] : $site->network_id;
if ( $network_id > 0 ) {
$network_check = $this->check_network_ids_exist( (array) $network_id );
$network_check = $this->check_network_ids( (array) $network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}

$network_access = $this->check_network_access( get_current_user_id(), (array) $network_id );
if ( is_wp_error( $network_access ) ) {
return $network_access;
}
}

if ( ! $this->check_edit_permission() ) {
Expand Down Expand Up @@ -789,6 +750,13 @@ public function delete_item_permissions_check( $request ) {
return $site;
}

if ( $site->network_id > 0 ) {
$network_check = $this->check_network_ids( (array) $site->network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}
}

if ( ! $this->check_delete_permission( $site ) ) {
return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this site.' ), array( 'status' => rest_authorization_required_code() ) );
}
Expand Down
87 changes: 75 additions & 12 deletions tests/phpunit/tests/rest-api/wpRestSitesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1999,7 +1999,7 @@ public function test_get_items_filter_with_includes_user() {
/**
* @ticket 40365
* @covers ::get_items_permissions_check
* @covers ::check_network_ids_exist
* @covers ::check_network_ids
* @group ms-required
*/
public function test_get_items_permissions_check_invalid_network_id() {
Expand All @@ -2015,7 +2015,7 @@ public function test_get_items_permissions_check_invalid_network_id() {
/**
* @ticket 40365
* @covers ::get_items_permissions_check
* @covers ::check_network_ids_exist
* @covers ::check_network_ids
* @group ms-required
*/
public function test_get_items_permissions_check_invalid_network_exclude_id() {
Expand All @@ -2031,7 +2031,7 @@ public function test_get_items_permissions_check_invalid_network_exclude_id() {
/**
* @ticket 40365
* @covers ::get_items_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_get_items_permissions_check_denies_access_to_another_network() {
Expand All @@ -2048,7 +2048,7 @@ public function test_get_items_permissions_check_denies_access_to_another_networ
/**
* @ticket 40365
* @covers ::get_items_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_get_items_permissions_check_allows_filtering_by_the_current_network() {
Expand All @@ -2066,7 +2066,7 @@ public function test_get_items_permissions_check_allows_filtering_by_the_current
/**
* @ticket 40365
* @covers ::create_item_permissions_check
* @covers ::check_network_ids_exist
* @covers ::check_network_ids
* @group ms-required
*/
public function test_create_item_permissions_check_invalid_network_id() {
Expand All @@ -2084,7 +2084,7 @@ public function test_create_item_permissions_check_invalid_network_id() {
/**
* @ticket 40365
* @covers ::create_item_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_create_item_permissions_check_denies_access_to_another_network() {
Expand All @@ -2103,7 +2103,7 @@ public function test_create_item_permissions_check_denies_access_to_another_netw
/**
* @ticket 40365
* @covers ::create_item_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_create_item_permissions_check_allows_a_super_admin_of_the_target_network() {
Expand All @@ -2123,7 +2123,7 @@ public function test_create_item_permissions_check_allows_a_super_admin_of_the_t
/**
* @ticket 40365
* @covers ::update_item_permissions_check
* @covers ::check_network_ids_exist
* @covers ::check_network_ids
* @group ms-required
*/
public function test_update_item_permissions_check_invalid_network_id() {
Expand All @@ -2141,7 +2141,7 @@ public function test_update_item_permissions_check_invalid_network_id() {
/**
* @ticket 40365
* @covers ::update_item_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_update_item_permissions_check_denies_moving_a_site_to_another_network() {
Expand All @@ -2161,7 +2161,7 @@ public function test_update_item_permissions_check_denies_moving_a_site_to_anoth
/**
* @ticket 40365
* @covers ::update_item_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_update_item_permissions_check_allows_the_sites_own_network_by_default() {
Expand All @@ -2175,10 +2175,73 @@ public function test_update_item_permissions_check_allows_the_sites_own_network_
$this->assertEquals( 200, $response->get_status() );
}

/**
* @ticket 40365
* @covers ::delete_item_permissions_check
* @covers ::check_network_ids
* @group ms-required
*/
public function test_delete_item_permissions_check_invalid_network_id() {
$blog_id = self::factory()->blog->create();

// Orphan the site from its network to simulate an invalid stored network ID.
wp_update_site( $blog_id, array( 'network_id' => REST_TESTS_IMPOSSIBLY_HIGH_NUMBER ) );

wp_set_current_user( self::$superadmin_id );

$request = new WP_REST_Request( 'DELETE', '/wp/v2/sites/' . $blog_id );
$request->set_param( 'id', $blog_id );

$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_network_id_invalid', $response, 400 );
}

/**
* @ticket 40365
* @covers ::delete_item_permissions_check
* @covers ::check_network_ids
* @group ms-required
*/
public function test_delete_item_permissions_check_denies_access_to_another_network() {
$network_id = self::factory()->network->create();
delete_network_option( $network_id, 'site_admins' );
$blog_id = self::factory()->blog->create( array( 'site_id' => $network_id ) );

wp_set_current_user( self::$superadmin_id );

$request = new WP_REST_Request( 'DELETE', '/wp/v2/sites/' . $blog_id );
$request->set_param( 'id', $blog_id );

$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_cannot_view_network', $response, 403 );
}

/**
* @ticket 40365
* @covers ::delete_item_permissions_check
* @covers ::check_network_ids
* @group ms-required
*/
public function test_delete_item_permissions_check_allows_a_super_admin_of_the_sites_network() {
$network_id = self::factory()->network->create();
$user = self::factory()->user->create_and_get();
update_network_option( $network_id, 'site_admins', array( $user->user_login ) );
// delete_sites is checked against the current network, so grant it there too.
grant_super_admin( $user->ID );
$blog_id = self::factory()->blog->create( array( 'site_id' => $network_id ) );

wp_set_current_user( $user->ID );

$request = new WP_REST_Request( 'DELETE', '/wp/v2/sites/' . $blog_id );
$request->set_param( 'id', $blog_id );

$this->assertTrue( $this->endpoint->delete_item_permissions_check( $request ) );
}

/**
* @ticket 40365
* @covers ::get_item_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_get_item_permissions_check_denies_a_site_on_another_network() {
Expand All @@ -2199,7 +2262,7 @@ public function test_get_item_permissions_check_denies_a_site_on_another_network
/**
* @ticket 40365
* @covers ::get_item_permissions_check
* @covers ::check_network_access
* @covers ::check_network_ids
* @group ms-required
*/
public function test_get_item_permissions_check_allows_a_site_on_the_current_network() {
Expand Down
9 changes: 1 addition & 8 deletions tests/qunit/fixtures/wp-api-generated.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@ mockedApiResponse.Schema = {
"wp-block-editor/v1",
"wp-abilities/v1"
],
"authentication": {
"application-passwords": {
"endpoints": {
"authorization": "http://example.org/wp-admin/authorize-application.php"
}
}
},
"authentication": [],
"routes": {
"/": {
"namespace": "",
Expand Down Expand Up @@ -11209,7 +11203,6 @@ mockedApiResponse.Schema = {
"required": false
},
"network": {
"default": 1,
"description": "The site's network ID. Default is the current network ID.",
"type": "integer",
"required": false
Expand Down