Skip to content

Commit 2bb252a

Browse files
Editor: Skip cross-origin isolation for third-party page builders.
Document-Isolation-Policy (DIP) isolates the document and blocks same-origin iframe access that page builders rely on. Skip DIP setup when a third-party page builder overrides the block editor via a custom `action` query parameter. Also gates `wp_is_client_side_media_processing_enabled()` on a secure context check, since `SharedArrayBuffer` requires a secure context (HTTPS or localhost). Props adamsilverstein, westonruter, mukesh27, louiswol94, manhar, illuminea. Fixes #64803. git-svn-id: https://develop.svn.wordpress.org/trunk@61947 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 2307f48 commit 2bb252a

4 files changed

Lines changed: 118 additions & 7 deletions

File tree

src/wp-includes/media.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6411,14 +6411,18 @@ function wp_get_image_editor_output_format( $filename, $mime_type ) {
64116411
* @return bool Whether client-side media processing is enabled.
64126412
*/
64136413
function wp_is_client_side_media_processing_enabled(): bool {
6414+
// This is due to SharedArrayBuffer requiring a secure context.
6415+
$host = strtolower( (string) strtok( $_SERVER['HTTP_HOST'] ?? '', ':' ) );
6416+
$enabled = ( is_ssl() || 'localhost' === $host || str_ends_with( $host, '.localhost' ) );
6417+
64146418
/**
64156419
* Filters whether client-side media processing is enabled.
64166420
*
64176421
* @since 7.0.0
64186422
*
6419-
* @param bool $enabled Whether client-side media processing is enabled. Default true.
6423+
* @param bool $enabled Whether client-side media processing is enabled. Default true if the page is served in a secure context.
64206424
*/
6421-
return (bool) apply_filters( 'wp_client_side_media_processing_enabled', true );
6425+
return (bool) apply_filters( 'wp_client_side_media_processing_enabled', $enabled );
64226426
}
64236427

64246428
/**
@@ -6431,7 +6435,7 @@ function wp_set_client_side_media_processing_flag(): void {
64316435
return;
64326436
}
64336437

6434-
wp_add_inline_script( 'wp-block-editor', 'window.__clientSideMediaProcessing = true', 'before' );
6438+
wp_add_inline_script( 'wp-block-editor', 'window.__clientSideMediaProcessing = true;', 'before' );
64356439

64366440
$chromium_version = wp_get_chromium_major_version();
64376441

@@ -6477,6 +6481,10 @@ function wp_get_chromium_major_version(): ?int {
64776481
* media processing in the editor. Uses Document-Isolation-Policy
64786482
* on supported browsers (Chromium 137+).
64796483
*
6484+
* Skips setup when a third-party page builder overrides the block
6485+
* editor via a custom `action` query parameter, as DIP would block
6486+
* same-origin iframe access that these editors rely on.
6487+
*
64806488
* @since 7.0.0
64816489
*/
64826490
function wp_set_up_cross_origin_isolation(): void {
@@ -6494,6 +6502,15 @@ function wp_set_up_cross_origin_isolation(): void {
64946502
return;
64956503
}
64966504

6505+
/*
6506+
* Skip when a third-party page builder overrides the block editor.
6507+
* DIP isolates the document into its own agent cluster,
6508+
* which blocks same-origin iframe access that these editors rely on.
6509+
*/
6510+
if ( isset( $_GET['action'] ) && 'edit' !== $_GET['action'] ) {
6511+
return;
6512+
}
6513+
64976514
// Cross-origin isolation is not needed if users can't upload files anyway.
64986515
if ( ! current_user_can( 'upload_files' ) ) {
64996516
return;

tests/phpunit/tests/media/wpCrossOriginIsolation.php

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,36 @@
66
* @group media
77
* @covers ::wp_set_up_cross_origin_isolation
88
* @covers ::wp_start_cross_origin_isolation_output_buffer
9+
* @covers ::wp_is_client_side_media_processing_enabled
910
*/
1011
class Tests_Media_wpCrossOriginIsolation extends WP_UnitTestCase {
1112

1213
/**
1314
* Original HTTP_USER_AGENT value.
14-
*
15-
* @var string|null
1615
*/
17-
private $original_user_agent;
16+
private ?string $original_user_agent;
17+
18+
/**
19+
* Original HTTP_HOST value.
20+
*/
21+
private ?string $original_http_host;
22+
23+
/**
24+
* Original HTTPS value.
25+
*/
26+
private ?string $original_https;
27+
28+
/**
29+
* Original $_GET['action'] value.
30+
*/
31+
private ?string $original_get_action;
1832

1933
public function set_up() {
2034
parent::set_up();
21-
$this->original_user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : null;
35+
$this->original_user_agent = $_SERVER['HTTP_USER_AGENT'] ?? null;
36+
$this->original_http_host = $_SERVER['HTTP_HOST'] ?? null;
37+
$this->original_https = $_SERVER['HTTPS'] ?? null;
38+
$this->original_get_action = $_GET['action'] ?? null;
2239
}
2340

2441
public function tear_down() {
@@ -28,6 +45,24 @@ public function tear_down() {
2845
$_SERVER['HTTP_USER_AGENT'] = $this->original_user_agent;
2946
}
3047

48+
if ( null === $this->original_http_host ) {
49+
unset( $_SERVER['HTTP_HOST'] );
50+
} else {
51+
$_SERVER['HTTP_HOST'] = $this->original_http_host;
52+
}
53+
54+
if ( null === $this->original_https ) {
55+
unset( $_SERVER['HTTPS'] );
56+
} else {
57+
$_SERVER['HTTPS'] = $this->original_https;
58+
}
59+
60+
if ( null === $this->original_get_action ) {
61+
unset( $_GET['action'] );
62+
} else {
63+
$_GET['action'] = $this->original_get_action;
64+
}
65+
3166
// Clean up any output buffers started during tests.
3267
while ( ob_get_level() > 1 ) {
3368
ob_end_clean();
@@ -124,6 +159,32 @@ public function test_does_not_start_output_buffer_for_safari() {
124159
$this->assertSame( $level_before, $level_after, 'Output buffer should not be started for Safari.' );
125160
}
126161

162+
/**
163+
* @ticket 64803
164+
*/
165+
public function test_client_side_processing_disabled_on_non_secure_origin() {
166+
$_SERVER['HTTP_HOST'] = 'example.com';
167+
$_SERVER['HTTPS'] = '';
168+
169+
$this->assertFalse(
170+
wp_is_client_side_media_processing_enabled(),
171+
'Client-side media processing should be disabled on non-secure, non-localhost origins.'
172+
);
173+
}
174+
175+
/**
176+
* @ticket 64803
177+
*/
178+
public function test_client_side_processing_enabled_on_localhost() {
179+
$_SERVER['HTTP_HOST'] = 'localhost';
180+
$_SERVER['HTTPS'] = '';
181+
182+
$this->assertTrue(
183+
wp_is_client_side_media_processing_enabled(),
184+
'Client-side media processing should be enabled on localhost.'
185+
);
186+
}
187+
127188
/**
128189
* This test must run in a separate process because the output buffer
129190
* callback sends HTTP headers via header(), which would fail in the

tests/phpunit/tests/rest-api/rest-attachments-controller.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3162,6 +3162,12 @@ static function ( $data ) use ( &$captured_data ) {
31623162
* @requires function imagejpeg
31633163
*/
31643164
public function test_sideload_scaled_image() {
3165+
add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
3166+
// Reinitialize REST server so the sideload route is registered.
3167+
global $wp_rest_server;
3168+
$wp_rest_server = new Spy_REST_Server();
3169+
do_action( 'rest_api_init', $wp_rest_server );
3170+
31653171
wp_set_current_user( self::$author_id );
31663172

31673173
// First, create an attachment.
@@ -3215,6 +3221,12 @@ public function test_sideload_scaled_image() {
32153221
* @requires function imagejpeg
32163222
*/
32173223
public function test_sideload_scaled_image_requires_auth() {
3224+
add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
3225+
// Reinitialize REST server so the sideload route is registered.
3226+
global $wp_rest_server;
3227+
$wp_rest_server = new Spy_REST_Server();
3228+
do_action( 'rest_api_init', $wp_rest_server );
3229+
32183230
wp_set_current_user( self::$author_id );
32193231

32203232
// Create an attachment.
@@ -3244,6 +3256,12 @@ public function test_sideload_scaled_image_requires_auth() {
32443256
* @ticket 64737
32453257
*/
32463258
public function test_sideload_route_includes_scaled_enum() {
3259+
add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
3260+
// Reinitialize REST server so the sideload route is registered.
3261+
global $wp_rest_server;
3262+
$wp_rest_server = new Spy_REST_Server();
3263+
do_action( 'rest_api_init', $wp_rest_server );
3264+
32473265
$server = rest_get_server();
32483266
$routes = $server->get_routes();
32493267

@@ -3266,6 +3284,12 @@ public function test_sideload_route_includes_scaled_enum() {
32663284
* @requires function imagejpeg
32673285
*/
32683286
public function test_sideload_scaled_unique_filename() {
3287+
add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
3288+
// Reinitialize REST server so the sideload route is registered.
3289+
global $wp_rest_server;
3290+
$wp_rest_server = new Spy_REST_Server();
3291+
do_action( 'rest_api_init', $wp_rest_server );
3292+
32693293
wp_set_current_user( self::$author_id );
32703294

32713295
// Create an attachment.
@@ -3300,6 +3324,12 @@ public function test_sideload_scaled_unique_filename() {
33003324
* @requires function imagejpeg
33013325
*/
33023326
public function test_sideload_scaled_unique_filename_conflict() {
3327+
add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
3328+
// Reinitialize REST server so the sideload route is registered.
3329+
global $wp_rest_server;
3330+
$wp_rest_server = new Spy_REST_Server();
3331+
do_action( 'rest_api_init', $wp_rest_server );
3332+
33033333
wp_set_current_user( self::$author_id );
33043334

33053335
// Create the first attachment.

tests/phpunit/tests/rest-api/rest-schema-setup.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase {
1616
public function set_up() {
1717
parent::set_up();
1818

19+
// Ensure client-side media processing is enabled so the sideload route is registered.
20+
add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
21+
1922
/** @var WP_REST_Server $wp_rest_server */
2023
global $wp_rest_server;
2124
$wp_rest_server = new Spy_REST_Server();

0 commit comments

Comments
 (0)