Completed
Push — add/jetpack-data-methods ( d7e5a6...2c93cb )
by
unknown
07:30
created

Jetpack_Provision::authorize_user()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 2
dl 0
loc 22
rs 9.568
c 0
b 0
f 0
1
<?php //phpcs:ignore
2
3
class Jetpack_Provision { //phpcs:ignore
4
5
	/**
6
	 * Responsible for checking pre-conditions, registering site, and returning an array of details
7
	 * that can be used to provision a plan for the site.
8
	 *
9
	 * @param array $named_args The array of arguments.
10
	 *
11
	 * @return WP_Error|array
12
	 */
13
	public static function register_and_build_request_body( $named_args ) {
14
		$url_args = array(
15
			'home_url' => 'WP_HOME',
16
			'site_url' => 'WP_SITEURL',
17
		);
18
19
		foreach ( $url_args as $url_arg => $constant_name ) {
20
			// Anonymous functions were introduced in 5.3.0. So, if we're running on
21
			// >= 5.3.0, use an anonymous function to set the home/siteurl value%s.
22
			//
23
			// Otherwise, fallback to setting the home/siteurl value via the WP_HOME and
24
			// WP_SITEURL constants if the constant hasn't already been defined.
25
			if ( isset( $named_args[ $url_arg ] ) ) {
26
				if ( version_compare( phpversion(), '5.3.0', '>=' ) ) {
27
					add_filter( $url_arg, function() use ( $url_arg, $named_args ) { // phpcs:ignore PHPCompatibility.FunctionDeclarations.NewClosure.Found
28
						return $named_args[ $url_arg ];
29
					}, 11 );
30
				} elseif ( ! defined( $constant_name ) ) {
31
					define( $constant_name, $named_args[ $url_arg ] );
32
				}
33
			}
34
		}
35
36
		// If Jetpack is currently connected, and is not in Safe Mode already, kick off a sync of the current
37
		// functions/callables so that we can test if this site is in IDC.
38
		if ( Jetpack::is_active() && ! Jetpack::validate_sync_error_idc_option() && Jetpack_Sync_Actions::sync_allowed() ) {
39
			Jetpack_Sync_Actions::do_full_sync( array( 'functions' => true ) );
40
			Jetpack_Sync_Actions::$sender->do_full_sync();
0 ignored issues
show
Bug introduced by
The property sender cannot be accessed from this context as it is declared private in class Jetpack_Sync_Actions.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
41
		}
42
43
		if ( Jetpack::validate_sync_error_idc_option() ) {
44
			return new WP_Error(
45
				'site_in_safe_mode',
46
				__( 'Can not provision a plan while in safe mode. See: https://jetpack.com/support/safe-mode/', 'jetpack' )
47
			);
48
		}
49
50
		$blog_id    = Jetpack_Options::get_option( 'id' );
51
		$blog_token = Jetpack_Data::get_access_token();
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack_Data::get_access_token() has been deprecated with message: 7.5 Use Connection_Manager instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
52
53
		if ( ! $blog_id || ! $blog_token || ( isset( $named_args['force_register'] ) && intval( $named_args['force_register'] ) ) ) {
54
			// This code mostly copied from Jetpack::admin_page_load.
55
			Jetpack::maybe_set_version_option();
56
			$registered = Jetpack::try_registration();
57
			if ( is_wp_error( $registered ) ) {
58
				return $registered;
59
			} elseif ( ! $registered ) {
60
				return new WP_Error( 'registration_error', __( 'There was an unspecified error registering the site', 'jetpack' ) );
61
			}
62
63
			$blog_id    = Jetpack_Options::get_option( 'id' );
0 ignored issues
show
Unused Code introduced by
$blog_id 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...
64
			$blog_token = Jetpack_Data::get_access_token();
0 ignored issues
show
Unused Code introduced by
$blog_token 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...
Deprecated Code introduced by
The method Jetpack_Data::get_access_token() has been deprecated with message: 7.5 Use Connection_Manager instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
65
		}
66
67
		// If the user isn't specified, but we have a current master user, then set that to current user.
68
		$master_user_id = Jetpack_Options::get_option( 'master_user' );
69
		if ( ! get_current_user_id() && $master_user_id ) {
70
			wp_set_current_user( $master_user_id );
71
		}
72
73
		$site_icon = get_site_icon_url();
74
75
		$auto_enable_sso = ( ! Jetpack::is_active() || Jetpack::is_module_active( 'sso' ) );
76
77
		/** This filter is documented in class.jetpack-cli.php */
78 View Code Duplication
		if ( apply_filters( 'jetpack_start_enable_sso', $auto_enable_sso ) ) {
79
			$redirect_uri = add_query_arg(
80
				array(
81
					'action'      => 'jetpack-sso',
82
					'redirect_to' => rawurlencode( admin_url() ),
83
				),
84
				wp_login_url() // TODO: come back to Jetpack dashboard?
85
			);
86
		} else {
87
			$redirect_uri = admin_url();
88
		}
89
90
		$request_body = array(
91
			'jp_version'   => JETPACK__VERSION,
92
			'redirect_uri' => $redirect_uri,
93
		);
94
95
		if ( $site_icon ) {
96
			$request_body['site_icon'] = $site_icon;
97
		}
98
99
		if ( get_current_user_id() ) {
100
			$user = wp_get_current_user();
101
102
			// Role.
103
			$role        = Jetpack::translate_current_user_to_role();
104
			$signed_role = Jetpack::sign_role( $role );
105
106
			$secrets = Jetpack::init()->generate_secrets( 'authorize' );
107
108
			// Jetpack auth stuff.
109
			$request_body['scope']  = $signed_role;
110
			$request_body['secret'] = $secrets['secret_1'];
111
112
			// User stuff.
113
			$request_body['user_id']    = $user->ID;
114
			$request_body['user_email'] = $user->user_email;
115
			$request_body['user_login'] = $user->user_login;
116
		}
117
118
		// Optional additional params.
119 View Code Duplication
		if ( isset( $named_args['wpcom_user_id'] ) && ! empty( $named_args['wpcom_user_id'] ) ) {
120
			$request_body['wpcom_user_id'] = $named_args['wpcom_user_id'];
121
		}
122
123
		// Override email of selected user.
124 View Code Duplication
		if ( isset( $named_args['wpcom_user_email'] ) && ! empty( $named_args['wpcom_user_email'] ) ) {
125
			$request_body['user_email'] = $named_args['wpcom_user_email'];
126
		}
127
128 View Code Duplication
		if ( isset( $named_args['plan'] ) && ! empty( $named_args['plan'] ) ) {
129
			$request_body['plan'] = $named_args['plan'];
130
		}
131
132 View Code Duplication
		if ( isset( $named_args['onboarding'] ) && ! empty( $named_args['onboarding'] ) ) {
133
			$request_body['onboarding'] = intval( $named_args['onboarding'] );
134
		}
135
136 View Code Duplication
		if ( isset( $named_args['force_connect'] ) && ! empty( $named_args['force_connect'] ) ) {
137
			$request_body['force_connect'] = intval( $named_args['force_connect'] );
138
		}
139
140
		if ( isset( $request_body['onboarding'] ) && (bool) $request_body['onboarding'] ) {
141
			Jetpack::create_onboarding_token();
142
		}
143
144
		return $request_body;
145
	}
146
147
	/**
148
	 * Given an access token and an array of arguments, will provision a plan for this site.
149
	 *
150
	 * @param string $access_token The access token from the partner.
151
	 * @param array  $named_args   The arguments used for registering the site and then provisioning a plan.
152
	 *
153
	 * @return WP_Error|array
154
	 */
155
	public static function partner_provision( $access_token, $named_args ) {
156
		// First, verify the token.
157
		$verify_response = self::verify_token( $access_token );
158
159
		if ( is_wp_error( $verify_response ) ) {
160
			return $verify_response;
161
		}
162
163
		$request_body = self::register_and_build_request_body( $named_args );
164
		if ( is_wp_error( $request_body ) ) {
165
			return $request_body;
166
		}
167
168
		$request = array(
169
			'headers' => array(
170
				'Authorization' => "Bearer $access_token",
171
				'Host'          => 'public-api.wordpress.com',
172
			),
173
			'timeout' => 60,
174
			'method'  => 'POST',
175
			'body'    => wp_json_encode( $request_body ),
176
		);
177
178
		$blog_id = Jetpack_Options::get_option( 'id' );
179
		$url     = esc_url_raw( sprintf(
180
			'https://%s/rest/v1.3/jpphp/%d/partner-provision',
181
			self::get_api_host(),
182
			$blog_id
183
		) );
184 View Code Duplication
		if ( ! empty( $named_args['partner_tracking_id'] ) ) {
185
			$url = esc_url_raw( add_query_arg( 'partner_tracking_id', $named_args['partner_tracking_id'], $url ) );
186
		}
187
188
		// Add calypso env if set.
189
		$calypso_env = Jetpack::get_calypso_env();
190
		if ( ! empty( $calypso_env ) ) {
191
			$url = add_query_arg( array( 'calypso_env' => $calypso_env ), $url );
192
		}
193
194
		$result = Jetpack_Client::_wp_remote_request( $url, $request );
195
196
		if ( is_wp_error( $result ) ) {
197
			return $result;
198
		}
199
200
		$response_code = wp_remote_retrieve_response_code( $result );
201
		$body_json     = json_decode( wp_remote_retrieve_body( $result ) );
202
203 View Code Duplication
		if ( 200 !== $response_code ) {
204
			if ( isset( $body_json->error ) ) {
205
				return new WP_Error( $body_json->error, $body_json->message );
206
			} else {
207
				return new WP_Error(
208
					'server_error',
209
					/* translators: %s is an HTTP status code retured from an API request. Ex. – 400 */
210
					sprintf( __( 'Request failed with code %s', 'jetpack' ), $response_code )
211
				);
212
			}
213
		}
214
215
		if ( isset( $body_json->access_token ) && is_user_logged_in() ) {
216
			// Check if this matches the existing token before replacing.
217
			$existing_token = Jetpack_Data::get_access_token( get_current_user_id() );
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack_Data::get_access_token() has been deprecated with message: 7.5 Use Connection_Manager instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
218
			if ( empty( $existing_token ) || $existing_token->secret !== $body_json->access_token ) {
219
				self::authorize_user( get_current_user_id(), $body_json->access_token );
220
			}
221
		}
222
223
		return $body_json;
224
	}
225
226
	private static function authorize_user( $user_id, $access_token ) {
227
		// authorize user and enable SSO
228
		Jetpack::update_user_token( $user_id, sprintf( '%s.%d', $access_token, $user_id ), true );
229
230
		/**
231
		 * Auto-enable SSO module for new Jetpack Start connections
232
		 *
233
		 * @since 5.0.0
234
		 *
235
		 * @param bool $enable_sso Whether to enable the SSO module. Default to true.
236
		 */
237
		$other_modules = apply_filters( 'jetpack_start_enable_sso', true )
238
			? array( 'sso' )
239
			: array();
240
241
		if ( $active_modules = Jetpack_Options::get_option( 'active_modules' ) ) {
242
			Jetpack::delete_active_modules();
243
			Jetpack::activate_default_modules( 999, 1, array_merge( $active_modules, $other_modules ), 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...
244
		} else {
245
			Jetpack::activate_default_modules( false, false, $other_modules, false );
246
		}
247
	}
248
249
	private static function verify_token( $access_token ) {
250
		$request = array(
251
			'headers' => array(
252
				'Authorization' => "Bearer " . $access_token,
253
				'Host'          => 'public-api.wordpress.com',
254
			),
255
			'timeout' => 10,
256
			'method'  => 'POST',
257
			'body'    => ''
258
		);
259
260
		$url = sprintf( 'https://%s/rest/v1.3/jpphp/partner-keys/verify', self::get_api_host() );
261
		$result = Jetpack_Client::_wp_remote_request( $url, $request );
262
263
		if ( is_wp_error( $result ) ) {
264
			return $result;
265
		}
266
267
		$response_code = wp_remote_retrieve_response_code( $result );
268
		$body_json     = json_decode( wp_remote_retrieve_body( $result ) );
269
270 View Code Duplication
		if( 200 !== $response_code ) {
271
			if ( isset( $body_json->error ) ) {
272
				return new WP_Error( $body_json->error, $body_json->message );
273
			} else {
274
				return new WP_Error( 'server_error', sprintf( __( 'Request failed with code %s', 'jetpack' ), $response_code ) );
275
			}
276
		}
277
278
		return true;
279
	}
280
281
	private static function get_api_host() {
282
		$env_api_host = getenv( 'JETPACK_START_API_HOST', true ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.getenv_local_onlyFound
283
		return $env_api_host ? $env_api_host : JETPACK__WPCOM_JSON_API_HOST;
284
	}
285
}
286