Completed
Push — update/google-translate-layout ( 38cf64...f54e3d )
by Jeremy
14:26
created

Jetpack_Client_Server::get_token()   D

Complexity

Conditions 22
Paths 94

Size

Total Lines 104
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 22
eloc 60
nc 94
nop 1
dl 0
loc 104
rs 4.6625
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
		$role              = Jetpack::translate_current_user_to_role();
16
		$redirect          = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
17
18
		check_admin_referer( "jetpack-authorize_{$role}_{$redirect}" );
19
20
		$result = $this->authorize( $data );
21
		if ( is_wp_error( $result ) ) {
22
			Jetpack::state( 'error', $result->get_error_code() );
23
			JetpackTracking::record_user_event( 'jpc_client_authorize_fail', array(
24
				'error_code' => $result->get_error_code(),
25
				'error_message' => $result->get_error_message()
26
			) );
27
		} else {
28
			/**
29
			 * Fires after the Jetpack client is authorized to communicate with WordPress.com.
30
			 *
31
			 * @since 4.2.0
32
			 *
33
			 * @param int Jetpack Blog ID.
34
			 */
35
			do_action( 'jetpack_client_authorized', Jetpack_Options::get_option( 'id' ) );
36
		}
37
38
		if ( wp_validate_redirect( $redirect ) ) {
39
			// Exit happens below in $this->do_exit()
40
			wp_safe_redirect( $redirect );
41
		} else {
42
			// Exit happens below in $this->do_exit()
43
			wp_safe_redirect( Jetpack::admin_url() );
44
		}
45
46
		JetpackTracking::record_user_event( 'jpc_client_authorize_success' );
47
48
		$this->do_exit();
49
	}
50
51
	function authorize( $data = array() ) {
52
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
0 ignored issues
show
Unused Code introduced by
$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...
53
54
		$jetpack_unique_connection = Jetpack_Options::get_option( 'unique_connection' );
55
		// Checking if site has been active/connected previously before recording unique connection
56
		if ( ! $jetpack_unique_connection ) {
57
			// jetpack_unique_connection option has never been set
58
			$jetpack_unique_connection = array(
59
				'connected'     => 0,
60
				'disconnected'  => 0,
61
				'version'       => '3.6.1',
62
			);
63
64
			update_option( 'jetpack_unique_connection', $jetpack_unique_connection );
65
66
			//track unique connection
67
			$jetpack = $this->get_jetpack();;
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
68
69
			$jetpack->stat( 'connections', 'unique-connection' );
70
			$jetpack->do_stats( 'server_side' );
71
		}
72
73
		// increment number of times connected
74
		$jetpack_unique_connection['connected'] += 1;
75
		Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection );
76
77
		$role = Jetpack::translate_current_user_to_role();
78
79
		if ( ! $role ) {
80
			return new Jetpack_Error( 'no_role', 'Invalid request.', 400 );
81
		}
82
83
		$cap = Jetpack::translate_role_to_cap( $role );
84
		if ( ! $cap ) {
85
			return new Jetpack_Error( 'no_cap', 'Invalid request.', 400 );
86
		}
87
88
		if ( ! empty( $data['error'] ) ) {
89
			return new Jetpack_Error( $data['error'], 'Error included in the request.', 400 );
90
		}
91
92
		if ( ! isset( $data['state'] ) ) {
93
			return new Jetpack_Error( 'no_state', 'Request must include state.', 400 );
94
		}
95
96
		if ( ! ctype_digit( $data['state'] ) ) {
97
			return new Jetpack_Error( $data['error'], 'State must be an integer.', 400 );
98
		}
99
100
		$current_user_id = get_current_user_id();
101
		if ( $current_user_id != $data['state'] ) {
102
			return new Jetpack_Error( 'wrong_state', 'State does not match current user.', 400 );
103
		}
104
105
		if ( empty( $data['code'] ) ) {
106
			return new Jetpack_Error( 'no_code', 'Request must include an authorization code.', 400 );
107
		}
108
109
		$token = $this->get_token( $data );
110
111
		if ( is_wp_error( $token ) ) {
112
			$code = $token->get_error_code();
113
			if ( empty( $code ) ) {
114
				$code = 'invalid_token';
115
			}
116
			return new Jetpack_Error( $code, $token->get_error_message(), 400 );
117
		}
118
119
		if ( ! $token ) {
120
			return new Jetpack_Error( 'no_token', 'Error generating token.', 400 );
121
		}
122
123
		$is_master_user = ! Jetpack::is_active();
124
125
		Jetpack::update_user_token( $current_user_id, sprintf( '%s.%d', $token, $current_user_id ), $is_master_user );
126
127
		if ( ! $is_master_user ) {
128
			Jetpack::state( 'message', 'linked' );
129
			// Don't activate anything since we are just connecting a user.
130
			return 'linked';
131
		}
132
133
		$redirect_on_activation_error = ( 'client' === $data['auth_type'] ) ? true : false;
134 View Code Duplication
		if ( $active_modules = Jetpack_Options::get_option( 'active_modules' ) ) {
135
			Jetpack::delete_active_modules();
136
137
			Jetpack::activate_default_modules( 999, 1, $active_modules, $redirect_on_activation_error, false );
0 ignored issues
show
Documentation introduced by
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...
138
		} else {
139
			Jetpack::activate_default_modules( false, false, array(), $redirect_on_activation_error, false );
140
		}
141
142
		// If redirect_uri is SSO, ensure SSO module is enabled
143
		parse_str( parse_url( $data['redirect_uri'], PHP_URL_QUERY ), $redirect_options );
144
		/** This filter is documented in class.jetpack-cli.php */
