updated plugin Jetpack Protect version 2.0.0

This commit is contained in:
2024-02-08 12:31:43 +00:00
committed by Gitium
parent ce653dd56c
commit 8d5e7cc070
192 changed files with 5244 additions and 2003 deletions

View File

@ -5,6 +5,44 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.15.0] - 2024-01-18
### Added
- Adding support for IDC when site URL is an IP address. [#34753]
## [0.14.1] - 2024-01-04
### Changed
- Updated package dependencies. [#34815]
## [0.14.0] - 2023-12-06
### Added
- Send a verifcation secret when URL is IP. [#34436]
### Changed
- Updated package dependencies. [#34416]
## [0.13.0] - 2023-12-03
### Added
- Store for persistent blog ID for multi-URL purposes. [#34262]
### Changed
- Updated package dependencies. [#34411]
## [0.12.1] - 2023-11-24
## [0.12.0] - 2023-11-20
### Added
- Added idc query argument to url for tracking multisite idcs. [#34090]
### Changed
- Replaced usage of strpos() with str_starts_with(). [#34135]
- Updated required PHP version to >= 7.0. [#34192]
## [0.11.3] - 2023-11-14
### Changed
- Updated package dependencies. [#34093]
## [0.11.2] - 2023-11-03
## [0.11.1] - 2023-10-19
### Changed
- Updated package dependencies. [#33687]
@ -435,6 +473,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated package dependencies.
- Use Connection/Urls for home_url and site_url functions migrated from Sync.
[0.15.0]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.14.1...v0.15.0
[0.14.1]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.14.0...v0.14.1
[0.14.0]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.13.0...v0.14.0
[0.13.0]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.12.1...v0.13.0
[0.12.1]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.12.0...v0.12.1
[0.12.0]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.11.3...v0.12.0
[0.11.3]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.11.2...v0.11.3
[0.11.2]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.11.1...v0.11.2
[0.11.1]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.11.0...v0.11.1
[0.11.0]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.10.7...v0.11.0
[0.10.7]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.10.6...v0.10.7

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '40e79e96702db6f6da6d');
<?php return array('dependencies' => array('react', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '2770a423a89e22f7aed3');

View File

@ -4,14 +4,15 @@
"type": "jetpack-library",
"license": "GPL-2.0-or-later",
"require": {
"automattic/jetpack-connection": "^1.58.2",
"automattic/jetpack-constants": "^1.6.23",
"automattic/jetpack-status": "^1.18.5",
"automattic/jetpack-logo": "^1.6.3",
"automattic/jetpack-assets": "^1.18.13"
"php": ">=7.0",
"automattic/jetpack-connection": "^2.2.0",
"automattic/jetpack-constants": "^2.0.0",
"automattic/jetpack-status": "^2.0.2",
"automattic/jetpack-logo": "^2.0.0",
"automattic/jetpack-assets": "^2.0.4"
},
"require-dev": {
"automattic/jetpack-changelogger": "^3.3.11",
"automattic/jetpack-changelogger": "^4.0.5",
"yoast/phpunit-polyfills": "1.1.0",
"automattic/wordbless": "@dev"
},
@ -56,7 +57,7 @@
"link-template": "https://github.com/Automattic/jetpack-identity-crisis/compare/v${old}...v${new}"
},
"branch-alias": {
"dev-trunk": "0.11.x-dev"
"dev-trunk": "0.15.x-dev"
}
},
"config": {

View File

@ -27,7 +27,12 @@ class Identity_Crisis {
/**
* Package Version
*/
const PACKAGE_VERSION = '0.11.1';
const PACKAGE_VERSION = '0.15.0';
/**
* Persistent WPCOM blog ID that stays in the options after disconnect.
*/
const PERSISTENT_BLOG_ID_OPTION_NAME = 'jetpack_persistent_blog_id';
/**
* Instance of the object.
@ -87,9 +92,13 @@ 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_connection_validate_urls_for_idc_mitigation_response', array( static::class, 'add_ip_requester_to_url_validation_response' ) );
add_filter( 'jetpack_options', array( static::class, 'reverse_wpcom_urls_for_idc' ) );
add_filter( 'jetpack_register_request_body', array( static::class, 'register_request_body' ) );
add_action( 'jetpack_site_registered', array( static::class, 'site_registered' ) );
$urls_in_crisis = self::check_identity_crisis();
if ( false === $urls_in_crisis ) {
return;
@ -113,6 +122,8 @@ class Identity_Crisis {
$connection->disconnect_site( false );
}
delete_option( static::PERSISTENT_BLOG_ID_OPTION_NAME );
// Clear IDC options.
self::clear_all_idc_options();
}
@ -199,10 +210,18 @@ class Identity_Crisis {
|| self::validate_sync_error_idc_option() ) {
return $url;
}
$home_url = Urls::home_url();
$site_url = Urls::site_url();
$hostname = wp_parse_url( $site_url, PHP_URL_HOST );
// If request is from an IP, make sure ip_requester option is set
if ( self::url_is_ip( $hostname ) ) {
self::maybe_update_ip_requester( $hostname );
}
$query_args = array(
'home' => Urls::home_url(),
'siteurl' => Urls::site_url(),
'home' => $home_url,
'siteurl' => $site_url,
);
if ( self::should_handle_idc() ) {
@ -213,6 +232,10 @@ class Identity_Crisis {
$query_args['migrate_for_idc'] = true;
}
if ( is_multisite() ) {
$query_args['multisite'] = true;
}
return add_query_arg( $query_args, $url );
}
@ -1337,4 +1360,153 @@ class Identity_Crisis {
return $response;
}
/**
* Check if URL is an IP.
*
* @param string $hostname The hostname to check.
* @return bool
*/
public static function url_is_ip( $hostname = null ) {
if ( ! $hostname ) {
$hostname = wp_parse_url( Urls::site_url(), PHP_URL_HOST );
}
$is_ip = filter_var( $hostname, FILTER_VALIDATE_IP ) !== false ? $hostname : false;
return $is_ip;
}
/**
* Add IDC-related data to the registration query.
*
* @param array $params The existing query params.
*
* @return array
*/
public static function register_request_body( array $params ) {
$persistent_blog_id = get_option( static::PERSISTENT_BLOG_ID_OPTION_NAME );
if ( $persistent_blog_id ) {
$params['persistent_blog_id'] = $persistent_blog_id;
$params['url_secret'] = URL_Secret::create_secret( 'registration_request_url_secret_failed' );
}
return $params;
}
/**
* Set the necessary options when site gets registered.
*
* @param int $blog_id The blog ID.
*
* @return void
*/
public static function site_registered( $blog_id ) {
update_option( static::PERSISTENT_BLOG_ID_OPTION_NAME, (int) $blog_id, false );
}
/**
* Check if we need to update the ip_requester option.
*
* @param string $hostname The hostname to check.
*
* @return void
*/
public static function maybe_update_ip_requester( $hostname ) {
// Check if transient exists
$transient_key = ip2long( $hostname );
if ( $transient_key && ! get_transient( 'jetpack_idc_ip_requester_' . $transient_key ) ) {
self::set_ip_requester_for_idc( $hostname, $transient_key );
}
}
/**
* If URL is an IP, add the IP value to the ip_requester option with its expiry value.
*
* @param string $hostname The hostname to check.
* @param int $transient_key The transient key.
*/
public static function set_ip_requester_for_idc( $hostname, $transient_key ) {
// Check if option exists
$data = Jetpack_Options::get_option( 'identity_crisis_ip_requester' );
$ip_requester = array(
'ip' => $hostname,
'expires_at' => time() + 360,
);
// If not set, initialize it
if ( empty( $data ) ) {
$data = array( $ip_requester );
} else {
$updated_data = array();
$updated_value = false;
// Remove expired values and update existing IP
foreach ( $data as $item ) {
if ( time() > $item['expires_at'] ) {
continue; // Skip expired IP
}
if ( $item['ip'] === $hostname ) {
$item['expires_at'] = time() + 360;
$updated_value = true;
}
$updated_data[] = $item;
}
if ( ! $updated_value || empty( $updated_data ) ) {
$updated_data[] = $ip_requester;
}
$data = $updated_data;
}
self::update_ip_requester( $data, $transient_key );
}
/**
* Update the ip_requester option and set a transient to expire in 5 minutes.
*
* @param array $data The data to be updated.
* @param int $transient_key The transient key.
*
* @return void
*/
public static function update_ip_requester( $data, $transient_key ) {
// Update the option
$updated = Jetpack_Options::update_option( 'identity_crisis_ip_requester', $data );
// Set a transient to expire in 5 minutes
if ( $updated ) {
$transient_name = 'jetpack_idc_ip_requester_' . $transient_key;
set_transient( $transient_name, $data, 300 );
}
}
/**
* Adds `ip_requester` to the `jetpack.idcUrlValidation` URL validation endpoint.
*
* @param array $response The enpoint response that we're modifying.
*
* @return array
*/
public static function add_ip_requester_to_url_validation_response( array $response ) {
$requesters = Jetpack_Options::get_option( 'identity_crisis_ip_requester' );
if ( $requesters ) {
// Loop through the requesters and add the IP to the response if it's not expired
$i = 0;
foreach ( $requesters as $ip ) {
if ( $ip['expires_at'] > time() ) {
$response['ip_requester'][] = $ip['ip'];
}
// Limit the response to five IPs
$i = ++$i;
if ( $i === 5 ) {
break;
}
}
return $response;
}
}
}

View File

@ -74,6 +74,24 @@ class REST_Endpoints {
'permission_callback' => array( static::class, 'url_secret_permission_check' ),
)
);
// Fetch URL verification secret.
register_rest_route(
'jetpack/v4',
'/identity-crisis/compare-url-secret',
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( static::class, 'compare_url_secret' ),
'permission_callback' => array( static::class, 'compare_url_secret_permission_check' ),
'args' => array(
'secret' => array(
'description' => __( 'URL secret to compare to the ones stored in the database.', 'jetpack-idc' ),
'type' => 'string',
'required' => true,
),
),
)
);
}
/**
@ -219,6 +237,31 @@ class REST_Endpoints {
);
}
/**
* Endpoint for comparing the existing secret.
*
* @param \WP_REST_Request $request The request sent to the WP REST API.
*
* @return WP_Error|\WP_REST_Response
*/
public static function compare_url_secret( $request ) {
$match = false;
$storage = new URL_Secret();
if ( $storage->exists() ) {
$remote_secret = $request->get_param( 'secret' );
$match = $remote_secret && hash_equals( $storage->get_secret(), $remote_secret );
}
return rest_ensure_response(
array(
'code' => 'success',
'match' => $match,
)
);
}
/**
* Verify url_secret create/fetch permissions (valid blog token authentication).
*
@ -233,4 +276,20 @@ class REST_Endpoints {
array( 'status' => rest_authorization_required_code() )
);
}
/**
* The endpoint is only available on non-connected sites.
* use `/identity-crisis/url-secret` for connected sites.
*
* @return true|WP_Error
*/
public static function compare_url_secret_permission_check() {
return ( new Connection_Manager() )->is_connected()
? new WP_Error(
'invalid_connection_status',
esc_html__( 'The endpoint is not available on connected sites.', 'jetpack-idc' ),
array( 'status' => 403 )
)
: true;
}
}

View File

@ -153,7 +153,7 @@ class UI {
$priority1 = ( array_key_exists( 'priority', $c1 ) && (int) $c1['priority'] ) ? (int) $c1['priority'] : 10;
$priority2 = ( array_key_exists( 'priority', $c2 ) && (int) $c2['priority'] ) ? (int) $c2['priority'] : 10;
return $priority1 > $priority2 ? 1 : -1;
return $priority1 <=> $priority2;
}
);
@ -165,7 +165,7 @@ class UI {
continue;
}
if ( isset( $_SERVER['REQUEST_URI'] ) && 0 === strpos( filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ) ), $consumer['admin_page'] ) && strlen( $consumer['admin_page'] ) > $consumer_url_length ) {
if ( isset( $_SERVER['REQUEST_URI'] ) && str_starts_with( filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ) ), $consumer['admin_page'] ) && strlen( $consumer['admin_page'] ) > $consumer_url_length ) {
$consumer_chosen = $consumer;
$consumer_url_length = strlen( $consumer['admin_page'] );
}

View File

@ -131,4 +131,27 @@ class URL_Secret {
private function generate_secret() {
return wp_generate_password( 12, false );
}
/**
* Generate secret for response.
*
* @param string $flow used to tell which flow generated the exception.
* @return string
*/
public static function create_secret( $flow = 'generating_secret_failed' ) {
$secret = null;
try {
$secret = new self();
$secret->create();
if ( $secret->exists() ) {
$secret = $secret->get_secret();
}
} catch ( Exception $e ) {
// Track the error and proceed.
( new Tracking() )->record_user_event( $flow, array( 'current_url' => Urls::site_url() ) );
}
return $secret;
}
}