PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
← All changes | _inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-email-preview.php +68 -36 13.8.3 → 16.3-a.7 View file →
@@ -5,13 +5,14 @@
5 5 * @package automattic/jetpack
6 6 */
7 7
8 8 use Automattic\Jetpack\Connection\Manager;
9 -use Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Abstract_Token_Subscription_Service;
9 +use Automattic\Jetpack\Connection\Traits\WPCOM_REST_API_Proxy_Request;
10 10 use Automattic\Jetpack\Status\Host;
11 11
12 -require_once __DIR__ . '/trait-wpcom-rest-api-proxy-request-trait.php';
13 -require_once JETPACK__PLUGIN_DIR . 'extensions/blocks/premium-content/_inc/subscription-service/include.php';
12 +if ( ! defined( 'ABSPATH' ) ) {
13 + exit( 0 );
14 +}
14 15
15 16 /**
16 17 * Class WPCOM_REST_API_V2_Endpoint_Email_Preview
17 18 *
@@ -18,9 +19,9 @@
18 19 * Returns an email preview given a post id.
19 20 */
20 21 class WPCOM_REST_API_V2_Endpoint_Email_Preview extends WP_REST_Controller {
21 22
22 - use WPCOM_REST_API_Proxy_Request_Trait;
23 + use WPCOM_REST_API_Proxy_Request;
23 24
24 25 /**
25 26 * Constructor.
26 27 */
@@ -43,31 +44,23 @@
43 44 public function register_routes() {
44 45 $options = array(
45 46 'show_in_index' => true,
46 47 'methods' => 'GET',
47 - // if this is not a wpcom site, we need to proxy the request to wpcom
48 - 'callback' => ( ( new Host() )->is_wpcom_simple() ) ? array(
49 - $this,
50 - 'email_preview',
51 - ) : array( $this, 'proxy_request_to_wpcom_as_user' ),
48 + 'callback' => array( $this, 'email_preview' ),
52 49 'permission_callback' => array( $this, 'permissions_check' ),
53 50 'args' => array(
54 - 'id' => array(
51 + 'post_id' => array(
55 52 'description' => __( 'Unique identifier for the post.', 'jetpack' ),
56 53 'type' => 'integer',
57 54 ),
58 - 'access' => array(
55 + 'access' => array(
59 56 'description' => __( 'Access level.', 'jetpack' ),
60 - 'enum' => array( Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY, Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_SUBSCRIBERS, Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_PAID_SUBSCRIBERS ),
61 - 'default' => Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY,
57 + 'enum' => array( 'everybody', 'subscribers', 'paid_subscribers' ),
58 + 'default' => 'everybody',
62 59 'validate_callback' => function ( $param ) {
63 60 return in_array(
64 61 $param,
65 - array(
66 - Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY,
67 - Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_SUBSCRIBERS,
68 - Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_PAID_SUBSCRIBERS,
69 - ),
62 + array( 'everybody', 'subscribers', 'paid_subscribers' ),
70 63 true
71 64 );
72 65 },
73 66 ),
@@ -81,23 +74,28 @@
81 74 );
82 75 }
83 76
84 77 /**
85 - * Checks if the user is connected and has access to edit the post
78 + * Checks whether the request may render an email preview.
86 79 *
80 + * The preview only renders the site's own post, so it needs the site to be connected
81 + * but not the requesting user. The `edit_post` capability check is the authorization.
82 + *
87 83 * @param WP_REST_Request $request Full data about the request.
88 84 *
89 - * @return true|WP_Error True if the request has edit access, WP_Error object otherwise.
85 + * @return true|WP_Error True if the request may render the preview, WP_Error object otherwise.
90 86 */
91 87 public function permissions_check( $request ) {
92 - if ( ! ( new Host() )->is_wpcom_simple() ) {
93 - if ( ! ( new Manager() )->is_user_connected() ) {
94 - return new WP_Error(
95 - 'rest_cannot_send_email_preview',
96 - __( 'Please connect your user account to WordPress.com', 'jetpack' ),
97 - array( 'status' => rest_authorization_required_code() )
98 - );
99 - }
88 + $is_wpcom_simple = ( new Host() )->is_wpcom_simple();
89 +
90 + // On a self-hosted site, the site must be connected before we can proxy the preview to WordPress.com.
91 + // This uses its own error code (not the user-connection one) so the client can tell the two apart.
92 + if ( ! $is_wpcom_simple && ! ( new Manager() )->is_connected() ) {
93 + return new WP_Error(
94 + 'rest_cannot_view_email_preview',
95 + __( 'Please connect your site to WordPress.com to preview emails.', 'jetpack' ),
96 + array( 'status' => rest_authorization_required_code() )
97 + );
100 98 }
101 99
102 100 $post = get_post( $request->get_param( 'post_id' ) );
103 101
@@ -108,27 +106,61 @@
108 106 array( 'status' => 404 )
109 107 );
110 108 }
111 109
112 - if ( ! current_user_can( 'edit_post', $post->ID ) ) {
113 - return new WP_Error(
114 - 'rest_forbidden_context',
115 - __( 'Please connect your user account to WordPress.com', 'jetpack' ),
116 - array( 'status' => rest_authorization_required_code() )
117 - );
110 + // Authorize any user who can edit the post: the local editor on self-hosted, a user-token request on WordPress.com.
111 + if ( current_user_can( 'edit_post', $post->ID ) ) {
112 + return true;
118 113 }
119 114
120 - return true;
115 + // On WordPress.com, a blog-token proxy authenticates as user 0 and fails the edit_post check
116 + // above, so authorize it by site ownership instead. The self-hosted endpoint already verified a
117 + // local editor could edit the post, and the blog token never reaches the browser.
118 + if ( $is_wpcom_simple && $this->is_authorized_blog_token_request() ) {
119 + return true;
120 + }
121 +
122 + return new WP_Error(
123 + 'rest_forbidden_context',
124 + __( 'Sorry, you are not allowed to preview emails on this site.', 'jetpack' ),
125 + array( 'status' => rest_authorization_required_code() )
126 + );
121 127 }
122 128
123 129 /**
124 - * Returns an email preview of a post.
130 + * Whether the request is a valid blog-token request authorized for the current site.
125 131 *
132 + * Runs on WordPress.com, where a proxied blog token authenticates as user 0.
133 + *
134 + * @return bool True if the request is authorized for the current Jetpack site.
135 + */
136 + private function is_authorized_blog_token_request() {
137 + if ( ! is_jetpack_site( get_current_blog_id() ) ) {
138 + return false;
139 + }
140 +
141 + if ( ! class_exists( 'WPCOM_REST_API_V2_Endpoint_Jetpack_Auth' ) ) {
142 + require_once dirname( __DIR__ ) . '/rest-api-plugins/endpoints/jetpack-auth.php';
143 + }
144 +
145 + $jp_auth_endpoint = new WPCOM_REST_API_V2_Endpoint_Jetpack_Auth();
146 +
147 + return true === $jp_auth_endpoint->is_jetpack_authorized_for_site();
148 + }
149 +
150 + /**
151 + * Returns an email preview of a post, or proxies the request to WordPress.com on non-wpcom sites.
152 + *
126 153 * @param WP_REST_Request $request Full data about the request.
127 154 *
128 155 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
129 156 */
130 157 public function email_preview( $request ) {
158 + // On a non-wpcom site, proxy to WordPress.com with the user's token, falling back to the site's blog token.
159 + if ( ! ( new Host() )->is_wpcom_simple() ) {
160 + return $this->proxy_request_to_wpcom( $request, '', 'user', true );
161 + }
162 +
131 163 $post_id = $request['post_id'];
132 164 $access = $request['access'];
133 165 $post = get_post( $post_id );
134 166 return rest_ensure_response(