Completed
Push — fix/visibility-condition-issue... ( eee6fd...a71c15 )
by
unknown
11:07
created

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