Completed
Push — add/goldsounds ( 0c869a )
by
unknown
10:18
created

Jetpack_Client_Server   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 260
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5
Metric Value
wmc 46
lcom 1
cbo 5
dl 0
loc 260
rs 8.3999

7 Methods

Rating   Name   Duplication   Size   Complexity  
A deactivate_plugin() 0 19 4
A get_jetpack() 0 3 1
A check_admin_referer() 0 3 1
A wp_safe_redirect() 0 3 1
A do_exit() 0 3 1
D authorize() 0 126 17
D get_token() 0 90 21

How to fix   Complexity   

Complex Class

Complex classes like Jetpack_Client_Server often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Jetpack_Client_Server, and based on these observations, apply Extract Interface, too.

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