updated plugin Jetpack Protect
version 1.4.2
This commit is contained in:
@ -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() );
|
||||
|
@ -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 {}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user