Completed
Push — add/update_master_user_on_role... ( be6106 )
by
unknown
28:35 queued 17:41
created

Jetpack_Client_Server::get_jetpack()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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