Repository navigation
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @jonnydmg. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
jonnydmg
left a comment
There was a problem hiding this comment.
There is a big PR to review. Good work getting this ready for core. This code a little old and some things have changed in core, so this PR needs to update accordingly.
Biggest things.
- We need to support sites with
is_site_meta_supportedfalse. There was some work done there to support it but not complete. - Site endpoint needs to be registered on single site. So it always exists then return an error on single site.
- WP_REST_Site_Meta_Fields has no test coverage at all.
- Single site needs tests.
- Super admin should be allowed to do everything on the endpoint.
- Code coverage and ticket need needs to be added to every test.
This feel like we are on the right track, if I am nitpicing here, becuase I think this good to go into core and just want to get the final bits to push forward into core.
I will wait until feedback is complete to do some real testing for this PR.
jonnydmg
left a comment
There was a problem hiding this comment.
There is a big PR to review. Good work getting this ready for core. This code a little old and some things have changed in core, so this PR needs to update accordingly.
Biggest things.
- We need to support sites with
is_site_meta_supportedfalse. There was some work done there to support it but not complete. - Site endpoint needs to be registered on single site. So it always exists then return an error on single site.
- WP_REST_Site_Meta_Fields has no test coverage at all.
- Single site needs tests.
- Super admin should be allowed to do everything on the endpoint.
- Code coverage and ticket need needs to be added to every test.
This feel like we are on the right track, if I am nitpicing here, becuase I think this good to go into core and just want to get the final bits to push forward into core.
I will wait until feedback is complete to do some real testing for this PR.
Introduces WP_REST_Sites_Controller plus tests. See #40365.
aa03545 to
cc81250
Compare
…and add missing group annotations
spacedmonkey
left a comment
There was a problem hiding this comment.
Here is a PR with some unit test improvements.
This is has unit tests that cover single site as well.
…oint-tests Tests: Add unit tests for WP_REST_Site_Meta_Fields functionality
…oint-more-tests Tests: Rename rest-sites-controller.php to wpRestSitesController.php …
Add format validation for the `domain` and `path` parameters in WP_REST_Sites_Controller so malformed values are rejected with a clean 400 rest_invalid_param instead of failing later inside wp_insert_site()/ wp_update_site() (which surfaces as a 500). domain must be a valid hostname or bare IPv4/IPv6 address, optionally followed by a port (bracketed IPv6 is intentionally not supported, so IPv6 addresses can't carry a port). path must start and end with a forward slash and be made up of characters valid in a URL path segment. Ticket #40365.
…t-check-exists' into feature/40365-rest-sites-endpoint-check-exists # Conflicts: # src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php
…oint-force-delete Enhance site deletion process to support force deletion and user removal
…oint-check-exists Check if domain exists before creating / updating.
spacedmonkey
left a comment
There was a problem hiding this comment.
I have spent a long time testing this and I am happy to say, I am happy to commit. Thanks for all the amazing work @lloc, thanks for getting this one across the line.
peterwilsoncc
left a comment
There was a problem hiding this comment.
While the changes to checking and getting super admins may be helpful for a programmatic API I don't think that querying one network from another via a public API is a security risk.
For example, this current implimentation exposes cross nmetwork sites when no network is specified.
- Install and network enable WP Multi Network
- Create a new network
- Create a new user (
n2admin) - Set n2admin as a super user of the second network
- Log in to the second network as n2admin
- Observe in the dashboard "My Networks" they only have access to network 2
- In the browser console run the command
wp.apiFetch( { 'path': '/wp/v2/sites' } ) - Observe the result contains details for both the network they are super admin of and the network
This is an example of why I made my earlier comment that the network should be inferred from the URL on which the request is being made. It's a security risk but, equally significantly, details of one network should not be made available from another. Doing so breaks the isolation multiple networks are intended to maintain.
That is a bug and sorry that one is me. This commit 959bf3d. I will fix it. Fixed in |
…work filter is provided
…point-current-network Site REST API: Default network id
|
@spacedmonkey @jonnydmg The endpoint just can't allow querying across network, it will introduce data exposure no matter how it's coded up Each network is entirely independent: logins, network activated plugins, mu-plugins can be network specific via One network may hard code super admins via The same will occur if one network filters the Even for sites on the same network, the plugins can differ site-to-site so the endpoint can't be available on sub-sites due to different plugins. This is what I think needs to happen before this can be considered secure enough to commit:
This will ensure that plugins and mu-plugins for the endpoint match what is loaded in the network admin currently. |
Remove cross-network functionality from WP_REST_Sites_Controller: - Drop the `network` and `network_exclude` collection parameters and the `network__in` orderby; collections are always limited to the current network. - Make the `network` schema property read-only, so sites can no longer be created on, or moved to, another network. - Replace check_network_ids() with site_in_network(), filterable via the new `rest_site_in_network` filter ( bool $in_network, WP_Site $site, int $network_id ). - Get, update and delete permission checks return `rest_unable_read_from_network` for a site that is not on the current network, before capability checks. - Simplify check_url_is_available() now that network_id is never supplied. - Remove the network permission tests, add coverage for every CRUD route against a site on a second network and for the filter, and regenerate the API fixture. See #40365. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hecks. The update and delete permission checks now return `rest_unable_update_from_network` and `rest_unable_delete_from_network` respectively, instead of `rest_unable_read_from_network`, for a site that is not on the current network. Tests now assert the code for each operation. See #40365. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sites endpoint no longer checks super admin status per network, so the `$network_id` parameter added to get_super_admins() and is_super_admin(), and the tests covering it, are no longer needed. Restore both functions and tests/phpunit/tests/user/capabilities.php to their trunk versions. See #40365. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Just a heads up, jonnydmg and spacedmonkey are both me!
I know there could be something on the subsite that could tweak the permsissoins. But if you have a plugin doing that, you could do a lot, like regsitering your own sites endpoint or otherwise expose site data. I am not sure this is something we can lock down. You would hope the network maintainer would lock this down. Thoughts @peterwilsoncc @lloc ? |
…point-no-network REST API: Limit the sites endpoint to the current network
|
I checked this against WP Multi Network. Peter's cross-network leak is already fixed: Proposal:
Anyone who wants cross-network management can restore it through the @peterwilsoncc @spacedmonkey Would that work for both of you? |
|
If we expose data to members of the site, should be consider making register meta only show if context=edit. Site meta would might have senative data in it. |
|
Thanks everyone for continuing to work through this. @lloc, you’ve done a great job moving a large and complicated change forward, testing it with WP Multi Network, and narrowing the remaining disagreement. I think @peterwilsoncc is likely right that the safest boundary for this controller is:
I am hesitant to add a I also don’t think the toolbar use-case needs to determine this controller’s security model, or necessarily needs to be implemented in core as part of this change. The toolbar already has a long history of accumulating responsibilities and blog/network queries, and my guess is we'd all prefer not to repeat some of those old design mistakes. 😆 If a client-side, cross-network "My Sites" API is needed later, that would be easier to review as a separate, read-only endpoint with a deliberately small and fixed response schema. (That keeps this controller aligned with network administration while giving the toolbar use case its own security and API-design discussion.) My personal preference is to keep this PR focused on current-network management from the network's main site, without the cross-network member exception. Thank you again everyone for all the work getting it this far. 💗 |
…esponse.
Following the review on PR 13055, the sites endpoint now behaves like the
network admin and is only usable from the network's main site:
- Create, update, delete and single-site reads return a 403
`rest_cannot_{create,edit,delete,view}_not_on_main_site` error from any
other site.
- Listing your own sites (`user=me` or your own ID) and a member reading
their site stay available from any site, but only in the view context.
- Users listing their own sites cannot filter or order by fields outside
the view context (`rest_forbidden_param`), so hidden values cannot be
inferred.
- The status flags, dates, `lang_id`, `post_count` and the site meta are
now edit-context only.
- Add a read-only `admin_url` field and build `home` and `siteurl` with
get_home_url() and get_site_url(), so their filters apply.
- Replace the write-only `title` property with a create-only, writable
`blogname`, and move `user_id` out of the schema into the create route
arguments. A POST to an existing site no longer runs the create path.
- Skip the site queries when the user filter matches no sites, while
still firing `rest_site_query`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The collection filter `user` and the create-only `user_id` argument described the same relationship under two names. Both are now `user`, sharing one schema that accepts a positive user ID or "me", and get_user_id_from_param() resolves "me" to the current user. - Invalid values such as `xyz`, `0`, `-1` or an empty string are now rejected with `rest_invalid_param` before the permission check. - Numeric strings are sanitized to integers. - An unknown administrator on creation returns `rest_user_invalid_id`. - Listing the sites of another user requires the capability to manage sites (`rest_forbidden_user`). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Both read permission checks reject `context=edit` up front with `rest_forbidden_context` unless the user can manage sites, before the member, main-site and site lookup checks, so an edit-context request does not reveal whether a site exists. - get_items_permissions_check() resolves the own-user filter once and reuses it for the other-user check, so a logged-out `user=me` now returns `rest_forbidden_user`. - The check against filtering or ordering by fields outside the view context now applies to every user without the capability, and still runs before the own-sites exemption. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@lloc @peterwilsoncc @JJJ I've opened lloc#12 against Main site only
Permissions
Response and schema
Other
All sites and site meta tests pass on multisite (254) and single site, and lint and PHPStan are clean. Feedback welcome, particularly on:
|
…point-feedback REST API: Main-site-only sites endpoint, tighter response and a single user parameter
|
Pushed a fix for the domain length @spacedmonkey flagged on 09-28.
It's all in one separate commit, so it's easy to revert if you'd rather handle this differently. |
|
@peterwilsoncc @JJJ, could you look at @spacedmonkey's questions in lloc#12? The first one decides whether we keep the "my sites" exception. It's limited to the view context and the current network, but it still works from subsites. If you'd rather require the main site for everything, I'm happy to remove it. |
Trac ticket: https://core.trac.wordpress.org/ticket/40365
There are some open questions that we should discuss in the trac ticket.