Completed
Push — branch-4.0 ( fc0d6f...bf547c )
by
unknown
08:22
created

class.jetpack-client-server.php (3 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
	/**
10
	 * Authorizations
11
	 */
12
	function client_authorize() {
13
		$data              = stripslashes_deep( $_GET );
14
		$data['auth_type'] = 'client';
15
		$jetpack           = $this->get_jetpack();
16
		$role              = $jetpack->translate_current_user_to_role();
17
		$redirect          = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
18
19
		$this->check_admin_referer( "jetpack-authorize_{$role}_{$redirect}" );
20
21
		$result = $this->authorize( $data );
22
		if ( is_wp_error( $result ) ) {
23
			Jetpack::state( 'error', $result->get_error_code() );
24
		}
25
26
		if ( wp_validate_redirect( $redirect ) ) {
27
			$this->wp_safe_redirect( $redirect );
28
		} else {
29
			$this->wp_safe_redirect( Jetpack::admin_url() );
30
		}
31
32
		$this->do_exit();
33
	}
34
35
	function authorize( $data = array() ) {
36
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
0 ignored issues
show
$redirect is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
37
38
		$jetpack_unique_connection = Jetpack_Options::get_option( 'unique_connection' );
39
		// Checking if site has been active/connected previously before recording unique connection
40
		if ( ! $jetpack_unique_connection ) {
41
			// jetpack_unique_connection option has never been set
42
			$jetpack_unique_connection = array(
43
				'connected'     => 0,
44
				'disconnected'  => 0,
45
				'version'       => '3.6.1'
46
			);
47
48
			update_option( 'jetpack_unique_connection', $jetpack_unique_connection );
49
50
			//track unique connection
51
			$jetpack = Jetpack::init();
52
53
			$jetpack->stat( 'connections', 'unique-connection' );
54
			$jetpack->do_stats( 'server_side' );
55
		}
56
57
		// increment number of times connected
58
		$jetpack_unique_connection['connected'] += 1;
59
		Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection );
60
61
		do {
62
			$jetpack = $this->get_jetpack();
63
			$role = $jetpack->translate_current_user_to_role();
64
65
			if ( ! $role ) {
66
				return new Jetpack_Error( 'no_role', 'Invalid request.', 400 );
67
			}
68
69
			$cap = $jetpack->translate_role_to_cap( $role );
70
			if ( !$cap ) {
71
				return new Jetpack_Error( 'no_cap', 'Invalid request.', 400 );
72
			}
73
74
			if ( ! empty( $data['error'] ) ) {
75
				return new Jetpack_Error( $data['error'], 'Error included in the request.', 400 );
76
			}
77
78
			if ( ! isset( $data['state'] ) ) {
79
				return new Jetpack_Error( 'no_state', 'Request must include state.', 400 );
80
			}
81
82
			if ( ! ctype_digit( $data['state'] ) ) {
83
				return new Jetpack_Error( $data['error'], 'State must be an integer.', 400 );
84
			}
85
86
			$current_user_id = get_current_user_id();
87
			if ( $current_user_id != $data['state'] ) {
88
				return new Jetpack_Error( 'wrong_state', 'State does not match current user.', 400 );
89
			}
90
91
			if ( empty( $data['code'] ) ) {
92
				return new Jetpack_Error( 'no_code', 'Request must include an authorization code.', 400 );
93
			}
94
95
			$token = $this->get_token( $data );
96
97
			if ( is_wp_error( $token ) ) {
98
				$code = $token->get_error_code();
99
				if ( empty( $code ) ) {
100
					$code = 'invalid_token';
101
				}
102
				return new Jetpack_Error( $code, $token->get_error_message(), 400 );
103
			}
104
105
			if ( ! $token ) {
106
				return new Jetpack_Error( 'no_token', 'Error generating token.', 400 );
107
			}
108
109
			$is_master_user = ! Jetpack::is_active();
110
111
			Jetpack::update_user_token( $current_user_id, sprintf( '%s.%d', $token, $current_user_id ), $is_master_user );
112
113
114
			if ( ! $is_master_user ) {
115
				// Don't activate anything since we are just connecting a user.
116
				return 'linked';
117
			}
118
119
			$redirect_on_activation_error = ( 'client' === $data['auth_type'] ) ? true : false;
120
			if ( $active_modules = Jetpack_Options::get_option( 'active_modules' ) ) {
121
				Jetpack_Options::delete_option( 'active_modules' );
122
123
				Jetpack::activate_default_modules( 999, 1, $active_modules, $redirect_on_activation_error );
124
			} else {
125
				Jetpack::activate_default_modules( false, false, array(), $redirect_on_activation_error );
126
			}
127
128
			// Sync all registers options and constants
129
			/** This action is documented in class.jetpack.php */
130
			do_action( 'jetpack_sync_all_registered_options' );
131
132
			// Start nonce cleaner
133
			wp_clear_scheduled_hook( 'jetpack_clean_nonces' );
134
			wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' );
135
		} while ( false );
136
137
		return 'authorized';
138
	}
