Automattic /
jetpack
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Jetpack XMLRPC Server. |
||
| 4 | * |
||
| 5 | * @package automattic/jetpack-connection |
||
| 6 | */ |
||
| 7 | |||
| 8 | use Automattic\Jetpack\Connection\Client; |
||
| 9 | use Automattic\Jetpack\Connection\Manager as Connection_Manager; |
||
| 10 | use Automattic\Jetpack\Roles; |
||
| 11 | use Automattic\Jetpack\Sync\Modules; |
||
| 12 | use Automattic\Jetpack\Sync\Functions; |
||
| 13 | use Automattic\Jetpack\Sync\Sender; |
||
| 14 | use Automattic\Jetpack\Tracking; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * Just a sack of functions. Not actually an IXR_Server |
||
| 18 | */ |
||
| 19 | class Jetpack_XMLRPC_Server { |
||
| 20 | /** |
||
| 21 | * The current error object |
||
| 22 | * |
||
| 23 | * @var \WP_Error |
||
| 24 | */ |
||
| 25 | public $error = null; |
||
| 26 | |||
| 27 | /** |
||
| 28 | * The current user |
||
| 29 | * |
||
| 30 | * @var \WP_User |
||
| 31 | */ |
||
| 32 | public $user = null; |
||
| 33 | |||
| 34 | /** |
||
| 35 | * The tracking manager object. |
||
| 36 | * |
||
| 37 | * @var Automattic\Jetpack\Tracking |
||
| 38 | */ |
||
| 39 | private $tracking; |
||
| 40 | |||
| 41 | /** |
||
| 42 | * The connection manager object. |
||
| 43 | * |
||
| 44 | * @var Automattic\Jetpack\Connection\Manager |
||
| 45 | */ |
||
| 46 | private $connection; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * Creates a new XMLRPC server object. |
||
| 50 | * |
||
| 51 | * @param Automattic\Jetpack\Connection\Manager $manager the connection manager object. |
||
|
0 ignored issues
–
show
|
|||
| 52 | */ |
||
| 53 | public function __construct( $manager = null ) { |
||
| 54 | $this->connection = is_null( $manager ) ? new Connection_Manager() : $manager; |
||
| 55 | $this->tracking = new Tracking( 'jetpack', $manager ); |
||
|
0 ignored issues
–
show
It seems like
$manager defined by parameter $manager on line 53 can also be of type object<Automattic\Jetpack\Connection\Manager>; however, Automattic\Jetpack\Tracking::__construct() does only seem to accept object<Automattic\Jetpac...onnection\Manager>|null, maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. Loading history...
|
|||
| 56 | } |
||
| 57 | |||
| 58 | /** |
||
| 59 | * Whitelist of the XML-RPC methods available to the Jetpack Server. If the |
||
| 60 | * user is not authenticated (->login()) then the methods are never added, |
||
| 61 | * so they will get a "does not exist" error. |
||
| 62 | * |
||
| 63 | * @param array $core_methods Core XMLRPC methods. |
||
| 64 | */ |
||
| 65 | public function xmlrpc_methods( $core_methods ) { |
||
| 66 | $jetpack_methods = array( |
||
| 67 | 'jetpack.jsonAPI' => array( $this, 'json_api' ), |
||
| 68 | 'jetpack.verifyAction' => array( $this, 'verify_action' ), |
||
| 69 | 'jetpack.getUser' => array( $this, 'get_user' ), |
||
| 70 | 'jetpack.remoteRegister' => array( $this, 'remote_register' ), |
||
| 71 | 'jetpack.remoteProvision' => array( $this, 'remote_provision' ), |
||
| 72 | ); |
||
| 73 | |||
| 74 | $this->user = $this->login(); |
||
|
0 ignored issues
–
show
It seems like
$this->login() can also be of type boolean. However, the property $user is declared as type object<WP_User>. Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||
| 75 | |||
| 76 | if ( $this->user ) { |
||
| 77 | $jetpack_methods = array_merge( |
||
| 78 | $jetpack_methods, |
||
| 79 | array( |
||
| 80 | 'jetpack.testConnection' => array( $this, 'test_connection' ), |
||
| 81 | 'jetpack.testAPIUserCode' => array( $this, 'test_api_user_code' ), |
||
| 82 | 'jetpack.featuresAvailable' => array( $this, 'features_available' ), |
||
| 83 | 'jetpack.featuresEnabled' => array( $this, 'features_enabled' ), |
||
| 84 | 'jetpack.disconnectBlog' => array( $this, 'disconnect_blog' ), |
||
| 85 | 'jetpack.unlinkUser' => array( $this, 'unlink_user' ), |
||
| 86 | 'jetpack.syncObject' => array( $this, 'sync_object' ), |
||
| 87 | 'jetpack.idcUrlValidation' => array( $this, 'validate_urls_for_idc_mitigation' ), |
||
| 88 | ) |
||
| 89 | ); |
||
| 90 | |||
| 91 | if ( isset( $core_methods['metaWeblog.editPost'] ) ) { |
||
| 92 | $jetpack_methods['metaWeblog.newMediaObject'] = $core_methods['metaWeblog.newMediaObject']; |
||
| 93 | $jetpack_methods['jetpack.updateAttachmentParent'] = array( $this, 'update_attachment_parent' ); |
||
| 94 | } |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Filters the XML-RPC methods available to Jetpack for authenticated users. |
||
| 98 | * |
||
| 99 | * @since 1.1.0 |
||
| 100 | * |
||
| 101 | * @param array $jetpack_methods XML-RPC methods available to the Jetpack Server. |
||
| 102 | * @param array $core_methods Available core XML-RPC methods. |
||
| 103 | * @param \WP_User $user Information about a given WordPress user. |
||
| 104 | */ |
||
| 105 | $jetpack_methods = apply_filters( 'jetpack_xmlrpc_methods', $jetpack_methods, $core_methods, $this->user ); |
||
| 106 | } |
||
| 107 | |||
| 108 | /** |
||
| 109 | * Filters the XML-RPC methods available to Jetpack for unauthenticated users. |
||
| 110 | * |
||
| 111 | * @since 3.0.0 |
||
| 112 | * |
||
| 113 | * @param array $jetpack_methods XML-RPC methods available to the Jetpack Server. |
||
| 114 | * @param array $core_methods Available core XML-RPC methods. |
||
| 115 | */ |
||
| 116 | return apply_filters( 'jetpack_xmlrpc_unauthenticated_methods', $jetpack_methods, $core_methods ); |
||
| 117 | } |
||
| 118 | |||
| 119 | /** |
||
| 120 | * Whitelist of the bootstrap XML-RPC methods |
||
| 121 | */ |
||
| 122 | public function bootstrap_xmlrpc_methods() { |
||
| 123 | return array( |
||
| 124 | 'jetpack.remoteAuthorize' => array( $this, 'remote_authorize' ), |
||
| 125 | 'jetpack.remoteRegister' => array( $this, 'remote_register' ), |
||
| 126 | ); |
||
| 127 | } |
||
| 128 | |||
| 129 | /** |
||
| 130 | * Additional method needed for authorization calls. |
||
| 131 | */ |
||
| 132 | public function authorize_xmlrpc_methods() { |
||
| 133 | return array( |
||
| 134 | 'jetpack.remoteAuthorize' => array( $this, 'remote_authorize' ), |
||
| 135 | ); |
||
| 136 | } |
||
| 137 | |||
| 138 | /** |
||
| 139 | * Remote provisioning methods. |
||
| 140 | */ |
||
| 141 | public function provision_xmlrpc_methods() { |
||
| 142 | return array( |
||
| 143 | 'jetpack.remoteRegister' => array( $this, 'remote_register' ), |
||
| 144 | 'jetpack.remoteProvision' => array( $this, 'remote_provision' ), |
||
| 145 | 'jetpack.remoteConnect' => array( $this, 'remote_connect' ), |
||
| 146 | 'jetpack.getUser' => array( $this, 'get_user' ), |
||
| 147 | ); |
||
| 148 | } |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Used to verify whether a local user exists and what role they have. |
||
| 152 | * |
||
| 153 | * @param int|string|array $request One of: |
||
| 154 | * int|string The local User's ID, username, or email address. |
||
| 155 | * array A request array containing: |
||
| 156 | * 0: int|string The local User's ID, username, or email address. |
||
| 157 | * |
||
| 158 | * @return array|\IXR_Error Information about the user, or error if no such user found: |
||
| 159 | * roles: string[] The user's rols. |
||
| 160 | * login: string The user's username. |
||
| 161 | * email_hash string[] The MD5 hash of the user's normalized email address. |
||
| 162 | * caps string[] The user's capabilities. |
||
| 163 | * allcaps string[] The user's granular capabilities, merged from role capabilities. |
||
| 164 | * token_key string The Token Key of the user's Jetpack token. Empty string if none. |
||
| 165 | */ |
||
| 166 | public function get_user( $request ) { |
||
| 167 | $user_id = is_array( $request ) ? $request[0] : $request; |
||
| 168 | |||
| 169 | if ( ! $user_id ) { |
||
| 170 | return $this->error( |
||
| 171 | new Jetpack_Error( |
||
| 172 | 'invalid_user', |
||
| 173 | __( 'Invalid user identifier.', 'jetpack' ), |
||
| 174 | 400 |
||
| 175 | ), |
||
| 176 | 'jpc_get_user_fail' |
||
| 177 | ); |
||
| 178 | } |
||
| 179 | |||
| 180 | $user = $this->get_user_by_anything( $user_id ); |
||
| 181 | |||
| 182 | if ( ! $user ) { |
||
| 183 | return $this->error( |
||
| 184 | new Jetpack_Error( |
||
| 185 | 'user_unknown', |
||
| 186 | __( 'User not found.', 'jetpack' ), |
||
| 187 | 404 |
||
| 188 | ), |
||
| 189 | 'jpc_get_user_fail' |
||
| 190 | ); |
||
| 191 | } |
||
| 192 | |||
| 193 | $connection = Jetpack::connection(); |
||
| 194 | $user_token = $connection->get_access_token( $user->ID ); |
||
| 195 | |||
| 196 | if ( $user_token ) { |
||
| 197 | list( $user_token_key ) = explode( '.', $user_token->secret ); |
||
| 198 | if ( $user_token_key === $user_token->secret ) { |
||
| 199 | $user_token_key = ''; |
||
| 200 | } |
||
| 201 | } else { |
||
| 202 | $user_token_key = ''; |
||
| 203 | } |
||
| 204 | |||
| 205 | return array( |
||
| 206 | 'id' => $user->ID, |
||
| 207 | 'login' => $user->user_login, |
||
| 208 | 'email_hash' => md5( strtolower( trim( $user->user_email ) ) ), |
||
| 209 | 'roles' => $user->roles, |
||
| 210 | 'caps' => $user->caps, |
||
| 211 | 'allcaps' => $user->allcaps, |
||
| 212 | 'token_key' => $user_token_key, |
||
| 213 | ); |
||
| 214 | } |
||
| 215 | |||
| 216 | /** |
||
| 217 | * Remote authorization XMLRPC method handler. |
||
| 218 | * |
||
| 219 | * @param array $request the request. |
||
| 220 | */ |
||
| 221 | public function remote_authorize( $request ) { |
||
| 222 | $user = get_user_by( 'id', $request['state'] ); |
||
| 223 | $this->tracking->record_user_event( 'jpc_remote_authorize_begin', array(), $user ); |
||
| 224 | |||
| 225 | foreach ( array( 'secret', 'state', 'redirect_uri', 'code' ) as $required ) { |
||
| 226 | if ( ! isset( $request[ $required ] ) || empty( $request[ $required ] ) ) { |
||
| 227 | return $this->error( new Jetpack_Error( 'missing_parameter', 'One or more parameters is missing from the request.', 400 ), 'jpc_remote_authorize_fail' ); |
||
| 228 | } |
||
| 229 | } |
||
| 230 | |||
| 231 | if ( ! $user ) { |
||
| 232 | return $this->error( new Jetpack_Error( 'user_unknown', 'User not found.', 404 ), 'jpc_remote_authorize_fail' ); |
||
| 233 | } |
||
| 234 | |||
| 235 | if ( Jetpack::is_active() && Jetpack::is_user_connected( $request['state'] ) ) { |
||
| 236 | return $this->error( new Jetpack_Error( 'already_connected', 'User already connected.', 400 ), 'jpc_remote_authorize_fail' ); |
||
| 237 | } |
||
| 238 | |||
| 239 | $verified = $this->verify_action( array( 'authorize', $request['secret'], $request['state'] ) ); |
||
| 240 | |||
| 241 | if ( is_a( $verified, 'IXR_Error' ) ) { |
||
| 242 | return $this->error( $verified, 'jpc_remote_authorize_fail' ); |
||
|
0 ignored issues
–
show
It seems like
$verified defined by $this->verify_action(arr...'], $request['state'])) on line 239 can also be of type string; however, Jetpack_XMLRPC_Server::error() does only seem to accept object<WP_Error>|object<IXR_Error>|null, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 243 | } |
||
| 244 | |||
| 245 | wp_set_current_user( $request['state'] ); |
||
| 246 | |||
| 247 | $client_server = new Jetpack_Client_Server(); |
||
| 248 | $result = $client_server->authorize( $request ); |
||
| 249 | |||
| 250 | if ( is_wp_error( $result ) ) { |
||
| 251 | return $this->error( $result, 'jpc_remote_authorize_fail' ); |
||
|
0 ignored issues
–
show
It seems like
$result defined by $client_server->authorize($request) on line 248 can also be of type string; however, Jetpack_XMLRPC_Server::error() does only seem to accept object<WP_Error>|object<IXR_Error>|null, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 252 | } |
||
| 253 | |||
| 254 | $this->tracking->record_user_event( 'jpc_remote_authorize_success' ); |
||
| 255 | |||
| 256 | return array( |
||
| 257 | 'result' => $result, |
||
| 258 | ); |
||
| 259 | } |
||
| 260 | |||
| 261 | /** |
||
| 262 | * This XML-RPC method is called from the /jpphp/provision endpoint on WPCOM in order to |
||
| 263 | * register this site so that a plan can be provisioned. |
||
| 264 | * |
||
| 265 | * @param array $request An array containing at minimum nonce and local_user keys. |
||
| 266 | * |
||
| 267 | * @return \WP_Error|array |
||
| 268 | */ |
||
| 269 | public function remote_register( $request ) { |
||
| 270 | $this->tracking->record_user_event( 'jpc_remote_register_begin', array() ); |
||
| 271 | |||
| 272 | $user = $this->fetch_and_verify_local_user( $request ); |
||
| 273 | |||
| 274 | if ( ! $user ) { |
||
| 275 | return $this->error( new WP_Error( 'input_error', __( 'Valid user is required', 'jetpack' ), 400 ), 'jpc_remote_register_fail' ); |
||
| 276 | } |
||
| 277 | |||
| 278 | if ( is_wp_error( $user ) || is_a( $user, 'IXR_Error' ) ) { |
||
| 279 | return $this->error( $user, 'jpc_remote_register_fail' ); |
||
| 280 | } |
||
| 281 | |||
| 282 | if ( empty( $request['nonce'] ) ) { |
||
| 283 | return $this->error( |
||
| 284 | new Jetpack_Error( |
||
| 285 | 'nonce_missing', |
||
| 286 | __( 'The required "nonce" parameter is missing.', 'jetpack' ), |
||
| 287 | 400 |
||
| 288 | ), |
||
| 289 | 'jpc_remote_register_fail' |
||
| 290 | ); |
||
| 291 | } |
||
| 292 | |||
| 293 | $nonce = sanitize_text_field( $request['nonce'] ); |
||
| 294 | unset( $request['nonce'] ); |
||
| 295 | |||
| 296 | $api_url = Jetpack::fix_url_for_bad_hosts( |
||
| 297 | $this->connection->api_url( 'partner_provision_nonce_check' ) |
||
| 298 | ); |
||
| 299 | $response = Client::_wp_remote_request( |
||
| 300 | esc_url_raw( add_query_arg( 'nonce', $nonce, $api_url ) ), |
||
| 301 | array( 'method' => 'GET' ), |
||
| 302 | true |
||
| 303 | ); |
||
| 304 | |||
| 305 | if ( |
||
| 306 | 200 !== wp_remote_retrieve_response_code( $response ) || |
||
| 307 | 'OK' !== trim( wp_remote_retrieve_body( $response ) ) |
||
| 308 | ) { |
||
| 309 | return $this->error( |
||
| 310 | new Jetpack_Error( |
||
| 311 | 'invalid_nonce', |
||
| 312 | __( 'There was an issue validating this request.', 'jetpack' ), |
||
| 313 | 400 |
||
| 314 | ), |
||
| 315 | 'jpc_remote_register_fail' |
||
| 316 | ); |
||
| 317 | } |
||
| 318 | |||
| 319 | if ( ! Jetpack_Options::get_option( 'id' ) || ! Jetpack_Data::get_access_token() || ! empty( $request['force'] ) ) { |
||
| 320 | wp_set_current_user( $user->ID ); |
||
| 321 | |||
| 322 | // This code mostly copied from Jetpack::admin_page_load. |
||
| 323 | Jetpack::maybe_set_version_option(); |
||
| 324 | $registered = Jetpack::try_registration(); |
||
| 325 | if ( is_wp_error( $registered ) ) { |
||
| 326 | return $this->error( $registered, 'jpc_remote_register_fail' ); |
||
| 327 | } elseif ( ! $registered ) { |
||
| 328 | return $this->error( |
||
| 329 | new Jetpack_Error( |
||
| 330 | 'registration_error', |
||
| 331 | __( 'There was an unspecified error registering the site', 'jetpack' ), |
||
| 332 | 400 |
||
| 333 | ), |
||
| 334 | 'jpc_remote_register_fail' |
||
| 335 | ); |
||
| 336 | } |
||
| 337 | } |
||
| 338 | |||
| 339 | $this->tracking->record_user_event( 'jpc_remote_register_success' ); |
||
| 340 | |||
| 341 | return array( |
||
| 342 | 'client_id' => Jetpack_Options::get_option( 'id' ), |
||
| 343 | ); |
||
| 344 | } |
||
| 345 | |||
| 346 | /** |
||
| 347 | * This XML-RPC method is called from the /jpphp/provision endpoint on WPCOM in order to |
||
| 348 | * register this site so that a plan can be provisioned. |
||
| 349 | * |
||
| 350 | * @param array $request An array containing at minimum a nonce key and a local_username key. |
||
| 351 | * |
||
| 352 | * @return \WP_Error|array |
||
| 353 | */ |
||
| 354 | public function remote_provision( $request ) { |
||
| 355 | $user = $this->fetch_and_verify_local_user( $request ); |
||
| 356 | |||
| 357 | if ( ! $user ) { |
||
| 358 | return $this->error( new WP_Error( 'input_error', __( 'Valid user is required', 'jetpack' ), 400 ), 'jpc_remote_provision_fail' ); |
||
| 359 | } |
||
| 360 | |||
| 361 | if ( is_wp_error( $user ) || is_a( $user, 'IXR_Error' ) ) { |
||
| 362 | return $this->error( $user, 'jpc_remote_provision_fail' ); |
||
| 363 | } |
||
| 364 | |||
| 365 | $site_icon = get_site_icon_url(); |
||
| 366 | |||
| 367 | $auto_enable_sso = ( ! Jetpack::is_active() || Jetpack::is_module_active( 'sso' ) ); |
||
| 368 | |||
| 369 | /** This filter is documented in class.jetpack-cli.php */ |
||
| 370 | View Code Duplication | if ( apply_filters( 'jetpack_start_enable_sso', $auto_enable_sso ) ) { |
|
| 371 | $redirect_uri = add_query_arg( |
||
| 372 | array( |
||
| 373 | 'action' => 'jetpack-sso', |
||
| 374 | 'redirect_to' => rawurlencode( admin_url() ), |
||
| 375 | ), |
||
| 376 | wp_login_url() // TODO: come back to Jetpack dashboard? |
||
| 377 | ); |
||
| 378 | } else { |
||
| 379 | $redirect_uri = admin_url(); |
||
| 380 | } |
||
| 381 | |||
| 382 | // Generate secrets. |
||
| 383 | $roles = new Roles(); |
||
| 384 | $role = $roles->translate_user_to_role( $user ); |
||
| 385 | $secrets = Jetpack::init()->generate_secrets( 'authorize', $user->ID ); |
||
| 386 | |||
| 387 | $response = array( |
||
| 388 | 'jp_version' => JETPACK__VERSION, |
||
| 389 | 'redirect_uri' => $redirect_uri, |
||
| 390 | 'user_id' => $user->ID, |
||
| 391 | 'user_email' => $user->user_email, |
||
| 392 | 'user_login' => $user->user_login, |
||
| 393 | 'scope' => Jetpack::sign_role( $role, $user->ID ), |
||
| 394 | 'secret' => $secrets['secret_1'], |
||
| 395 | 'is_active' => Jetpack::is_active(), |
||
| 396 | ); |
||
| 397 | |||
| 398 | if ( $site_icon ) { |
||
| 399 | $response['site_icon'] = $site_icon; |
||
| 400 | } |
||
| 401 | |||
| 402 | if ( ! empty( $request['onboarding'] ) ) { |
||
| 403 | Jetpack::create_onboarding_token(); |
||
| 404 | $response['onboarding_token'] = Jetpack_Options::get_option( 'onboarding' ); |
||
| 405 | } |
||
| 406 | |||
| 407 | return $response; |
||
| 408 | } |
||
| 409 | |||
| 410 | /** |
||
| 411 | * Given an array containing a local user identifier and a nonce, will attempt to fetch and set |
||
| 412 | * an access token for the given user. |
||
| 413 | * |
||
| 414 | * @param array $request An array containing local_user and nonce keys at minimum. |
||
| 415 | * @param \IXR_Client $ixr_client The client object, optional. |
||
|
0 ignored issues
–
show
Should the type for parameter
$ixr_client not be false|IXR_Client?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 416 | * @return mixed |
||
| 417 | */ |
||
| 418 | public function remote_connect( $request, $ixr_client = false ) { |
||
| 419 | if ( Jetpack::is_active() ) { |
||
| 420 | return $this->error( |
||
| 421 | new WP_Error( |
||
| 422 | 'already_connected', |
||
| 423 | __( 'Jetpack is already connected.', 'jetpack' ), |
||
| 424 | 400 |
||
| 425 | ), |
||
| 426 | 'jpc_remote_connect_fail' |
||
| 427 | ); |
||
| 428 | } |
||
| 429 | |||
| 430 | $user = $this->fetch_and_verify_local_user( $request ); |
||
| 431 | |||
| 432 | if ( ! $user || is_wp_error( $user ) || is_a( $user, 'IXR_Error' ) ) { |
||
| 433 | return $this->error( |
||
| 434 | new WP_Error( |
||
| 435 | 'input_error', |
||
| 436 | __( 'Valid user is required.', 'jetpack' ), |
||
| 437 | 400 |
||
| 438 | ), |
||
| 439 | 'jpc_remote_connect_fail' |
||
| 440 | ); |
||
| 441 | } |
||
| 442 | |||
| 443 | if ( empty( $request['nonce'] ) ) { |
||
| 444 | return $this->error( |
||
| 445 | new WP_Error( |
||
| 446 | 'input_error', |
||
| 447 | __( 'A non-empty nonce must be supplied.', 'jetpack' ), |
||
| 448 | 400 |
||
| 449 | ), |
||
| 450 | 'jpc_remote_connect_fail' |
||
| 451 | ); |
||
| 452 | } |
||
| 453 | |||
| 454 | if ( ! $ixr_client ) { |
||
| 455 | Jetpack::load_xml_rpc_client(); |
||
| 456 | $ixr_client = new Jetpack_IXR_Client(); |
||
| 457 | } |
||
| 458 | $ixr_client->query( |
||
| 459 | 'jetpack.getUserAccessToken', |
||
| 460 | array( |
||
| 461 | 'nonce' => sanitize_text_field( $request['nonce'] ), |
||
| 462 | 'external_user_id' => $user->ID, |
||
| 463 | ) |
||
| 464 | ); |
||
| 465 | |||
| 466 | $token = $ixr_client->isError() ? false : $ixr_client->getResponse(); |
||
| 467 | if ( empty( $token ) ) { |
||
| 468 | return $this->error( |
||
| 469 | new WP_Error( |
||
| 470 | 'token_fetch_failed', |
||
| 471 | __( 'Failed to fetch user token from WordPress.com.', 'jetpack' ), |
||
| 472 | 400 |
||
| 473 | ), |
||
| 474 | 'jpc_remote_connect_fail' |
||
| 475 | ); |
||
| 476 | } |
||
| 477 | $token = sanitize_text_field( $token ); |
||
| 478 | |||
| 479 | Jetpack::update_user_token( $user->ID, sprintf( '%s.%d', $token, $user->ID ), true ); |
||
| 480 | |||
| 481 | $this->do_post_authorization(); |
||
| 482 | |||
| 483 | return Jetpack::is_active(); |
||
| 484 | } |
||
| 485 | |||
| 486 | /** |
||
| 487 | * Getter for the local user to act as. |
||
| 488 | * |
||
| 489 | * @param array $request the current request data. |
||
| 490 | */ |
||
| 491 | private function fetch_and_verify_local_user( $request ) { |
||
| 492 | if ( empty( $request['local_user'] ) ) { |
||
| 493 | return $this->error( |
||
| 494 | new Jetpack_Error( |
||
| 495 | 'local_user_missing', |
||
| 496 | __( 'The required "local_user" parameter is missing.', 'jetpack' ), |
||
| 497 | 400 |
||
| 498 | ), |
||
| 499 | 'jpc_remote_provision_fail' |
||
| 500 | ); |
||
| 501 | } |
||
| 502 | |||
| 503 | // Local user is used to look up by login, email or ID. |
||
| 504 | $local_user_info = $request['local_user']; |
||
| 505 | |||
| 506 | return $this->get_user_by_anything( $local_user_info ); |
||
| 507 | } |
||
| 508 | |||
| 509 | /** |
||
| 510 | * Gets the user object by its data. |
||
| 511 | * |
||
| 512 | * @param string $user_id can be any identifying user data. |
||
| 513 | */ |
||
| 514 | private function get_user_by_anything( $user_id ) { |
||
| 515 | $user = get_user_by( 'login', $user_id ); |
||
| 516 | |||
| 517 | if ( ! $user ) { |
||
| 518 | $user = get_user_by( 'email', $user_id ); |
||
| 519 | } |
||
| 520 | |||
| 521 | if ( ! $user ) { |
||
| 522 | $user = get_user_by( 'ID', $user_id ); |
||
| 523 | } |
||
| 524 | |||
| 525 | return $user; |
||
| 526 | } |
||
| 527 | |||
| 528 | /** |
||
| 529 | * Track an error. |
||
| 530 | * |
||
| 531 | * @param string $name Event name. |
||
| 532 | * @param \WP_Error|\IXR_Error $error The error object. |
||
| 533 | * @param \WP_User $user The user object. |
||
|
0 ignored issues
–
show
Should the type for parameter
$user not be WP_User|null?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 534 | */ |
||
| 535 | private function tracks_record_error( $name, $error, $user = null ) { |
||
| 536 | if ( is_wp_error( $error ) ) { |
||
| 537 | $this->tracking->record_user_event( |
||
| 538 | $name, |
||
| 539 | array( |
||
| 540 | 'error_code' => $error->get_error_code(), |
||
|
0 ignored issues
–
show
The method
get_error_code() does not seem to exist on object<WP_Error>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 541 | 'error_message' => $error->get_error_message(), |
||
|
0 ignored issues
–
show
The method
get_error_message() does not seem to exist on object<WP_Error>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 542 | ), |
||
| 543 | $user |
||
| 544 | ); |
||
| 545 | } elseif ( is_a( $error, '\\IXR_Error' ) ) { |
||
| 546 | $this->tracking->record_user_event( |
||
| 547 | $name, |
||
| 548 | array( |
||
| 549 | 'error_code' => $error->code, |
||
| 550 | 'error_message' => $error->message, |
||
| 551 | ), |
||
| 552 | $user |
||
| 553 | ); |
||
| 554 | } |
||
| 555 | |||
| 556 | return $error; |
||
| 557 | } |
||
| 558 | |||
| 559 | /** |
||
| 560 | * Possible error_codes: |
||
| 561 | * |
||
| 562 | * - verify_secret_1_missing |
||
| 563 | * - verify_secret_1_malformed |
||
| 564 | * - verify_secrets_missing: verification secrets are not found in database |
||
| 565 | * - verify_secrets_incomplete: verification secrets are only partially found in database |
||
| 566 | * - verify_secrets_expired: verification secrets have expired |
||
| 567 | * - verify_secrets_mismatch: stored secret_1 does not match secret_1 sent by Jetpack.WordPress.com |
||
| 568 | * - state_missing: required parameter of state not found |
||
| 569 | * - state_malformed: state is not a digit |
||
| 570 | * - invalid_state: state in request does not match the stored state |
||
| 571 | * |
||
| 572 | * The 'authorize' and 'register' actions have additional error codes |
||
| 573 | * |
||
| 574 | * Possible values for action are `authorize`, `publicize` and `register`. |
||
| 575 | * |
||
| 576 | * state_missing: a state ( user id ) was not supplied |
||
| 577 | * state_malformed: state is not the correct data type |
||
| 578 | * invalid_state: supplied state does not match the stored state |
||
| 579 | * |
||
| 580 | * @param array $params action parameters. |
||
| 581 | * @return \WP_Error|string secret_2 on success, WP_Error( error_code => error_code, error_message => error description, error_data => status code ) on failure |
||
| 582 | */ |
||
| 583 | public function verify_action( $params ) { |
||
| 584 | $action = $params[0]; |
||
| 585 | $verify_secret = $params[1]; |
||
| 586 | $state = isset( $params[2] ) ? $params[2] : ''; |
||
| 587 | $user = get_user_by( 'id', $state ); |
||
| 588 | $tracks_failure_event_name = ''; |
||
| 589 | |||
| 590 | if ( 'authorize' === $action ) { |
||
| 591 | $tracks_failure_event_name = 'jpc_verify_authorize_fail'; |
||
| 592 | $this->tracking->record_user_event( 'jpc_verify_authorize_begin', array(), $user ); |
||
| 593 | } |
||
| 594 | if ( 'publicize' === $action ) { |
||
| 595 | // This action is used on a response from a direct XML-RPC done from WordPress.com. |
||
| 596 | $tracks_failure_event_name = 'jpc_verify_publicize_fail'; |
||
| 597 | $this->tracking->record_user_event( 'jpc_verify_publicize_begin', array(), $user ); |
||
| 598 | } |
||
| 599 | if ( 'register' === $action ) { |
||
| 600 | $tracks_failure_event_name = 'jpc_verify_register_fail'; |
||
| 601 | $this->tracking->record_user_event( 'jpc_verify_register_begin', array(), $user ); |
||
| 602 | } |
||
| 603 | |||
| 604 | if ( empty( $verify_secret ) ) { |
||
| 605 | return $this->error( new Jetpack_Error( 'verify_secret_1_missing', sprintf( 'The required "%s" parameter is missing.', 'secret_1' ), 400 ), $tracks_failure_event_name, $user ); |
||
| 606 | } elseif ( ! is_string( $verify_secret ) ) { |
||
| 607 | return $this->error( new Jetpack_Error( 'verify_secret_1_malformed', sprintf( 'The required "%s" parameter is malformed.', 'secret_1' ), 400 ), $tracks_failure_event_name, $user ); |
||
| 608 | } elseif ( empty( $state ) ) { |
||
| 609 | return $this->error( new Jetpack_Error( 'state_missing', sprintf( 'The required "%s" parameter is missing.', 'state' ), 400 ), $tracks_failure_event_name, $user ); |
||
| 610 | } elseif ( ! ctype_digit( $state ) ) { |
||
| 611 | return $this->error( new Jetpack_Error( 'state_malformed', sprintf( 'The required "%s" parameter is malformed.', 'state' ), 400 ), $tracks_failure_event_name, $user ); |
||
| 612 | } |
||
| 613 | |||
| 614 | $secrets = Jetpack::get_secrets( $action, $state ); |
||
| 615 | |||
| 616 | if ( ! $secrets ) { |
||
| 617 | Jetpack::delete_secrets( $action, $state ); |
||
| 618 | return $this->error( new Jetpack_Error( 'verify_secrets_missing', 'Verification secrets not found', 400 ), $tracks_failure_event_name, $user ); |
||
| 619 | } |
||
| 620 | |||
| 621 | if ( is_wp_error( $secrets ) ) { |
||
| 622 | Jetpack::delete_secrets( $action, $state ); |
||
| 623 | return $this->error( new Jetpack_Error( $secrets->get_error_code(), $secrets->get_error_message(), 400 ), $tracks_failure_event_name, $user ); |
||
| 624 | } |
||
| 625 | |||
| 626 | if ( empty( $secrets['secret_1'] ) || empty( $secrets['secret_2'] ) || empty( $secrets['exp'] ) ) { |
||
| 627 | Jetpack::delete_secrets( $action, $state ); |
||
| 628 | return $this->error( new Jetpack_Error( 'verify_secrets_incomplete', 'Verification secrets are incomplete', 400 ), $tracks_failure_event_name, $user ); |
||
| 629 | } |
||
| 630 | |||
| 631 | if ( ! hash_equals( $verify_secret, $secrets['secret_1'] ) ) { |
||
| 632 | Jetpack::delete_secrets( $action, $state ); |
||
| 633 | return $this->error( new Jetpack_Error( 'verify_secrets_mismatch', 'Secret mismatch', 400 ), $tracks_failure_event_name, $user ); |
||
| 634 | } |
||
| 635 | |||
| 636 | Jetpack::delete_secrets( $action, $state ); |
||
| 637 | |||
| 638 | if ( 'authorize' === $action ) { |
||
| 639 | $this->tracking->record_user_event( 'jpc_verify_authorize_success', array(), $user ); |
||
| 640 | } |
||
| 641 | if ( 'publicize' === $action ) { |
||
| 642 | $this->tracking->record_user_event( 'jpc_verify_publicize_success', array(), $user ); |
||
| 643 | } |
||
| 644 | if ( 'register' === $action ) { |
||
| 645 | $this->tracking->record_user_event( 'jpc_verify_register_success', array(), $user ); |
||
| 646 | } |
||
| 647 | |||
| 648 | return $secrets['secret_2']; |
||
| 649 | } |
||
| 650 | |||
| 651 | /** |
||
| 652 | * Wrapper for wp_authenticate( $username, $password ); |
||
| 653 | * |
||
| 654 | * @return \WP_User|bool |
||
| 655 | */ |
||
| 656 | public function login() { |
||
| 657 | Jetpack::connection()->require_jetpack_authentication(); |
||
| 658 | $user = wp_authenticate( 'username', 'password' ); |
||
| 659 | if ( is_wp_error( $user ) ) { |
||
| 660 | if ( 'authentication_failed' === $user->get_error_code() ) { // Generic error could mean most anything. |
||
| 661 | $this->error = new Jetpack_Error( 'invalid_request', 'Invalid Request', 403 ); |
||
| 662 | } else { |
||
| 663 | $this->error = $user; |
||
| 664 | } |
||
| 665 | return false; |
||
| 666 | } elseif ( ! $user ) { // Shouldn't happen. |
||
| 667 | $this->error = new Jetpack_Error( 'invalid_request', 'Invalid Request', 403 ); |
||
| 668 | return false; |
||
| 669 | } |
||
| 670 | |||
| 671 | return $user; |
||
| 672 | } |
||
| 673 | |||
| 674 | /** |
||
| 675 | * Returns the current error as an \IXR_Error |
||
| 676 | * |
||
| 677 | * @param \WP_Error|\IXR_Error $error The error object, optional. |
||
|
0 ignored issues
–
show
Should the type for parameter
$error not be WP_Error|IXR_Error|null?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 678 | * @param string $tracks_event_name The event name. |
||
|
0 ignored issues
–
show
Should the type for parameter
$tracks_event_name not be string|null?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 679 | * @param \WP_User $user The user object. |
||
|
0 ignored issues
–
show
Should the type for parameter
$user not be WP_User|null?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 680 | * @return bool|\IXR_Error |
||
| 681 | */ |
||
| 682 | public function error( $error = null, $tracks_event_name = null, $user = null ) { |
||
| 683 | // Record using Tracks. |
||
| 684 | if ( null !== $tracks_event_name ) { |
||
| 685 | $this->tracks_record_error( $tracks_event_name, $error, $user ); |
||
|
0 ignored issues
–
show
It seems like
$error defined by parameter $error on line 682 can also be of type null; however, Jetpack_XMLRPC_Server::tracks_record_error() does only seem to accept object<WP_Error>|object<IXR_Error>, maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. Loading history...
|
|||
| 686 | } |
||
| 687 | |||
| 688 | if ( ! is_null( $error ) ) { |
||
| 689 | $this->error = $error; |
||
|
0 ignored issues
–
show
It seems like
$error can also be of type object<IXR_Error>. However, the property $error is declared as type object<WP_Error>. Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||
| 690 | } |
||
| 691 | |||
| 692 | if ( is_wp_error( $this->error ) ) { |
||
| 693 | $code = $this->error->get_error_data(); |
||
|
0 ignored issues
–
show
The method
get_error_data() does not seem to exist on object<WP_Error>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 694 | if ( ! $code ) { |
||
| 695 | $code = -10520; |
||
| 696 | } |
||
| 697 | $message = sprintf( 'Jetpack: [%s] %s', $this->error->get_error_code(), $this->error->get_error_message() ); |
||
|
0 ignored issues
–
show
The method
get_error_code() does not seem to exist on object<WP_Error>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
The method
get_error_message() does not seem to exist on object<WP_Error>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 698 | return new \IXR_Error( $code, $message ); |
||
| 699 | } elseif ( is_a( $this->error, 'IXR_Error' ) ) { |
||
| 700 | return $this->error; |
||
| 701 | } |
||
| 702 | |||
| 703 | return false; |
||
| 704 | } |
||
| 705 | |||
| 706 | /* API Methods */ |
||
| 707 | |||
| 708 | /** |
||
| 709 | * Just authenticates with the given Jetpack credentials. |
||
| 710 | * |
||
| 711 | * @return string The current Jetpack version number |
||
| 712 | */ |
||
| 713 | public function test_connection() { |
||
| 714 | return JETPACK__VERSION; |
||
| 715 | } |
||
| 716 | |||
| 717 | /** |
||
| 718 | * Test the API user code. |
||
| 719 | * |
||
| 720 | * @param array $args arguments identifying the test site. |
||
| 721 | */ |
||
| 722 | public function test_api_user_code( $args ) { |
||
| 723 | $client_id = (int) $args[0]; |
||
| 724 | $user_id = (int) $args[1]; |
||
| 725 | $nonce = (string) $args[2]; |
||
| 726 | $verify = (string) $args[3]; |
||
| 727 | |||
| 728 | if ( ! $client_id || ! $user_id || ! strlen( $nonce ) || 32 !== strlen( $verify ) ) { |
||
| 729 | return false; |
||
| 730 | } |
||
| 731 | |||
| 732 | $user = get_user_by( 'id', $user_id ); |
||
| 733 | if ( ! $user || is_wp_error( $user ) ) { |
||
| 734 | return false; |
||
| 735 | } |
||
| 736 | |||
| 737 | /* phpcs:ignore |
||
| 738 | debugging |
||
| 739 | error_log( "CLIENT: $client_id" ); |
||
| 740 | error_log( "USER: $user_id" ); |
||
| 741 | error_log( "NONCE: $nonce" ); |
||
| 742 | error_log( "VERIFY: $verify" ); |
||
| 743 | */ |
||
| 744 | |||
| 745 | $jetpack_token = Jetpack_Data::get_access_token( $user_id ); |
||
| 746 | |||
| 747 | $api_user_code = get_user_meta( $user_id, "jetpack_json_api_$client_id", true ); |
||
| 748 | if ( ! $api_user_code ) { |
||
| 749 | return false; |
||
| 750 | } |
||
| 751 | |||
| 752 | $hmac = hash_hmac( |
||
| 753 | 'md5', |
||
| 754 | json_encode( // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode |
||
| 755 | (object) array( |
||
| 756 | 'client_id' => (int) $client_id, |
||
| 757 | 'user_id' => (int) $user_id, |
||
| 758 | 'nonce' => (string) $nonce, |
||
| 759 | 'code' => (string) $api_user_code, |
||
| 760 | ) |
||
| 761 | ), |
||
| 762 | $jetpack_token->secret |
||
| 763 | ); |
||
| 764 | |||
| 765 | if ( ! hash_equals( $hmac, $verify ) ) { |
||
| 766 | return false; |
||
| 767 | } |
||
| 768 | |||
| 769 | return $user_id; |
||
| 770 | } |
||
| 771 | |||
| 772 | /** |
||
| 773 | * Disconnect this blog from the connected wordpress.com account |
||
| 774 | * |
||
| 775 | * @return boolean |
||
| 776 | */ |
||
| 777 | public function disconnect_blog() { |
||
| 778 | |||
| 779 | // For tracking. |
||
| 780 | if ( ! empty( $this->user->ID ) ) { |
||
| 781 | wp_set_current_user( $this->user->ID ); |
||
| 782 | } |
||
| 783 | |||
| 784 | Jetpack::log( 'disconnect' ); |
||
| 785 | Jetpack::disconnect(); |
||
| 786 | |||
| 787 | return true; |
||
| 788 | } |
||
| 789 | |||
| 790 | /** |
||
| 791 | * Unlink a user from WordPress.com |
||
| 792 | * |
||
| 793 | * This will fail if called by the Master User. |
||
| 794 | */ |
||
| 795 | public function unlink_user() { |
||
| 796 | Jetpack::log( 'unlink' ); |
||
| 797 | return Jetpack::unlink_user(); |
||
| 798 | } |
||
| 799 | |||
| 800 | /** |
||
| 801 | * Returns any object that is able to be synced. |
||
| 802 | * |
||
| 803 | * @param array $args the synchronized object parameters. |
||
| 804 | */ |
||
| 805 | public function sync_object( $args ) { |
||
| 806 | // For example: posts, post, 5. |
||
| 807 | list( $module_name, $object_type, $id ) = $args; |
||
| 808 | |||
| 809 | $sync_module = Modules::get_module( $module_name ); |
||
| 810 | $codec = Sender::get_instance()->get_codec(); |
||
| 811 | |||
| 812 | return $codec->encode( $sync_module->get_object_by_id( $object_type, $id ) ); |
||
| 813 | } |
||
| 814 | |||
| 815 | /** |
||
| 816 | * Returns the home URL and site URL for the current site which can be used on the WPCOM side for |
||
| 817 | * IDC mitigation to decide whether sync should be allowed if the home and siteurl values differ between WPCOM |
||
| 818 | * and the remote Jetpack site. |
||
| 819 | * |
||
| 820 | * @return array |
||
| 821 | */ |
||
| 822 | public function validate_urls_for_idc_mitigation() { |
||
| 823 | return array( |
||
| 824 | 'home' => Functions::home_url(), |
||
| 825 | 'siteurl' => Functions::site_url(), |
||
| 826 | ); |
||
| 827 | } |
||
| 828 | |||
| 829 | /** |
||
| 830 | * Returns what features are available. Uses the slug of the module files. |
||
| 831 | * |
||
| 832 | * @return array |
||
| 833 | */ |
||
| 834 | View Code Duplication | public function features_available() { |
|
| 835 | $raw_modules = Jetpack::get_available_modules(); |
||
| 836 | $modules = array(); |
||
| 837 | foreach ( $raw_modules as $module ) { |
||
| 838 | $modules[] = Jetpack::get_module_slug( $module ); |
||
| 839 | } |
||
| 840 | |||
| 841 | return $modules; |
||
| 842 | } |
||
| 843 | |||
| 844 | /** |
||
| 845 | * Returns what features are enabled. Uses the slug of the modules files. |
||
| 846 | * |
||
| 847 | * @return array |
||
| 848 | */ |
||
| 849 | View Code Duplication | public function features_enabled() { |
|
| 850 | $raw_modules = Jetpack::get_active_modules(); |
||
| 851 | $modules = array(); |
||
| 852 | foreach ( $raw_modules as $module ) { |
||
| 853 | $modules[] = Jetpack::get_module_slug( $module ); |
||
| 854 | } |
||
| 855 | |||
| 856 | return $modules; |
||
| 857 | } |
||
| 858 | |||
| 859 | /** |
||
| 860 | * Updates the attachment parent object. |
||
| 861 | * |
||
| 862 | * @param array $args attachment and parent identifiers. |
||
| 863 | */ |
||
| 864 | public function update_attachment_parent( $args ) { |
||
| 865 | $attachment_id = (int) $args[0]; |
||
| 866 | $parent_id = (int) $args[1]; |
||
| 867 | |||
| 868 | return wp_update_post( |
||
| 869 | array( |
||
| 870 | 'ID' => $attachment_id, |
||
| 871 | 'post_parent' => $parent_id, |
||
| 872 | ) |
||
| 873 | ); |
||
| 874 | } |
||
| 875 | |||
| 876 | /** |
||
| 877 | * Serve a JSON API request. |
||
| 878 | * |
||
| 879 | * @param array $args request arguments. |
||
| 880 | */ |
||
| 881 | public function json_api( $args = array() ) { |
||
| 882 | $json_api_args = $args[0]; |
||
| 883 | $verify_api_user_args = $args[1]; |
||
| 884 | |||
| 885 | $method = (string) $json_api_args[0]; |
||
| 886 | $url = (string) $json_api_args[1]; |
||
| 887 | $post_body = is_null( $json_api_args[2] ) ? null : (string) $json_api_args[2]; |
||
| 888 | $user_details = (array) $json_api_args[4]; |
||
| 889 | $locale = (string) $json_api_args[5]; |
||
| 890 | |||
| 891 | if ( ! $verify_api_user_args ) { |
||
| 892 | $user_id = 0; |
||
| 893 | } elseif ( 'internal' === $verify_api_user_args[0] ) { |
||
| 894 | $user_id = (int) $verify_api_user_args[1]; |
||
| 895 | if ( $user_id ) { |
||
| 896 | $user = get_user_by( 'id', $user_id ); |
||
| 897 | if ( ! $user || is_wp_error( $user ) ) { |
||
| 898 | return false; |
||
| 899 | } |
||
| 900 | } |
||
| 901 | } else { |
||
| 902 | $user_id = call_user_func( array( $this, 'test_api_user_code' ), $verify_api_user_args ); |
||
| 903 | if ( ! $user_id ) { |
||
| 904 | return false; |
||
| 905 | } |
||
| 906 | } |
||
| 907 | |||
| 908 | /* phpcs:ignore |
||
| 909 | debugging |
||
| 910 | error_log( "-- begin json api via jetpack debugging -- " ); |
||
| 911 | error_log( "METHOD: $method" ); |
||
| 912 | error_log( "URL: $url" ); |
||
| 913 | error_log( "POST BODY: $post_body" ); |
||
| 914 | error_log( "VERIFY_ARGS: " . print_r( $verify_api_user_args, 1 ) ); |
||
| 915 | error_log( "VERIFIED USER_ID: " . (int) $user_id ); |
||
| 916 | error_log( "-- end json api via jetpack debugging -- " ); |
||
| 917 | */ |
||
| 918 | |||
| 919 | if ( 'en' !== $locale ) { |
||
| 920 | // .org mo files are named slightly different from .com, and all we have is this the locale -- try to guess them. |
||
| 921 | $new_locale = $locale; |
||
| 922 | if ( strpos( $locale, '-' ) !== false ) { |
||
| 923 | $locale_pieces = explode( '-', $locale ); |
||
| 924 | $new_locale = $locale_pieces[0]; |
||
| 925 | $new_locale .= ( ! empty( $locale_pieces[1] ) ) ? '_' . strtoupper( $locale_pieces[1] ) : ''; |
||
| 926 | } else { |
||
| 927 | // .com might pass 'fr' because thats what our language files are named as, where core seems |
||
| 928 | // to do fr_FR - so try that if we don't think we can load the file. |
||
| 929 | if ( ! file_exists( WP_LANG_DIR . '/' . $locale . '.mo' ) ) { |
||
| 930 | $new_locale = $locale . '_' . strtoupper( $locale ); |
||
| 931 | } |
||
| 932 | } |
||
| 933 | |||
| 934 | if ( file_exists( WP_LANG_DIR . '/' . $new_locale . '.mo' ) ) { |
||
| 935 | unload_textdomain( 'default' ); |
||
| 936 | load_textdomain( 'default', WP_LANG_DIR . '/' . $new_locale . '.mo' ); |
||
| 937 | } |
||
| 938 | } |
||
| 939 | |||
| 940 | $old_user = wp_get_current_user(); |
||
| 941 | wp_set_current_user( $user_id ); |
||
| 942 | |||
| 943 | if ( $user_id ) { |
||
| 944 | $token_key = false; |
||
| 945 | } else { |
||
| 946 | $verified = Jetpack::connection()->verify_xml_rpc_signature(); |
||
| 947 | $token_key = $verified['token_key']; |
||
| 948 | } |
||
| 949 | |||
| 950 | $token = Jetpack_Data::get_access_token( $user_id, $token_key ); |
||
| 951 | if ( ! $token || is_wp_error( $token ) ) { |
||
| 952 | return false; |
||
| 953 | } |
||
| 954 | |||
| 955 | define( 'REST_API_REQUEST', true ); |
||
| 956 | define( 'WPCOM_JSON_API__BASE', 'public-api.wordpress.com/rest/v1' ); |
||
| 957 | |||
| 958 | // needed? |
||
| 959 | require_once ABSPATH . 'wp-admin/includes/admin.php'; |
||
| 960 | |||
| 961 | require_once JETPACK__PLUGIN_DIR . 'class.json-api.php'; |
||
| 962 | $api = WPCOM_JSON_API::init( $method, $url, $post_body ); |
||
| 963 | $api->token_details['user'] = $user_details; |
||
| 964 | require_once JETPACK__PLUGIN_DIR . 'class.json-api-endpoints.php'; |
||
| 965 | |||
| 966 | $display_errors = ini_set( 'display_errors', 0 ); // phpcs:ignore WordPress.PHP.IniSet |
||
| 967 | ob_start(); |
||
| 968 | $api->serve( false ); |
||
| 969 | $output = ob_get_clean(); |
||
| 970 | ini_set( 'display_errors', $display_errors ); // phpcs:ignore WordPress.PHP.IniSet |
||
| 971 | |||
| 972 | $nonce = wp_generate_password( 10, false ); |
||
| 973 | $hmac = hash_hmac( 'md5', $nonce . $output, $token->secret ); |
||
| 974 | |||
| 975 | wp_set_current_user( isset( $old_user->ID ) ? $old_user->ID : 0 ); |
||
| 976 | |||
| 977 | return array( |
||
| 978 | (string) $output, |
||
| 979 | (string) $nonce, |
||
| 980 | (string) $hmac, |
||
| 981 | ); |
||
| 982 | } |
||
| 983 | |||
| 984 | /** |
||
| 985 | * Handles authorization actions after connecting a site, such as enabling modules. |
||
| 986 | * |
||
| 987 | * This do_post_authorization() is used in this class, as opposed to calling |
||
| 988 | * Jetpack::handle_post_authorization_actions() directly so that we can mock this method as necessary. |
||
| 989 | * |
||
| 990 | * @return void |
||
| 991 | */ |
||
| 992 | public function do_post_authorization() { |
||
| 993 | /** This filter is documented in class.jetpack-cli.php */ |
||
| 994 | $enable_sso = apply_filters( 'jetpack_start_enable_sso', true ); |
||
| 995 | Jetpack::handle_post_authorization_actions( $enable_sso, false, false ); |
||
| 996 | } |
||
| 997 | } |
||
| 998 |
This check looks for
@paramannotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.