Merged in feature/MAW-855-import-code-into-aws (pull request #2)
code import from pantheon * code import from pantheon
This commit is contained in:
@@ -154,7 +154,7 @@ class Client {
|
||||
if ( is_array( $body ) ) {
|
||||
// We cast this to a new variable, because the array form of $body needs to be
|
||||
// maintained so it can be passed into the request later on in the code.
|
||||
if ( count( $body ) > 0 ) {
|
||||
if ( array() !== $body ) {
|
||||
$body_to_hash = wp_json_encode( self::_stringify_data( $body ) );
|
||||
} else {
|
||||
$body_to_hash = '';
|
||||
@@ -206,7 +206,7 @@ class Client {
|
||||
$request['headers'] = array_merge(
|
||||
$args['headers'],
|
||||
array(
|
||||
'Authorization' => 'X_JETPACK ' . join( ' ', $header_pieces ),
|
||||
'Authorization' => 'X_JETPACK ' . implode( ' ', $header_pieces ),
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ class Error_Handler {
|
||||
'invalid_body_hash',
|
||||
'invalid_nonce',
|
||||
'signature_mismatch',
|
||||
'invalid_connection_owner',
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -139,7 +140,7 @@ class Error_Handler {
|
||||
|
||||
// If the site gets reconnected, clear errors.
|
||||
add_action( 'jetpack_site_registered', array( $this, 'delete_all_errors' ) );
|
||||
add_action( 'jetpack_get_site_data_success', array( $this, 'delete_all_errors' ) );
|
||||
add_action( 'jetpack_get_site_data_success', array( $this, 'delete_all_api_errors' ) );
|
||||
add_filter( 'jetpack_connection_disconnect_site_wpcom', array( $this, 'delete_all_errors_and_return_unfiltered_value' ) );
|
||||
add_filter( 'jetpack_connection_delete_all_tokens', array( $this, 'delete_all_errors_and_return_unfiltered_value' ) );
|
||||
add_action( 'jetpack_unlinked_user', array( $this, 'delete_all_errors' ) );
|
||||
@@ -170,6 +171,7 @@ class Error_Handler {
|
||||
case 'signature_mismatch':
|
||||
case 'no_user_tokens':
|
||||
case 'no_token_for_user':
|
||||
case 'invalid_connection_owner':
|
||||
add_action( 'admin_notices', array( $this, 'generic_admin_notice_error' ) );
|
||||
add_action( 'react_connection_errors_initial_state', array( $this, 'jetpack_react_dashboard_error' ) );
|
||||
$this->error_code = $error_code;
|
||||
@@ -277,7 +279,8 @@ class Error_Handler {
|
||||
$stored_errors[ $error_code ][ $user_id ] = $error_array;
|
||||
|
||||
// Let's store a maximum of 5 different user ids for each error code.
|
||||
if ( count( $stored_errors[ $error_code ] ) > 5 ) {
|
||||
$error_code_count = is_countable( $stored_errors[ $error_code ] ) ? count( $stored_errors[ $error_code ] ) : 0;
|
||||
if ( $error_code_count > 5 ) {
|
||||
// array_shift will destroy keys here because they are numeric, so manually remove first item.
|
||||
$keys = array_keys( $stored_errors[ $error_code ] );
|
||||
unset( $stored_errors[ $error_code ][ $keys[0] ] );
|
||||
@@ -308,7 +311,7 @@ class Error_Handler {
|
||||
|
||||
$signature_details = $data['signature_details'];
|
||||
|
||||
if ( ! isset( $signature_details['token'] ) || empty( $signature_details['token'] ) ) {
|
||||
if ( ! isset( $signature_details['token'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -389,12 +392,14 @@ class Error_Handler {
|
||||
* @return string $the user id or `invalid` if user id not present.
|
||||
*/
|
||||
public function get_user_id_from_token( $token ) {
|
||||
$parsed_token = explode( ':', wp_unslash( $token ) );
|
||||
$user_id = 'invalid';
|
||||
|
||||
if ( isset( $parsed_token[2] ) && ctype_digit( $parsed_token[2] ) ) {
|
||||
$user_id = $parsed_token[2];
|
||||
} else {
|
||||
$user_id = 'invalid';
|
||||
if ( $token ) {
|
||||
$parsed_token = explode( ':', wp_unslash( $token ) );
|
||||
|
||||
if ( isset( $parsed_token[2] ) && ctype_digit( $parsed_token[2] ) ) {
|
||||
$user_id = $parsed_token[2];
|
||||
}
|
||||
}
|
||||
|
||||
return $user_id;
|
||||
@@ -482,6 +487,47 @@ class Error_Handler {
|
||||
$this->delete_verified_errors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored and verified API errors from the database, leave the non-API errors intact.
|
||||
*
|
||||
* @since 1.54.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete_all_api_errors() {
|
||||
$type_filter = function ( $errors ) {
|
||||
if ( is_array( $errors ) ) {
|
||||
foreach ( $errors as $key => $error ) {
|
||||
if ( ! empty( $error['error_type'] ) && in_array( $error['error_type'], array( 'xmlrpc', 'rest' ), true ) ) {
|
||||
unset( $errors[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count( $errors ) ? $errors : null;
|
||||
};
|
||||
|
||||
$stored_errors = $this->get_stored_errors();
|
||||
if ( is_array( $stored_errors ) && count( $stored_errors ) ) {
|
||||
$stored_errors = array_filter( array_map( $type_filter, $stored_errors ) );
|
||||
if ( count( $stored_errors ) ) {
|
||||
update_option( static::STORED_ERRORS_OPTION, $stored_errors );
|
||||
} else {
|
||||
delete_option( static::STORED_ERRORS_OPTION );
|
||||
}
|
||||
}
|
||||
|
||||
$verified_errors = $this->get_verified_errors();
|
||||
if ( is_array( $verified_errors ) && count( $verified_errors ) ) {
|
||||
$verified_errors = array_filter( array_map( $type_filter, $verified_errors ) );
|
||||
if ( count( $verified_errors ) ) {
|
||||
update_option( static::STORED_VERIFIED_ERRORS_OPTION, $verified_errors );
|
||||
} else {
|
||||
delete_option( static::STORED_VERIFIED_ERRORS_OPTION );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored and verified errors from the database and returns unfiltered value
|
||||
*
|
||||
|
||||
@@ -29,6 +29,8 @@ class Initial_State {
|
||||
private static function get_data() {
|
||||
global $wp_version;
|
||||
|
||||
$status = new Status();
|
||||
|
||||
return array(
|
||||
'apiRoot' => esc_url_raw( rest_url() ),
|
||||
'apiNonce' => wp_create_nonce( 'wp_rest' ),
|
||||
@@ -37,8 +39,10 @@ class Initial_State {
|
||||
'userConnectionData' => REST_Connector::get_user_connection_data( false ),
|
||||
'connectedPlugins' => REST_Connector::get_connection_plugins( false ),
|
||||
'wpVersion' => $wp_version,
|
||||
'siteSuffix' => ( new Status() )->get_site_suffix(),
|
||||
'siteSuffix' => $status->get_site_suffix(),
|
||||
'connectionErrors' => Error_Handler::get_instance()->get_verified_errors(),
|
||||
'isOfflineMode' => $status->is_offline_mode(),
|
||||
'calypsoEnv' => ( new Status\Host() )->get_calypso_env(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -55,4 +59,17 @@ class Initial_State {
|
||||
return 'var JP_CONNECTION_INITIAL_STATE=JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( self::get_data() ) ) . '"));';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the initial state using an inline script.
|
||||
*
|
||||
* @param string $handle The JS script handle.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function render_script( $handle ) {
|
||||
if ( ! static::$rendered ) {
|
||||
wp_add_inline_script( $handle, static::render(), 'before' );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use Automattic\Jetpack\Constants;
|
||||
use Automattic\Jetpack\Heartbeat;
|
||||
use Automattic\Jetpack\Roles;
|
||||
use Automattic\Jetpack\Status;
|
||||
use Automattic\Jetpack\Status\Host;
|
||||
use Automattic\Jetpack\Terms_Of_Service;
|
||||
use Automattic\Jetpack\Tracking;
|
||||
use Jetpack_IXR_Client;
|
||||
@@ -134,6 +135,9 @@ class Manager {
|
||||
|
||||
// Initialize connection notices.
|
||||
new Connection_Notice();
|
||||
|
||||
// Initialize token locks.
|
||||
new Tokens_Locks();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,7 +207,6 @@ class Manager {
|
||||
// The jetpack.authorize method should be available for unauthenticated users on a site with an
|
||||
// active Jetpack connection, so that additional users can link their account.
|
||||
$callback = array( $this->xmlrpc_server, 'authorize_xmlrpc_methods' );
|
||||
|
||||
} else {
|
||||
// Any other unsigned request should expose the bootstrap methods.
|
||||
$callback = array( $this->xmlrpc_server, 'bootstrap_xmlrpc_methods' );
|
||||
@@ -785,6 +788,25 @@ class Manager {
|
||||
$connection_owner = get_userdata( $user_token->external_user_id );
|
||||
}
|
||||
|
||||
if ( $connection_owner === false ) {
|
||||
Error_Handler::get_instance()->report_error(
|
||||
new WP_Error(
|
||||
'invalid_connection_owner',
|
||||
'Invalid connection owner',
|
||||
array(
|
||||
'user_id' => $user_id,
|
||||
'has_user_token' => (bool) $user_token,
|
||||
'error_type' => 'connection',
|
||||
'signature_details' => array(
|
||||
'token' => '',
|
||||
),
|
||||
)
|
||||
),
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return $connection_owner;
|
||||
}
|
||||
|
||||
@@ -1046,6 +1068,11 @@ class Manager {
|
||||
* @return true|WP_Error The error object.
|
||||
*/
|
||||
public function register( $api_endpoint = 'register' ) {
|
||||
// Clean-up leftover tokens just in-case.
|
||||
// This fixes an edge case that was preventing users to register when the blog token was missing but
|
||||
// there were still leftover user tokens present.
|
||||
$this->delete_all_connection_tokens( true );
|
||||
|
||||
add_action( 'pre_update_jetpack_option_register', array( '\\Jetpack_Options', 'delete_option' ) );
|
||||
$secrets = ( new Secrets() )->generate( 'register', get_current_user_id(), 600 );
|
||||
|
||||
@@ -1125,7 +1152,7 @@ class Manager {
|
||||
'timeout' => $timeout,
|
||||
);
|
||||
|
||||
$args['body'] = $this->apply_activation_source_to_args( $args['body'] );
|
||||
$args['body'] = static::apply_activation_source_to_args( $args['body'] );
|
||||
|
||||
// TODO: fix URLs for bad hosts.
|
||||
$response = Client::_wp_remote_request(
|
||||
@@ -1643,6 +1670,11 @@ class Manager {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ( new Status() )->is_offline_mode() && ! apply_filters( 'jetpack_connection_disconnect_site_wpcom_offline_mode', false ) ) {
|
||||
// Prevent potential disconnect of the live site by removing WPCOM tokens.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires upon the disconnect attempt.
|
||||
* Return `false` to prevent the disconnect.
|
||||
@@ -1686,7 +1718,6 @@ class Manager {
|
||||
( new Tracking() )->record_user_event( 'restore_connection_reconnect' );
|
||||
|
||||
$this->disconnect_site_wpcom( true );
|
||||
$this->delete_all_connection_tokens( true );
|
||||
|
||||
return $this->register();
|
||||
}
|
||||
@@ -1884,10 +1915,11 @@ class Manager {
|
||||
'site_lang' => get_locale(),
|
||||
'site_created' => $this->get_assumed_site_creation_date(),
|
||||
'allow_site_connection' => ! $this->has_connected_owner(),
|
||||
'calypso_env' => ( new Host() )->get_calypso_env(),
|
||||
)
|
||||
);
|
||||
|
||||
$body = $this->apply_activation_source_to_args( urlencode_deep( $body ) );
|
||||
$body = static::apply_activation_source_to_args( urlencode_deep( $body ) );
|
||||
|
||||
$api_url = $this->api_url( 'authorize' );
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ class Nonce_Handler {
|
||||
// Removing zeroes in case AUTO_INCREMENT of the options table is broken, and all ID's are zeroes.
|
||||
$ids = array_filter( $ids );
|
||||
|
||||
if ( ! count( $ids ) ) {
|
||||
if ( array() === $ids ) {
|
||||
// There's nothing to remove.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Automattic\Jetpack\Connection;
|
||||
*/
|
||||
class Package_Version {
|
||||
|
||||
const PACKAGE_VERSION = '1.51.7';
|
||||
const PACKAGE_VERSION = '1.57.0';
|
||||
|
||||
const PACKAGE_SLUG = 'connection';
|
||||
|
||||
|
||||
@@ -521,7 +521,7 @@ class REST_Connector {
|
||||
*/
|
||||
public static function is_request_signed_by_jetpack_debugger( $pub_key = null ) {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_GET['signature'], $_GET['timestamp'], $_GET['url'], $_GET['rest_route'] ) ) {
|
||||
if ( ! isset( $_GET['signature'] ) || ! isset( $_GET['timestamp'] ) || ! isset( $_GET['url'] ) || ! isset( $_GET['rest_route'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class Secrets {
|
||||
$user_id = get_current_user_id();
|
||||
}
|
||||
|
||||
$callable = apply_filters( 'jetpack_connection_secret_generator', array( get_called_class(), 'secret_callable_method' ) );
|
||||
$callable = apply_filters( 'jetpack_connection_secret_generator', array( static::class, 'secret_callable_method' ) );
|
||||
|
||||
$secrets = Jetpack_Options::get_raw_option(
|
||||
self::LEGACY_SECRETS_OPTION_NAME,
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* The Jetpack Connection Tokens Locks class file.
|
||||
*
|
||||
* @package automattic/jetpack-connection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Connection;
|
||||
|
||||
/**
|
||||
*
|
||||
* Jetpack Connection tokens cleanup during migration.
|
||||
* This class encapsulates plugin or tool specific code that activates token lock upon migration.
|
||||
*
|
||||
* The connection tokens are locked to the current domain.
|
||||
* If the database is imported on another site (domain name doesn't match), the tokens get removed.
|
||||
*
|
||||
* @see https://github.com/Automattic/jetpack/pull/23597
|
||||
* @see \Automattic\Jetpack\Connection\Tokens::is_locked()
|
||||
*/
|
||||
class Tokens_Locks {
|
||||
|
||||
/**
|
||||
* Whether the class has been initialized.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $is_initialized = false;
|
||||
|
||||
/**
|
||||
* Run the initializers if they haven't been run already.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( static::$is_initialized ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->init_aiowpm();
|
||||
|
||||
static::$is_initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token lock for AIOWPM plugin export.
|
||||
*
|
||||
* @param array $params The filter parameters.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function aiowpm_set_lock( $params ) {
|
||||
( new Tokens() )->set_lock();
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the token lock for AIOWPM plugin export.
|
||||
*
|
||||
* @param array $params The filter parameters.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function aiowpm_remove_lock( $params ) {
|
||||
( new Tokens() )->remove_lock();
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the All-in-One-WP-Migration plugin hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function init_aiowpm() {
|
||||
add_filter( 'ai1wm_export', array( $this, 'aiowpm_set_lock' ), 180 );
|
||||
add_filter( 'ai1wm_export', array( $this, 'aiowpm_remove_lock' ), 250 );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -552,7 +552,7 @@ class Tokens {
|
||||
$nonce = substr( sha1( wp_rand( 0, 1000000 ) ), 0, 10 );
|
||||
}
|
||||
|
||||
$normalized_request_string = join(
|
||||
$normalized_request_string = implode(
|
||||
"\n",
|
||||
array(
|
||||
$token_key,
|
||||
@@ -576,7 +576,7 @@ class Tokens {
|
||||
$header_pieces[] = sprintf( '%s="%s"', $key, $value );
|
||||
}
|
||||
|
||||
return join( ' ', $header_pieces );
|
||||
return implode( ' ', $header_pieces );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user