145
		if ( isset( $redirect_options['action'] ) && 'jetpack-sso' === $redirect_options['action'] && apply_filters( 'jetpack_start_enable_sso', true ) ) {
146
			Jetpack::activate_module( 'sso', false, false );
147
		}
148
149
		// Since this is a fresh connection, be sure to clear out IDC options
150
		Jetpack_IDC::clear_all_idc_options();
151
152
		// Start nonce cleaner
153
		wp_clear_scheduled_hook( 'jetpack_clean_nonces' );
154
		wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' );
155
156
		Jetpack::state( 'message', 'authorized' );
157
		return 'authorized';
158
	}
159
160
	public static function deactivate_plugin( $probable_file, $probable_title ) {
161
		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
162
		if ( is_plugin_active( $probable_file ) ) {
163
			deactivate_plugins( $probable_file );
164
			return 1;
165
		} else {
166
			// If the plugin is not in the usual place, try looking through all active plugins.
167
			$active_plugins = Jetpack::get_active_plugins();
168
			foreach ( $active_plugins as $plugin ) {
169
				$data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
170
				if ( $data['Name'] == $probable_title ) {
171
					deactivate_plugins( $plugin );
172
					return 1;
173
				}
174
			}
175
		}
176
177
		return 0;
178
	}
179
180
	/**
181
	 * @return object|WP_Error
182
	 */
183
	function get_token( $data ) {
184
		$role = Jetpack::translate_current_user_to_role();
185
186
		if ( ! $role ) {
187
			return new Jetpack_Error( 'role', __( 'An administrator for this blog must set up the Jetpack connection.', 'jetpack' ) );
188
		}
189
190
		$client_secret = Jetpack_Data::get_access_token();
191
		if ( ! $client_secret ) {
192
			return new Jetpack_Error( 'client_secret', __( 'You need to register your Jetpack before connecting it.', 'jetpack' ) );
193
		}
194
195
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
196
		$redirect_uri = ( 'calypso' === $data['auth_type'] )
197
			? $data['redirect_uri']
198
			: add_query_arg( array(
199
				'action' => 'authorize',
200
				'_wpnonce' => wp_create_nonce( "jetpack-authorize_{$role}_{$redirect}" ),
201
				'redirect' => $redirect ? urlencode( $redirect ) : false,
202
			), menu_page_url( 'jetpack', false ) );
203
204
		// inject identity for analytics
205
		$tracks_identity = jetpack_tracks_get_identity( get_current_user_id() );
206
207
		$body = array(
208
			'client_id' => Jetpack_Options::get_option( 'id' ),
209
			'client_secret' => $client_secret->secret,
210
			'grant_type' => 'authorization_code',
211
			'code' => $data['code'],
212
			'redirect_uri' => $redirect_uri,
213
			'_ui' => $tracks_identity['_ui'],
214
			'_ut' => $tracks_identity['_ut'],
215
		);
216
217
		$args = array(
218
			'method' => 'POST',
219
			'body' => $body,
220
			'headers' => array(
221
				'Accept' => 'application/json',
222
			),
223
		);
224
		$response = Jetpack_Client::_wp_remote_request( Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'token' ) ), $args );
225
226
		if ( is_wp_error( $response ) ) {
227
			return new Jetpack_Error( 'token_http_request_failed', $response->get_error_message() );
228
		}
229
230
		$code = wp_remote_retrieve_response_code( $response );
231
		$entity = wp_remote_retrieve_body( $response );
232
233
		if ( $entity ) {
234
			$json = json_decode( $entity );
235
		} else {
236
			$json = false;
237
		}
238
239
		if ( 200 != $code || ! empty( $json->error ) ) {
240
			if ( empty( $json->error ) ) {
241
				return new Jetpack_Error( 'unknown', '', $code );
242
			}
243
244
			$error_description = isset( $json->error_description ) ? sprintf( __( 'Error Details: %s', 'jetpack' ), (string) $json->error_description ) : '';
245
246
			return new Jetpack_Error( (string) $json->error, $error_description, $code );
247
		}
248
249
		if ( empty( $json->access_token ) || ! is_scalar( $json->access_token ) ) {
250
			return new Jetpack_Error( 'access_token', '', $code );
251
		}
252
253
		if ( empty( $json->token_type ) || 'X_JETPACK' != strtoupper( $json->token_type ) ) {
254
			return new Jetpack_Error( 'token_type', '', $code );
255
		}
256
257
		if ( empty( $json->scope ) ) {
258
			return new Jetpack_Error( 'scope', 'No Scope', $code );
259
		}
260
261
		@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...
262
		if ( empty( $role ) || empty( $hmac ) ) {
263
			return new Jetpack_Error( 'scope', 'Malformed Scope', $code );
264
		}
265
266
		if ( Jetpack::sign_role( $role ) !== $json->scope ) {
267
			return new Jetpack_Error( 'scope', 'Invalid Scope', $code );
268
		}
269
270
		if ( ! $cap = Jetpack::translate_role_to_cap( $role ) ) {
271
			return new Jetpack_Error( 'scope', 'No Cap', $code );
272
		}
273
274
		if ( ! current_user_can( $cap ) ) {
275
			return new Jetpack_Error( 'scope', 'current_user_cannot', $code );
276
		}
277
278
		/**
279
		 * Fires after user has successfully received an auth token.
280
		 *
281
		 * @since 3.9.0
282
		 */
283
		do_action( 'jetpack_user_authorized' );
284
285
		return (string) $json->access_token;
286
	}
287
288
	public function get_jetpack() {
289
		return Jetpack::init();
290
	}
291
292
	public function do_exit() {
293
		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...
294
	}
295
}
296