-
Notifications
You must be signed in to change notification settings - Fork 651
Rethink how we work with meta #1425
Description
Since we first implemented meta, we've been very restrictive. Meta available through the API is limited in the following ways:
- Serialised data is not available at all. You cannot read serialised data, you cannot write serialised data, and you cannot write normal data to a field that has serialised data already.
- Protected meta fields (typically, those beginning with
_) are not available at all. - All other meta is available only to those with the ability to edit the post.
These restrictions apply to all meta fields, with no real way to enable exposing meta in any further extensive way.
We always wanted to start out with the most restrictive policy on meta and then open it up slowly depending on use cases. I think it's time we did that. :)
Serialised Data
Serialised data should still not be available. We cannot open access to serialised data:
- Allowing read or write access is lossy. Internal PHP objects cannot be exposed as JSON without losing at least the class information. Saving the objects would always be a
stdClassinstance. - Converting PHP objects to JSON has privacy problems. Public properties are converted directly to a JSON object, which is a problem if the class does not mark protected properties correctly.
- Exposing PHP objects as a serialised string has privacy problems. All properties, both public and private, are exposed, which may be dangerous depending on the implementation of the class.
- Allowing write access for serialised strings has security problems. Serialised data can instantiate any class with any properties it needs, which essentially allows Remote Code Execution and a whole class of bugs.
Protected Meta
Rather than checking if meta fields are protected or not, we should leave this responsibility to the capabilities system. WP's meta-cap system already has meta capabilities for add_post_meta, edit_post_meta, and delete_post_meta. Internally, these use is_protected_meta by default, but allow register_meta to override this. This would allow overriding the protected meta system using WP's existing APIs, and would open meta up a bit more nicely. Bonus: we encourage use of the register_meta API, which is pretty neat.
One notable missing part here is read_post_meta. @nacin and I have discussed this in the past, and we're in favour of adding this. In the meantime, we could easily add a shim on the map_meta_cap filter.
Authenticated Access
Assuming we change protected meta, internally these all still check edit_post on the post, since the existing meta-caps are all write-based. However, with read_post_meta, we'd want to expose this publicly.
Ideally, the system would have been designed with this in mind. auth_callback already receives the capability we're trying to use, so it'd be basically perfect. However, using the existing auth callback from register_meta may be dangerous, as it usually relies on edit_post.
As a stop-gap, I'd suggest we check this, and check against a whitelist of meta keys to expose publicly. By default, this would be a blank array, but with the ability to add extra keys into it, similar to the query_vars filter.
It's a suboptimal solution, but it does allow us to retrofit the system to allow this.
With this, you could expose meta by doing:
register_meta( 'post', 'my_meta_key', null, 'my_validation_callback' );
function my_validation_callback( $allowed, $key, $post_id, $user_id, $cap, $caps ) {
switch ( $cap ) {
case 'read_post_meta':
case 'update_post_meta':
case 'add_post_meta':
case 'delete_post_meta':
return true;
default:
return false;
}
}
add_filter( 'rest_public_meta_keys', function ( $keys ) {
$keys[] = 'my_meta_key';
return $keys;
} );Anyone have anything they'd like to add? Anything I've overlooked here?