PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.8.3
Jetpack – WP Security, Backup, Speed, & Growth v7.8.3
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 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 All 500 releases
jetpack / class.jetpack-client-server.php
class.jetpack-client-server.php
308 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use Automattic\Jetpack\Connection\Client;
4 use Automattic\Jetpack\Roles;
5 use Automattic\Jetpack\Tracking;
6
7 /**
8 * Client = Plugin
9 * Client Server = API Methods the Plugin must respond to
10 */
11 class Jetpack_Client_Server {
12
13 /**
14 * Authorizations
15 */
16 function client_authorize() {
17 $data = stripslashes_deep( $_GET );
18 $data['auth_type'] = 'client';
19 $roles = new Roles();
20 $role = $roles->translate_current_user_to_role();
21 $redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
22
23 check_admin_referer( "jetpack-authorize_{$role}_{$redirect}" );
24
25 $tracking = new Tracking();
26 $result = $this->authorize( $data );
27 if ( is_wp_error( $result ) ) {
28 Jetpack::state( 'error', $result->get_error_code() );
29
30 $tracking->record_user_event(
31 'jpc_client_authorize_fail',
32 array(
33 'error_code' => $result->get_error_code(),
34 'error_message' => $result->get_error_message(),
35 )
36 );
37 } else {
38 /**
39 * Fires after the Jetpack client is authorized to communicate with WordPress.com.
40 *
41 * @since 4.2.0
42 *
43 * @param int Jetpack Blog ID.
44 */
45 do_action( 'jetpack_client_authorized', Jetpack_Options::get_option( 'id' ) );
46 }
47
48 if ( wp_validate_redirect( $redirect ) ) {
49 // Exit happens below in $this->do_exit()
50 wp_safe_redirect( $redirect );
51 } else {
52 // Exit happens below in $this->do_exit()
53 wp_safe_redirect( Jetpack::admin_url() );
54 }
55
56 $tracking->record_user_event( 'jpc_client_authorize_success' );
57
58 $this->do_exit();
59 }
60
61 function authorize( $data = array() ) {
62 $redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
63
64 $jetpack_unique_connection = Jetpack_Options::get_option( 'unique_connection' );
65 // Checking if site has been active/connected previously before recording unique connection
66 if ( ! $jetpack_unique_connection ) {
67 // jetpack_unique_connection option has never been set
68 $jetpack_unique_connection = array(
69 'connected' => 0,
70 'disconnected' => 0,
71 'version' => '3.6.1',
72 );
73
74 update_option( 'jetpack_unique_connection', $jetpack_unique_connection );
75
76 // track unique connection
77 $jetpack = $this->get_jetpack();
78
79 $jetpack->stat( 'connections', 'unique-connection' );
80 $jetpack->do_stats( 'server_side' );
81 }
82
83 // increment number of times connected
84 $jetpack_unique_connection['connected'] += 1;
85 Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection );
86
87 $roles = new Roles();
88 $role = $roles->translate_current_user_to_role();
89
90 if ( ! $role ) {
91 return new Jetpack_Error( 'no_role', 'Invalid request.', 400 );
92 }
93
94 $cap = $roles->translate_role_to_cap( $role );
95 if ( ! $cap ) {
96 return new Jetpack_Error( 'no_cap', 'Invalid request.', 400 );
97 }
98
99 if ( ! empty( $data['error'] ) ) {
100 return new Jetpack_Error( $data['error'], 'Error included in the request.', 400 );
101 }
102
103 if ( ! isset( $data['state'] ) ) {
104 return new Jetpack_Error( 'no_state', 'Request must include state.', 400 );
105 }
106
107 if ( ! ctype_digit( $data['state'] ) ) {
108 return new Jetpack_Error( $data['error'], 'State must be an integer.', 400 );
109 }
110
111 $current_user_id = get_current_user_id();
112 if ( $current_user_id != $data['state'] ) {
113 return new Jetpack_Error( 'wrong_state', 'State does not match current user.', 400 );
114 }
115
116 if ( empty( $data['code'] ) ) {
117 return new Jetpack_Error( 'no_code', 'Request must include an authorization code.', 400 );
118 }
119
120 $token = $this->get_token( $data );
121
122 if ( is_wp_error( $token ) ) {
123 $code = $token->get_error_code();
124 if ( empty( $code ) ) {
125 $code = 'invalid_token';
126 }
127 return new Jetpack_Error( $code, $token->get_error_message(), 400 );
128 }
129
130 if ( ! $token ) {
131 return new Jetpack_Error( 'no_token', 'Error generating token.', 400 );
132 }
133
134 $is_master_user = ! Jetpack::is_active();
135
136 Jetpack::update_user_token( $current_user_id, sprintf( '%s.%d', $token, $current_user_id ), $is_master_user );
137
138 if ( ! $is_master_user ) {
139 Jetpack::state( 'message', 'linked' );
140 // Don't activate anything since we are just connecting a user.
141 return 'linked';
142 }
143
144 // If this site has been through the Jetpack Onboarding flow, delete the onboarding token
145 Jetpack::invalidate_onboarding_token();
146
147 // If redirect_uri is SSO, ensure SSO module is enabled
148 parse_str( parse_url( $data['redirect_uri'], PHP_URL_QUERY ), $redirect_options );
149
150 /** This filter is documented in class.jetpack-cli.php */
151 $jetpack_start_enable_sso = apply_filters( 'jetpack_start_enable_sso', true );
152
153 $activate_sso = (
154 isset( $redirect_options['action'] ) &&
155 'jetpack-sso' === $redirect_options['action'] &&
156 $jetpack_start_enable_sso
157 );
158
159 $do_redirect_on_error = ( 'client' === $data['auth_type'] );
160
161 Jetpack::handle_post_authorization_actions( $activate_sso, $do_redirect_on_error );
162
163 return 'authorized';
164 }
165
166 public static function deactivate_plugin( $probable_file, $probable_title ) {
167 include_once ABSPATH . 'wp-admin/includes/plugin.php';
168 if ( is_plugin_active( $probable_file ) ) {
169 deactivate_plugins( $probable_file );
170 return 1;
171 } else {
172 // If the plugin is not in the usual place, try looking through all active plugins.
173 $active_plugins = Jetpack::get_active_plugins();
174 foreach ( $active_plugins as $plugin ) {
175 $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
176 if ( $data['Name'] == $probable_title ) {
177 deactivate_plugins( $plugin );
178 return 1;
179 }
180 }
181 }
182
183 return 0;
184 }
185
186 /**
187 * @return object|WP_Error
188 */
189 function get_token( $data ) {
190 $roles = new Roles();
191 $role = $roles->translate_current_user_to_role();
192
193 if ( ! $role ) {
194 return new Jetpack_Error( 'role', __( 'An administrator for this blog must set up the Jetpack connection.', 'jetpack' ) );
195 }
196
197 $client_secret = Jetpack_Data::get_access_token();
198 if ( ! $client_secret ) {
199 return new Jetpack_Error( 'client_secret', __( 'You need to register your Jetpack before connecting it.', 'jetpack' ) );
200 }
201
202 $redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
203 $redirect_uri = ( 'calypso' === $data['auth_type'] )
204 ? $data['redirect_uri']
205 : add_query_arg(
206 array(
207 'action' => 'authorize',
208 '_wpnonce' => wp_create_nonce( "jetpack-authorize_{$role}_{$redirect}" ),
209 'redirect' => $redirect ? urlencode( $redirect ) : false,
210 ),
211 menu_page_url( 'jetpack', false )
212 );
213
214 // inject identity for analytics
215 $tracks = new Automattic\Jetpack\Tracking();
216 $tracks_identity = $tracks->tracks_get_identity( get_current_user_id() );
217
218 $body = array(
219 'client_id' => Jetpack_Options::get_option( 'id' ),
220 'client_secret' => $client_secret->secret,
221 'grant_type' => 'authorization_code',
222 'code' => $data['code'],
223 'redirect_uri' => $redirect_uri,
224 '_ui' => $tracks_identity['_ui'],
225 '_ut' => $tracks_identity['_ut'],
226 );
227
228 $args = array(
229 'method' => 'POST',
230 'body' => $body,
231 'headers' => array(
232 'Accept' => 'application/json',
233 ),
234 );
235 $response = Client::_wp_remote_request( Jetpack::fix_url_for_bad_hosts( Jetpack::connection()->api_url( 'token' ) ), $args );
236
237 if ( is_wp_error( $response ) ) {
238 return new Jetpack_Error( 'token_http_request_failed', $response->get_error_message() );
239 }
240
241 $code = wp_remote_retrieve_response_code( $response );
242 $entity = wp_remote_retrieve_body( $response );
243
244 if ( $entity ) {
245 $json = json_decode( $entity );
246 } else {
247 $json = false;
248 }
249
250 if ( 200 != $code || ! empty( $json->error ) ) {
251 if ( empty( $json->error ) ) {
252 return new Jetpack_Error( 'unknown', '', $code );
253 }
254
255 $error_description = isset( $json->error_description ) ? sprintf( __( 'Error Details: %s', 'jetpack' ), (string) $json->error_description ) : '';
256
257 return new Jetpack_Error( (string) $json->error, $error_description, $code );
258 }
259
260 if ( empty( $json->access_token ) || ! is_scalar( $json->access_token ) ) {
261 return new Jetpack_Error( 'access_token', '', $code );
262 }
263
264 if ( empty( $json->token_type ) || 'X_JETPACK' != strtoupper( $json->token_type ) ) {
265 return new Jetpack_Error( 'token_type', '', $code );
266 }
267
268 if ( empty( $json->scope ) ) {
269 return new Jetpack_Error( 'scope', 'No Scope', $code );
270 }
271
272 @list( $role, $hmac ) = explode( ':', $json->scope );
273 if ( empty( $role ) || empty( $hmac ) ) {
274 return new Jetpack_Error( 'scope', 'Malformed Scope', $code );
275 }
276
277 if ( Jetpack::connection()->sign_role( $role ) !== $json->scope ) {
278 return new Jetpack_Error( 'scope', 'Invalid Scope', $code );
279 }
280
281 $cap = $roles->translate_role_to_cap( $role );
282 if ( ! $cap ) {
283 return new Jetpack_Error( 'scope', 'No Cap', $code );
284 }
285
286 if ( ! current_user_can( $cap ) ) {
287 return new Jetpack_Error( 'scope', 'current_user_cannot', $code );
288 }
289
290 /**
291 * Fires after user has successfully received an auth token.
292 *
293 * @since 3.9.0
294 */
295 do_action( 'jetpack_user_authorized' );
296
297 return (string) $json->access_token;
298 }
299
300 public function get_jetpack() {
301 return Jetpack::init();
302 }
303
304 public function do_exit() {
305 exit;
306 }
307 }
308