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

@ -9,9 +9,15 @@ import './style.scss';
* The initial renderer function.
*/
function render() {
const container = document.getElementById( 'jp-identity-crisis-container' );
if ( ! window.hasOwnProperty( 'JP_IDENTITY_CRISIS__INITIAL_STATE' ) ) {
return;
}
if ( null === container || ! window.hasOwnProperty( 'JP_IDENTITY_CRISIS__INITIAL_STATE' ) ) {
const container = document.getElementById(
window.JP_IDENTITY_CRISIS__INITIAL_STATE.containerID || 'jp-identity-crisis-container'
);
if ( null === container ) {
return;
}
@ -30,7 +36,6 @@ function render() {
} = window.JP_IDENTITY_CRISIS__INITIAL_STATE;
if ( ! isSafeModeConfirmed ) {
// @todo: Remove fallback when we drop support for WP 6.1
const component = (
<IDCScreen
wpcomHomeUrl={ wpcomHomeUrl }
@ -48,12 +53,8 @@ function render() {
possibleDynamicSiteUrlDetected={ possibleDynamicSiteUrlDetected }
/>
);
if ( WPElement.createRoot ) {
WPElement.createRoot( container ).render( component );
} else {
WPElement.render( component, container );
}
WPElement.createRoot( container ).render( component );
}
}
render();
window.addEventListener( 'load', () => render() );

View File

@ -0,0 +1,13 @@
<?php
/**
* Exception class for the Identity Crisis package.
*
* @package automattic/jetpack-identity-crisis
*/
namespace Automattic\Jetpack\IdentityCrisis;
/**
* Exception class for the Identity Crisis package.
*/
class Exception extends \Exception {}

View File

@ -10,10 +10,9 @@ namespace Automattic\Jetpack;
use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Connection\Urls;
use Automattic\Jetpack\Constants as Constants;
use Automattic\Jetpack\IdentityCrisis\Exception;
use Automattic\Jetpack\IdentityCrisis\UI;
use Automattic\Jetpack\Status as Status;
use Automattic\Jetpack\Tracking as Tracking;
use Automattic\Jetpack\IdentityCrisis\URL_Secret;
use Jetpack_Options;
use WP_Error;
@ -28,7 +27,7 @@ class Identity_Crisis {
/**
* Package Version
*/
const PACKAGE_VERSION = '0.8.40';
const PACKAGE_VERSION = '0.11.1';
/**
* Instance of the object.
@ -87,6 +86,10 @@ class Identity_Crisis {
add_filter( 'jetpack_remote_request_url', array( $this, 'add_idc_query_args_to_url' ) );
add_filter( 'jetpack_connection_validate_urls_for_idc_mitigation_response', array( static::class, 'add_secret_to_url_validation_response' ) );
add_filter( 'jetpack_options', array( static::class, 'reverse_wpcom_urls_for_idc' ) );
$urls_in_crisis = self::check_identity_crisis();
if ( false === $urls_in_crisis ) {
return;
@ -144,14 +147,14 @@ class Identity_Crisis {
foreach ( (array) $processed_items as $item ) {
// First, is this item a jetpack_sync_callable action? If so, then proceed.
$callable_args = ( is_array( $item ) && isset( $item[0], $item[1] ) && 'jetpack_sync_callable' === $item[0] )
$callable_args = ( is_array( $item ) && isset( $item[0] ) && isset( $item[1] ) && 'jetpack_sync_callable' === $item[0] )
? $item[1]
: null;
// Second, if $callable_args is set, check if the callable was home_url or site_url. If so,
// clear the migrate option.
if (
isset( $callable_args, $callable_args[0] )
isset( $callable_args[0] )
&& ( 'home_url' === $callable_args[0] || 'site_url' === $callable_args[1] )
) {
Jetpack_Options::delete_option( 'migrate_for_idc' );
@ -168,7 +171,7 @@ class Identity_Crisis {
public function wordpress_init() {
if ( current_user_can( 'jetpack_disconnect' ) ) {
if (
isset( $_GET['jetpack_idc_clear_confirmation'], $_GET['_wpnonce'] ) &&
isset( $_GET['jetpack_idc_clear_confirmation'] ) && isset( $_GET['_wpnonce'] ) &&
wp_verify_nonce( $_GET['_wpnonce'], 'jetpack_idc_clear_confirmation' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WordPress core doesn't unslash or verify nonces either.
) {
Jetpack_Options::delete_option( 'safe_mode_confirmed' );
@ -284,7 +287,6 @@ class Identity_Crisis {
if ( ! $connection->is_connected() || ( new Status() )->is_offline_mode() || ! self::validate_sync_error_idc_option() ) {
return false;
}
return Jetpack_Options::get_option( 'sync_error_idc' );
}
@ -335,7 +337,7 @@ class Identity_Crisis {
);
if ( in_array( $error_code, $allowed_idc_error_codes, true ) ) {
\Jetpack_Options::update_option(
Jetpack_Options::update_option(
'sync_error_idc',
self::get_sync_error_idc_option( $response )
);
@ -436,6 +438,24 @@ class Identity_Crisis {
return $is_valid;
}
/**
* Reverses WP.com URLs stored in sync_error_idc option.
*
* @param array $sync_error error option containing reversed URLs.
* @return array
*/
public static function reverse_wpcom_urls_for_idc( $sync_error ) {
if ( isset( $sync_error['reversed_url'] ) ) {
if ( array_key_exists( 'wpcom_siteurl', $sync_error ) ) {
$sync_error['wpcom_siteurl'] = strrev( $sync_error['wpcom_siteurl'] );
}
if ( array_key_exists( 'wpcom_home', $sync_error ) ) {
$sync_error['wpcom_home'] = strrev( $sync_error['wpcom_home'] );
}
}
return $sync_error;
}
/**
* Normalizes a url by doing three things:
* - Strips protocol
@ -505,6 +525,12 @@ class Identity_Crisis {
$returned_values[ $key ] = $normalized_url;
}
// We need to protect WPCOM URLs from search & replace by reversing them. See https://wp.me/pf5801-3R
// Add 'reversed_url' key for backward compatibility
if ( array_key_exists( 'wpcom_home', $returned_values ) && array_key_exists( 'wpcom_siteurl', $returned_values ) ) {
$returned_values['reversed_url'] = true;
$returned_values = self::reverse_wpcom_urls_for_idc( $returned_values );
}
return $returned_values;
}
@ -1286,4 +1312,29 @@ class Identity_Crisis {
return $path;
}
/**
* Adds `url_secret` to the `jetpack.idcUrlValidation` URL validation endpoint.
* Adds `url_secret_error` in case of an error.
*
* @param array $response The endpoint response that we're modifying.
*
* @return array
* phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag -- The exception is being caught, false positive.
*/
public static function add_secret_to_url_validation_response( array $response ) {
try {
$secret = new URL_Secret();
$secret->create();
if ( $secret->exists() ) {
$response['url_secret'] = $secret->get_secret();
}
} catch ( Exception $e ) {
$response['url_secret_error'] = new WP_Error( 'unable_to_create_url_secret', $e->getMessage() );
}
return $response;
}
}

View File

@ -8,6 +8,7 @@
namespace Automattic\Jetpack\IdentityCrisis;
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Connection\Rest_Authentication;
use Jetpack_Options;
use WP_Error;
use WP_REST_Server;
@ -62,6 +63,17 @@ class REST_Endpoints {
),
)
);
// Fetch URL verification secret.
register_rest_route(
'jetpack/v4',
'/identity-crisis/url-secret',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( static::class, 'fetch_url_secret' ),
'permission_callback' => array( static::class, 'url_secret_permission_check' ),
)
);
}
/**
@ -184,4 +196,41 @@ class REST_Endpoints {
return new WP_Error( 'invalid_user_permission_identity_crisis', $error_msg, array( 'status' => rest_authorization_required_code() ) );
}
/**
* Endpoint for fetching the existing secret.
*
* @return WP_Error|\WP_REST_Response
*/
public static function fetch_url_secret() {
$secret = new URL_Secret();
if ( ! $secret->exists() ) {
return new WP_Error( 'missing_url_secret', esc_html__( 'URL secret does not exist.', 'jetpack-idc' ) );
}
return rest_ensure_response(
array(
'code' => 'success',
'data' => array(
'secret' => $secret->get_secret(),
'expires_at' => $secret->get_expires_at(),
),
)
);
}
/**
* Verify url_secret create/fetch permissions (valid blog token authentication).
*
* @return true|WP_Error
*/
public static function url_secret_permission_check() {
return Rest_Authentication::is_signed_with_blog_token()
? true
: new WP_Error(
'invalid_user_permission_identity_crisis',
esc_html__( 'You do not have the correct user permissions to perform this action.', 'jetpack-idc' ),
array( 'status' => rest_authorization_required_code() )
);
}
}