139
140
	public static function deactivate_plugin( $probable_file, $probable_title ) {
141
		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
142
		if ( is_plugin_active( $probable_file ) ) {
143
			deactivate_plugins( $probable_file );
144
			return 1;
145
		} else {
146
			// If the plugin is not in the usual place, try looking through all active plugins.
147
			$active_plugins = Jetpack::get_active_plugins();
148
			foreach ( $active_plugins as $plugin ) {
149
				$data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
150
				if ( $data['Name'] == $probable_title ) {
151
					deactivate_plugins( $plugin );
152
					return 1;
153
				}
154
			}
155
		}
156
157
		return 0;
158
	}
159
160
	/**
161
	 * @return object|WP_Error
162
	 */
163
	function get_token( $data ) {
164
		$jetpack = $this->get_jetpack();
165
		$role = $jetpack->translate_current_user_to_role();
166
167
		if ( ! $role ) {
168
			return new Jetpack_Error( 'role', __( 'An administrator for this blog must set up the Jetpack connection.', 'jetpack' ) );
169
		}
170
171
		$client_secret = Jetpack_Data::get_access_token();
172
		if ( !$client_secret ) {
173
			return new Jetpack_Error( 'client_secret', __( 'You need to register your Jetpack before connecting it.', 'jetpack' ) );
174
		}
175
176
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
177
		$redirect_uri = ( 'calypso' === $data['auth_type'] )
178
			? $data['redirect_uri']
179
			: add_query_arg( array(
180
				'action' => 'authorize',
181
				'_wpnonce' => wp_create_nonce( "jetpack-authorize_{$role}_{$redirect}" ),
182
				'redirect' => $redirect ? urlencode( $redirect ) : false,
183
			), menu_page_url( 'jetpack', false ) );
184
185
		$body = array(
186
			'client_id' => Jetpack_Options::get_option( 'id' ),
187
			'client_secret' => $client_secret->secret,
188
			'grant_type' => 'authorization_code',
189
			'code' => $data['code'],
190
			'redirect_uri' => $redirect_uri,
191
		);
192
193
		$args = array(
194
			'method' => 'POST',
195
			'body' => $body,
196
			'headers' => array(
197
				'Accept' => 'application/json',
198
			),
199
		);
200
		$response = Jetpack_Client::_wp_remote_request( Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'token' ) ), $args );
201
202
		if ( is_wp_error( $response ) ) {
203
			return new Jetpack_Error( 'token_http_request_failed', $response->get_error_message() );
204
		}
205
206
		$code = wp_remote_retrieve_response_code( $response );
207
		$entity = wp_remote_retrieve_body( $response );
208
209
		if ( $entity )
210
			$json = json_decode( $entity );
211
		else
212
			$json = false;
213
214
		if ( 200 != $code || !empty( $json->error ) ) {
215
			if ( empty( $json->error ) )
216
				return new Jetpack_Error( 'unknown', '', $code );
217
218
			$error_description = isset( $json->error_description ) ? sprintf( __( 'Error Details: %s', 'jetpack' ), (string) $json->error_description ) : '';
219
220
			return new Jetpack_Error( (string) $json->error, $error_description, $code );
221
		}
222
223
		if ( empty( $json->access_token ) || !is_scalar( $json->access_token ) ) {
224
			return new Jetpack_Error( 'access_token', '', $code );
225
		}
226
227
		if ( empty( $json->token_type ) || 'X_JETPACK' != strtoupper( $json->token_type ) ) {
228
			return new Jetpack_Error( 'token_type', '', $code );
229
		}
230
231
		if ( empty( $json->scope ) ) {
232
			return new Jetpack_Error( 'scope', 'No Scope', $code );
233
		}
234
		@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...
235
		if ( empty( $role ) || empty( $hmac ) ) {
236
			return new Jetpack_Error( 'scope', 'Malformed Scope', $code );
237
		}
238
		if ( $jetpack->sign_role( $role ) !== $json->scope ) {
239
			return new Jetpack_Error( 'scope', 'Invalid Scope', $code );
240
		}
241
242
		if ( !$cap = $jetpack->translate_role_to_cap( $role ) )
243
			return new Jetpack_Error( 'scope', 'No Cap', $code );
244
		if ( ! current_user_can( $cap ) )
245
			return new Jetpack_Error( 'scope', 'current_user_cannot', $code );
246
247
		/**
248
		 * Fires after user has successfully received an auth token.
249
		 *
250
		 * @since 3.9.0
251
		 */
252
		do_action( 'jetpack_user_authorized' );
253
254
		return (string) $json->access_token;
255
	}
256
257
	public function get_jetpack() {
258
		return Jetpack::init();
259
	}
260
261
	public function check_admin_referer( $action ) {
262
		return check_admin_referer( $action );
263
	}
264
265
	public function wp_safe_redirect( $redirect ) {
266
		return wp_safe_redirect( $redirect );
267
	}
268
269
	public function do_exit() {
270
		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...
271
	}
272
273
}
274