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 | * The Jetpack Connection manager class file. |
||
| 4 | * |
||
| 5 | * @package jetpack-connection |
||
| 6 | */ |
||
| 7 | |||
| 8 | namespace Automattic\Jetpack\Connection; |
||
| 9 | |||
| 10 | use Automattic\Jetpack\Constants; |
||
| 11 | |||
| 12 | /** |
||
| 13 | * The Jetpack Connection Manager class that is used as a single gateway between WordPress.com |
||
| 14 | * and Jetpack. |
||
| 15 | */ |
||
| 16 | class Manager implements Manager_Interface { |
||
| 17 | |||
| 18 | const SECRETS_MISSING = 'secrets_missing'; |
||
| 19 | const SECRETS_EXPIRED = 'secrets_expired'; |
||
| 20 | const SECRETS_OPTION_NAME = 'jetpack_secrets'; |
||
| 21 | const MAGIC_NORMAL_TOKEN_KEY = ';normal;'; |
||
| 22 | const JETPACK_MASTER_USER = true; |
||
| 23 | |||
| 24 | /** |
||
| 25 | * The procedure that should be run to generate secrets. |
||
| 26 | * |
||
| 27 | * @var Callable |
||
| 28 | */ |
||
| 29 | protected $secret_callable; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * Initializes all needed hooks and request handlers. Handles API calls, upload |
||
| 33 | * requests, authentication requests. Also XMLRPC options requests. |
||
| 34 | * Fallback XMLRPC is also a bridge, but probably can be a class that inherits |
||
| 35 | * this one. Among other things it should strip existing methods. |
||
| 36 | * |
||
| 37 | * @param Array $methods an array of API method names for the Connection to accept and |
||
| 38 | * pass on to existing callables. It's possible to specify whether |
||
| 39 | * each method should be available for unauthenticated calls or not. |
||
| 40 | * @see Jetpack::__construct |
||
| 41 | */ |
||
| 42 | public function initialize( $methods ) { |
||
| 43 | $methods; |
||
| 44 | } |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Returns true if the current site is connected to WordPress.com. |
||
| 48 | * |
||
| 49 | * @return Boolean is the site connected? |
||
| 50 | */ |
||
| 51 | public function is_active() { |
||
| 52 | return (bool) $this->get_access_token( self::JETPACK_MASTER_USER ); |
||
|
0 ignored issues
–
show
|
|||
| 53 | } |
||
| 54 | |||
| 55 | /** |
||
| 56 | * Returns true if the user with the specified identifier is connected to |
||
| 57 | * WordPress.com. |
||
| 58 | * |
||
| 59 | * @param Integer|Boolean $user_id the user identifier. |
||
| 60 | * @return Boolean is the user connected? |
||
| 61 | */ |
||
| 62 | public function is_user_connected( $user_id = false ) { |
||
| 63 | $user_id = false === $user_id ? get_current_user_id() : absint( $user_id ); |
||
| 64 | if ( ! $user_id ) { |
||
| 65 | return false; |
||
| 66 | } |
||
| 67 | |||
| 68 | return (bool) $this->get_access_token( $user_id ); |
||
| 69 | } |
||
| 70 | |||
| 71 | /** |
||
| 72 | * Get the wpcom user data of the current|specified connected user. |
||
| 73 | * |
||
| 74 | * @param Integer $user_id the user identifier. |
||
|
0 ignored issues
–
show
Should the type for parameter
$user_id not be integer|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...
|
|||
| 75 | * @return Object the user object. |
||
| 76 | */ |
||
| 77 | View Code Duplication | public function get_connected_user_data( $user_id = null ) { |
|
| 78 | if ( ! $user_id ) { |
||
|
0 ignored issues
–
show
The expression
$user_id of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
Loading history...
|
|||
| 79 | $user_id = get_current_user_id(); |
||
| 80 | } |
||
| 81 | |||
| 82 | $transient_key = "jetpack_connected_user_data_$user_id"; |
||
| 83 | $cached_user_data = get_transient( $transient_key ); |
||
| 84 | |||
| 85 | if ( $cached_user_data ) { |
||
| 86 | return $cached_user_data; |
||
| 87 | } |
||
| 88 | |||
| 89 | \Jetpack::load_xml_rpc_client(); |
||
| 90 | $xml = new \Jetpack_IXR_Client( |
||
| 91 | array( |
||
| 92 | 'user_id' => $user_id, |
||
| 93 | ) |
||
| 94 | ); |
||
| 95 | $xml->query( 'wpcom.getUser' ); |
||
| 96 | if ( ! $xml->isError() ) { |
||
| 97 | $user_data = $xml->getResponse(); |
||
| 98 | set_transient( $transient_key, $xml->getResponse(), DAY_IN_SECONDS ); |
||
| 99 | return $user_data; |
||
| 100 | } |
||
| 101 | |||
| 102 | return false; |
||
| 103 | } |
||
| 104 | |||
| 105 | /** |
||
| 106 | * Is the user the connection owner. |
||
| 107 | * |
||
| 108 | * @param Integer $user_id the user identifier. |
||
| 109 | * @return Boolean is the user the connection owner? |
||
| 110 | */ |
||
| 111 | public function is_connection_owner( $user_id ) { |
||
| 112 | return $user_id; |
||
| 113 | } |
||
| 114 | |||
| 115 | /** |
||
| 116 | * Unlinks the current user from the linked WordPress.com user |
||
| 117 | * |
||
| 118 | * @param Integer $user_id the user identifier. |
||
| 119 | */ |
||
| 120 | public static function disconnect_user( $user_id ) { |
||
| 121 | return $user_id; |
||
| 122 | } |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Initializes a transport server, whatever it may be, saves into the object property. |
||
| 126 | * Should be changed to be protected. |
||
| 127 | */ |
||
| 128 | public function initialize_server() { |
||
| 129 | |||
| 130 | } |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Checks if the current request is properly authenticated, bails if not. |
||
| 134 | * Should be changed to be protected. |
||
| 135 | */ |
||
| 136 | public function require_authentication() { |
||
| 137 | |||
| 138 | } |
||
| 139 | |||
| 140 | /** |
||
| 141 | * Verifies the correctness of the request signature. |
||
| 142 | * Should be changed to be protected. |
||
| 143 | */ |
||
| 144 | public function verify_signature() { |
||
| 145 | |||
| 146 | } |
||
| 147 | |||
| 148 | /** |
||
| 149 | * Attempts Jetpack registration which sets up the site for connection. Should |
||
| 150 | * remain public because the call to action comes from the current site, not from |
||
| 151 | * WordPress.com. |
||
| 152 | * |
||
| 153 | * @return Integer zero on success, or a bitmask on failure. |
||
| 154 | */ |
||
| 155 | public function register() { |
||
| 156 | return 0; |
||
| 157 | } |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Returns the callable that would be used to generate secrets. |
||
| 161 | * |
||
| 162 | * @return Callable a function that returns a secure string to be used as a secret. |
||
| 163 | */ |
||
| 164 | protected function get_secret_callable() { |
||
| 165 | if ( ! isset( $this->secret_callable ) ) { |
||
| 166 | /** |
||
| 167 | * Allows modification of the callable that is used to generate connection secrets. |
||
| 168 | * |
||
| 169 | * @param Callable a function or method that returns a secret string. |
||
| 170 | */ |
||
| 171 | $this->secret_callable = apply_filters( 'jetpack_connection_secret_generator', 'wp_generate_password' ); |
||
| 172 | } |
||
| 173 | |||
| 174 | return $this->secret_callable; |
||
| 175 | } |
||
| 176 | |||
| 177 | /** |
||
| 178 | * Generates two secret tokens and the end of life timestamp for them. |
||
| 179 | * |
||
| 180 | * @param String $action The action name. |
||
| 181 | * @param Integer $user_id The user identifier. |
||
| 182 | * @param Integer $exp Expiration time in seconds. |
||
| 183 | */ |
||
| 184 | public function generate_secrets( $action, $user_id, $exp ) { |
||
| 185 | $callable = $this->get_secret_callable(); |
||
| 186 | |||
| 187 | $secrets = \Jetpack_Options::get_raw_option( |
||
| 188 | self::SECRETS_OPTION_NAME, |
||
| 189 | array() |
||
| 190 | ); |
||
| 191 | |||
| 192 | $secret_name = 'jetpack_' . $action . '_' . $user_id; |
||
| 193 | |||
| 194 | if ( |
||
| 195 | isset( $secrets[ $secret_name ] ) && |
||
| 196 | $secrets[ $secret_name ]['exp'] > time() |
||
| 197 | ) { |
||
| 198 | return $secrets[ $secret_name ]; |
||
| 199 | } |
||
| 200 | |||
| 201 | $secret_value = array( |
||
| 202 | 'secret_1' => call_user_func( $callable ), |
||
| 203 | 'secret_2' => call_user_func( $callable ), |
||
| 204 | 'exp' => time() + $exp, |
||
| 205 | ); |
||
| 206 | |||
| 207 | $secrets[ $secret_name ] = $secret_value; |
||
| 208 | |||
| 209 | \Jetpack_Options::update_raw_option( self::SECRETS_OPTION_NAME, $secrets ); |
||
| 210 | return $secrets[ $secret_name ]; |
||
| 211 | } |
||
| 212 | |||
| 213 | /** |
||
| 214 | * Returns two secret tokens and the end of life timestamp for them. |
||
| 215 | * |
||
| 216 | * @param String $action The action name. |
||
| 217 | * @param Integer $user_id The user identifier. |
||
| 218 | * @return string|array an array of secrets or an error string. |
||
| 219 | */ |
||
| 220 | public function get_secrets( $action, $user_id ) { |
||
| 221 | $secret_name = 'jetpack_' . $action . '_' . $user_id; |
||
| 222 | $secrets = \Jetpack_Options::get_raw_option( |
||
| 223 | self::SECRETS_OPTION_NAME, |
||
| 224 | array() |
||
| 225 | ); |
||
| 226 | |||
| 227 | if ( ! isset( $secrets[ $secret_name ] ) ) { |
||
| 228 | return self::SECRETS_MISSING; |
||
| 229 | } |
||
| 230 | |||
| 231 | if ( $secrets[ $secret_name ]['exp'] < time() ) { |
||
| 232 | $this->delete_secrets( $action, $user_id ); |
||
| 233 | return self::SECRETS_EXPIRED; |
||
| 234 | } |
||
| 235 | |||
| 236 | return $secrets[ $secret_name ]; |
||
| 237 | } |
||
| 238 | |||
| 239 | /** |
||
| 240 | * Deletes secret tokens in case they, for example, have expired. |
||
| 241 | * |
||
| 242 | * @param String $action The action name. |
||
| 243 | * @param Integer $user_id The user identifier. |
||
| 244 | */ |
||
| 245 | public function delete_secrets( $action, $user_id ) { |
||
| 246 | $secret_name = 'jetpack_' . $action . '_' . $user_id; |
||
| 247 | $secrets = \Jetpack_Options::get_raw_option( |
||
| 248 | self::SECRETS_OPTION_NAME, |
||
| 249 | array() |
||
| 250 | ); |
||
| 251 | if ( isset( $secrets[ $secret_name ] ) ) { |
||
| 252 | unset( $secrets[ $secret_name ] ); |
||
| 253 | \Jetpack_Options::update_raw_option( self::SECRETS_OPTION_NAME, $secrets ); |
||
| 254 | } |
||
| 255 | } |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Responds to a WordPress.com call to register the current site. |
||
| 259 | * Should be changed to protected. |
||
| 260 | * |
||
| 261 | * @param array $registration_data Array of [ secret_1, user_id ]. |
||
| 262 | */ |
||
| 263 | public function handle_registration( array $registration_data ) { |
||
| 264 | list( $registration_secret_1, $registration_user_id ) = $registration_data; |
||
| 265 | if ( empty( $registration_user_id ) ) { |
||
| 266 | return new \WP_Error( 'registration_state_invalid', __( 'Invalid Registration State', 'jetpack' ), 400 ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'registration_state_invalid'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 267 | } |
||
| 268 | |||
| 269 | return $this->verify_secrets( 'register', $registration_secret_1, (int) $registration_user_id ); |
||
| 270 | } |
||
| 271 | |||
| 272 | /** |
||
| 273 | * Verify a Previously Generated Secret. |
||
| 274 | * |
||
| 275 | * @param string $action The type of secret to verify. |
||
| 276 | * @param string $secret_1 The secret string to compare to what is stored. |
||
| 277 | * @param int $user_id The user ID of the owner of the secret. |
||
| 278 | */ |
||
| 279 | protected function verify_secrets( $action, $secret_1, $user_id ) { |
||
| 280 | $allowed_actions = array( 'register', 'authorize', 'publicize' ); |
||
| 281 | if ( ! in_array( $action, $allowed_actions, true ) ) { |
||
| 282 | return new \WP_Error( 'unknown_verification_action', 'Unknown Verification Action', 400 ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'unknown_verification_action'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 283 | } |
||
| 284 | |||
| 285 | $user = get_user_by( 'id', $user_id ); |
||
| 286 | |||
| 287 | /** |
||
| 288 | * We've begun verifying the previously generated secret. |
||
| 289 | * |
||
| 290 | * @since 7.5.0 |
||
| 291 | * |
||
| 292 | * @param string $action The type of secret to verify. |
||
| 293 | * @param \WP_User $user The user object. |
||
| 294 | */ |
||
| 295 | do_action( 'jetpack_verify_secrets_begin', $action, $user ); |
||
| 296 | |||
| 297 | $return_error = function( \WP_Error $error ) use ( $action, $user ) { |
||
| 298 | /** |
||
| 299 | * Verifying of the previously generated secret has failed. |
||
| 300 | * |
||
| 301 | * @since 7.5.0 |
||
| 302 | * |
||
| 303 | * @param string $action The type of secret to verify. |
||
| 304 | * @param \WP_User $user The user object. |
||
| 305 | * @param \WP_Error $error The error object. |
||
| 306 | */ |
||
| 307 | do_action( 'jetpack_verify_secrets_fail', $action, $user, $error ); |
||
| 308 | |||
| 309 | return $error; |
||
| 310 | }; |
||
| 311 | |||
| 312 | $stored_secrets = $this->get_secrets( $action, $user_id ); |
||
| 313 | $this->delete_secrets( $action, $user_id ); |
||
| 314 | |||
| 315 | if ( empty( $secret_1 ) ) { |
||
| 316 | return $return_error( |
||
| 317 | new \WP_Error( |
||
| 318 | 'verify_secret_1_missing', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'verify_secret_1_missing'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 319 | /* translators: "%s" is the name of a paramter. It can be either "secret_1" or "state". */ |
||
| 320 | sprintf( __( 'The required "%s" parameter is missing.', 'jetpack' ), 'secret_1' ), |
||
| 321 | 400 |
||
| 322 | ) |
||
| 323 | ); |
||
| 324 | } elseif ( ! is_string( $secret_1 ) ) { |
||
| 325 | return $return_error( |
||
| 326 | new \WP_Error( |
||
| 327 | 'verify_secret_1_malformed', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'verify_secret_1_malformed'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 328 | /* translators: "%s" is the name of a paramter. It can be either "secret_1" or "state". */ |
||
| 329 | sprintf( __( 'The required "%s" parameter is malformed.', 'jetpack' ), 'secret_1' ), |
||
| 330 | 400 |
||
| 331 | ) |
||
| 332 | ); |
||
| 333 | } elseif ( empty( $user_id ) ) { |
||
| 334 | // $user_id is passed around during registration as "state". |
||
| 335 | return $return_error( |
||
| 336 | new \WP_Error( |
||
| 337 | 'state_missing', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'state_missing'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 338 | /* translators: "%s" is the name of a paramter. It can be either "secret_1" or "state". */ |
||
| 339 | sprintf( __( 'The required "%s" parameter is missing.', 'jetpack' ), 'state' ), |
||
| 340 | 400 |
||
| 341 | ) |
||
| 342 | ); |
||
| 343 | } elseif ( ! ctype_digit( (string) $user_id ) ) { |
||
| 344 | return $return_error( |
||
| 345 | new \WP_Error( |
||
| 346 | 'verify_secret_1_malformed', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'verify_secret_1_malformed'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 347 | /* translators: "%s" is the name of a paramter. It can be either "secret_1" or "state". */ |
||
| 348 | sprintf( __( 'The required "%s" parameter is malformed.', 'jetpack' ), 'state' ), |
||
| 349 | 400 |
||
| 350 | ) |
||
| 351 | ); |
||
| 352 | } |
||
| 353 | |||
| 354 | if ( ! $stored_secrets ) { |
||
| 355 | return $return_error( |
||
| 356 | new \WP_Error( |
||
| 357 | 'verify_secrets_missing', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'verify_secrets_missing'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 358 | __( 'Verification secrets not found', 'jetpack' ), |
||
| 359 | 400 |
||
| 360 | ) |
||
| 361 | ); |
||
| 362 | } elseif ( is_wp_error( $stored_secrets ) ) { |
||
| 363 | $stored_secrets->add_data( 400 ); |
||
|
0 ignored issues
–
show
|
|||
| 364 | return $return_error( $stored_secrets ); |
||
| 365 | } elseif ( empty( $stored_secrets['secret_1'] ) || empty( $stored_secrets['secret_2'] ) || empty( $stored_secrets['exp'] ) ) { |
||
| 366 | return $return_error( |
||
| 367 | new \WP_Error( |
||
| 368 | 'verify_secrets_incomplete', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'verify_secrets_incomplete'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 369 | __( 'Verification secrets are incomplete', 'jetpack' ), |
||
| 370 | 400 |
||
| 371 | ) |
||
| 372 | ); |
||
| 373 | } elseif ( ! hash_equals( $secret_1, $stored_secrets['secret_1'] ) ) { |
||
| 374 | return $return_error( |
||
| 375 | new \WP_Error( |
||
| 376 | 'verify_secrets_mismatch', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'verify_secrets_mismatch'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 377 | __( 'Secret mismatch', 'jetpack' ), |
||
| 378 | 400 |
||
| 379 | ) |
||
| 380 | ); |
||
| 381 | } |
||
| 382 | |||
| 383 | /** |
||
| 384 | * We've succeeded at verifying the previously generated secret. |
||
| 385 | * |
||
| 386 | * @since 7.5.0 |
||
| 387 | * |
||
| 388 | * @param string $action The type of secret to verify. |
||
| 389 | * @param \WP_User $user The user object. |
||
| 390 | */ |
||
| 391 | do_action( 'jetpack_verify_secrets_success', $action, $user ); |
||
| 392 | |||
| 393 | return $stored_secrets['secret_2']; |
||
| 394 | } |
||
| 395 | |||
| 396 | /** |
||
| 397 | * Responds to a WordPress.com call to authorize the current user. |
||
| 398 | * Should be changed to protected. |
||
| 399 | */ |
||
| 400 | public function handle_authorization() { |
||
| 401 | |||
| 402 | } |
||
| 403 | |||
| 404 | /** |
||
| 405 | * Builds a URL to the Jetpack connection auth page. |
||
| 406 | * This needs rethinking. |
||
| 407 | * |
||
| 408 | * @param bool $raw If true, URL will not be escaped. |
||
| 409 | * @param bool|string $redirect If true, will redirect back to Jetpack wp-admin landing page after connection. |
||
| 410 | * If string, will be a custom redirect. |
||
| 411 | * @param bool|string $from If not false, adds 'from=$from' param to the connect URL. |
||
| 412 | * @param bool $register If true, will generate a register URL regardless of the existing token, since 4.9.0. |
||
| 413 | * |
||
| 414 | * @return string Connect URL |
||
| 415 | */ |
||
| 416 | public function build_connect_url( $raw, $redirect, $from, $register ) { |
||
| 417 | return array( $raw, $redirect, $from, $register ); |
||
| 418 | } |
||
| 419 | |||
| 420 | /** |
||
| 421 | * Disconnects from the Jetpack servers. |
||
| 422 | * Forgets all connection details and tells the Jetpack servers to do the same. |
||
| 423 | */ |
||
| 424 | public function disconnect_site() { |
||
| 425 | |||
| 426 | } |
||
| 427 | |||
| 428 | /** |
||
| 429 | * The Base64 Encoding of the SHA1 Hash of the Input. |
||
| 430 | * |
||
| 431 | * @param string $text The string to hash. |
||
| 432 | * @return string |
||
| 433 | */ |
||
| 434 | public function sha1_base64( $text ) { |
||
| 435 | return base64_encode( sha1( $text, true ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode |
||
| 436 | } |
||
| 437 | |||
| 438 | /** |
||
| 439 | * This function mirrors Jetpack_Data::is_usable_domain() in the WPCOM codebase. |
||
| 440 | * |
||
| 441 | * @param string $domain The domain to check. |
||
| 442 | * |
||
| 443 | * @return bool|WP_Error |
||
| 444 | */ |
||
| 445 | public function is_usable_domain( $domain ) { |
||
| 446 | |||
| 447 | // If it's empty, just fail out. |
||
| 448 | if ( ! $domain ) { |
||
| 449 | return new \WP_Error( |
||
| 450 | 'fail_domain_empty', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'fail_domain_empty'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 451 | /* translators: %1$s is a domain name. */ |
||
| 452 | sprintf( __( 'Domain `%1$s` just failed is_usable_domain check as it is empty.', 'jetpack' ), $domain ) |
||
| 453 | ); |
||
| 454 | } |
||
| 455 | |||
| 456 | /** |
||
| 457 | * Skips the usuable domain check when connecting a site. |
||
| 458 | * |
||
| 459 | * Allows site administrators with domains that fail gethostname-based checks to pass the request to WP.com |
||
| 460 | * |
||
| 461 | * @since 4.1.0 |
||
| 462 | * |
||
| 463 | * @param bool If the check should be skipped. Default false. |
||
| 464 | */ |
||
| 465 | if ( apply_filters( 'jetpack_skip_usuable_domain_check', false ) ) { |
||
| 466 | return true; |
||
| 467 | } |
||
| 468 | |||
| 469 | // None of the explicit localhosts. |
||
| 470 | $forbidden_domains = array( |
||
| 471 | 'wordpress.com', |
||
| 472 | 'localhost', |
||
| 473 | 'localhost.localdomain', |
||
| 474 | '127.0.0.1', |
||
| 475 | 'local.wordpress.test', // VVV pattern. |
||
| 476 | 'local.wordpress-trunk.test', // VVV pattern. |
||
| 477 | 'src.wordpress-develop.test', // VVV pattern. |
||
| 478 | 'build.wordpress-develop.test', // VVV pattern. |
||
| 479 | ); |
||
| 480 | View Code Duplication | if ( in_array( $domain, $forbidden_domains, true ) ) { |
|
| 481 | return new \WP_Error( |
||
| 482 | 'fail_domain_forbidden', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'fail_domain_forbidden'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 483 | sprintf( |
||
| 484 | /* translators: %1$s is a domain name. */ |
||
| 485 | __( |
||
| 486 | 'Domain `%1$s` just failed is_usable_domain check as it is in the forbidden array.', |
||
| 487 | 'jetpack' |
||
| 488 | ), |
||
| 489 | $domain |
||
| 490 | ) |
||
| 491 | ); |
||
| 492 | } |
||
| 493 | |||
| 494 | // No .test or .local domains. |
||
| 495 | View Code Duplication | if ( preg_match( '#\.(test|local)$#i', $domain ) ) { |
|
| 496 | return new \WP_Error( |
||
| 497 | 'fail_domain_tld', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'fail_domain_tld'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 498 | sprintf( |
||
| 499 | /* translators: %1$s is a domain name. */ |
||
| 500 | __( |
||
| 501 | 'Domain `%1$s` just failed is_usable_domain check as it uses an invalid top level domain.', |
||
| 502 | 'jetpack' |
||
| 503 | ), |
||
| 504 | $domain |
||
| 505 | ) |
||
| 506 | ); |
||
| 507 | } |
||
| 508 | |||
| 509 | // No WPCOM subdomains. |
||
| 510 | View Code Duplication | if ( preg_match( '#\.WordPress\.com$#i', $domain ) ) { |
|
| 511 | return new \WP_Error( |
||
| 512 | 'fail_subdomain_wpcom', |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'fail_subdomain_wpcom'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 513 | sprintf( |
||
| 514 | /* translators: %1$s is a domain name. */ |
||
| 515 | __( |
||
| 516 | 'Domain `%1$s` just failed is_usable_domain check as it is a subdomain of WordPress.com.', |
||
| 517 | 'jetpack' |
||
| 518 | ), |
||
| 519 | $domain |
||
| 520 | ) |
||
| 521 | ); |
||
| 522 | } |
||
| 523 | |||
| 524 | // If PHP was compiled without support for the Filter module (very edge case). |
||
| 525 | if ( ! function_exists( 'filter_var' ) ) { |
||
| 526 | // Just pass back true for now, and let wpcom sort it out. |
||
| 527 | return true; |
||
| 528 | } |
||
| 529 | |||
| 530 | return true; |
||
| 531 | } |
||
| 532 | |||
| 533 | /** |
||
| 534 | * Gets the requested token. |
||
| 535 | * |
||
| 536 | * Tokens are one of two types: |
||
| 537 | * 1. Blog Tokens: These are the "main" tokens. Each site typically has one Blog Token, |
||
| 538 | * though some sites can have multiple "Special" Blog Tokens (see below). These tokens |
||
| 539 | * are not associated with a user account. They represent the site's connection with |
||
| 540 | * the Jetpack servers. |
||
| 541 | * 2. User Tokens: These are "sub-"tokens. Each connected user account has one User Token. |
||
| 542 | * |
||
| 543 | * All tokens look like "{$token_key}.{$private}". $token_key is a public ID for the |
||
| 544 | * token, and $private is a secret that should never be displayed anywhere or sent |
||
| 545 | * over the network; it's used only for signing things. |
||
| 546 | * |
||
| 547 | * Blog Tokens can be "Normal" or "Special". |
||
| 548 | * * Normal: The result of a normal connection flow. They look like |
||
| 549 | * "{$random_string_1}.{$random_string_2}" |
||
| 550 | * That is, $token_key and $private are both random strings. |
||
| 551 | * Sites only have one Normal Blog Token. Normal Tokens are found in either |
||
| 552 | * Jetpack_Options::get_option( 'blog_token' ) (usual) or the JETPACK_BLOG_TOKEN |
||
| 553 | * constant (rare). |
||
| 554 | * * Special: A connection token for sites that have gone through an alternative |
||
| 555 | * connection flow. They look like: |
||
| 556 | * ";{$special_id}{$special_version};{$wpcom_blog_id};.{$random_string}" |
||
| 557 | * That is, $private is a random string and $token_key has a special structure with |
||
| 558 | * lots of semicolons. |
||
| 559 | * Most sites have zero Special Blog Tokens. Special tokens are only found in the |
||
| 560 | * JETPACK_BLOG_TOKEN constant. |
||
| 561 | * |
||
| 562 | * In particular, note that Normal Blog Tokens never start with ";" and that |
||
| 563 | * Special Blog Tokens always do. |
||
| 564 | * |
||
| 565 | * When searching for a matching Blog Tokens, Blog Tokens are examined in the following |
||
| 566 | * order: |
||
| 567 | * 1. Defined Special Blog Tokens (via the JETPACK_BLOG_TOKEN constant) |
||
| 568 | * 2. Stored Normal Tokens (via Jetpack_Options::get_option( 'blog_token' )) |
||
| 569 | * 3. Defined Normal Tokens (via the JETPACK_BLOG_TOKEN constant) |
||
| 570 | * |
||
| 571 | * @param int|false $user_id false: Return the Blog Token. int: Return that user's User Token. |
||
| 572 | * @param string|false $token_key If provided, check that the token matches the provided input. |
||
| 573 | * @param bool|true $suppress_errors If true, return a falsy value when the token isn't found; When false, return a descriptive WP_Error when the token isn't found. |
||
| 574 | * |
||
| 575 | * @return object|false |
||
| 576 | */ |
||
| 577 | public function get_access_token( $user_id = false, $token_key = false, $suppress_errors = true ) { |
||
| 578 | $possible_special_tokens = array(); |
||
| 579 | $possible_normal_tokens = array(); |
||
| 580 | $user_tokens = \Jetpack_Options::get_option( 'user_tokens' ); |
||
| 581 | |||
| 582 | if ( $user_id ) { |
||
| 583 | if ( ! $user_tokens ) { |
||
| 584 | return $suppress_errors ? false : new \WP_Error( 'no_user_tokens' ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'no_user_tokens'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 585 | } |
||
| 586 | if ( self::JETPACK_MASTER_USER === $user_id ) { |
||
| 587 | $user_id = \Jetpack_Options::get_option( 'master_user' ); |
||
| 588 | if ( ! $user_id ) { |
||
| 589 | return $suppress_errors ? false : new \WP_Error( 'empty_master_user_option' ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'empty_master_user_option'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 590 | } |
||
| 591 | } |
||
| 592 | if ( ! isset( $user_tokens[ $user_id ] ) || ! $user_tokens[ $user_id ] ) { |
||
| 593 | return $suppress_errors ? false : new \WP_Error( 'no_token_for_user', sprintf( 'No token for user %d', $user_id ) ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'no_token_for_user'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 594 | } |
||
| 595 | $user_token_chunks = explode( '.', $user_tokens[ $user_id ] ); |
||
| 596 | if ( empty( $user_token_chunks[1] ) || empty( $user_token_chunks[2] ) ) { |
||
| 597 | return $suppress_errors ? false : new \WP_Error( 'token_malformed', sprintf( 'Token for user %d is malformed', $user_id ) ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'token_malformed'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 598 | } |
||
| 599 | if ( $user_token_chunks[2] !== (string) $user_id ) { |
||
| 600 | return $suppress_errors ? false : new \WP_Error( 'user_id_mismatch', sprintf( 'Requesting user_id %d does not match token user_id %d', $user_id, $user_token_chunks[2] ) ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'user_id_mismatch'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 601 | } |
||
| 602 | $possible_normal_tokens[] = "{$user_token_chunks[0]}.{$user_token_chunks[1]}"; |
||
| 603 | } else { |
||
| 604 | $stored_blog_token = \Jetpack_Options::get_option( 'blog_token' ); |
||
| 605 | if ( $stored_blog_token ) { |
||
| 606 | $possible_normal_tokens[] = $stored_blog_token; |
||
| 607 | } |
||
| 608 | |||
| 609 | $defined_tokens = Constants::is_defined( 'JETPACK_BLOG_TOKEN' ) |
||
| 610 | ? explode( ',', Constants::get_constant( 'JETPACK_BLOG_TOKEN' ) ) |
||
| 611 | : array(); |
||
| 612 | |||
| 613 | foreach ( $defined_tokens as $defined_token ) { |
||
| 614 | if ( ';' === $defined_token[0] ) { |
||
| 615 | $possible_special_tokens[] = $defined_token; |
||
| 616 | } else { |
||
| 617 | $possible_normal_tokens[] = $defined_token; |
||
| 618 | } |
||
| 619 | } |
||
| 620 | } |
||
| 621 | |||
| 622 | if ( self::MAGIC_NORMAL_TOKEN_KEY === $token_key ) { |
||
| 623 | $possible_tokens = $possible_normal_tokens; |
||
| 624 | } else { |
||
| 625 | $possible_tokens = array_merge( $possible_special_tokens, $possible_normal_tokens ); |
||
| 626 | } |
||
| 627 | |||
| 628 | if ( ! $possible_tokens ) { |
||
|
0 ignored issues
–
show
The expression
$possible_tokens of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||
| 629 | return $suppress_errors ? false : new \WP_Error( 'no_possible_tokens' ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'no_possible_tokens'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 630 | } |
||
| 631 | |||
| 632 | $valid_token = false; |
||
| 633 | |||
| 634 | if ( false === $token_key ) { |
||
| 635 | // Use first token. |
||
| 636 | $valid_token = $possible_tokens[0]; |
||
| 637 | } elseif ( self::MAGIC_NORMAL_TOKEN_KEY === $token_key ) { |
||
| 638 | // Use first normal token. |
||
| 639 | $valid_token = $possible_tokens[0]; // $possible_tokens only contains normal tokens because of earlier check. |
||
| 640 | } else { |
||
| 641 | // Use the token matching $token_key or false if none. |
||
| 642 | // Ensure we check the full key. |
||
| 643 | $token_check = rtrim( $token_key, '.' ) . '.'; |
||
| 644 | |||
| 645 | foreach ( $possible_tokens as $possible_token ) { |
||
| 646 | if ( hash_equals( substr( $possible_token, 0, strlen( $token_check ) ), $token_check ) ) { |
||
| 647 | $valid_token = $possible_token; |
||
| 648 | break; |
||
| 649 | } |
||
| 650 | } |
||
| 651 | } |
||
| 652 | |||
| 653 | if ( ! $valid_token ) { |
||
| 654 | return $suppress_errors ? false : new \WP_Error( 'no_valid_token' ); |
||
|
0 ignored issues
–
show
The call to
WP_Error::__construct() has too many arguments starting with 'no_valid_token'.
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the Loading history...
|
|||
| 655 | } |
||
| 656 | |||
| 657 | return (object) array( |
||
| 658 | 'secret' => $valid_token, |
||
| 659 | 'external_user_id' => (int) $user_id, |
||
| 660 | ); |
||
| 661 | } |
||
| 662 | } |
||
| 663 |
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: