updated plugin Jetpack Protect version 1.4.2

This commit is contained in:
2023-10-22 22:21:06 +00:00
committed by Gitium
parent f512d25847
commit f07dfae114
242 changed files with 6494 additions and 1502 deletions

View File

@ -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 ),
)
);

View File

@ -240,5 +240,4 @@ class Connection_Notice {
echo '</p>';
echo '</div>';
}
}

View File

@ -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
*
@ -726,5 +772,4 @@ class Error_Handler {
$this->report_error( $error, false, true );
}
}

View File

@ -249,5 +249,4 @@ class Heartbeat {
WP_CLI::line( sprintf( __( 'Last heartbeat sent at: %s', 'jetpack-connection' ), $last_date ) );
}
}
}

View File

@ -14,13 +14,6 @@ use Automattic\Jetpack\Status;
*/
class Initial_State {
/**
* Whether the initial state was already rendered
*
* @var boolean
*/
private static $rendered = false;
/**
* Get the initial state data.
*
@ -29,6 +22,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 +32,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(),
);
}
@ -48,11 +45,17 @@ class Initial_State {
* @return string
*/
public static function render() {
if ( self::$rendered ) {
return null;
}
self::$rendered = true;
return 'var JP_CONNECTION_INITIAL_STATE=JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( self::get_data() ) ) . '"));';
return 'var JP_CONNECTION_INITIAL_STATE; typeof JP_CONNECTION_INITIAL_STATE === "object" || (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 ) {
wp_add_inline_script( $handle, static::render(), 'before' );
}
}

View File

@ -7,11 +7,12 @@
namespace Automattic\Jetpack\Connection;
use Automattic\Jetpack\A8c_Mc_Stats as A8c_Mc_Stats;
use Automattic\Jetpack\A8c_Mc_Stats;
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' );
@ -2107,7 +2139,6 @@ class Manager {
'wordpress.com',
'localhost',
'localhost.localdomain',
'127.0.0.1',
'local.wordpress.test', // VVV pattern.
'local.wordpress-trunk.test', // VVV pattern.
'src.wordpress-develop.test', // VVV pattern.
@ -2163,6 +2194,24 @@ class Manager {
return true;
}
$domain = preg_replace( '#^https?://#', '', untrailingslashit( $domain ) );
if ( filter_var( $domain, FILTER_VALIDATE_IP )
&& ! filter_var( $domain, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE )
) {
return new \WP_Error(
'fail_ip_forbidden',
sprintf(
/* translators: %1$s is a domain name. */
__(
'IP address `%1$s` just failed is_usable_domain check as it is in the private network.',
'jetpack-connection'
),
$domain
)
);
}
return true;
}

View File

@ -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;
}
@ -209,5 +209,4 @@ class Nonce_Handler {
return true;
}
}

View File

@ -108,5 +108,4 @@ class Package_Version_Tracker {
set_transient( self::CACHED_FAILED_REQUEST_KEY, time(), self::CACHED_FAILED_REQUEST_EXPIRATION );
}
}
}

View File

@ -12,7 +12,7 @@ namespace Automattic\Jetpack\Connection;
*/
class Package_Version {
const PACKAGE_VERSION = '1.51.7';
const PACKAGE_VERSION = '1.58.2';
const PACKAGE_SLUG = 'connection';

View File

@ -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;
}

View File

@ -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,

View File

@ -108,5 +108,4 @@ class Terms_Of_Service {
protected function set_reject() {
\Jetpack_Options::update_option( self::OPTION_NAME, false );
}
}

View File

@ -0,0 +1,76 @@
<?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 );
}
}

View File

@ -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 );
}
/**

View File

@ -183,5 +183,4 @@ class Urls {
public static function main_network_site_url() {
return self::get_protocol_normalized_url( 'main_network_site_url', network_site_url() );
}
}

View File

@ -81,7 +81,7 @@ class XMLRPC_Async_Call {
public static function do_calls() {
foreach ( self::$clients as $client_blog_id => $blog_clients ) {
if ( $client_blog_id > 0 ) {
$switch_success = switch_to_blog( $client_blog_id, true );
$switch_success = switch_to_blog( $client_blog_id );
if ( ! $switch_success ) {
continue;