Completed
Push — add/sync-rest-2 ( 1be3a0...df1b9f )
by
unknown
18:45 queued 09:48
created

class.jetpack-client-server.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Client = Plugin
5
 * Client Server = API Methods the Plugin must respond to
6
 */
7
class Jetpack_Client_Server {
8
9
	function authorize() {
10
		$data = stripslashes_deep( $_GET );
11
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
12
13
		$jetpack_unique_connection = Jetpack_Options::get_option( 'unique_connection' );
14
		// Checking if site has been active/connected previously before recording unique connection
15
		if ( ! $jetpack_unique_connection ) {
16
			// jetpack_unique_connection option has never been set
17
			$jetpack_unique_connection = array(
18
				'connected'     => 0,
19
				'disconnected'  => 0,
20
				'version'       => '3.6.1'
21
			);
22
23
			update_option( 'jetpack_unique_connection', $jetpack_unique_connection );
24
25
			//track unique connection
26
			$jetpack = Jetpack::init();
27
28
			$jetpack->stat( 'connections', 'unique-connection' );
29
			$jetpack->do_stats( 'server_side' );
30
		}
31
32
		// increment number of times connected
33
		$jetpack_unique_connection['connected'] += 1;
34
		Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection );
35
36
		do {
37
			$role = Jetpack::translate_current_user_to_role();
38
39
			if ( !$role ) {
40
				Jetpack::state( 'error', 'no_role' );
41
				break;
42
			}
43
44
			$cap = Jetpack::translate_role_to_cap( $role );
45
			if ( !$cap ) {
46
				Jetpack::state( 'error', 'no_cap' );
47
				break;
48
			}
49
50
			$this->check_admin_referer( "jetpack-authorize_{$role}_{$redirect}" );
51
52
			if ( !empty( $data['error'] ) ) {
53
				Jetpack::state( 'error', $data['error'] );
54
				break;
55
			}
56
57
			if ( empty( $data['state'] ) ) {
58
				Jetpack::state( 'error', 'no_state' );
59
				break;
60
			}
61
62
			if ( !ctype_digit( $data['state'] ) ) {
63
				Jetpack::state( 'error', 'invalid_state' );
64
				break;
65
			}
66
67
			$current_user_id = get_current_user_id();
68
			if ( $current_user_id != $data['state'] ) {
69
				Jetpack::state( 'error', 'wrong_state' );
70
				break;
71
			}
72
73
			if ( empty( $data['code'] ) ) {
74
				Jetpack::state( 'error', 'no_code' );
75
				break;
76
			}
77
78
			$token = $this->get_token( $data );
79
80
			if ( is_wp_error( $token ) ) {
81
				if ( $error = $token->get_error_code() )
82
					Jetpack::state( 'error', $error );
83
				else
84
					Jetpack::state( 'error', 'invalid_token' );
85
86
				Jetpack::state( 'error_description', $token->get_error_message() );
87
88
				break;
89
			}
90
91
			if ( !$token ) {
92
				Jetpack::state( 'error', 'no_token' );
93
				break;
94
			}
95
96
			$is_master_user = ! Jetpack::is_active();
97
98
			Jetpack::update_user_token( $current_user_id, sprintf( '%s.%d', $token, $current_user_id ), $is_master_user );
99
100
101
			if ( $is_master_user ) {
102
				Jetpack::state( 'message', 'authorized' );
103
			} else {
104
				Jetpack::state( 'message', 'linked' );
105
				// Don't activate anything since we are just connecting a user.
106
				break;
107
			}
108
109
			if ( $active_modules = Jetpack_Options::get_option( 'active_modules' ) ) {
110
				Jetpack_Options::delete_option( 'active_modules' );
111
112
				Jetpack::activate_default_modules( 999, 1, $active_modules );
0 ignored issues
show
999 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
113
			} else {
114
				Jetpack::activate_default_modules();
115
			}
116
117
			// Sync all registers options and constants
118
			/** This action is documented in class.jetpack.php */
119
			do_action( 'jetpack_sync_all_registered_options' );
120
121
			// Start nonce cleaner
122
			wp_clear_scheduled_hook( 'jetpack_clean_nonces' );
123
			wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' );
124
		} while ( false );
125
126
		if ( wp_validate_redirect( $redirect ) ) {
127
			$this->wp_safe_redirect( $redirect );
128
		} else {
129
			$this->wp_safe_redirect( Jetpack::admin_url() );
130
		}
131
132
		$this->do_exit();
133
	}