View File

@ -10,7 +10,7 @@ namespace Automattic\Jetpack\IdentityCrisis;
use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Identity_Crisis;
use Automattic\Jetpack\Status\Host;
use Automattic\Jetpack\Tracking as Tracking;
use Automattic\Jetpack\Tracking;
use Jetpack_Options;
use Jetpack_Tracks_Client;
@ -119,6 +119,15 @@ class UI {
'consumerData' => static::get_consumer_data(),
'isAdmin' => $is_admin,
'possibleDynamicSiteUrlDetected' => $possible_dynamic_site_url_detected,
/**
* Use the filter to provide custom HTML elecontainer ID.
*
* @since 0.10.0
*
* @param string|null $containerID The container ID.
*/
'containerID' => apply_filters( 'identity_crisis_container_id', null ),
);
}
@ -189,5 +198,4 @@ class UI {
return 'self-hosted';
}
}

View File

@ -0,0 +1,134 @@
<?php
/**
* IDC URL secret functionality.
*
* @package automattic/jetpack-identity-crisis
*/
namespace Automattic\Jetpack\IdentityCrisis;
use Jetpack_Options;
/**
* IDC URL secret functionality.
* A short-lived secret used to verify whether an IDC is coming from the same vs a different Jetpack site.
*/
class URL_Secret {
/**
* The options key used to store the secret.
*/
const OPTION_KEY = 'identity_crisis_url_secret';
/**
* Secret lifespan (5 minutes)
*/
const LIFESPAN = 300;
/**
* The URL secret string.
*
* @var string|null
*/
private $secret = null;
/**
* The URL secret expiration date in unix timestamp.
*
* @var string|null
*/
private $expires_at = null;
/**
* Initialize the class.
*/
public function __construct() {
$secret_data = $this->fetch();
if ( $secret_data !== null ) {
$this->secret = $secret_data['secret'];
$this->expires_at = $secret_data['expires_at'];
}
}
/**
* Fetch the URL secret from the database.
*
* @return array|null
*/
private function fetch() {
$data = Jetpack_Options::get_option( static::OPTION_KEY );
if ( $data === false || empty( $data['secret'] ) || empty( $data['expires_at'] ) ) {
return null;
}
if ( time() > $data['expires_at'] ) {
Jetpack_Options::delete_option( static::OPTION_KEY );
return null;
}
return $data;
}
/**
* Create new secret and save it in the options.
*
* @throws Exception Thrown if unable to save the new secret.
*
* @return bool
*/
public function create() {
$secret_data = array(
'secret' => $this->generate_secret(),
'expires_at' => time() + static::LIFESPAN,
);
$result = Jetpack_Options::update_option( static::OPTION_KEY, $secret_data );
if ( ! $result ) {
throw new Exception( esc_html__( 'Unable to save new URL secret', 'jetpack-idc' ) );
}
$this->secret = $secret_data['secret'];
$this->expires_at = $secret_data['expires_at'];
return true;
}
/**
* Get the URL secret.
*
* @return string|null
*/
public function get_secret() {
return $this->secret;
}
/**
* Get the URL secret expiration date.
*
* @return string|null
*/
public function get_expires_at() {
return $this->expires_at;
}
/**
* Check if the secret exists.
*
* @return bool
*/
public function exists() {
return $this->secret && $this->expires_at;
}
/**
* Generate the secret string.
*
* @return string
*/
private function generate_secret() {
return wp_generate_password( 12, false );
}
}