{"action":"created","issue":{"url":"https://api.github.com/repos/WP-API/WP-API/issues/1425","labels_url":"https://api.github.com/repos/WP-API/WP-API/issues/1425/labels{/name}","comments_url":"https://api.github.com/repos/WP-API/WP-API/issues/1425/comments","events_url":"https://api.github.com/repos/WP-API/WP-API/issues/1425/events","html_url":"https://github.com/WP-API/WP-API/issues/1425","id":97065094,"number":1425,"title":"Rethink how we work with meta","user":{"login":"rmccue","id":21655,"avatar_url":"https://avatars.githubusercontent.com/u/21655?v=3","gravatar_id":"","url":"https://api.github.com/users/rmccue","html_url":"https://github.com/rmccue","followers_url":"https://api.github.com/users/rmccue/followers","following_url":"https://api.github.com/users/rmccue/following{/other_user}","gists_url":"https://api.github.com/users/rmccue/gists{/gist_id}","starred_url":"https://api.github.com/users/rmccue/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmccue/subscriptions","organizations_url":"https://api.github.com/users/rmccue/orgs","repos_url":"https://api.github.com/users/rmccue/repos","events_url":"https://api.github.com/users/rmccue/events{/privacy}","received_events_url":"https://api.github.com/users/rmccue/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/WP-API/WP-API/labels/Discussion","name":"Discussion","color":"eb6420"},{"url":"https://api.github.com/repos/WP-API/WP-API/labels/Enhancement","name":"Enhancement","color":"009800"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/WP-API/WP-API/milestones/28","html_url":"https://github.com/WP-API/WP-API/milestones/2.0%20Beta%2012","labels_url":"https://api.github.com/repos/WP-API/WP-API/milestones/28/labels","id":1521103,"number":28,"title":"2.0 Beta 12","description":null,"creator":{"login":"danielbachhuber","id":36432,"avatar_url":"https://avatars.githubusercontent.com/u/36432?v=3","gravatar_id":"","url":"https://api.github.com/users/danielbachhuber","html_url":"https://github.com/danielbachhuber","followers_url":"https://api.github.com/users/danielbachhuber/followers","following_url":"https://api.github.com/users/danielbachhuber/following{/other_user}","gists_url":"https://api.github.com/users/danielbachhuber/gists{/gist_id}","starred_url":"https://api.github.com/users/danielbachhuber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danielbachhuber/subscriptions","organizations_url":"https://api.github.com/users/danielbachhuber/orgs","repos_url":"https://api.github.com/users/danielbachhuber/repos","events_url":"https://api.github.com/users/danielbachhuber/events{/privacy}","received_events_url":"https://api.github.com/users/danielbachhuber/received_events","type":"User","site_admin":false},"open_issues":24,"closed_issues":6,"state":"open","created_at":"2016-01-20T02:33:53Z","updated_at":"2016-01-28T07:16:36Z","due_on":null,"closed_at":null},"comments":14,"created_at":"2015-07-24T14:27:05Z","updated_at":"2016-01-28T12:12:05Z","closed_at":null,"body":"Since we first implemented meta, we've been very restrictive. Meta available through the API is limited in the following ways:\r\n\r\n* 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.\r\n* Protected meta fields (typically, those beginning with `_`) are not available at all.\r\n* All other meta is available only to those with the ability to edit the post.\r\n\r\nThese restrictions apply to all meta fields, with no real way to enable exposing meta in any further extensive way.\r\n\r\nWe 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. :)\r\n\r\nSerialised Data\r\n---------------\r\nSerialised data should still not be available. We cannot open access to serialised data:\r\n\r\n* 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 `stdClass` instance.\r\n* 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.\r\n* 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.\r\n* 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.\r\n\r\nProtected Meta\r\n--------------\r\nRather 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.\r\n\r\nOne 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.\r\n\r\nAuthenticated Access\r\n--------------------\r\nAssuming 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.\r\n\r\nIdeally, 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`.\r\n\r\nAs 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.\r\n\r\nIt's a suboptimal solution, but it does allow us to retrofit the system to allow this.\r\n\r\nWith this, you could expose meta by doing:\r\n\r\n```php\r\nregister_meta( 'post', 'my_meta_key', null, 'my_validation_callback' );\r\nfunction my_validation_callback( $allowed, $key, $post_id, $user_id, $cap, $caps ) {\r\n\tswitch ( $cap ) {\r\n\t\tcase 'read_post_meta':\r\n\t\tcase 'update_post_meta':\r\n\t\tcase 'add_post_meta':\r\n\t\tcase 'delete_post_meta':\r\n\t\t\treturn true;\r\n\r\n\t\tdefault:\r\n\t\t\treturn false;\r\n\t}\r\n}\r\n\r\nadd_filter( 'rest_public_meta_keys', function ( $keys ) {\r\n\t$keys[] = 'my_meta_key';\r\n\treturn $keys;\r\n} );\r\n```\r\n\r\nAnyone have anything they'd like to add? Anything I've overlooked here?\r\n"},"comment":{"url":"https://api.github.com/repos/WP-API/WP-API/issues/comments/176149359","html_url":"https://github.com/WP-API/WP-API/issues/1425#issuecomment-176149359","issue_url":"https://api.github.com/repos/WP-API/WP-API/issues/1425","id":176149359,"user":{"login":"danielbachhuber","id":36432,"avatar_url":"https://avatars.githubusercontent.com/u/36432?v=3","gravatar_id":"","url":"https://api.github.com/users/danielbachhuber","html_url":"https://github.com/danielbachhuber","followers_url":"https://api.github.com/users/danielbachhuber/followers","following_url":"https://api.github.com/users/danielbachhuber/following{/other_user}","gists_url":"https://api.github.com/users/danielbachhuber/gists{/gist_id}","starred_url":"https://api.github.com/users/danielbachhuber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danielbachhuber/subscriptions","organizations_url":"https://api.github.com/users/danielbachhuber/orgs","repos_url":"https://api.github.com/users/danielbachhuber/repos","events_url":"https://api.github.com/users/danielbachhuber/events{/privacy}","received_events_url":"https://api.github.com/users/danielbachhuber/received_events","type":"User","site_admin":false},"created_at":"2016-01-28T12:12:04Z","updated_at":"2016-01-28T12:12:04Z","body":"@digitalkaoz I've removed your comment, as we can't officially support insecure code snippets."}}