134
135
	public static function deactivate_plugin( $probable_file, $probable_title ) {
136
		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
137
		if ( is_plugin_active( $probable_file ) ) {
138
			deactivate_plugins( $probable_file );
139
			return 1;
140
		} else {
141
			// If the plugin is not in the usual place, try looking through all active plugins.
142
			$active_plugins = Jetpack::get_active_plugins();
143
			foreach ( $active_plugins as $plugin ) {
144
				$data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
145
				if ( $data['Name'] == $probable_title ) {
146
					deactivate_plugins( $plugin );
147
					return 1;
148
				}
149
			}
150
		}
151
152
		return 0;
153
	}
154
155
	/**
156
	 * @return object|WP_Error
157
	 */
158
	function get_token( $data ) {
159
		$jetpack = $this->get_jetpack();
160
		$role = $jetpack->translate_current_user_to_role();
161
162
		if ( !$role ) {
163
			return new Jetpack_Error( 'role', __( 'An administrator for this blog must set up the Jetpack connection.', 'jetpack' ) );
164
		}
165
166
		$client_secret = Jetpack_Data::get_access_token();
167
		if ( !$client_secret ) {
168
			return new Jetpack_Error( 'client_secret', __( 'You need to register your Jetpack before connecting it.', 'jetpack' ) );
169
		}
170
171
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
172
173
		$body = array(
174
			'client_id' => Jetpack_Options::get_option( 'id' ),
175
			'client_secret' => $client_secret->secret,
176
			'grant_type' => 'authorization_code',
177
			'code' => $data['code'],
178
			'redirect_uri' => add_query_arg( array(
179
				'action' => 'authorize',
180
				'_wpnonce' => wp_create_nonce( "jetpack-authorize_{$role}_{$redirect}" ),
181
				'redirect' => $redirect ? urlencode( $redirect ) : false,
182
			), menu_page_url( 'jetpack', false ) ),
183
		);
184
185
		$args = array(
186
			'method' => 'POST',
187
			'body' => $body,
188
			'headers' => array(
189
				'Accept' => 'application/json',
190
			),
191
		);
192
		$response = Jetpack_Client::_wp_remote_request( Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'token' ) ), $args );
193
194
		if ( is_wp_error( $response ) ) {
195
			return new Jetpack_Error( 'token_http_request_failed', $response->get_error_message() );
196
		}
197
198
		$code = wp_remote_retrieve_response_code( $response );
199
		$entity = wp_remote_retrieve_body( $response );
200
201
		if ( $entity )
202
			$json = json_decode( $entity );
203
		else
204
			$json = false;
205
206
		if ( 200 != $code || !empty( $json->error ) ) {
207
			if ( empty( $json->error ) )
208
				return new Jetpack_Error( 'unknown', '', $code );
209
210
			$error_description = isset( $json->error_description ) ? sprintf( __( 'Error Details: %s', 'jetpack' ), (string) $json->error_description ) : '';
211
212
			return new Jetpack_Error( (string) $json->error, $error_description, $code );
213
		}
214
215
		if ( empty( $json->access_token ) || !is_scalar( $json->access_token ) ) {
216
			return new Jetpack_Error( 'access_token', '', $code );
217
		}
218
219
		if ( empty( $json->token_type ) || 'X_JETPACK' != strtoupper( $json->token_type ) ) {
220
			return new Jetpack_Error( 'token_type', '', $code );
221
		}
222
223
		if ( empty( $json->scope ) ) {
224
			return new Jetpack_Error( 'scope', 'No Scope', $code );
225
		}
226
		@list( $role, $hmac ) = explode( ':', $json->scope );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
227
		if ( empty( $role ) || empty( $hmac ) ) {
228
			return new Jetpack_Error( 'scope', 'Malformed Scope', $code );
229
		}
230
		if ( $jetpack->sign_role( $role ) !== $json->scope ) {
231
			return new Jetpack_Error( 'scope', 'Invalid Scope', $code );
232
		}
233
234
		if ( !$cap = $jetpack->translate_role_to_cap( $role ) )
235
			return new Jetpack_Error( 'scope', 'No Cap', $code );
236
		if ( ! current_user_can( $cap ) )
237
			return new Jetpack_Error( 'scope', 'current_user_cannot', $code );
238
239
		/**
240
		 * Fires after user has successfully received an auth token.
241
		 *
242
		 * @since 3.9.0
243
		 */
244
		do_action( 'jetpack_user_authorized' );
245
246
		return (string) $json->access_token;
247
	}
248
249
	public function get_jetpack() {
250
		return Jetpack::init();
251
	}
252
253
	public function check_admin_referer( $action ) {
254
		return check_admin_referer( $action );
255
	}
256
257
	public function wp_safe_redirect( $redirect ) {
258
		return wp_safe_redirect( $redirect );
259
	}
260
261
	public function do_exit() {
262
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method do_exit() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
263
	}
264
265
}
266