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 +87 -27 13.7.2 → 16.3-a.7 View file →
@@ -5,11 +5,14 @@
5 5 * @package automattic/jetpack
6 6 */
7 7
8 8 use Automattic\Jetpack\Connection\Manager;
9 +use Automattic\Jetpack\Connection\Traits\WPCOM_REST_API_Proxy_Request;
9 10 use Automattic\Jetpack\Status\Host;
10 11
11 -require_once __DIR__ . '/trait-wpcom-rest-api-proxy-request-trait.php';
12 +if ( ! defined( 'ABSPATH' ) ) {
13 + exit( 0 );
14 +}
12 15
13 16 /**
14 17 * Class WPCOM_REST_API_V2_Endpoint_Email_Preview
15 18 *
@@ -16,9 +19,9 @@
16 19 * Returns an email preview given a post id.
17 20 */
18 21 class WPCOM_REST_API_V2_Endpoint_Email_Preview extends WP_REST_Controller {
19 22
20 - use WPCOM_REST_API_Proxy_Request_Trait;
23 + use WPCOM_REST_API_Proxy_Request;
21 24
22 25 /**
23 26 * Constructor.
24 27 */
@@ -41,19 +44,27 @@
41 44 public function register_routes() {
42 45 $options = array(
43 46 'show_in_index' => true,
44 47 'methods' => 'GET',
45 - // if this is not a wpcom site, we need to proxy the request to wpcom
46 - 'callback' => ( ( new Host() )->is_wpcom_simple() ) ? array(
47 - $this,
48 - 'email_preview',
49 - ) : array( $this, 'proxy_request_to_wpcom_as_user' ),
48 + 'callback' => array( $this, 'email_preview' ),
50 49 'permission_callback' => array( $this, 'permissions_check' ),
51 50 'args' => array(
52 - 'id' => array(
51 + 'post_id' => array(
53 52 'description' => __( 'Unique identifier for the post.', 'jetpack' ),
54 53 'type' => 'integer',
55 54 ),
55 + 'access' => array(
56 + 'description' => __( 'Access level.', 'jetpack' ),
57 + 'enum' => array( 'everybody', 'subscribers', 'paid_subscribers' ),
58 + 'default' => 'everybody',
59 + 'validate_callback' => function ( $param ) {
60 + return in_array(
61 + $param,
62 + array( 'everybody', 'subscribers', 'paid_subscribers' ),
63 + true
64 + );
65 + },
66 + ),
56 67 ),
57 68 );
58 69
59 70 register_rest_route(
@@ -63,23 +74,28 @@
63 74 );
64 75 }
65 76
66 77 /**
67 - * Checks if the user is connected and has access to edit the post
78 + * Checks whether the request may render an email preview.
68 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 + *
69 83 * @param WP_REST_Request $request Full data about the request.
70 84 *
71 - * @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.
72 86 */
73 87 public function permissions_check( $request ) {
74 - if ( ! ( new Host() )->is_wpcom_simple() ) {
75 - if ( ! ( new Manager() )->is_user_connected() ) {
76 - return new WP_Error(
77 - 'rest_cannot_send_email_preview',
78 - __( 'Please connect your user account to WordPress.com', 'jetpack' ),
79 - array( 'status' => rest_authorization_required_code() )
80 - );
81 - }
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 + );
82 98 }
83 99
84 100 $post = get_post( $request->get_param( 'post_id' ) );
85 101
@@ -90,32 +106,76 @@
90 106 array( 'status' => 404 )
91 107 );
92 108 }
93 109
94 - if ( ! current_user_can( 'edit_post', $post->ID ) ) {
95 - return new WP_Error(
96 - 'rest_forbidden_context',
97 - __( 'Please connect your user account to WordPress.com', 'jetpack' ),
98 - array( 'status' => rest_authorization_required_code() )
99 - );
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;
100 113 }
101 114
102 - 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 + );
103 127 }
104 128
105 129 /**
106 - * Returns an email preview of a post.
130 + * Whether the request is a valid blog-token request authorized for the current site.
107 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 + *
108 153 * @param WP_REST_Request $request Full data about the request.
109 154 *
110 155 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
111 156 */
112 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 +
113 163 $post_id = $request['post_id'];
164 + $access = $request['access'];
114 165 $post = get_post( $post_id );
115 166 return rest_ensure_response(
116 167 array(
117 - 'html' => apply_filters( 'jetpack_generate_email_preview_html', '', $post ),
168 + /**
169 + * Filters the generated email preview HTML.
170 + *
171 + * @since 13.8
172 + *
173 + * @param string $html The generated HTML for the email preview.
174 + * @param WP_Post $post The post object.
175 + * @param string $access The access level.
176 + */
177 + 'html' => apply_filters( 'jetpack_generate_email_preview_html', '', $post, $access ),
118 178 )
119 179 );
120 180 }
121 181 }